@projectwallace/css-code-quality 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/css-code-quality.cjs +1 -1
- package/dist/css-code-quality.cjs.map +1 -1
- package/dist/css-code-quality.modern.js +1 -1
- package/dist/css-code-quality.modern.js.map +1 -1
- package/dist/css-code-quality.module.js +1 -1
- package/dist/css-code-quality.module.js.map +1 -1
- package/dist/css-code-quality.umd.js +1 -1
- package/dist/css-code-quality.umd.js.map +1 -1
- package/package.json +13 -7
- package/src/complexity.js +126 -0
- package/src/complexity.test.js +126 -0
- package/src/core.js +47 -0
- package/src/core.test.js +11 -0
- package/src/index.js +7 -0
- package/src/index.test.js +20 -0
- package/src/maintainability.js +150 -0
- package/src/maintainability.test.js +191 -0
- package/src/performance.js +77 -0
- package/src/performance.test.js +194 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export const guards = [
|
|
2
|
+
|
|
3
|
+
// Should not contain @import rules
|
|
4
|
+
result => ({
|
|
5
|
+
id: 'Imports',
|
|
6
|
+
score: result.atrules.import.total * 10,
|
|
7
|
+
value: result.atrules.import.total,
|
|
8
|
+
actuals: Object.keys(result.atrules.import.unique),
|
|
9
|
+
}),
|
|
10
|
+
|
|
11
|
+
// Should not contain empty rules
|
|
12
|
+
result => ({
|
|
13
|
+
id: 'EmptyRules',
|
|
14
|
+
score: result.rules.empty.total,
|
|
15
|
+
value: result.rules.empty.total,
|
|
16
|
+
}),
|
|
17
|
+
|
|
18
|
+
// Too many selectors appear multiple times
|
|
19
|
+
result => {
|
|
20
|
+
const outcome = {
|
|
21
|
+
id: 'SelectorDuplications',
|
|
22
|
+
score: 0,
|
|
23
|
+
value: 1 - result.selectors.uniquenessRatio,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (result.selectors.uniquenessRatio < 0.66) {
|
|
27
|
+
outcome.score = Math.floor((1 - result.selectors.uniquenessRatio) * 10)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return outcome
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// Too many declarations appear multiple times
|
|
34
|
+
result => {
|
|
35
|
+
const outcome = {
|
|
36
|
+
id: 'DeclarationDuplications',
|
|
37
|
+
score: 0,
|
|
38
|
+
value: 1 - result.declarations.unique.ratio,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (result.declarations.unique.ratio < 0.66) {
|
|
42
|
+
outcome.score = Math.floor((1 - result.declarations.unique.ratio) * 10)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return outcome
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// The total amount of CSS should not be too high
|
|
49
|
+
result => ({
|
|
50
|
+
id: 'CssSize',
|
|
51
|
+
score: result.stylesheet.size > 200_000 ? 5 : 0,
|
|
52
|
+
value: result.stylesheet.size,
|
|
53
|
+
}),
|
|
54
|
+
|
|
55
|
+
// Should not contain (too much) comments
|
|
56
|
+
// Deduct 1 point for every 250 bytes
|
|
57
|
+
result => {
|
|
58
|
+
const { comments } = result.stylesheet
|
|
59
|
+
return {
|
|
60
|
+
id: 'TooMuchComments',
|
|
61
|
+
score: Math.min(10, Math.floor(comments.size / 250)),
|
|
62
|
+
value: comments.size,
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// Should not contain too much embedded content
|
|
67
|
+
// Deduct 1 point for every 250 bytes
|
|
68
|
+
result => {
|
|
69
|
+
const { size } = result.stylesheet.embeddedContent
|
|
70
|
+
return {
|
|
71
|
+
id: 'TooMuchEmbeddedContent',
|
|
72
|
+
score: Math.min(20, Math.floor(size.total / 250)),
|
|
73
|
+
value: size.total,
|
|
74
|
+
actuals: Object.keys(result.stylesheet.embeddedContent.unique),
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
]
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { suite } from 'uvu'
|
|
2
|
+
import * as assert from 'uvu/assert'
|
|
3
|
+
import { calculate } from './index.js'
|
|
4
|
+
|
|
5
|
+
const Performance = suite('Performance')
|
|
6
|
+
|
|
7
|
+
Performance('does not deduct points for not having @import', () => {
|
|
8
|
+
const actual = calculate(`
|
|
9
|
+
test { color: green; }
|
|
10
|
+
`)
|
|
11
|
+
assert.is(actual.performance.score, 100)
|
|
12
|
+
assert.is(actual.performance.violations.length, 0)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
Performance('deducts points for having a single @import', () => {
|
|
16
|
+
const actual = calculate(`
|
|
17
|
+
@import url('some-url');
|
|
18
|
+
test { color: green; }
|
|
19
|
+
`)
|
|
20
|
+
assert.is(actual.performance.score, 90)
|
|
21
|
+
assert.equal(actual.performance.violations, [
|
|
22
|
+
{
|
|
23
|
+
id: 'Imports',
|
|
24
|
+
value: 1,
|
|
25
|
+
score: 10,
|
|
26
|
+
actuals: [`url('some-url')`],
|
|
27
|
+
},
|
|
28
|
+
])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
Performance('deducts points for having multiple @imports', () => {
|
|
32
|
+
const actual = calculate(`
|
|
33
|
+
@import url('some-url');
|
|
34
|
+
@import url('another-url');
|
|
35
|
+
test { color: green; }
|
|
36
|
+
`)
|
|
37
|
+
assert.is(actual.performance.score, 80)
|
|
38
|
+
assert.equal(actual.performance.violations, [
|
|
39
|
+
{
|
|
40
|
+
id: 'Imports',
|
|
41
|
+
value: 2,
|
|
42
|
+
score: 20,
|
|
43
|
+
actuals: [`url('some-url')`, `url('another-url')`],
|
|
44
|
+
},
|
|
45
|
+
])
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
Performance('does not deduct points for not having empty rules', () => {
|
|
49
|
+
const actual = calculate(`test { color: green; }`)
|
|
50
|
+
assert.is(actual.performance.score, 100)
|
|
51
|
+
assert.is(actual.performance.violations.length, 0)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
Performance('deducts points for having a single empty rule', () => {
|
|
55
|
+
const actual = calculate(`
|
|
56
|
+
test-empty {}
|
|
57
|
+
test { color: green; }
|
|
58
|
+
`)
|
|
59
|
+
assert.is(actual.performance.score, 99)
|
|
60
|
+
assert.equal(actual.performance.violations, [
|
|
61
|
+
{
|
|
62
|
+
id: 'EmptyRules',
|
|
63
|
+
score: 1,
|
|
64
|
+
value: 1,
|
|
65
|
+
}
|
|
66
|
+
])
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
Performance('deducts points for having multiple empty rules', () => {
|
|
70
|
+
const actual = calculate(`
|
|
71
|
+
test-empty1 {}
|
|
72
|
+
test-empty2 {}
|
|
73
|
+
test { color: green; }
|
|
74
|
+
`)
|
|
75
|
+
assert.is(actual.performance.score, 98)
|
|
76
|
+
assert.equal(actual.performance.violations, [
|
|
77
|
+
{
|
|
78
|
+
id: 'EmptyRules',
|
|
79
|
+
score: 2,
|
|
80
|
+
value: 2,
|
|
81
|
+
},
|
|
82
|
+
])
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
Performance('does not deduct points for having unique selectors', () => {
|
|
86
|
+
const actual = calculate(`
|
|
87
|
+
test1 { color: green; }
|
|
88
|
+
test2 { color: red; }
|
|
89
|
+
`)
|
|
90
|
+
assert.is(actual.performance.score, 100)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
Performance('deducts points for having low selector uniqueness', () => {
|
|
94
|
+
const actual = calculate(`
|
|
95
|
+
test1 { color: green; }
|
|
96
|
+
test1 { color: red; }
|
|
97
|
+
test2 { color: magenta; }
|
|
98
|
+
test2 { color: blue; }
|
|
99
|
+
`)
|
|
100
|
+
assert.is(actual.performance.score, 95)
|
|
101
|
+
assert.equal(actual.performance.violations, [
|
|
102
|
+
{
|
|
103
|
+
id: 'SelectorDuplications',
|
|
104
|
+
score: 5,
|
|
105
|
+
value: 2 / 4
|
|
106
|
+
},
|
|
107
|
+
])
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
Performance('does not deduct points for having unique declarations', () => {
|
|
111
|
+
const actual = calculate(`
|
|
112
|
+
test1 { color: green; }
|
|
113
|
+
test2 { color: red; }
|
|
114
|
+
`)
|
|
115
|
+
assert.is(actual.performance.score, 100)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
Performance('deducts points for having low declaration uniqueness', () => {
|
|
119
|
+
const actual = calculate(`
|
|
120
|
+
test1 { color: green; }
|
|
121
|
+
test2 { color: green; }
|
|
122
|
+
test3 { color: red; }
|
|
123
|
+
test4 { color: red; }
|
|
124
|
+
`)
|
|
125
|
+
assert.is(actual.performance.score, 95)
|
|
126
|
+
assert.equal(actual.performance.violations, [
|
|
127
|
+
{
|
|
128
|
+
id: 'DeclarationDuplications',
|
|
129
|
+
score: 5,
|
|
130
|
+
value: 2 / 4
|
|
131
|
+
}
|
|
132
|
+
])
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
Performance('does not deduct points for small stylesheets', () => {
|
|
136
|
+
const actual = calculate(`
|
|
137
|
+
test { color: green; }
|
|
138
|
+
`);
|
|
139
|
+
assert.is(actual.performance.score, 100)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
Performance('deducts points for large stylesheets', () => {
|
|
143
|
+
const fixture = new Array(10_000)
|
|
144
|
+
.fill('')
|
|
145
|
+
.map((_, index) => `selector-${index} { opacity: 0.${index}}`)
|
|
146
|
+
.join('')
|
|
147
|
+
const actual = calculate(fixture)
|
|
148
|
+
|
|
149
|
+
assert.is(actual.performance.score, 95)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
Performance('deducts points for having comments', () => {
|
|
153
|
+
const fixture = new Array(100)
|
|
154
|
+
.fill('/* a comment to take up some space */')
|
|
155
|
+
.map((comment, index) => `${comment} selector-${index} { opacity: 0.${index} }`)
|
|
156
|
+
.join('')
|
|
157
|
+
const actual = calculate(fixture)
|
|
158
|
+
|
|
159
|
+
assert.is(actual.performance.score, 90)
|
|
160
|
+
assert.equal(actual.performance.violations, [
|
|
161
|
+
{
|
|
162
|
+
id: 'TooMuchComments',
|
|
163
|
+
score: 10,
|
|
164
|
+
value: 3300,
|
|
165
|
+
},
|
|
166
|
+
])
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
Performance('deducts points for having embedded content', () => {
|
|
170
|
+
function generateEmbed(index) {
|
|
171
|
+
return `data:image/svg+xml,%3Csvg%20id%3D%22Layer_${index}%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20195.6%20107.8%22%3E%3Cpath%20fill%3D%22%23B5B5B5%22%20class%3D%22st0%22%20d%3D%22M97.8%20107.8c-2.6%200-5.1-1-7.1-2.9L2.9%2017.1C-1%2013.2-1%206.8%202.9%202.9%206.8-1%2013.2-1%2017.1%202.9l80.7%2080.7%2080.7-80.7c3.9-3.9%2010.2-3.9%2014.1%200%203.9%203.9%203.9%2010.2%200%2014.1l-87.8%2087.8c-1.9%202-4.4%203-7%203z%22%2F%3E%3C%2Fsvg%3E`
|
|
172
|
+
}
|
|
173
|
+
const fixture = new Array(100)
|
|
174
|
+
.fill('')
|
|
175
|
+
.map((_, index) => `
|
|
176
|
+
selector-${index} {
|
|
177
|
+
background: url(${generateEmbed(index)});
|
|
178
|
+
}
|
|
179
|
+
`)
|
|
180
|
+
.join('')
|
|
181
|
+
const actual = calculate(fixture)
|
|
182
|
+
|
|
183
|
+
assert.is(actual.performance.score, 80)
|
|
184
|
+
assert.equal(actual.performance.violations, [
|
|
185
|
+
{
|
|
186
|
+
id: 'TooMuchEmbeddedContent',
|
|
187
|
+
score: 20,
|
|
188
|
+
value: 45990,
|
|
189
|
+
actuals: new Array(100).fill('').map((_, index) => generateEmbed(index)),
|
|
190
|
+
},
|
|
191
|
+
])
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
Performance.run()
|