@projectwallace/css-analyzer 5.0.0-alpha.1 → 5.0.2

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.
Files changed (48) hide show
  1. package/dist/analyzer.cjs +1 -1
  2. package/dist/analyzer.cjs.map +1 -1
  3. package/dist/analyzer.modern.js +2 -0
  4. package/dist/analyzer.modern.js.map +1 -0
  5. package/dist/analyzer.module.js +1 -1
  6. package/dist/analyzer.module.js.map +1 -1
  7. package/dist/analyzer.umd.js +1 -1
  8. package/dist/analyzer.umd.js.map +1 -1
  9. package/package.json +10 -10
  10. package/dist/analyzer.js +0 -2
  11. package/dist/analyzer.js.map +0 -1
  12. package/src/aggregate-collection.js +0 -113
  13. package/src/aggregate-collection.test.js +0 -47
  14. package/src/atrules/atrules.js +0 -76
  15. package/src/atrules/atrules.test.js +0 -289
  16. package/src/context-collection.js +0 -36
  17. package/src/countable-collection.js +0 -46
  18. package/src/declarations/declarations.js +0 -46
  19. package/src/declarations/declarations.test.js +0 -113
  20. package/src/index.js +0 -259
  21. package/src/index.test.js +0 -60
  22. package/src/properties/properties.js +0 -48
  23. package/src/properties/properties.test.js +0 -138
  24. package/src/rules/rules.js +0 -57
  25. package/src/rules/rules.test.js +0 -247
  26. package/src/selectors/complexity.test.js +0 -123
  27. package/src/selectors/selectors.js +0 -122
  28. package/src/selectors/selectors.test.js +0 -189
  29. package/src/selectors/specificity.js +0 -201
  30. package/src/selectors/specificity.test.js +0 -247
  31. package/src/smoke.test.js +0 -39
  32. package/src/stylesheet/stylesheet.test.js +0 -88
  33. package/src/values/animations.js +0 -53
  34. package/src/values/animations.test.js +0 -154
  35. package/src/values/box-shadows.test.js +0 -82
  36. package/src/values/colors.js +0 -192
  37. package/src/values/colors.test.js +0 -804
  38. package/src/values/font-families.js +0 -98
  39. package/src/values/font-families.test.js +0 -119
  40. package/src/values/font-sizes.js +0 -92
  41. package/src/values/font-sizes.test.js +0 -120
  42. package/src/values/text-shadows.test.js +0 -93
  43. package/src/values/units.test.js +0 -72
  44. package/src/values/values.js +0 -30
  45. package/src/values/vendor-prefix.js +0 -45
  46. package/src/values/vendor-prefix.test.js +0 -64
  47. package/src/values/z-index.test.js +0 -54
  48. package/src/vendor-prefix.js +0 -16
