Skip to content
This repository was archived by the owner on Aug 16, 2022. It is now read-only.

Commit a15bd01

Browse files
committed
test: add style compiler tests
1 parent 0c781d0 commit a15bd01

File tree

4 files changed

+255
-84
lines changed

4 files changed

+255
-84
lines changed

package-lock.json

Lines changed: 53 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"rollup-plugin-commonjs": "^8.2.6",
3838
"rollup-plugin-image": "^1.0.2",
3939
"rollup-plugin-node-resolve": "^3.0.2",
40+
"sugarss": "^1.0.1",
4041
"vue": "^2.5.13"
4142
},
4243
"peerDependencies": {
Lines changed: 67 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,79 @@
11
const postcss = require('postcss')
22
const selectorParser = require('postcss-selector-parser')
33

4-
module.exports = postcss.plugin('add-id', function (opts) {
5-
return function (root) {
6-
const keyframes = Object.create(null)
4+
module.exports = postcss.plugin('add-id', ({ id }) => root => {
5+
const keyframes = Object.create(null)
76

8-
root.each(function rewriteSelector (node) {
9-
if (!node.selector) {
10-
// handle media queries
11-
if (node.type === 'atrule') {
12-
if (node.name === 'media') {
13-
node.each(rewriteSelector)
14-
} else if (node.name === 'keyframes') {
15-
// register keyframes
16-
keyframes[node.params] = node.params = node.params + '-' + opts.id
17-
}
7+
root.each(function rewriteSelector (node) {
8+
if (!node.selector) {
9+
// handle media queries
10+
if (node.type === 'atrule') {
11+
if (node.name === 'media' || node.name === 'supports') {
12+
node.each(rewriteSelector)
13+
} else if (/-?keyframes$/.test(node.name)) {
14+
// register keyframes
15+
keyframes[node.params] = node.params = node.params + '-' + id
1816
}
19-
return
2017
}
21-
node.selector = selectorParser(function (selectors) {
22-
selectors.each(function (selector) {
23-
let node = null
24-
selector.each(function (n) {
25-
// ">>>" combinator
26-
if (n.type === 'combinator' && n.value === '>>>') {
27-
n.value = ' '
28-
n.spaces.before = n.spaces.after = ''
29-
return false
30-
}
31-
// /deep/ alias for >>>, since >>> doesn't work in SASS
32-
if (n.type === 'tag' && n.value === '/deep/') {
33-
const prev = n.prev()
34-
if (prev.type === 'combinator' && prev.value === ' ') {
35-
prev.remove()
36-
}
37-
n.remove()
38-
return false
18+
return
19+
}
20+
node.selector = selectorParser(selectors => {
21+
selectors.each(selector => {
22+
let node = null
23+
selector.each(n => {
24+
// ">>>" combinator
25+
if (n.type === 'combinator' && n.value === '>>>') {
26+
n.value = ' '
27+
n.spaces.before = n.spaces.after = ''
28+
return false
29+
}
30+
// /deep/ alias for >>>, since >>> doesn't work in SASS
31+
if (n.type === 'tag' && n.value === '/deep/') {
32+
const prev = n.prev()
33+
if (prev && prev.type === 'combinator' && prev.value === ' ') {
34+
prev.remove()
3935
}
40-
if (n.type !== 'pseudo' && n.type !== 'combinator') {
41-
node = n
36+
n.remove()
37+
return false
38+
}
39+
if (n.type !== 'pseudo' && n.type !== 'combinator') {
40+
node = n
41+
}
42+
})
43+
selector.insertAfter(node, selectorParser.attribute({
44+
attribute: id
45+
}))
46+
})
47+
}).process(node.selector).result
48+
})
49+
50+
// If keyframes are found in this <style>, find and rewrite animation names
51+
// in declarations.
52+
// Caveat: this only works for keyframes and animation rules in the same
53+
// <style> element.
54+
if (Object.keys(keyframes).length) {
55+
root.walkDecls(decl => {
56+
// individual animation-name declaration
57+
if (/-?animation-name$/.test(decl.prop)) {
58+
decl.value = decl.value.split(',')
59+
.map(v => keyframes[v.trim()] || v.trim())
60+
.join(',')
61+
}
62+
// shorthand
63+
if (/-?animation$/.test(decl.prop)) {
64+
decl.value = decl.value.split(',')
65+
.map(v => {
66+
const vals = v.trim().split(/\s+/)
67+
const i = vals.findIndex(val => keyframes[val])
68+
if (i !== -1) {
69+
vals.splice(i, 1, keyframes[vals[i]])
70+
return vals.join(' ')
71+
} else {
72+
return v
4273
}
4374
})
44-
selector.insertAfter(node, selectorParser.attribute({
45-
attribute: opts.id
46-
}))
47-
})
48-
}).process(node.selector).result
75+
.join(',')
76+
}
4977
})
50-
51-
// If keyframes are found in this <style>, find and rewrite animation names
52-
// in declarations.
53-
// Caveat: this only works for keyframes and animation rules in the same
54-
// <style> element.
55-
if (Object.keys(keyframes).length) {
56-
root.walkDecls(decl => {
57-
// individual animation-name declaration
58-
if (/-?animation-name$/.test(decl.prop)) {
59-
decl.value = decl.value.split(',')
60-
.map(v => keyframes[v.trim()] || v.trim())
61-
.join(',')
62-
}
63-
// shorthand
64-
if (/-?animation$/.test(decl.prop)) {
65-
decl.value = decl.value.split(',')
66-
.map(v => {
67-
const vals = v.trim().split(/\s+/)
68-
const i = vals.findIndex(val => keyframes[val])
69-
if (i !== -1) {
70-
vals.splice(i, 1, keyframes[vals[i]])
71-
72-
return vals.join(' ')
73-
} else {
74-
return v
75-
}
76-
})
77-
.join(',')
78-
}
79-
})
80-
}
8178
}
8279
})

test/style-compiler.spec.js

Lines changed: 134 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,143 @@
11
const compiler = require('../src/style-compiler')
22

3-
test('should rewrite scoped style', () => {
4-
const style = {
5-
code: '.foo { color: red }',
6-
descriptor: {
7-
scoped: true
8-
}
3+
const style = {
4+
code: `
5+
.test {
6+
color: yellow;
7+
}
8+
.test:after {
9+
content: 'bye!';
10+
}
11+
h1 {
12+
color: green;
13+
}
14+
.anim {
15+
animation: color 5s infinite, other 5s;
16+
}
17+
.anim-2 {
18+
animation-name: color;
19+
animation-duration: 5s;
20+
}
21+
.anim-3 {
22+
animation: 5s color infinite, 5s other;
23+
}
24+
.anim-multiple {
25+
animation: color 5s infinite, opacity 2s;
26+
}
27+
.anim-multiple-2 {
28+
animation-name: color, opacity;
29+
animation-duration: 5s, 2s;
30+
}
31+
32+
@keyframes color {
33+
from { color: red; }
34+
to { color: green; }
35+
}
36+
@-webkit-keyframes color {
37+
from { color: red; }
38+
to { color: green; }
39+
}
40+
@keyframes opacity {
41+
from { opacity: 0; }
42+
to { opacity: 1; }
43+
}
44+
@-webkit-keyframes opacity {
45+
from { opacity: 0; }
46+
to { opacity: 1; }
47+
}
48+
.foo p >>> .bar {
49+
color: red;
50+
}
51+
@media print {
52+
.foo {
53+
color: #000;
54+
}
55+
}
56+
@supports ( color: #000 ) {
57+
.foo {
58+
color: #000;
959
}
10-
const compiled = compiler(style, 'foo.vue', { scopeId: 'xxx', needMap: false })
11-
expect(compiled.code.indexOf('.foo[xxx]')).toBeGreaterThan(-1)
60+
}
61+
`.trim(),
62+
descriptor: {
63+
scoped: true
64+
}
65+
}
66+
67+
const compiled = compiler(style, 'foo.vue', { scopeId: 'xxx' })
68+
69+
test('scoped', () => {
70+
expect(compiled.code).toEqual(expect.stringContaining('.test[xxx]'))
71+
expect(compiled.code).toEqual(expect.stringContaining(`.test[xxx] {\n color: yellow;\n}`))
72+
expect(compiled.code).toEqual(expect.stringContaining(`.test[xxx]:after {\n content: \'bye!\';\n}`))
73+
expect(compiled.code).toEqual(expect.stringContaining(`h1[xxx] {\n color: green;\n}`))
74+
// scoped keyframes
75+
expect(compiled.code).toEqual(expect.stringContaining(`.anim[xxx] {\n animation: color-xxx 5s infinite, other 5s;`))
76+
expect(compiled.code).toEqual(expect.stringContaining(`.anim-2[xxx] {\n animation-name: color-xxx`))
77+
expect(compiled.code).toEqual(expect.stringContaining(`.anim-3[xxx] {\n animation: 5s color-xxx infinite, 5s other;`))
78+
expect(compiled.code).toEqual(expect.stringContaining(`@keyframes color-xxx {`))
79+
expect(compiled.code).toEqual(expect.stringContaining(`@-webkit-keyframes color-xxx {`))
80+
81+
expect(compiled.code).toEqual(expect.stringContaining(`.anim-multiple[xxx] {\n animation: color-xxx 5s infinite,opacity-xxx 2s;`))
82+
expect(compiled.code).toEqual(expect.stringContaining(`.anim-multiple-2[xxx] {\n animation-name: color-xxx,opacity-xxx;`))
83+
expect(compiled.code).toEqual(expect.stringContaining(`@keyframes opacity-xxx {`))
84+
expect(compiled.code).toEqual(expect.stringContaining(`@-webkit-keyframes opacity-xxx {`))
85+
// >>> combinator
86+
expect(compiled.code).toEqual(expect.stringContaining(`.foo p[xxx] .bar {\n color: red;\n}`))
87+
})
88+
89+
test('media query', () => {
90+
expect(compiled.code).toEqual(expect.stringContaining(`@media print {\n.foo[xxx] {\n color: #000;\n}\n}`))
91+
})
92+
93+
test('supports query', () => {
94+
expect(compiled.code).toEqual(expect.stringContaining(`@supports ( color: #000 ) {\n.foo[xxx] {\n color: #000;\n}\n}`))
1295
})
1396

14-
test('should generate sourcemap', () => {
97+
test('sourcemap', () => {
98+
expect(
99+
compiler(style, 'foo.vue', { scopeId: 'xxx' }).map
100+
).toBeTruthy()
101+
102+
expect(
103+
compiler(style, 'foo.vue', { scopeId: 'xxx', needMap: false }).map
104+
).toEqual(undefined)
105+
})
106+
107+
test('css modules', () => {
15108
const style = {
16-
code: '.foo { color: red }',
17-
descriptor: {
18-
scoped: true
19-
}
109+
code: `
110+
.red {
111+
color: red;
112+
}
113+
@keyframes fade {
114+
from { opacity: 1; } to { opacity: 0; }
115+
}
116+
.animate {
117+
animation: fade 1s;
118+
}
119+
`,
120+
descriptor: { module: true }
20121
}
21122
const compiled = compiler(style, 'foo.vue', { scopeId: 'xxx' })
22-
expect(compiled.map).toBeTruthy()
123+
124+
expect(compiled.modules).toHaveProperty('red', expect.stringMatching(/^red-[0-9a-z]{10}$/i))
125+
expect(compiled.modules).toHaveProperty('animate', expect.stringMatching(/^animate-[0-9a-z]{10}$/i))
126+
expect(compiled.modules).toHaveProperty('fade', expect.stringMatching(/^fade-[0-9a-z]{10}$/i))
127+
128+
expect(compiled.code).toEqual(expect.stringContaining(`animation: ${compiled.modules.fade} 1s;`))
129+
})
130+
131+
test('postcss options', () => {
132+
const style = {
133+
code: `
134+
h1
135+
color: red
136+
font-size: 14px
137+
`,
138+
descriptor: {}
139+
}
140+
const compiled = compiler(style, 'foo.vue', { scopeId: 'xxx', options: { parser: require('sugarss') }})
141+
142+
expect(compiled.code).toEqual(expect.stringContaining(`h1 {\n color: red;\n font-size: 14px\n}`))
23143
})

0 commit comments

Comments
 (0)