@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,98 +0,0 @@
1
- import * as csstree from 'css-tree'
2
- import { CountableCollection } from '../countable-collection.js'
3
-
4
- const systemKeywords = {
5
- // Global CSS keywords
6
- 'inherit': 1,
7
- 'initial': 1,
8
- 'unset': 1,
9
- 'revert': 1,
10
-
11
- // System font keywords
12
- 'caption': 1,
13
- 'icon': 1,
14
- 'menu': 1,
15
- 'message-box': 1,
16
- 'small-caption': 1,
17
- 'status-bar': 1,
18
- }
19
-
20
- const keywordDisallowList = {
21
- // font-weight, font-stretch, font-style
22
- 'normal': 1,
23
-
24
- // font-size keywords
25
- 'xx-small': 1,
26
- 'x-small': 1,
27
- 'small': 1,
28
- 'medium': 1,
29
- 'large': 1,
30
- 'x-large': 1,
31
- 'xx-large': 1,
32
- 'larger': 1,
33
- 'smaller': 1,
34
-
35
- // font-weight keywords
36
- 'bold': 1,
37
- 'bolder': 1,
38
- 'lighter': 1,
39
-
40
- // font-stretch keywords
41
- 'ultra-condensed': 1,
42
- 'extra-condensed': 1,
43
- 'condensed': 1,
44
- 'semi-condensed': 1,
45
- 'semi-expanded': 1,
46
- 'expanded': 1,
47
- 'extra-expanded': 1,
48
- 'ultra-expanded': 1,
49
-
50
- // font-style keywords
51
- 'italic': 1,
52
- 'oblique': 1,
53
- }
54
-
55
- const COMMA = 44 // ','.charCodeAt(0) === 44
56
-
57
- const analyzeFontFamilies = ({ fontValues, fontFamilyValues }) => {
58
- const all = new CountableCollection(fontFamilyValues)
59
-
60
- for (let index = 0; index < fontValues.length; index++) {
61
- const value = fontValues[index]
62
-
63
- // Avoid tree traversal as soon as possible
64
- const firstChild = value.children.first
65
-
66
- if (firstChild.type === 'Identifier' && systemKeywords[firstChild.name]) {
67
- continue
68
- }
69
-
70
- const parts = []
71
-
72
- csstree.walk(value, {
73
- reverse: true,
74
- enter: function (fontNode) {
75
- if (fontNode.type === 'String') {
76
- return parts.unshift(fontNode)
77
- }
78
- if (fontNode.type === 'Operator' && fontNode.value.charCodeAt(0) === COMMA) {
79
- return parts.unshift(fontNode)
80
- }
81
- if (fontNode.type === 'Identifier') {
82
- if (keywordDisallowList[fontNode.name]) {
83
- return this.skip
84
- }
85
- return parts.unshift(fontNode)
86
- }
87
- }
88
- })
89
-
90
- all.push(parts.map(csstree.generate).join(''))
91
- }
92
-
93
- return all.count()
94
- }
95
-
96
- export {
97
- analyzeFontFamilies
98
- }
@@ -1,119 +0,0 @@
1
- import { suite } from 'uvu';
2
- import * as assert from 'uvu/assert';
3
- import { analyze } from '../index.js'
4
-
5
- const FontFamilies = suite('FontFamilies')
6
-
7
- FontFamilies('recognizes a font-family', () => {
8
- const fixture = `
9
- test {
10
- font-family: "Droid Sans", serif;
11
- font-family: sans-serif;
12
- font-family: "Arial Black", "Arial Bold", Gadget, sans-serif;
13
- font-family: "Brush Script MT", cursive;
14
- font-family: monospace;
15
- font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
16
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
17
-
18
- /* Unrelated */
19
- color: brown;
20
- font-size: 12px;
21
- }
22
- `
23
- const actual = analyze(fixture).values.fontFamilies
24
- const expected = {
25
- total: 7,
26
- totalUnique: 7,
27
- unique: {
28
- '"Droid Sans", serif': 1,
29
- 'sans-serif': 1,
30
- '"Arial Black", "Arial Bold", Gadget, sans-serif': 1,
31
- '"Brush Script MT", cursive': 1,
32
- 'monospace': 1,
33
- 'Consolas, "Liberation Mono", Menlo, Courier, monospace': 1,
34
- '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"': 1,
35
- },
36
- uniquenessRatio: 7 / 7
37
- }
38
-
39
- assert.equal(actual, expected)
40
- })
41
-
42
- FontFamilies('extracts the `font` shorthand', () => {
43
- const fixture = `
44
- test {
45
- font: large "Noto Sans";
46
- font: normal normal 1em/1 "Source Sans Pro", serif;
47
- font: normal normal 1.2em serif;
48
- font: 400 1.3em/1 serif;
49
- font: 1em / 1 serif;
50
- font: 1em/ 1 serif;
51
- font: 1em /1 serif;
52
- font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
53
- font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
54
- font: 0/0 a; /* As generated by some css minifiers */
55
-
56
- /* Unrelated */
57
- color: brown;
58
- font-size: 12px;
59
- }
60
- `
61
- const actual = analyze(fixture).values.fontFamilies
62
- const expected = {
63
- total: 10,
64
- totalUnique: 6,
65
- unique: {
66
- '"Noto Sans"': 1,
67
- '"Source Sans Pro",serif': 1,
68
- 'serif': 5,
69
- '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"': 1,
70
- 'Consolas,"Liberation Mono",Menlo,Courier,monospace': 1,
71
- 'a': 1,
72
- },
73
- uniquenessRatio: 6 / 10
74
- }
75
- assert.equal(actual, expected)
76
- })
77
-
78
- FontFamilies('handles system fonts', () => {
79
- // Source: https://drafts.csswg.org/css-fonts-3/#font-prop
80
- const fixture = `
81
- test {
82
- font: menu; /* use the font settings for system menus */
83
- font: large menu; /* use a font family named "menu" */
84
- }
85
- `
86
- const actual = analyze(fixture).values.fontFamilies
87
- const expected = {
88
- total: 1,
89
- totalUnique: 1,
90
- unique: {
91
- 'menu': 1
92
- },
93
- uniquenessRatio: 1 / 1
94
- }
95
-
96
- assert.equal(actual, expected)
97
- })
98
-
99
- FontFamilies('ignores keywords and global values', () => {
100
- const fixture = `
101
- test {
102
- font: inherit;
103
- font: initial;
104
- font: unset;
105
- font: revert;
106
- }
107
- `
108
- const actual = analyze(fixture).values.fontFamilies
109
- const expected = {
110
- total: 0,
111
- totalUnique: 0,
112
- unique: {},
113
- uniquenessRatio: 0
114
- }
115
-
116
- assert.equal(actual, expected)
117
- })
118
-
119
- FontFamilies.run()
@@ -1,92 +0,0 @@
1
- import * as csstree from 'css-tree'
2
- import { CountableCollection } from '../countable-collection.js'
3
-
4
- const sizeKeywords = {
5
- 'xx-small': 1,
6
- 'x-small': 1,
7
- 'small': 1,
8
- 'medium': 1,
9
- 'large': 1,
10
- 'x-large': 1,
11
- 'xx-large': 1,
12
- 'larger': 1,
13
- 'smaller': 1,
14
- }
15
-
16
- const keywords = {
17
- // Global CSS keywords
18
- 'inherit': 1,
19
- 'initial': 1,
20
- 'unset': 1,
21
- 'revert': 1,
22
-
23
- // System font keywords
24
- 'caption': 1,
25
- 'icon': 1,
26
- 'menu': 1,
27
- 'message-box': 1,
28
- 'small-caption': 1,
29
- 'status-bar': 1,
30
- }
31
-
32
- const ZERO = 48 // '0'.charCodeAt(0) === 48
33
- const SLASH = 47 // '/'.charCodeAt(0) === 47
34
-
35
- const analyzeFontSizes = ({ stringifyNode, fontSizeValues, fontValues }) => {
36
- const all = new CountableCollection(fontSizeValues)
37
-
38
- for (let index = 0; index < fontValues.length; index++) {
39
- const fontNode = fontValues[index];
40
- // Try to eliminate a keyword before we continue
41
- const firstChild = fontNode.children.first
42
-
43
- if (firstChild.type === 'Identifier' && keywords[firstChild.name]) {
44
- continue
45
- }
46
-
47
- let operator = false
48
- let size
49
-
50
- csstree.walk(fontNode, {
51
- enter: function (fontNode) {
52
- switch (fontNode.type) {
53
- case 'Number': {
54
- // Special case for `font: 0/0 a`
55
- if (fontNode.value.charCodeAt(0) === ZERO) {
56
- size = '0'
57
- return this.break
58
- }
59
- }
60
- case 'Operator': {
61
- if (fontNode.value.charCodeAt(0) === SLASH) {
62
- operator = true
63
- }
64
- break
65
- }
66
- case 'Dimension': {
67
- if (!operator) {
68
- size = stringifyNode(fontNode)
69
- return this.break
70
- }
71
- }
72
- case 'Identifier': {
73
- if (sizeKeywords[fontNode.name]) {
74
- size = fontNode.name
75
- return this.break
76
- }
77
- }
78
- }
79
- }
80
- })
81
-
82
- if (size) {
83
- all.push(size)
84
- }
85
- }
86
-
87
- return all.count()
88
- }
89
-
90
- export {
91
- analyzeFontSizes
92
- }
@@ -1,120 +0,0 @@
1
- import { suite } from 'uvu';
2
- import * as assert from 'uvu/assert';
3
- import { analyze } from '../index.js'
4
-
5
- const FontSizes = suite('FontSizes')
6
-
7
- FontSizes('recognizes a font-size', () => {
8
- const fixture = `
9
- test {
10
- font-size: 10px;
11
- font-size: small;
12
- font-size: 1em;
13
- font-size: calc(3vw + 1em);
14
-
15
- /* Unrelated */
16
- color: brown;
17
- font-family: serif;
18
- }
19
- `
20
- const actual = analyze(fixture).values.fontSizes
21
- const expected = {
22
- total: 4,
23
- totalUnique: 4,
24
- unique: {
25
- '10px': 1,
26
- 'small': 1,
27
- '1em': 1,
28
- 'calc(3vw + 1em)': 1,
29
- },
30
- uniquenessRatio: 4 / 4
31
- }
32
-
33
- assert.equal(actual, expected)
34
- })
35
-
36
- FontSizes('extracts the `font` shorthand', () => {
37
- const fixture = `
38
- test {
39
- font: large "Noto Sans";
40
- font: normal normal 1em/1 "Source Sans Pro", serif;
41
- font: normal normal 1.2em serif;
42
- font: 400 1.3em/1 serif;
43
- font: 1em / 1 serif;
44
- font: 1em/ 1 serif;
45
- font: 1em /1 serif;
46
- font: 2em/1.4em serif;
47
- font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
48
- font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
49
- font: 0/0 a; /* As generated by some css minifiers */
50
-
51
- /* Unrelated */
52
- color: brown;
53
- font-family: serif;
54
- }
55
- `
56
- const actual = analyze(fixture).values.fontSizes
57
- const expected = {
58
- total: 11,
59
- totalUnique: 7,
60
- unique: {
61
- '0': 1,
62
- 'large': 1,
63
- '1em': 4,
64
- '1.2em': 1,
65
- '1.3em': 1,
66
- '2em': 1,
67
- '11px': 2,
68
- },
69
- uniquenessRatio: 7 / 11
70
- }
71
- assert.equal(actual, expected)
72
- })
73
-
74
- FontSizes('handles system fonts', () => {
75
- // Source: https://drafts.csswg.org/css-fonts-3/#font-prop
76
- const fixture = `
77
- test {
78
- font: menu; /* use the font settings for system menus */
79
- font: large menu; /* use a font family named "menu" */
80
- }
81
- `
82
- const actual = analyze(fixture).values.fontSizes
83
- const expected = {
84
- total: 1,
85
- totalUnique: 1,
86
- unique: {
87
- 'large': 1,
88
- },
89
- uniquenessRatio: 1
90
- }
91
-
92
- assert.equal(actual, expected)
93
- })
94
-
95
- FontSizes('ignores keywords and global values', () => {
96
- const fixture = `
97
- test {
98
- font: inherit;
99
- font: initial;
100
- font: unset;
101
- font: revert;
102
-
103
- /*TODO:font-size: inherit;
104
- font-size: initial;
105
- font-size: unset;
106
- font-size: revert;*/
107
- }
108
- `
109
- const actual = analyze(fixture).values.fontSizes
110
- const expected = {
111
- total: 0,
112
- totalUnique: 0,
113
- unique: {},
114
- uniquenessRatio: 0
115
- }
116
-
117
- assert.equal(actual, expected)
118
- })
119
-
120
- FontSizes.run()
@@ -1,93 +0,0 @@
1
- import { suite } from 'uvu'
2
- import * as assert from 'uvu/assert'
3
- import { analyze } from '../index.js'
4
-
5
- const TextShadows = suite('TextShadows')
6
-
7
- TextShadows('finds simple values', () => {
8
- const fixture = `
9
- text-shadows-simple {
10
- text-shadow: 1px 1px 2px black;
11
- text-shadow: #fc0 1px 0 10px;
12
- text-shadow: 5px 5px #558abb;
13
- text-shadow: white 2px 5px;
14
- text-shadow: 5px 10px;
15
- text-shadow: red 0 -2px;
16
- }
17
- `
18
- const actual = analyze(fixture).values.textShadows
19
- const expected = {
20
- total: 6,
21
- unique: {
22
- '1px 1px 2px black': 1,
23
- '#fc0 1px 0 10px': 1,
24
- '5px 5px #558abb': 1,
25
- 'white 2px 5px': 1,
26
- '5px 10px': 1,
27
- 'red 0 -2px': 1,
28
- },
29
- totalUnique: 6,
30
- uniquenessRatio: 1
31
- }
32
-
33
- assert.equal(actual, expected)
34
- })
35
-
36
- TextShadows('finds complex values', () => {
37
- const fixture = `
38
- text-shadows-complex {
39
- text-shadow: 1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue;
40
- }
41
- `
42
- const actual = analyze(fixture).values.textShadows
43
- const expected = {
44
- total: 1,
45
- unique: {
46
- '1px 1px 2px black, 0 0 1em blue, 0 0 0.2em blue': 1,
47
- },
48
- totalUnique: 1,
49
- uniquenessRatio: 1
50
- }
51
-
52
- assert.equal(actual, expected)
53
- })
54
-
55
- TextShadows('finds vendor prefixed values', () => {
56
- const fixture = `
57
- text-shadows-vendor-prefixed {
58
- -webkit-text-shadow: 1px 1px 2px black;
59
- }
60
- `
61
- const actual = analyze(fixture).values.textShadows
62
- const expected = {
63
- total: 1,
64
- unique: {
65
- '1px 1px 2px black': 1,
66
- },
67
- totalUnique: 1,
68
- uniquenessRatio: 1
69
- }
70
-
71
- assert.equal(actual, expected)
72
- })
73
-
74
- TextShadows('ignores keywords', () => {
75
- const fixture = `
76
- text-shadows-keyword {
77
- text-shadow: initial;
78
- text-shadow: none;
79
- text-shadow: inherit;
80
- }
81
- `
82
- const actual = analyze(fixture).values.textShadows
83
- const expected = {
84
- total: 0,
85
- unique: {},
86
- totalUnique: 0,
87
- uniquenessRatio: 0
88
- }
89
-
90
- assert.equal(actual, expected)
91
- })
92
-
93
- TextShadows.run()
@@ -1,72 +0,0 @@
1
- import { suite } from 'uvu'
2
- import * as assert from 'uvu/assert'
3
- import { analyze } from '../index.js'
4
-
5
- const Units = suite('Units')
6
-
7
- Units('analyzes length units', () => {
8
- const fixture = `
9
- test {
10
- font: normal 10px/11px Arial;
11
- font: 14px sans-serif;
12
- }
13
-
14
- @media (min-width: 10em) {
15
- test2 {
16
- width: 12vw;
17
- height: 13vmin;
18
- }
19
- }
20
-
21
- @supports (hover: hover) {
22
- @media all {
23
- @media screen and (max-width: 100px) {
24
- line-height: 2;
25
- }
26
- }
27
- }
28
- `
29
- const result = analyze(fixture)
30
- const actual = result.values.units
31
-
32
- const expected = {
33
- total: 5,
34
- totalUnique: 3,
35
- uniquenessRatio: 3 / 5,
36
- unique: {
37
- px: 3,
38
- vw: 1,
39
- vmin: 1,
40
- },
41
- itemsPerContext: {
42
- font: {
43
- total: 3,
44
- totalUnique: 1,
45
- uniquenessRatio: 1 / 3,
46
- unique: {
47
- px: 3,
48
- },
49
- },
50
- width: {
51
- total: 1,
52
- totalUnique: 1,
53
- uniquenessRatio: 1,
54
- unique: {
55
- vw: 1,
56
- },
57
- },
58
- height: {
59
- total: 1,
60
- totalUnique: 1,
61
- uniquenessRatio: 1,
62
- unique: {
63
- vmin: 1,
64
- },
65
- },
66
- },
67
- }
68
-
69
- assert.equal(actual, expected)
70
- })
71
-
72
- Units.run()
@@ -1,30 +0,0 @@
1
- import { CountableCollection } from '../countable-collection.js'
2
-
3
- const keywords = {
4
- 'auto': 1,
5
- 'inherit': 1,
6
- 'initial': 1,
7
- 'unset': 1,
8
- 'revert': 1,
9
- 'none': 1, // for `text-shadow`
10
- }
11
-
12
- const analyzeValues = ({ values, stringifyNode }) => {
13
- const all = new CountableCollection()
14
-
15
- for (let i = 0; i < values.length; i++) {
16
- const node = values[i]
17
- const firstChild = node.children.first
18
-
19
- if (!firstChild) continue
20
- if (firstChild.type === 'Identifier' && keywords[firstChild.name]) continue
21
-
22
- all.push(stringifyNode(node))
23
- }
24
-
25
- return all.count()
26
- }
27
-
28
- export {
29
- analyzeValues
30
- }
@@ -1,45 +0,0 @@
1
- import { CountableCollection } from '../countable-collection.js'
2
- import { hasVendorPrefix } from '../vendor-prefix.js'
3
-
4
- function isAstVendorPrefixed(children) {
5
- children = children.toArray()
6
-
7
- for (let index = 0; index < children.length; index++) {
8
- const child = children[index];
9
-
10
- if (child.type === 'Identifier' && child.name.length >= 3) {
11
- if (hasVendorPrefix(child.name)) {
12
- return true
13
- }
14
- }
15
-
16
- if (child.type === 'Function') {
17
- if (hasVendorPrefix(child.name)) {
18
- return true
19
- }
20
-
21
- if (child.children && isAstVendorPrefixed(child.children)) {
22
- return true
23
- }
24
- }
25
- }
26
- return false
27
- }
28
-
29
- const analyzeVendorPrefixes = ({ values, stringifyNode }) => {
30
- const all = new CountableCollection()
31
-
32
- for (let i = 0; i < values.length; i++) {
33
- const value = values[i]
34
-
35
- if (value.children && isAstVendorPrefixed(value.children)) {
36
- all.push(stringifyNode(value))
37
- }
38
- }
39
-
40
- return all.count()
41
- }
42
-
43
- export {
44
- analyzeVendorPrefixes
45
- }