@@ -1,247 +0,0 @@
1
- import { suite } from 'uvu';
2
- import * as assert from 'uvu/assert';
3
- import { analyze } from '../index.js'
4
-
5
- const Rules = suite('Rules')
6
-
7
- Rules('should count rules', () => {
8
- assert.is(analyze(`
9
- html {
10
- color: black;
11
- }
12
- test {}
13
- `).rules.total, 2)
14
- })
15
-
16
- Rules('should count empty rules', () => {
17
- assert.is(1, analyze(`test{}`).rules.empty.total)
18
- assert.is(analyze('@media print {}').rules.empty.total, 0)
19
- assert.is(analyze(`
20
- @media print {
21
- empty {}
22
- }
23
- `).rules.empty.total, 1)
24
- assert.is(analyze('test { color: red; }').rules.empty.total, 0)
25
- })
26
-
27
- Rules('calculate the minimum selectors', () => {
28
- assert.is(analyze(`
29
- html {}
30
- a,
31
- b {}
32
- `).rules.selectors.min, 1)
33
- })
34
-
35
- Rules('calculate the maximum selectors', () => {
36
- assert.is(analyze(`
37
- html {}
38
- a,
39
- b {}
40
- `).rules.selectors.max, 2)
41
- })
42
-
43
- Rules('calculate the mode of selectors', () => {
44
- assert.is(analyze(`
45
- html {}
46
- a,
47
- b {}
48
- x {}
49
- `).rules.selectors.mode, 1)
50
- })
51
-
52
- Rules('calculate the mean of selectors', () => {
53
- assert.is(analyze(`
54
- html {}
55
- a,
56
- b {}
57
- `).rules.selectors.mean, 1.5)
58
- })
59
-
60
- Rules('calculate the median of selectors', () => {
61
- assert.is(analyze(`
62
- html {}
63
- a,
64
- b {}
65
- `).rules.selectors.median, 1.5)
66
- })
67
-
68
- Rules('calculate the range of selectors', () => {
69
- assert.is(analyze(`
70
- html {}
71
-
72
- a,
73
- b {}
74
-
75
- a,
76
- b,
77
- c {}
78
- `).rules.selectors.range, 2)
79
- })
80
-
81
-
82
- Rules('calculate the minimum declarations', () => {
83
- assert.is(analyze(`
84
- html {}
85
- test {
86
- color: red;
87
- }
88
- `).rules.declarations.min, 0)
89
- assert.is(analyze('@media print {}').rules.declarations.min, 0)
90
- })
91
-
92
- Rules('calculate the maximum declarations', () => {
93
- assert.is(analyze(`
94
- html {}
95
- test {
96
- a: 1;
97
- b: 2;
98
- c: 3;
99
- }
100
- `).rules.declarations.max, 3)
101
-
102
- assert.is(analyze(`
103
- html {}
104
- test {
105
- a: 1;
106
- b: 2;
107
- c: 3;
108
- }
109
-
110
- @media print {
111
- test {
112
- a: 1;
113
- b: 2;
114
- c: 3;
115
- d: 4;
116
- }
117
- }
118
- `).rules.declarations.max, 4)
119
- })
120
-
121
- Rules('calculate the mode of declarations', () => {
122
- assert.is(analyze(`
123
- html {
124
- a: 1;
125
- }
126
- test {
127
- a: 1;
128
- }
129
- test {
130
- a: 1;
131
- b: 2;
132
- }
133
- `).rules.declarations.mode, 1)
134
- })
135
-
136
- Rules('calculate the mean of declarations', () => {
137
- assert.is(analyze(`
138
- html {
139
- a: 1;
140
- }
141
- a {
142
- a: 1;
143
- b: 2;
144
- }
145
- b {
146
- a: 1;
147
- b: 2;
148
- c: 3;
149
- }
150
- `).rules.declarations.mean, 2)
151
- })
152
-
153
- Rules('calculate the median of declarations', () => {
154
- assert.is(analyze(`
155
- html {
156
- a: 1;
157
- }
158
- a {
159
- a: 1;
160
- b: 2;
161
- }
162
- b {
163
- a: 1;
164
- b: 2;
165
- c: 3;
166
- }
167
- `).rules.declarations.median, 2)
168
- })
169
-
170
- Rules('calculate the range of declarations', () => {
171
- assert.is(analyze(`
172
- html {
173
- a: 1;
174
- }
175
- a {
176
- a: 1;
177
- b: 2;
178
- }
179
- b {
180
- a: 1;
181
- b: 2;
182
- c: 3;
183
- }
184
- `).rules.declarations.range, 2)
185
- })
186
-
187
- Rules('return a list of declaration counts per rule', () => {
188
- const actual = analyze(`
189
- html {
190
- a: 1;
191
- }
192
- a {
193
- a: 1;
194
- b: 2;
195
- }
196
- b {
197
- a: 1;
198
- b: 2;
199
- c: 3;
200
- }
201
-
202
- @media print {
203
- @supports (display: grid) {
204
- c {
205
- a: 1;
206
- b: 2;
207
- }
208
- d {}
209
- }
210
- }
211
- `).rules.declarations.items
212
- const expected = [1, 2, 3, 2, 0]
213
- assert.equal(actual, expected)
214
- })
215
-
216
- Rules('return a list of selectors counts per rule', () => {
217
- const actual = analyze(`
218
- x {
219
- a: 1;
220
- }
221
- a,
222
- b {
223
- a: 1;
224
- b: 2;
225
- }
226
- c,
227
- d,
228
- e {
229
- a: 1;
230
- b: 2;
231
- c: 3;
232
- }
233
-
234
- @media print {
235
- @supports (display: grid) {
236
- f {
237
- a: 1;
238
- b: 2;
239
- }
240
- }
241
- }
242
- `).rules.declarations.items
243
- const expected = [1, 2, 3, 2]
244
- assert.equal(actual, expected)
245
- })
246
-
247
- Rules.run()
@@ -1,123 +0,0 @@
1
- import { suite } from 'uvu'
2
- import * as assert from 'uvu/assert'
3
- import { analyze } from '../index.js'
4
-
5
- const Complexity = suite('Selector Complexity')
6
-
7
- const fixture = `
8
- *,
9
- * + *,
10
- a,
11
- a b,
12
- a + b,
13
- a ~ b,
14
- #id,
15
- .className,
16
- [attr],
17
- [attr=value],
18
- :where(#id, .class),
19
- main > :is(h1, h2) {}
20
- `
21
-
22
- Complexity('calculates complexity', () => {
23
- const actual = analyze(fixture).selectors.complexity.items
24
- const expected = [
25
- 1,
26
- 3,
27
- 1,
28
- 3,
29
- 3,
30
- 3,
31
- 1,
32
- 1,
33
- 1,
34
- 2,
35
- 3,
36
- 5,
37
- ]
38
-
39
- assert.equal(actual, expected)
40
- })
41
-
42
- Complexity('calculates complexity uniqueness', () => {
43
- const actual = analyze(fixture).selectors.complexity
44
- const expected = {
45
- '1': 5,
46
- '2': 1,
47
- '3': 5,
48
- '5': 1
49
- }
50
-
51
- assert.is(actual.totalUnique, 4)
52
- assert.is(actual.uniquenessRatio, 4 / 12)
53
- assert.equal(actual.unique, expected)
54
- })
55
-
56
- Complexity('calculates the lowest complexity', () => {
57
- const fixture = `
58
- #test,
59
- .me,
60
- now,
61
- [crazy] ~ .selector > for [no|="good"] {}
62
- `
63
- const actual = analyze(fixture).selectors.complexity.min
64
- assert.equal(actual, 1)
65
- })
66
-
67
- Complexity('calculates the highest complexity', () => {
68
- const fixture = `
69
- #test,
70
- .me,
71
- now,
72
- [crazy] ~ .selector > for [no|="good"] {}
73
- `
74
- const actual = analyze(fixture).selectors.complexity.max
75
- assert.equal(actual, 8)
76
- })
77
-
78
- Complexity('calculates the complexity mean', () => {
79
- const fixture = `
80
- #test,
81
- .me,
82
- now,
83
- [crazy] ~ .selector > for [no|="good"] {}
84
- `
85
- const result = analyze(fixture)
86
- const actual = result.selectors.complexity.mean
87
- assert.equal(actual, (1 + 1 + 1 + 8) / 4)
88
- })
89
-
90
- Complexity('calculates the complexity mode', () => {
91
- const fixture = `
92
- #test,
93
- .me,
94
- now,
95
- [crazy] ~ .selector > for [no|="good"] {}
96
- `
97
- const actual = analyze(fixture).selectors.complexity.mode
98
- assert.equal(actual, 1)
99
- })
100
-
101
- Complexity('calculates the complexity median', () => {
102
- const fixture = `
103
- #test,
104
- .me,
105
- now,
106
- [crazy] ~ .selector > check {}
107
- `
108
- const actual = analyze(fixture).selectors.complexity.median
109
- assert.equal(actual, 1)
110
- })
111
-
112
- Complexity('calculates total complexity', () => {
113
- const fixture = `
114
- #test,
115
- .me,
116
- now,
117
- [crazy] ~ .selector > for [no|="good"] {}
118
- `
119
- const actual = analyze(fixture).selectors.complexity.sum
120
- assert.equal(actual, 11)
121
- })
122
-
123
- Complexity.run()
@@ -1,122 +0,0 @@
1
- import { analyzeSpecificity, compareSpecificity } from './specificity.js'
2
- import { AggregateCollection } from '../aggregate-collection.js'
3
- import { CountableCollection } from '../countable-collection.js'
4
-
5
- /** @typedef {[number, number, number]} Specificity */
6
-
7
- const analyzeSelectors = ({ stringifyNode, selectors }) => {
8
- const counts = Object.create(null)
9
- const cache = Object.create(null)
10
- const totalSelectors = selectors.length
11
-
12
- /** @type Specificity|undefined */
13
- let maxSpecificity
14
- /** @type Specificity|undefined */
15
- let minSpecificity
16
- let specificityA = new AggregateCollection(totalSelectors)
17
- let specificityB = new AggregateCollection(totalSelectors)
18
- let specificityC = new AggregateCollection(totalSelectors)
19
- let totalUnique = 0
20
- const complexityAggregator = new AggregateCollection(totalSelectors);
21
-
22
- const specificities = []
23
- const complexities = []
24
- const ids = new CountableCollection()
25
- const a11y = new CountableCollection()
26
- const keyframes = new CountableCollection()
27
-
28
- for (let i = 0; i < totalSelectors; i++) {
29
- const node = selectors[i];
30
- const value = stringifyNode(node)
31
-
32
- if (node.isKeyframeSelector) {
33
- keyframes.push(value)
34
- // Do not attempt to further analyze <keyframe-selectors>
35
- continue
36
- }
37
-
38
- const { specificity, complexity, isId, isA11y } = cache[value] || analyzeSpecificity(node)
39
-
40
- if (isId) {
41
- ids.push(value)
42
- }
43
-
44
- if (isA11y) {
45
- a11y.push(value)
46
- }
47
-
48
- if (!cache[value]) {
49
- cache[value] = { complexity, specificity, isId, isA11y }
50
- totalUnique++
51
- counts[value] = 1
52
- } else {
53
- counts[value]++
54
- }
55
-
56
- complexityAggregator.add(complexity)
57
-
58
- if (maxSpecificity === undefined) {
59
- maxSpecificity = specificity
60
- }
61
-
62
- if (minSpecificity === undefined) {
63
- minSpecificity = specificity
64
- }
65
-
66
- specificityA.add(specificity[0])
67
- specificityB.add(specificity[1])
68
- specificityC.add(specificity[2])
69
-
70
- if (minSpecificity !== undefined && compareSpecificity(minSpecificity, specificity) < 0) {
71
- minSpecificity = specificity
72
- }
73
-
74
- if (maxSpecificity !== undefined && compareSpecificity(maxSpecificity, specificity) > 0) {
75
- maxSpecificity = specificity
76
- }
77
-
78
- specificities.push(specificity)
79
- complexities.push(complexity)
80
- }
81
-
82
- const aggregatesA = specificityA.aggregate()
83
- const aggregatesB = specificityB.aggregate()
84
- const aggregatesC = specificityC.aggregate()
85
- const complexityCount = new CountableCollection(complexities).count()
86
-
87
- return {
88
- total: totalSelectors,
89
- totalUnique,
90
- uniquenessRatio: totalUnique / totalSelectors,
91
- specificity: {
92
- sum: [aggregatesA.sum, aggregatesB.sum, aggregatesC.sum],
93
- min: minSpecificity,
94
- max: maxSpecificity,
95
- mean: [aggregatesA.mean, aggregatesB.mean, aggregatesC.mean],
96
- mode: [aggregatesA.mode, aggregatesB.mode, aggregatesC.mode],
97
- median: [aggregatesA.median, aggregatesB.median, aggregatesC.median],
98
- items: specificities
99
- },
100
- complexity: {
101
- ...complexityAggregator.aggregate(),
102
- ...complexityCount,
103
- items: complexities,
104
- },
105
- id: {
106
- ...ids.count(),
107
- ratio: ids.size() / totalSelectors,
108
- },
109
- accessibility: {
110
- ...a11y.count(),
111
- ratio: a11y.size() / totalSelectors,
112
- },
113
- keyframes: {
114
- ...keyframes.count(),
115
- ratio: keyframes.size() / totalSelectors,
116
- }
117
- }
118
- }
119
-
120
- export {
121
- analyzeSelectors
122
- }
@@ -1,189 +0,0 @@
1
- import { suite } from 'uvu'
2
- import * as assert from 'uvu/assert'
3
- import { analyze } from '../index.js'
4
-
5
- const Selectors = suite('Selectors')
6
-
7
- Selectors('are analyzed', () => {
8
- const fixture = `
9
- rule {
10
- color: green;
11
- }
12
-
13
- @media print {
14
- @media (min-width: 1000px) {
15
- @supports (display: grid) {
16
- another-rule {
17
- color: purple;
18
- }
19
- }
20
- }
21
- }
22
- `
23
- const actual = analyze(fixture).selectors.total
24
-
25
- assert.equal(actual, 2)
26
- })
27
-
28
- Selectors('have their complexity calculated', () => {
29
- const fixture = `
30
- rule {
31
- color: green;
32
- }
33
-
34
- @media print {
35
- @media (min-width: 1000px) {
36
- @supports (display: grid) {
37
- another-rule {
38
- color: purple;
39
- }
40
- }
41
- }
42
- }
43
- `
44
- const actual = analyze(fixture).selectors.complexity.items
45
- const expected = [1, 1]
46
-
47
- assert.equal(actual, expected)
48
- })
49
-
50
- Selectors('have their specificity calculated', () => {
51
- const fixture = `
52
- rule {
53
- color: green;
54
- }
55
-
56
- @media print {
57
- @media (min-width: 1000px) {
58
- @supports (display: grid) {
59
- another-rule {
60
- color: purple;
61
- }
62
- }
63
- }
64
- }
65
- `
66
- const actual = analyze(fixture)
67
- const expected = [
68
- [0, 0, 1,],
69
- [0, 0, 1,]
70
- ]
71
-
72
- assert.equal(actual.selectors.specificity.items, expected)
73
- assert.equal(actual.selectors.total, 2)
74
- })
75
-
76
- Selectors('calculates selector uniqueness', () => {
77
- const fixture = `
78
- a {}
79
- b {}
80
-
81
- @media print {
82
- b {}
83
- c {}
84
- }
85
- `
86
- const actual = analyze(fixture).selectors
87
-
88
- assert.is(actual.total, 4)
89
- assert.is(actual.totalUnique, 3)
90
- assert.is(actual.uniquenessRatio, 3 / 4)
91
- })
92
-
93
- Selectors('counts <keyframes-selector>s', () => {
94
- const fixture = `
95
- myElement1 {
96
- opacity: 1;
97
- }
98
-
99
- @keyframes test1 {
100
- from {
101
- opacity: 1;
102
- }
103
- 50% {
104
- opacity: 0;
105
- }
106
- to {
107
- opacity: 1;
108
- }
109
- }
110
-
111
- @media only screen {
112
- myElement2 {
113
- opacity: 1;
114
- }
115
-
116
- @keyframes test2 {
117
- from {
118
- opacity: 0.1;
119
- }
120
- }
121
- }
122
- `
123
- const result = analyze(fixture)
124
- const actual = result.selectors
125
- assert.is(actual.total, 6)
126
- assert.equal(actual.keyframes, {
127
- total: 4,
128
- totalUnique: 3,
129
- unique: {
130
- from: 2,
131
- to: 1,
132
- '50%': 1
133
- },
134
- uniquenessRatio: 3 / 4,
135
- ratio: 4 / 6
136
- })
137
- })
138
-
139
- Selectors('counts ID selectors', () => {
140
- const fixture = `
141
- #myId,
142
- #myId,
143
- element#id,
144
- #multiple #ids { }
145
-
146
- /* Not an ID */
147
- [href="#hash"] { }
148
- `
149
- const actual = analyze(fixture).selectors.id
150
- const expected = {
151
- total: 4,
152
- totalUnique: 3,
153
- unique: {
154
- '#myId': 2,
155
- 'element#id': 1,
156
- '#multiple #ids': 1,
157
- },
158
- uniquenessRatio: 3 / 4,
159
- ratio: 4 / 5
160
- }
161
-
162
- assert.equal(actual, expected)
163
- })
164
-
165
- Selectors('counts Accessibility selectors', () => {
166
- const fixture = `
167
- [aria-hidden],
168
- img[role="presentation"] {}
169
-
170
- /* false positives */
171
- img[loading="lazy"],
172
- [hidden] {}
173
- `
174
- const actual = analyze(fixture).selectors.accessibility
175
- const expected = {
176
- total: 2,
177
- totalUnique: 2,
178
- unique: {
179
- '[aria-hidden]': 1,
180
- 'img[role="presentation"]': 1,
181
- },
182
- uniquenessRatio: 1 / 1,
183
- ratio: 2 / 4
184
- }
185
-
186
- assert.equal(actual, expected)
187
- })
188
-
189
- Selectors.run()