From 120772f44e9ce364f6a12724b23d1879711b768d Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sat, 14 Oct 2023 12:33:28 +0200 Subject: [PATCH 1/6] WIP: try out CSSTree@next --- package-lock.json | 29 ++++---- package.json | 2 +- src/__fixtures__/bol-com-20231008.json | 2 +- src/__fixtures__/cnn-20231008.json | 66 ++++++++++++++----- src/__fixtures__/gazelle-20231008.json | 4 +- src/__fixtures__/github-20231008.json | 62 ++++++++++------- .../smashing-magazine-20231008.json | 16 ++--- src/atrules/atrules.js | 10 +-- src/atrules/atrules.test.js | 13 +++- src/index.js | 12 ++-- 10 files changed, 133 insertions(+), 83 deletions(-) diff --git a/package-lock.json b/package-lock.json index a30ea10..790be83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@bramus/specificity": "^2.3.0", - "css-tree": "^2.3.1" + "css-tree": "git://github.com/csstree/csstree.git#26a64c716fd7913a4cfa6b735791e558737e1bf2" }, "devDependencies": { "microbundle": "^0.15.1", @@ -2295,10 +2295,11 @@ }, "node_modules/css-tree": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "resolved": "git+ssh://git@github.com/csstree/csstree.git#26a64c716fd7913a4cfa6b735791e558737e1bf2", + "integrity": "sha512-H9DUqHJ6gSayg06fRmxkHSBhqmPsWDmyHeP9O/E2qTYRQyPLjNPcXsFXVt8PGjNUGsN3tI4mMWZnZLca4r9c3g==", + "license": "MIT", "dependencies": { - "mdn-data": "2.0.30", + "mdn-data": "2.1.0", "source-map-js": "^1.0.1" }, "engines": { @@ -3612,9 +3613,9 @@ } }, "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.1.0.tgz", + "integrity": "sha512-dbAWH6A+2NGuVJlQFrTKHJc07Vqn5frnhyTOGz+7BsK7V2hHdoBcwoiyV3QVhLHYpM/zqe2OSUn5ZWbVXLBB8A==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -6897,11 +6898,11 @@ } }, "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "version": "git+ssh://git@github.com/csstree/csstree.git#26a64c716fd7913a4cfa6b735791e558737e1bf2", + "integrity": "sha512-H9DUqHJ6gSayg06fRmxkHSBhqmPsWDmyHeP9O/E2qTYRQyPLjNPcXsFXVt8PGjNUGsN3tI4mMWZnZLca4r9c3g==", + "from": "css-tree@git://github.com/csstree/csstree.git#26a64c716fd7913a4cfa6b735791e558737e1bf2", "requires": { - "mdn-data": "2.0.30", + "mdn-data": "2.1.0", "source-map-js": "^1.0.1" } }, @@ -7776,9 +7777,9 @@ } }, "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.1.0.tgz", + "integrity": "sha512-dbAWH6A+2NGuVJlQFrTKHJc07Vqn5frnhyTOGz+7BsK7V2hHdoBcwoiyV3QVhLHYpM/zqe2OSUn5ZWbVXLBB8A==" }, "merge-stream": { "version": "2.0.0", diff --git a/package.json b/package.json index 9cddcdd..2b33732 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ ], "dependencies": { "@bramus/specificity": "^2.3.0", - "css-tree": "^2.3.1" + "css-tree": "git://github.com/csstree/csstree.git#26a64c716fd7913a4cfa6b735791e558737e1bf2" }, "devDependencies": { "microbundle": "^0.15.1", diff --git a/src/__fixtures__/bol-com-20231008.json b/src/__fixtures__/bol-com-20231008.json index 6655514..16657f0 100644 --- a/src/__fixtures__/bol-com-20231008.json +++ b/src/__fixtures__/bol-com-20231008.json @@ -199,7 +199,7 @@ "total": 5, "totalUnique": 3, "unique": { - "((-webkit-clip-path:polygon(0 50%, 100% 100%, 100%0)) or (clip-path:polygon(0 50%, 100% 100%, 100%0)))": 3, + "(-webkit-clip-path:polygon(0 50%, 100% 100%, 100%0)) or (clip-path:polygon(0 50%, 100% 100%, 100%0))": 3, "(-webkit-clip-path:polygon(0 50%, 100% 50%, 100%0))": 1, "(-webkit-clip-path:polygon(0 50%, 100% 20%, 100% 80%))": 1 }, diff --git a/src/__fixtures__/cnn-20231008.json b/src/__fixtures__/cnn-20231008.json index 68e5457..af4d11a 100644 --- a/src/__fixtures__/cnn-20231008.json +++ b/src/__fixtures__/cnn-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 10127, + "sourceLinesOfCode": 10132, "linesOfCode": 14690, "size": 821224, "comments": { @@ -6942,9 +6942,9 @@ } }, "selectors": { - "total": 4036, - "totalUnique": 2618, - "uniquenessRatio": 0.6486620416253717, + "total": 4041, + "totalUnique": 2619, + "uniquenessRatio": 0.6481069042316259, "specificity": { "min": [ 0, @@ -6962,9 +6962,9 @@ 1936 ], "mean": [ - 0.0004955401387512388, - 3.064420218037661, - 0.4796828543111992 + 0.0004949269982677555, + 3.0606285572878003, + 0.47908933432318734 ], "mode": [ 0, @@ -7462,6 +7462,11 @@ 4, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 3, @@ -7562,6 +7567,11 @@ 5, 2 ], + [ + 0, + 0, + 0 + ], [ 0, 5, @@ -8037,6 +8047,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 5, @@ -14492,6 +14507,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 3, @@ -27147,6 +27167,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 4, @@ -27158,7 +27183,7 @@ 1 ] ], - "total": 4036, + "total": 4041, "totalUnique": 27, "unique": { "0,0,1": 17, @@ -27170,6 +27195,7 @@ "0,3,1": 284, "0,4,0": 239, "0,4,1": 336, + "0,0,0": 6, "0,6,1": 113, "0,5,1": 373, "0,5,2": 114, @@ -27186,24 +27212,23 @@ "0,1,2": 8, "0,1,4": 1, "0,7,2": 4, - "0,0,0": 1, "0,8,0": 2 }, - "uniquenessRatio": 0.006689791873141724 + "uniquenessRatio": 0.0066815144766146995 }, "complexity": { "min": 1, "max": 18, - "mean": 5.616947472745292, + "mean": 5.612472160356347, "mode": 3, "median": 5, "range": 17, - "sum": 22670, - "total": 4036, + "sum": 22680, + "total": 4041, "totalUnique": 17, "unique": { "1": 552, - "2": 208, + "2": 213, "3": 727, "4": 414, "5": 346, @@ -27220,7 +27245,7 @@ "16": 8, "18": 4 }, - "uniquenessRatio": 0.00421209117938553, + "uniquenessRatio": 0.004206879485275922, "items": [ 1, 1, @@ -27319,6 +27344,7 @@ 4, 8, 8, + 2, 5, 5, 5, @@ -27339,6 +27365,7 @@ 8, 11, 11, + 2, 10, 11, 9, @@ -27434,6 +27461,7 @@ 10, 12, 12, + 2, 10, 7, 9, @@ -28725,6 +28753,7 @@ 10, 12, 12, + 2, 5, 5, 5, @@ -31256,6 +31285,7 @@ 1, 8, 13, + 2, 6, 11 ] @@ -31268,7 +31298,7 @@ "#taui-mvpdpicker": 1 }, "uniquenessRatio": 1, - "ratio": 0.0004955401387512388 + "ratio": 0.0004949269982677555 }, "accessibility": { "total": 4, @@ -31280,7 +31310,7 @@ ".kiln-edit-mode .kiln-overlay-form.byline button[aria-label='Do Magic']:hover": 1 }, "uniquenessRatio": 1, - "ratio": 0.0009910802775024777 + "ratio": 0.000989853996535511 }, "keyframes": { "total": 12, @@ -31304,7 +31334,7 @@ ".ad-feedback__container .ad-feedback__comment:-ms-input-placeholder": 1 }, "uniquenessRatio": 1, - "ratio": 0.0009910802775024777 + "ratio": 0.000989853996535511 }, "combinators": { "total": 5663, diff --git a/src/__fixtures__/gazelle-20231008.json b/src/__fixtures__/gazelle-20231008.json index ada1f35..ce296d2 100644 --- a/src/__fixtures__/gazelle-20231008.json +++ b/src/__fixtures__/gazelle-20231008.json @@ -190,7 +190,7 @@ "totalUnique": 3, "unique": { "(-webkit-overflow-scrolling: touch)": 1, - "(-webkit-appearance:none) and (not (stroke-color:transparent))": 1, + "(-webkit-appearance:none) and (not (stroke-color:transparent)": 1, "(-webkit-appearance:none)": 1 }, "uniquenessRatio": 1, @@ -198,7 +198,7 @@ "total": 2, "totalUnique": 2, "unique": { - "(-webkit-appearance:none) and (not (stroke-color:transparent))": 1, + "(-webkit-appearance:none) and (not (stroke-color:transparent)": 1, "(-webkit-appearance:none)": 1 }, "uniquenessRatio": 1 diff --git a/src/__fixtures__/github-20231008.json b/src/__fixtures__/github-20231008.json index eeba813..c3cbfc9 100644 --- a/src/__fixtures__/github-20231008.json +++ b/src/__fixtures__/github-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 33278, + "sourceLinesOfCode": 33281, "linesOfCode": 51852, "size": 1206900, "comments": { @@ -27243,9 +27243,9 @@ } }, "selectors": { - "total": 10736, - "totalUnique": 9591, - "uniquenessRatio": 0.893349478390462, + "total": 10739, + "totalUnique": 9594, + "uniquenessRatio": 0.893379271813018, "specificity": { "min": [ 0, @@ -27259,13 +27259,13 @@ ], "sum": [ 12, - 19836, + 19841, 2273 ], "mean": [ - 0.0011177347242921013, - 1.8476154992548435, - 0.21171758569299554 + 0.0011174224788155322, + 1.8475649501815812, + 0.21165844119564206 ], "mode": [ 0, @@ -42508,6 +42508,11 @@ 2, 0 ], + [ + 0, + 2, + 0 + ], [ 0, 2, @@ -46648,6 +46653,11 @@ 1, 2 ], + [ + 0, + 1, + 0 + ], [ 0, 2, @@ -60193,6 +60203,11 @@ 2, 0 ], + [ + 0, + 2, + 0 + ], [ 0, 3, @@ -80959,11 +80974,11 @@ 0 ] ], - "total": 10736, + "total": 10739, "totalUnique": 35, "unique": { - "0,1,0": 4261, - "0,2,0": 2345, + "0,1,0": 4262, + "0,2,0": 2347, "0,1,1": 631, "0,2,1": 568, "0,0,1": 115, @@ -80998,23 +81013,23 @@ "1,0,4": 1, "1,0,3": 1 }, - "uniquenessRatio": 0.0032600596125186287 + "uniquenessRatio": 0.0032591488965453023 }, "complexity": { "min": 1, "max": 17, - "mean": 2.779433681073025, + "mean": 2.7793090604339326, "mode": 1, "median": 2, "range": 16, - "sum": 29840, - "total": 10736, + "sum": 29847, + "total": 10739, "totalUnique": 16, "unique": { - "1": 4355, - "2": 1060, + "1": 4356, + "2": 1061, "3": 1966, - "4": 1317, + "4": 1318, "5": 1040, "6": 477, "7": 299, @@ -81028,7 +81043,7 @@ "15": 1, "17": 1 }, - "uniquenessRatio": 0.0014903129657228018, + "uniquenessRatio": 0.0014898966384207096, "items": [ 1, 1, @@ -84076,6 +84091,7 @@ 3, 4, 2, + 2, 5, 3, 1, @@ -84904,6 +84920,7 @@ 1, 4, 3, + 1, 4, 1, 2, @@ -87612,6 +87629,7 @@ 1, 4, 6, + 4, 2, 5, 6, @@ -91786,7 +91804,7 @@ "#user-content-toctitle h2": 1 }, "uniquenessRatio": 1, - "ratio": 0.0011177347242921013 + "ratio": 0.0011174224788155322 }, "accessibility": { "total": 331, @@ -92111,7 +92129,7 @@ ".repo-access-add-team[aria-selected=true] .team-description": 1 }, "uniquenessRatio": 0.9577039274924471, - "ratio": 0.030830849478390463 + "ratio": 0.030822236707328428 }, "keyframes": { "total": 188, @@ -92178,7 +92196,7 @@ ".faq-mktg summary::-webkit-details-marker": 1 }, "uniquenessRatio": 1, - "ratio": 0.0028874813710879285 + "ratio": 0.002886674736940125 }, "combinators": { "total": 6287, diff --git a/src/__fixtures__/smashing-magazine-20231008.json b/src/__fixtures__/smashing-magazine-20231008.json index c49b444..158c705 100644 --- a/src/__fixtures__/smashing-magazine-20231008.json +++ b/src/__fixtures__/smashing-magazine-20231008.json @@ -43027,21 +43027,21 @@ "complexity": { "min": 1, "max": 13, - "mean": 2.9806863252284876, + "mean": 2.9803414381789963, "mode": 1, "median": 3, "range": 12, - "sum": 17285, + "sum": 17283, "total": 5799, "totalUnique": 12, "unique": { "1": 2266, "2": 486, "3": 1340, - "4": 430, - "5": 539, - "6": 220, - "7": 239, + "4": 431, + "5": 538, + "6": 221, + "7": 238, "8": 97, "9": 62, "10": 37, @@ -46194,10 +46194,10 @@ 5, 5, 5, - 5, + 4, 5, 7, - 7, + 6, 5, 5, 7, diff --git a/src/atrules/atrules.js b/src/atrules/atrules.js index 61828a8..8bb48c7 100644 --- a/src/atrules/atrules.js +++ b/src/atrules/atrules.js @@ -47,18 +47,14 @@ export function isMediaBrowserhack(prelude) { let returnValue = false walk(prelude, function (node) { - if (node.type === 'MediaQuery' - && node.children.size === 1 - && node.children.first.type === 'Identifier' - ) { - node = node.children.first + if (node.type === 'MediaQuery' && node.mediaType !== null) { // Note: CSSTree adds a trailing space to \\9 - if (startsWith('\\0', node.name) || endsWith('\\9 ', node.name)) { + if (startsWith('\\0', node.mediaType) || endsWith('\\9 ', node.mediaType)) { returnValue = true return this.break } } - if (node.type === 'MediaFeature') { + if (node.type === 'Feature' && node.kind === 'media') { if (node.value !== null && node.value.unit === '\\0') { returnValue = true return this.break diff --git a/src/atrules/atrules.test.js b/src/atrules/atrules.test.js index a9e6f2a..b65d1cc 100644 --- a/src/atrules/atrules.test.js +++ b/src/atrules/atrules.test.js @@ -8,6 +8,11 @@ AtRules('finds @layer', () => { // Fixture is pretty much a straight copy from all code examples from // https://css-tricks.com/css-cascade-layers/ const fixture = ` + @import url('test.css') layer; + @import url('test.css') layer(); + @import url('test.css') layer(test); + @import url('test.css') layer(test.abc); + /* establish a layer order up-front, from lowest to highest priority */ @layer reset, defaults, patterns, components, utilities, overrides; @@ -74,8 +79,8 @@ AtRules('finds @layer', () => { ` const actual = analyze(fixture).atrules.layer const expected = { - total: 46, - totalUnique: 25, + total: 48, + totalUnique: 27, unique: { "defaults": 5, "layer-1": 1, @@ -102,8 +107,10 @@ AtRules('finds @layer', () => { "layouts": 1, "structures": 1, "overrides": 1, + "test": 1, + "test.abc": 1, }, - uniquenessRatio: 25 / 46 + uniquenessRatio: 27 / 48 } assert.equal(actual, expected) diff --git a/src/index.js b/src/index.js index a20a7ed..010e121 100644 --- a/src/index.js +++ b/src/index.js @@ -181,6 +181,7 @@ export function analyze(css, options = {}) { if (atRuleName === 'media') { let prelude = stringifyNode(node.prelude) medias.push(prelude, node.prelude.loc) + if (isMediaBrowserhack(node.prelude)) { mediaBrowserhacks.push(prelude, node.prelude.loc) } @@ -214,13 +215,6 @@ export function analyze(css, options = {}) { containers.push(stringifyNode(node.prelude), node.prelude.loc) break } - if (atRuleName === 'layer') { - let prelude = stringifyNode(node.prelude) - prelude - .split(',') - .forEach(name => layers.push(name.trim(), node.prelude.loc)) - break - } if (atRuleName === 'property') { let prelude = stringifyNode(node.prelude) registeredProperties.push(prelude, node.prelude.loc) @@ -228,6 +222,10 @@ export function analyze(css, options = {}) { } break } + case 'Layer': { + layers.push(node.name, node.loc) + break + } case 'Rule': { let numSelectors = node.prelude.children ? node.prelude.children.size : 0 let numDeclarations = node.block.children ? node.block.children.size : 0 From 9f73da305db02a6746c47b1a75c82421ce9d90ca Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sat, 14 Oct 2023 15:20:23 +0200 Subject: [PATCH 2/6] fix duplicate Conditions --- src/__fixtures__/cnn-20231008.json | 66 ++++++++------------------- src/__fixtures__/github-20231008.json | 62 +++++++++---------------- src/atrules/atrules.test.js | 10 ++-- src/index.js | 23 ++++++---- 4 files changed, 62 insertions(+), 99 deletions(-) diff --git a/src/__fixtures__/cnn-20231008.json b/src/__fixtures__/cnn-20231008.json index af4d11a..68e5457 100644 --- a/src/__fixtures__/cnn-20231008.json +++ b/src/__fixtures__/cnn-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 10132, + "sourceLinesOfCode": 10127, "linesOfCode": 14690, "size": 821224, "comments": { @@ -6942,9 +6942,9 @@ } }, "selectors": { - "total": 4041, - "totalUnique": 2619, - "uniquenessRatio": 0.6481069042316259, + "total": 4036, + "totalUnique": 2618, + "uniquenessRatio": 0.6486620416253717, "specificity": { "min": [ 0, @@ -6962,9 +6962,9 @@ 1936 ], "mean": [ - 0.0004949269982677555, - 3.0606285572878003, - 0.47908933432318734 + 0.0004955401387512388, + 3.064420218037661, + 0.4796828543111992 ], "mode": [ 0, @@ -7462,11 +7462,6 @@ 4, 1 ], - [ - 0, - 0, - 0 - ], [ 0, 3, @@ -7567,11 +7562,6 @@ 5, 2 ], - [ - 0, - 0, - 0 - ], [ 0, 5, @@ -8047,11 +8037,6 @@ 6, 1 ], - [ - 0, - 0, - 0 - ], [ 0, 5, @@ -14507,11 +14492,6 @@ 6, 1 ], - [ - 0, - 0, - 0 - ], [ 0, 3, @@ -27167,11 +27147,6 @@ 6, 1 ], - [ - 0, - 0, - 0 - ], [ 0, 4, @@ -27183,7 +27158,7 @@ 1 ] ], - "total": 4041, + "total": 4036, "totalUnique": 27, "unique": { "0,0,1": 17, @@ -27195,7 +27170,6 @@ "0,3,1": 284, "0,4,0": 239, "0,4,1": 336, - "0,0,0": 6, "0,6,1": 113, "0,5,1": 373, "0,5,2": 114, @@ -27212,23 +27186,24 @@ "0,1,2": 8, "0,1,4": 1, "0,7,2": 4, + "0,0,0": 1, "0,8,0": 2 }, - "uniquenessRatio": 0.0066815144766146995 + "uniquenessRatio": 0.006689791873141724 }, "complexity": { "min": 1, "max": 18, - "mean": 5.612472160356347, + "mean": 5.616947472745292, "mode": 3, "median": 5, "range": 17, - "sum": 22680, - "total": 4041, + "sum": 22670, + "total": 4036, "totalUnique": 17, "unique": { "1": 552, - "2": 213, + "2": 208, "3": 727, "4": 414, "5": 346, @@ -27245,7 +27220,7 @@ "16": 8, "18": 4 }, - "uniquenessRatio": 0.004206879485275922, + "uniquenessRatio": 0.00421209117938553, "items": [ 1, 1, @@ -27344,7 +27319,6 @@ 4, 8, 8, - 2, 5, 5, 5, @@ -27365,7 +27339,6 @@ 8, 11, 11, - 2, 10, 11, 9, @@ -27461,7 +27434,6 @@ 10, 12, 12, - 2, 10, 7, 9, @@ -28753,7 +28725,6 @@ 10, 12, 12, - 2, 5, 5, 5, @@ -31285,7 +31256,6 @@ 1, 8, 13, - 2, 6, 11 ] @@ -31298,7 +31268,7 @@ "#taui-mvpdpicker": 1 }, "uniquenessRatio": 1, - "ratio": 0.0004949269982677555 + "ratio": 0.0004955401387512388 }, "accessibility": { "total": 4, @@ -31310,7 +31280,7 @@ ".kiln-edit-mode .kiln-overlay-form.byline button[aria-label='Do Magic']:hover": 1 }, "uniquenessRatio": 1, - "ratio": 0.000989853996535511 + "ratio": 0.0009910802775024777 }, "keyframes": { "total": 12, @@ -31334,7 +31304,7 @@ ".ad-feedback__container .ad-feedback__comment:-ms-input-placeholder": 1 }, "uniquenessRatio": 1, - "ratio": 0.000989853996535511 + "ratio": 0.0009910802775024777 }, "combinators": { "total": 5663, diff --git a/src/__fixtures__/github-20231008.json b/src/__fixtures__/github-20231008.json index c3cbfc9..eeba813 100644 --- a/src/__fixtures__/github-20231008.json +++ b/src/__fixtures__/github-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 33281, + "sourceLinesOfCode": 33278, "linesOfCode": 51852, "size": 1206900, "comments": { @@ -27243,9 +27243,9 @@ } }, "selectors": { - "total": 10739, - "totalUnique": 9594, - "uniquenessRatio": 0.893379271813018, + "total": 10736, + "totalUnique": 9591, + "uniquenessRatio": 0.893349478390462, "specificity": { "min": [ 0, @@ -27259,13 +27259,13 @@ ], "sum": [ 12, - 19841, + 19836, 2273 ], "mean": [ - 0.0011174224788155322, - 1.8475649501815812, - 0.21165844119564206 + 0.0011177347242921013, + 1.8476154992548435, + 0.21171758569299554 ], "mode": [ 0, @@ -42508,11 +42508,6 @@ 2, 0 ], - [ - 0, - 2, - 0 - ], [ 0, 2, @@ -46653,11 +46648,6 @@ 1, 2 ], - [ - 0, - 1, - 0 - ], [ 0, 2, @@ -60203,11 +60193,6 @@ 2, 0 ], - [ - 0, - 2, - 0 - ], [ 0, 3, @@ -80974,11 +80959,11 @@ 0 ] ], - "total": 10739, + "total": 10736, "totalUnique": 35, "unique": { - "0,1,0": 4262, - "0,2,0": 2347, + "0,1,0": 4261, + "0,2,0": 2345, "0,1,1": 631, "0,2,1": 568, "0,0,1": 115, @@ -81013,23 +80998,23 @@ "1,0,4": 1, "1,0,3": 1 }, - "uniquenessRatio": 0.0032591488965453023 + "uniquenessRatio": 0.0032600596125186287 }, "complexity": { "min": 1, "max": 17, - "mean": 2.7793090604339326, + "mean": 2.779433681073025, "mode": 1, "median": 2, "range": 16, - "sum": 29847, - "total": 10739, + "sum": 29840, + "total": 10736, "totalUnique": 16, "unique": { - "1": 4356, - "2": 1061, + "1": 4355, + "2": 1060, "3": 1966, - "4": 1318, + "4": 1317, "5": 1040, "6": 477, "7": 299, @@ -81043,7 +81028,7 @@ "15": 1, "17": 1 }, - "uniquenessRatio": 0.0014898966384207096, + "uniquenessRatio": 0.0014903129657228018, "items": [ 1, 1, @@ -84091,7 +84076,6 @@ 3, 4, 2, - 2, 5, 3, 1, @@ -84920,7 +84904,6 @@ 1, 4, 3, - 1, 4, 1, 2, @@ -87629,7 +87612,6 @@ 1, 4, 6, - 4, 2, 5, 6, @@ -91804,7 +91786,7 @@ "#user-content-toctitle h2": 1 }, "uniquenessRatio": 1, - "ratio": 0.0011174224788155322 + "ratio": 0.0011177347242921013 }, "accessibility": { "total": 331, @@ -92129,7 +92111,7 @@ ".repo-access-add-team[aria-selected=true] .team-description": 1 }, "uniquenessRatio": 0.9577039274924471, - "ratio": 0.030822236707328428 + "ratio": 0.030830849478390463 }, "keyframes": { "total": 188, @@ -92196,7 +92178,7 @@ ".faq-mktg summary::-webkit-details-marker": 1 }, "uniquenessRatio": 1, - "ratio": 0.002886674736940125 + "ratio": 0.0028874813710879285 }, "combinators": { "total": 6287, diff --git a/src/atrules/atrules.test.js b/src/atrules/atrules.test.js index b65d1cc..3bfbc52 100644 --- a/src/atrules/atrules.test.js +++ b/src/atrules/atrules.test.js @@ -296,16 +296,20 @@ AtRules('finds @supports', () => { @media (min-width: 0) { @supports (-webkit-appearance: none) {} } + + /* Should not wrap in extra (), because CSSTree will see it as 2 Conditions */ + @supports not (stroke-color: transparent) {} ` const actual = analyze(fixture).atrules.supports - assert.equal(actual.total, 4) - assert.equal(actual.totalUnique, 3) - assert.equal(actual.uniquenessRatio, 3 / 4) + assert.equal(actual.total, 5) + assert.equal(actual.totalUnique, 4) + assert.equal(actual.uniquenessRatio, 4 / 5) assert.equal(actual.unique, { '(filter: blur(5px))': 1, '(display: table-cell) and (display: list-item)': 1, '(-webkit-appearance: none)': 2, + 'not (stroke-color: transparent)': 1, }) }) diff --git a/src/index.js b/src/index.js index 010e121..bf70a6b 100644 --- a/src/index.js +++ b/src/index.js @@ -187,14 +187,6 @@ export function analyze(css, options = {}) { } break } - if (atRuleName === 'supports') { - let prelude = stringifyNode(node.prelude) - supports.push(prelude, node.prelude.loc) - if (isSupportsBrowserhack(node.prelude)) { - supportsBrowserhacks.push(prelude, node.prelude.loc) - } - break - } if (endsWith('keyframes', atRuleName)) { let name = '@' + atRuleName + ' ' + stringifyNode(node.prelude) if (hasVendorPrefix(atRuleName)) { @@ -226,6 +218,21 @@ export function analyze(css, options = {}) { layers.push(node.name, node.loc) break } + case 'Condition': { + if (node.kind === 'supports') { + if (node.children && node.children.size === 1 && node.children.first.type === 'Condition') { + break + } + let prelude = stringifyNode(node) + supports.push(prelude, node.loc) + + if (isSupportsBrowserhack(node)) { + supportsBrowserhacks.push(prelude, node.loc) + } + return this.skip + } + break + } case 'Rule': { let numSelectors = node.prelude.children ? node.prelude.children.size : 0 let numDeclarations = node.block.children ? node.block.children.size : 0 From 7eeca7071e499d9b6a965d3526cabcc211331a00 Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sat, 14 Oct 2023 15:42:50 +0200 Subject: [PATCH 3/6] revert Condition parsing --- src/__fixtures__/cnn-20231008.json | 66 +++++++++++++++++++-------- src/__fixtures__/github-20231008.json | 62 ++++++++++++++++--------- src/index.js | 25 ++++------ 3 files changed, 98 insertions(+), 55 deletions(-) diff --git a/src/__fixtures__/cnn-20231008.json b/src/__fixtures__/cnn-20231008.json index 68e5457..af4d11a 100644 --- a/src/__fixtures__/cnn-20231008.json +++ b/src/__fixtures__/cnn-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 10127, + "sourceLinesOfCode": 10132, "linesOfCode": 14690, "size": 821224, "comments": { @@ -6942,9 +6942,9 @@ } }, "selectors": { - "total": 4036, - "totalUnique": 2618, - "uniquenessRatio": 0.6486620416253717, + "total": 4041, + "totalUnique": 2619, + "uniquenessRatio": 0.6481069042316259, "specificity": { "min": [ 0, @@ -6962,9 +6962,9 @@ 1936 ], "mean": [ - 0.0004955401387512388, - 3.064420218037661, - 0.4796828543111992 + 0.0004949269982677555, + 3.0606285572878003, + 0.47908933432318734 ], "mode": [ 0, @@ -7462,6 +7462,11 @@ 4, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 3, @@ -7562,6 +7567,11 @@ 5, 2 ], + [ + 0, + 0, + 0 + ], [ 0, 5, @@ -8037,6 +8047,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 5, @@ -14492,6 +14507,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 3, @@ -27147,6 +27167,11 @@ 6, 1 ], + [ + 0, + 0, + 0 + ], [ 0, 4, @@ -27158,7 +27183,7 @@ 1 ] ], - "total": 4036, + "total": 4041, "totalUnique": 27, "unique": { "0,0,1": 17, @@ -27170,6 +27195,7 @@ "0,3,1": 284, "0,4,0": 239, "0,4,1": 336, + "0,0,0": 6, "0,6,1": 113, "0,5,1": 373, "0,5,2": 114, @@ -27186,24 +27212,23 @@ "0,1,2": 8, "0,1,4": 1, "0,7,2": 4, - "0,0,0": 1, "0,8,0": 2 }, - "uniquenessRatio": 0.006689791873141724 + "uniquenessRatio": 0.0066815144766146995 }, "complexity": { "min": 1, "max": 18, - "mean": 5.616947472745292, + "mean": 5.612472160356347, "mode": 3, "median": 5, "range": 17, - "sum": 22670, - "total": 4036, + "sum": 22680, + "total": 4041, "totalUnique": 17, "unique": { "1": 552, - "2": 208, + "2": 213, "3": 727, "4": 414, "5": 346, @@ -27220,7 +27245,7 @@ "16": 8, "18": 4 }, - "uniquenessRatio": 0.00421209117938553, + "uniquenessRatio": 0.004206879485275922, "items": [ 1, 1, @@ -27319,6 +27344,7 @@ 4, 8, 8, + 2, 5, 5, 5, @@ -27339,6 +27365,7 @@ 8, 11, 11, + 2, 10, 11, 9, @@ -27434,6 +27461,7 @@ 10, 12, 12, + 2, 10, 7, 9, @@ -28725,6 +28753,7 @@ 10, 12, 12, + 2, 5, 5, 5, @@ -31256,6 +31285,7 @@ 1, 8, 13, + 2, 6, 11 ] @@ -31268,7 +31298,7 @@ "#taui-mvpdpicker": 1 }, "uniquenessRatio": 1, - "ratio": 0.0004955401387512388 + "ratio": 0.0004949269982677555 }, "accessibility": { "total": 4, @@ -31280,7 +31310,7 @@ ".kiln-edit-mode .kiln-overlay-form.byline button[aria-label='Do Magic']:hover": 1 }, "uniquenessRatio": 1, - "ratio": 0.0009910802775024777 + "ratio": 0.000989853996535511 }, "keyframes": { "total": 12, @@ -31304,7 +31334,7 @@ ".ad-feedback__container .ad-feedback__comment:-ms-input-placeholder": 1 }, "uniquenessRatio": 1, - "ratio": 0.0009910802775024777 + "ratio": 0.000989853996535511 }, "combinators": { "total": 5663, diff --git a/src/__fixtures__/github-20231008.json b/src/__fixtures__/github-20231008.json index eeba813..c3cbfc9 100644 --- a/src/__fixtures__/github-20231008.json +++ b/src/__fixtures__/github-20231008.json @@ -1,6 +1,6 @@ { "stylesheet": { - "sourceLinesOfCode": 33278, + "sourceLinesOfCode": 33281, "linesOfCode": 51852, "size": 1206900, "comments": { @@ -27243,9 +27243,9 @@ } }, "selectors": { - "total": 10736, - "totalUnique": 9591, - "uniquenessRatio": 0.893349478390462, + "total": 10739, + "totalUnique": 9594, + "uniquenessRatio": 0.893379271813018, "specificity": { "min": [ 0, @@ -27259,13 +27259,13 @@ ], "sum": [ 12, - 19836, + 19841, 2273 ], "mean": [ - 0.0011177347242921013, - 1.8476154992548435, - 0.21171758569299554 + 0.0011174224788155322, + 1.8475649501815812, + 0.21165844119564206 ], "mode": [ 0, @@ -42508,6 +42508,11 @@ 2, 0 ], + [ + 0, + 2, + 0 + ], [ 0, 2, @@ -46648,6 +46653,11 @@ 1, 2 ], + [ + 0, + 1, + 0 + ], [ 0, 2, @@ -60193,6 +60203,11 @@ 2, 0 ], + [ + 0, + 2, + 0 + ], [ 0, 3, @@ -80959,11 +80974,11 @@ 0 ] ], - "total": 10736, + "total": 10739, "totalUnique": 35, "unique": { - "0,1,0": 4261, - "0,2,0": 2345, + "0,1,0": 4262, + "0,2,0": 2347, "0,1,1": 631, "0,2,1": 568, "0,0,1": 115, @@ -80998,23 +81013,23 @@ "1,0,4": 1, "1,0,3": 1 }, - "uniquenessRatio": 0.0032600596125186287 + "uniquenessRatio": 0.0032591488965453023 }, "complexity": { "min": 1, "max": 17, - "mean": 2.779433681073025, + "mean": 2.7793090604339326, "mode": 1, "median": 2, "range": 16, - "sum": 29840, - "total": 10736, + "sum": 29847, + "total": 10739, "totalUnique": 16, "unique": { - "1": 4355, - "2": 1060, + "1": 4356, + "2": 1061, "3": 1966, - "4": 1317, + "4": 1318, "5": 1040, "6": 477, "7": 299, @@ -81028,7 +81043,7 @@ "15": 1, "17": 1 }, - "uniquenessRatio": 0.0014903129657228018, + "uniquenessRatio": 0.0014898966384207096, "items": [ 1, 1, @@ -84076,6 +84091,7 @@ 3, 4, 2, + 2, 5, 3, 1, @@ -84904,6 +84920,7 @@ 1, 4, 3, + 1, 4, 1, 2, @@ -87612,6 +87629,7 @@ 1, 4, 6, + 4, 2, 5, 6, @@ -91786,7 +91804,7 @@ "#user-content-toctitle h2": 1 }, "uniquenessRatio": 1, - "ratio": 0.0011177347242921013 + "ratio": 0.0011174224788155322 }, "accessibility": { "total": 331, @@ -92111,7 +92129,7 @@ ".repo-access-add-team[aria-selected=true] .team-description": 1 }, "uniquenessRatio": 0.9577039274924471, - "ratio": 0.030830849478390463 + "ratio": 0.030822236707328428 }, "keyframes": { "total": 188, @@ -92178,7 +92196,7 @@ ".faq-mktg summary::-webkit-details-marker": 1 }, "uniquenessRatio": 1, - "ratio": 0.0028874813710879285 + "ratio": 0.002886674736940125 }, "combinators": { "total": 6287, diff --git a/src/index.js b/src/index.js index bf70a6b..5a709c7 100644 --- a/src/index.js +++ b/src/index.js @@ -187,6 +187,16 @@ export function analyze(css, options = {}) { } break } + if (atRuleName === 'supports') { + let prelude = node.prelude + let condition = stringifyNode(prelude) + supports.push(condition, prelude.loc) + + if (isSupportsBrowserhack(prelude)) { + supportsBrowserhacks.push(condition, prelude.loc) + } + break + } if (endsWith('keyframes', atRuleName)) { let name = '@' + atRuleName + ' ' + stringifyNode(node.prelude) if (hasVendorPrefix(atRuleName)) { @@ -218,21 +228,6 @@ export function analyze(css, options = {}) { layers.push(node.name, node.loc) break } - case 'Condition': { - if (node.kind === 'supports') { - if (node.children && node.children.size === 1 && node.children.first.type === 'Condition') { - break - } - let prelude = stringifyNode(node) - supports.push(prelude, node.loc) - - if (isSupportsBrowserhack(node)) { - supportsBrowserhacks.push(prelude, node.loc) - } - return this.skip - } - break - } case 'Rule': { let numSelectors = node.prelude.children ? node.prelude.children.size : 0 let numDeclarations = node.block.children ? node.block.children.size : 0 From 1fef8bbc7281b0e0e43cdabc9d14acf69babb9a0 Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 15 Oct 2023 09:53:35 +0200 Subject: [PATCH 4/6] Skip `font-tech()` in SupportsCondition test --- src/atrules/atrules.test.js | 47 +++++++++++++++++++++++++++++++++---- src/index.js | 10 ++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/atrules/atrules.test.js b/src/atrules/atrules.test.js index 3bfbc52..ed74212 100644 --- a/src/atrules/atrules.test.js +++ b/src/atrules/atrules.test.js @@ -248,11 +248,16 @@ AtRules('finds @imports', () => { @import url('../example.css') layer; @import url('remedy.css') layer(reset.remedy); + + @import 'test.css' supports((display: grid)); + @import 'test.css' supports(not (display: grid)); + @import 'test.css' supports(selector(a:has(b))); + /*@import "test.css" supports((selector(h2 > p) and (font-tech(color-COLRv1))));*/ ` - const actual = analyze(fixture).atrules.import + const actual = analyze(fixture).atrules const expected = { - total: 7, - totalUnique: 7, + total: 10, + totalUnique: 10, unique: { '"https://example.com/without-url"': 1, 'url("https://example.com/with-url")': 1, @@ -261,11 +266,45 @@ AtRules('finds @imports', () => { 'url(\'example.css\') layer(named-layer)': 1, 'url(\'../example.css\') layer': 1, 'url(\'remedy.css\') layer(reset.remedy)': 1, + "'test.css' supports((display: grid))": 1, + "'test.css' supports(not (display: grid))": 1, + "'test.css' supports(selector(a:has(b)))": 1, + // '"test.css" supports((selector(h2 > p) and (font-tech(color-COLRv1))))': 1, }, uniquenessRatio: 1, } - assert.equal(actual, expected) + assert.equal(actual.import, expected) + + const expected_supports = { + total: 3, + totalUnique: 3, + unique: { + "(display: grid)": 1, + "not (display: grid)": 1, + "selector(a:has(b))": 1, + // "selector(h2 > p) and (font-tech(color-COLRv1))": 1, + }, + uniquenessRatio: 1, + browserhacks: { + total: 0, + totalUnique: 0, + unique: {}, + uniquenessRatio: 0, + } + } + assert.equal(actual.supports, expected_supports, 'Incorrect SupportsCondition matches') + + const expected_layers = { + total: 2, + totalUnique: 2, + unique: { + 'named-layer': 1, + 'reset.remedy': 1, + }, + uniquenessRatio: 1, + } + assert.equal(actual.layer, expected_layers, 'Incorrect Layer matches') }) AtRules('finds @charsets', () => { diff --git a/src/index.js b/src/index.js index 5a709c7..8768b51 100644 --- a/src/index.js +++ b/src/index.js @@ -206,6 +206,16 @@ export function analyze(css, options = {}) { break } if (atRuleName === 'import') { + walk(node, function (prelude_node) { + if (prelude_node.type === 'Condition' && prelude_node.kind === 'supports') { + supports.push(stringifyNode(prelude_node), prelude_node.loc) + + if (isSupportsBrowserhack(prelude_node)) { + supportsBrowserhacks.push(stringifyNode(prelude_node), prelude_node.loc) + } + return this.break + } + }) imports.push(stringifyNode(node.prelude), node.prelude.loc) break } From 2020c294f4c9fd79dc6c6fa9e742b68abe21aaa6 Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 15 Oct 2023 10:05:23 +0200 Subject: [PATCH 5/6] cache @import supports prelude --- src/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 8768b51..347dca8 100644 --- a/src/index.js +++ b/src/index.js @@ -208,10 +208,11 @@ export function analyze(css, options = {}) { if (atRuleName === 'import') { walk(node, function (prelude_node) { if (prelude_node.type === 'Condition' && prelude_node.kind === 'supports') { - supports.push(stringifyNode(prelude_node), prelude_node.loc) + let prelude = stringifyNode(prelude_node) + supports.push(prelude, prelude_node.loc) if (isSupportsBrowserhack(prelude_node)) { - supportsBrowserhacks.push(stringifyNode(prelude_node), prelude_node.loc) + supportsBrowserhacks.push(prelude, prelude_node.loc) } return this.break } From c03a9796462078cfe505a7f64dd653e05f2380db Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 15 Oct 2023 11:27:41 +0200 Subject: [PATCH 6/6] improve `@supports` tests --- src/atrules/atrules.test.js | 45 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/src/atrules/atrules.test.js b/src/atrules/atrules.test.js index ed74212..7ae862b 100644 --- a/src/atrules/atrules.test.js +++ b/src/atrules/atrules.test.js @@ -338,17 +338,21 @@ AtRules('finds @supports', () => { /* Should not wrap in extra (), because CSSTree will see it as 2 Conditions */ @supports not (stroke-color: transparent) {} + @supports (not (stroke-color: transparent)) {} ` const actual = analyze(fixture).atrules.supports + delete actual.browserhacks - assert.equal(actual.total, 5) - assert.equal(actual.totalUnique, 4) - assert.equal(actual.uniquenessRatio, 4 / 5) - assert.equal(actual.unique, { - '(filter: blur(5px))': 1, - '(display: table-cell) and (display: list-item)': 1, - '(-webkit-appearance: none)': 2, - 'not (stroke-color: transparent)': 1, + assert.equal(actual, { + total: 6, + totalUnique: 4, + uniquenessRatio: 4 / 6, + unique: { + '(filter: blur(5px))': 1, + '(display: table-cell) and (display: list-item)': 1, + '(-webkit-appearance: none)': 2, + 'not (stroke-color: transparent)': 2, + } }) }) @@ -405,19 +409,22 @@ AtRules('finds @media', () => { } ` const actual = analyze(fixture).atrules.media + delete actual.browserhacks - assert.is(actual.total, 7) - assert.is(actual.totalUnique, 7) - assert.equal(actual.unique, { - 'screen': 1, - 'screen and (min-width: 33em)': 1, - '(min-width: 20px)': 1, - '(max-width: 200px)': 1, - 'screen or print': 1, - 'all and (transform-3d), (-webkit-transform-3d)': 1, - '(min-width: 0)': 1, + assert.equal(actual, { + total: 7, + totalUnique: 7, + uniquenessRatio: 1, + unique: { + 'screen': 1, + 'screen and (min-width: 33em)': 1, + '(min-width: 20px)': 1, + '(max-width: 200px)': 1, + 'screen or print': 1, + 'all and (transform-3d), (-webkit-transform-3d)': 1, + '(min-width: 0)': 1, + } }) - assert.is(actual.uniquenessRatio, 1) }) AtRules('finds @media browserhacks', () => {