From 794d3aac01459858345307ee4dee86aad69d1206 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Thu, 21 Nov 2024 21:40:28 -0500 Subject: [PATCH 1/6] Separate out csstree --- package-lock.json | 273 ++++++++++++++++++++++++++++++++++++++++++---- package.json | 3 +- src/cascade.ts | 10 +- src/fallback.ts | 80 +++++++------- src/parse.ts | 78 ++++++------- src/utils.ts | 46 ++++---- vite.config.ts | 2 + 7 files changed, 362 insertions(+), 130 deletions(-) diff --git a/package-lock.json b/package-lock.json index 28707152..ffd48ac2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "@floating-ui/dom": "^1.6.12", "@types/css-tree": "^2.3.8", "css-tree": "^3.0.0", - "nanoid": "^5.0.8" + "nanoid": "^5.0.8", + "rollup-plugin-bundle-stats": "^4.17.0" }, "devDependencies": { "@playwright/test": "1.43.1", @@ -406,6 +407,68 @@ "integrity": "sha512-1uLNT5NZsUVIGS4syuHwTzZ8HycMPyr6POA3FCE4GbMtc4rhoJk8aZKtNIRthJYfL+iioppi+rTfH3olMPr9nA==", "dev": true }, + "node_modules/@bundle-stats/cli-utils": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@bundle-stats/cli-utils/-/cli-utils-4.17.0.tgz", + "integrity": "sha512-JIQBOda71sEyDOfJ0/YIIatwVnEB8UsbyFmHbTZXMqVhPU7ddnRzmYmPgmnqPkhqss3tjArTHGS+HIL9Kvs7Cw==", + "dependencies": { + "@bundle-stats/html-templates": "^4.17.0", + "@bundle-stats/plugin-webpack-filter": "^4.17.0", + "@bundle-stats/utils": "^4.17.0", + "find-cache-dir": "^3.1.0", + "lodash": "^4.17.21", + "stream-chain": "^3.0.1", + "stream-json": "^1.8.0" + }, + "engines": { + "node": ">= 14.0" + } + }, + "node_modules/@bundle-stats/html-templates": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@bundle-stats/html-templates/-/html-templates-4.17.0.tgz", + "integrity": "sha512-B9AYHV1hyioS8S5qpWmP7vEn1npBWJHV/tSEHRFQTJOpGZdn6L0jHyzvofRvopqirTff++UpVS3TelN+Elh/tQ==" + }, + "node_modules/@bundle-stats/plugin-webpack-filter": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-filter/-/plugin-webpack-filter-4.17.0.tgz", + "integrity": "sha512-sGC1c7oiRNKY19OLNB2Yha88Yt+UC7OJWlk8O6HBvN/OO8ACvZ6DuxRMNBXMyP0cDDAJlcY9v9rzy0bbnegzAw==", + "engines": { + "node": ">= 14.0" + }, + "peerDependencies": { + "core-js": "^3.0.0" + } + }, + "node_modules/@bundle-stats/plugin-webpack-validate": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@bundle-stats/plugin-webpack-validate/-/plugin-webpack-validate-4.17.0.tgz", + "integrity": "sha512-dsCAIYiQ1ohRt7wyR5gfQCT3OKLjHxRZ3F/uL0gnBO56+xnvDzO/s+A5QO4EerlXIRIUBW8JWWuYAhe8ccdFjA==", + "dependencies": { + "lodash": "4.17.21", + "superstruct": "2.0.2" + }, + "engines": { + "node": ">= 14.0" + } + }, + "node_modules/@bundle-stats/utils": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@bundle-stats/utils/-/utils-4.17.0.tgz", + "integrity": "sha512-0/8/hebdV7QzPBZW7uyKClWpSsxVsQ/DfDwmNkmXSOq45eTeVNXozyvdYgwmLz0Ff9tVMyXu0Kb6iAVL6Hpt+g==", + "dependencies": { + "@bundle-stats/plugin-webpack-filter": "^4.17.0", + "@bundle-stats/plugin-webpack-validate": "^4.17.0", + "serialize-query-params": "2.0.2" + }, + "engines": { + "node": ">= 14.0" + }, + "peerDependencies": { + "core-js": "^3.0.0", + "lodash": "^4.0.0" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -1306,7 +1369,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "android" @@ -1319,7 +1381,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -1332,7 +1393,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1345,7 +1405,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -1358,7 +1417,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1371,7 +1429,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1384,7 +1441,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1397,7 +1453,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1410,7 +1465,6 @@ "cpu": [ "ppc64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1423,7 +1477,6 @@ "cpu": [ "riscv64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1436,7 +1489,6 @@ "cpu": [ "s390x" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1449,7 +1501,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1462,7 +1513,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -1475,7 +1525,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1488,7 +1537,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1501,7 +1549,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -1551,8 +1598,7 @@ "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/glob-to-regexp": { "version": "0.4.4", @@ -2412,6 +2458,11 @@ "node": ">=14" } }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2424,6 +2475,17 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/core-js": { + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz", + "integrity": "sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==", + "hasInstallScript": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -3523,6 +3585,44 @@ "node": ">=8" } }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3613,7 +3713,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -4782,6 +4881,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -5416,6 +5520,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -5469,7 +5581,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -5595,6 +5706,65 @@ "node": ">=4" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/playwright": { "version": "1.43.1", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.43.1.tgz", @@ -5938,7 +6108,6 @@ "version": "4.24.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", - "dev": true, "dependencies": { "@types/estree": "1.0.6" }, @@ -5969,6 +6138,32 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup-plugin-bundle-stats": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-bundle-stats/-/rollup-plugin-bundle-stats-4.17.0.tgz", + "integrity": "sha512-qib0al0arhVlF1/nXynKNXbE5uUWuGr0GNzs+Dpub8Wu2bEvb3m5WaMpotXrK8d4pYoBpC8v38fXSqH0H+tapA==", + "dependencies": { + "@bundle-stats/cli-utils": "^4.17.0", + "rollup-plugin-webpack-stats": "0.4.1" + }, + "engines": { + "node": ">= 16.0" + }, + "peerDependencies": { + "rollup": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/rollup-plugin-webpack-stats": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-webpack-stats/-/rollup-plugin-webpack-stats-0.4.1.tgz", + "integrity": "sha512-Zi7t0G7FtA55LNcU9B3s2gBo3PODbdo+288Cw2/4sA8+o9H/ahhWZ25UxADeHwriAzW808iDpPbB81C5jGLIbg==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "^3.0.0 || ^4.0.0" + } + }, "node_modules/rrweb-cssom": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", @@ -6084,6 +6279,11 @@ "node": ">=10" } }, + "node_modules/serialize-query-params": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/serialize-query-params/-/serialize-query-params-2.0.2.tgz", + "integrity": "sha512-1chMo1dST4pFA9RDXAtF0Rbjaut4is7bzFbI1Z26IuMub68pNCILku85aYmeFhvnY//BXUPUhoRMjYcsT93J/Q==" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -6278,6 +6478,14 @@ "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", "dev": true }, + "node_modules/stream-chain": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-3.3.2.tgz", + "integrity": "sha512-YvRznt2X9tLSQlQXkYxp9FGcp6uUwBG9VAyjgo53Ov+Ctk36R49xB6NUia37T7owHyi3UtvI6achAj4ufBSaNg==", + "funding": { + "url": "https://github.com/sponsors/uhop" + } + }, "node_modules/stream-combiner": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", @@ -6287,6 +6495,19 @@ "duplexer": "~0.1.1" } }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/stream-json/node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -6596,6 +6817,14 @@ "node": ">=8" } }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/package.json b/package.json index 91083cd4..0e2fe36a 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,8 @@ "@floating-ui/dom": "^1.6.12", "@types/css-tree": "^2.3.8", "css-tree": "^3.0.0", - "nanoid": "^5.0.8" + "nanoid": "^5.0.8", + "rollup-plugin-bundle-stats": "^4.17.0" }, "devDependencies": { "@playwright/test": "1.43.1", diff --git a/src/cascade.ts b/src/cascade.ts index 8cf4dca0..f58220f9 100644 --- a/src/cascade.ts +++ b/src/cascade.ts @@ -1,4 +1,5 @@ -import * as csstree from 'css-tree'; +import { type Block, type CssNode, } from 'css-tree'; +import walk from 'css-tree/walker'; import { generateCSS, @@ -34,10 +35,7 @@ export const SHIFTED_PROPERTIES: Record = { * Shift property declarations for properties that are not yet natively * supported into custom properties. */ -function shiftUnsupportedProperties( - node: csstree.CssNode, - block?: csstree.Block, -) { +function shiftUnsupportedProperties(node: CssNode, block?: Block) { if (isDeclaration(node) && SHIFTED_PROPERTIES[node.property] && block) { block.children.appendData({ ...node, @@ -56,7 +54,7 @@ export function cascadeCSS(styleData: StyleData[]) { for (const styleObj of styleData) { let changed = false; const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Declaration', enter(node) { const block = this.rule?.block; diff --git a/src/fallback.ts b/src/fallback.ts index 7692c749..f2ebcbe4 100644 --- a/src/fallback.ts +++ b/src/fallback.ts @@ -1,4 +1,16 @@ -import * as csstree from 'css-tree'; +import { + type Atrule, + type Block, + type CssNode, + type Declaration, + type Identifier, + type Raw, + type Rule, + type SelectorList, + type Value, +} from 'css-tree'; +import walk from 'css-tree/walker'; +import {clone, List} from 'css-tree/utils'; import { nanoid } from 'nanoid/non-secure'; import { getCSSPropertyValue } from './dom.js'; @@ -30,9 +42,8 @@ import { } from './utils.js'; // https://github.com/import-js/eslint-plugin-import/issues/3019 -// eslint-disable-next-line import/namespace -interface AtRuleRaw extends csstree.Atrule { - prelude: csstree.Raw | null; +interface AtRuleRaw extends Atrule { + prelude: Raw | null; } // `key` is the `@position-try` block uuid @@ -148,12 +159,12 @@ interface PositionTryDefPositionArea { } interface PositionTryDefAtRule { type: 'at-rule'; - atRule: csstree.Identifier['name']; + atRule: Identifier['name']; } interface PositionTryDefAtRuleWithTactic { type: 'at-rule-with-try-tactic'; tactics: PositionTryOptionsTryTactics[]; - atRule: csstree.Identifier['name']; + atRule: Identifier['name']; } type PositionTryObject = @@ -168,12 +179,12 @@ export function isPositionAreaProp( return POSITION_AREA_PROPS.includes(property as PositionAreaProperty); } -function isDeclaration(node: csstree.CssNode): node is DeclarationWithValue { +function isDeclaration(node: CssNode): node is DeclarationWithValue { return node.type === 'Declaration'; } function isPositionTryFallbacksDeclaration( - node: csstree.CssNode, + node: CssNode, ): node is DeclarationWithValue { return ( node.type === 'Declaration' && node.property === 'position-try-fallbacks' @@ -181,18 +192,16 @@ function isPositionTryFallbacksDeclaration( } function isPositionTryOrderDeclaration( - node: csstree.CssNode, + node: CssNode, ): node is DeclarationWithValue { return node.type === 'Declaration' && node.property === 'position-try-order'; } -function isPositionTryDeclaration( - node: csstree.CssNode, -): node is DeclarationWithValue { +function isPositionTryDeclaration(node: CssNode): node is DeclarationWithValue { return node.type === 'Declaration' && node.property === 'position-try'; } -function isPositionTryAtRule(node: csstree.CssNode): node is AtRuleRaw { +function isPositionTryAtRule(node: CssNode): node is AtRuleRaw { return node.type === 'Atrule' && node.name === 'position-try'; } @@ -365,7 +374,7 @@ function mapPositionArea( function mapMargin( key: string, - valueAst: csstree.Value, + valueAst: Value, tactic: PositionTryOptionsTryTactics, ) { // TODO: Handle flip-start @@ -401,10 +410,10 @@ function mapMargin( // Parses a value into an AST. const getValueAST = (property: string, val: string) => { - const ast = getAST(`#id{${property}: ${val};}`) as csstree.Block; - const astDeclaration = (ast.children.first as csstree.Rule)?.block.children - .first as csstree.Declaration; - return astDeclaration.value as csstree.Value; + const ast = getAST(`#id{${property}: ${val};}`) as Block; + const astDeclaration = (ast.children.first as Rule)?.block.children + .first as Declaration; + return astDeclaration.value as Value; }; export function applyTryTacticToBlock( @@ -425,7 +434,7 @@ export function applyTryTacticToBlock( // todo: This does not support percentage anchor-side values, nor anchor // functions that are passed through custom properties. - csstree.walk(valueAst, { + walk(valueAst, { visit: 'Function', enter(node) { if (isAnchorFunction(node)) { @@ -454,7 +463,7 @@ export function applyTryTacticToBlock( return declarations; } -function parsePositionTryFallbacks(list: csstree.List) { +function parsePositionTryFallbacks(list: List) { const positionOptions = splitCommaList(list); const tryObjects: PositionTryObject[] = []; positionOptions.forEach((option) => { @@ -503,24 +512,22 @@ function parsePositionTryFallbacks(list: csstree.List) { return tryObjects; } -function getPositionTryFallbacksDeclaration(node: csstree.Declaration) { +function getPositionTryFallbacksDeclaration(node: Declaration) { if (isPositionTryFallbacksDeclaration(node) && node.value.children.first) { return parsePositionTryFallbacks(node.value.children); } return []; } -export function getPositionTryDeclaration(node: csstree.Declaration): { +export function getPositionTryDeclaration(node: Declaration): { order?: PositionTryOrder; options?: PositionTryObject[]; } { if (isPositionTryDeclaration(node) && node.value.children.first) { - const declarationNode = csstree.clone(node) as DeclarationWithValue; + const declarationNode = clone(node) as DeclarationWithValue; let order: PositionTryOrder | undefined; // get potential order - const firstName = ( - declarationNode.value.children.first as csstree.Identifier - ).name; + const firstName = (declarationNode.value.children.first as Identifier).name; if (firstName && isPositionTryOrder(firstName)) { order = firstName; declarationNode.value.children.shift(); @@ -532,17 +539,16 @@ export function getPositionTryDeclaration(node: csstree.Declaration): { return {}; } -function getPositionTryOrderDeclaration(node: csstree.Declaration) { +function getPositionTryOrderDeclaration(node: Declaration) { if (isPositionTryOrderDeclaration(node) && node.value.children.first) { return { - order: (node.value.children.first as csstree.Identifier) - .name as PositionTryOrder, + order: (node.value.children.first as Identifier).name as PositionTryOrder, }; } return {}; } -export function getPositionFallbackValues(node: csstree.Declaration): { +export function getPositionFallbackValues(node: Declaration): { order?: PositionTryOrder; options?: PositionTryObject[]; } { @@ -559,9 +565,7 @@ export function getPositionFallbackValues(node: csstree.Declaration): { } // https://drafts.csswg.org/css-anchor-position-1/#accepted-position-try-properties -export function isAcceptedPositionTryProperty( - declaration: csstree.Declaration, -) { +export function isAcceptedPositionTryProperty(declaration: Declaration) { return ( isInsetProp(declaration.property) || isMarginProp(declaration.property) || @@ -571,7 +575,7 @@ export function isAcceptedPositionTryProperty( ); } -export function getPositionTryRules(node: csstree.Atrule) { +export function getPositionTryRules(node: Atrule) { if ( isPositionTryAtRule(node) && node.prelude?.value && @@ -602,7 +606,7 @@ export function parsePositionFallbacks(styleData: StyleData[]) { // First, find all uses of `@position-try` for (const styleObj of styleData) { const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Atrule', enter(node) { // Parse `@position-try` rules @@ -623,10 +627,10 @@ export function parsePositionFallbacks(styleData: StyleData[]) { let changed = false; const fallbacksAdded = new Set(); const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Declaration', enter(node) { - const rule = this.rule?.prelude as csstree.SelectorList | undefined; + const rule = this.rule?.prelude as SelectorList | undefined; const selectors = getSelectors(rule); if (!selectors.length) return; @@ -694,7 +698,7 @@ export function parsePositionFallbacks(styleData: StyleData[]) { }, block: { type: 'Block', - children: new csstree.List().fromArray( + children: new List().fromArray( Object.entries(fallbacks[name].declarations).map( ([prop, val]) => ({ type: 'Declaration', diff --git a/src/parse.ts b/src/parse.ts index 46e81f70..bcdfca81 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -1,4 +1,13 @@ -import * as csstree from 'css-tree'; +import { + type CssNode, + type Declaration, + type FunctionNode, + type Identifier, + type List, + type Percentage, + type SelectorList, +} from 'css-tree'; +import walk from 'css-tree/walker'; import { nanoid } from 'nanoid/non-secure'; import { @@ -71,44 +80,34 @@ export interface TryBlock { declarations: Partial>; } -function isAnchorNameDeclaration( - node: csstree.CssNode, -): node is DeclarationWithValue { +function isAnchorNameDeclaration(node: CssNode): node is DeclarationWithValue { return node.type === 'Declaration' && node.property === 'anchor-name'; } -function isAnchorScopeDeclaration( - node: csstree.CssNode, -): node is DeclarationWithValue { +function isAnchorScopeDeclaration(node: CssNode): node is DeclarationWithValue { return node.type === 'Declaration' && node.property === 'anchor-scope'; } -function isAnchorSizeFunction( - node: csstree.CssNode | null, -): node is csstree.FunctionNode { +function isAnchorSizeFunction(node: CssNode | null): node is FunctionNode { return Boolean( node && node.type === 'Function' && node.name === 'anchor-size', ); } -function isVarFunction( - node: csstree.CssNode | null, -): node is csstree.FunctionNode { +function isVarFunction(node: CssNode | null): node is FunctionNode { return Boolean(node && node.type === 'Function' && node.name === 'var'); } -export function isIdentifier( - node: csstree.CssNode, -): node is csstree.Identifier { +export function isIdentifier(node: CssNode): node is Identifier { return Boolean(node.type === 'Identifier' && node.name); } -function isPercentage(node: csstree.CssNode): node is csstree.Percentage { +function isPercentage(node: CssNode): node is Percentage { return Boolean(node.type === 'Percentage' && node.value); } function parseAnchorFn( - node: csstree.FunctionNode, + node: FunctionNode, replaceCss?: boolean, ): AnchorFunction { let anchorName: string | undefined, @@ -118,7 +117,7 @@ function parseAnchorFn( foundComma = false, customPropName: string | undefined; - const args: csstree.CssNode[] = []; + const args: CssNode[] = []; node.children.toArray().forEach((child) => { if (foundComma) { fallbackValue = `${fallbackValue}${generateCSS(child)}`; @@ -131,7 +130,7 @@ function parseAnchorFn( args.push(child); }); - let [name, sideOrSize]: (csstree.CssNode | undefined)[] = args; + let [name, sideOrSize]: (CssNode | undefined)[] = args; if (!sideOrSize) { // If we only have one argument assume it is the (required) anchor-side/size sideOrSize = name; @@ -143,7 +142,7 @@ function parseAnchorFn( anchorName = name.name; } else if (isVarFunction(name) && name.children.first) { // Store CSS custom prop for anchor name - customPropName = (name.children.first as csstree.Identifier).name; + customPropName = (name.children.first as Identifier).name; } } if (sideOrSize) { @@ -187,9 +186,7 @@ function parseAnchorFn( } function getAnchorNames(node: DeclarationWithValue) { - return (node.value.children as csstree.List).map( - ({ name }) => name, - ); + return (node.value.children as List).map(({ name }) => name); } let anchorNames: AnchorSelectors = {}; @@ -217,10 +214,7 @@ function resetStores() { customPropReplacements = {}; } -function getAnchorFunctionData( - node: csstree.CssNode, - declaration: csstree.Declaration | null, -) { +function getAnchorFunctionData(node: CssNode, declaration: Declaration | null) { if ((isAnchorFunction(node) || isAnchorSizeFunction(node)) && declaration) { if (declaration.property.startsWith('--')) { const original = generateCSS(declaration.value); @@ -287,8 +281,8 @@ export async function parseCSS(styleData: StyleData[]) { for (const styleObj of styleData) { let changed = false; const ast = getAST(styleObj.css); - csstree.walk(ast, function (node) { - const rule = this.rule?.prelude as csstree.SelectorList | undefined; + walk(ast, function (node) { + const rule = this.rule?.prelude as SelectorList | undefined; const selectors = getSelectors(rule); // Parse `anchor-name` declaration @@ -374,10 +368,10 @@ export async function parseCSS(styleData: StyleData[]) { for (const styleObj of styleData) { let changed = false; const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Function', enter(node) { - const rule = this.rule?.prelude as csstree.SelectorList | undefined; + const rule = this.rule?.prelude as SelectorList | undefined; const declaration = this.declaration; const prop = declaration?.property; if ( @@ -386,13 +380,11 @@ export async function parseCSS(styleData: StyleData[]) { declaration && prop && node.children.first && - customPropsToCheck.has( - (node.children.first as csstree.Identifier).name, - ) && + customPropsToCheck.has((node.children.first as Identifier).name) && // For now, we only want assignments to other CSS custom properties prop.startsWith('--') ) { - const child = node.children.first as csstree.Identifier; + const child = node.children.first as Identifier; // Find anchor data assigned to this custom property const anchorFns = customPropAssignments[child.name] ?? []; // Find anchor data assigned to another custom property referenced @@ -444,10 +436,10 @@ export async function parseCSS(styleData: StyleData[]) { for (const styleObj of styleData) { let changed = false; const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Function', enter(node) { - const rule = this.rule?.prelude as csstree.SelectorList | undefined; + const rule = this.rule?.prelude as SelectorList | undefined; const declaration = this.declaration; const prop = declaration?.property; @@ -460,7 +452,7 @@ export async function parseCSS(styleData: StyleData[]) { // Now we only want assignments to inset/sizing properties (isInsetProp(prop) || isSizingProp(prop)) ) { - const child = node.children.first as csstree.Identifier; + const child = node.children.first as Identifier; // Find anchor data assigned to this custom property const anchorFns = customPropAssignments[child.name] ?? []; // Find anchor data assigned to another custom property referenced @@ -604,18 +596,16 @@ export async function parseCSS(styleData: StyleData[]) { for (const styleObj of styleData) { let changed = false; const ast = getAST(styleObj.css); - csstree.walk(ast, { + walk(ast, { visit: 'Function', enter(node) { if ( isVarFunction(node) && - (node.children.first as csstree.Identifier)?.name?.startsWith( - '--', - ) && + (node.children.first as Identifier)?.name?.startsWith('--') && this.declaration?.property?.startsWith('--') && this.block ) { - const child = node.children.first as csstree.Identifier; + const child = node.children.first as Identifier; const positions = customPropReplacements[child.name]; if (positions) { for (const [propUuid, value] of Object.entries(positions)) { diff --git a/src/utils.ts b/src/utils.ts index 45c37fde..fa3aad07 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,4 +1,16 @@ -import * as csstree from 'css-tree'; +import { + type CssNode, + type Declaration, + type FunctionNode, + type Identifier, + type List, + type Selector as CssTreeSelector, + type SelectorList, + type Value, +} from 'css-tree'; +import {clone} from 'css-tree/utils'; +import parse from 'css-tree/parser'; +import generate from 'css-tree/generator'; import { nanoid } from 'nanoid/non-secure'; import type { Selector } from './dom.js'; @@ -6,40 +18,36 @@ import type { Selector } from './dom.js'; export const INSTANCE_UUID = nanoid(); // https://github.com/import-js/eslint-plugin-import/issues/3019 -// eslint-disable-next-line import/namespace -export interface DeclarationWithValue extends csstree.Declaration { - value: csstree.Value; + +export interface DeclarationWithValue extends Declaration { + value: Value; } -export function isAnchorFunction( - node: csstree.CssNode | null, -): node is csstree.FunctionNode { +export function isAnchorFunction(node: CssNode | null): node is FunctionNode { return Boolean(node && node.type === 'Function' && node.name === 'anchor'); } export function getAST(cssText: string) { - return csstree.parse(cssText, { + return parse(cssText, { parseAtrulePrelude: false, parseCustomProperty: true, }); } -export function generateCSS(ast: csstree.CssNode) { - return csstree.generate(ast, { +export function generateCSS(ast: CssNode) { + return generate(ast, { // Default `safe` adds extra (potentially breaking) spaces for compatibility // with old browsers. mode: 'spec', }); } -export function isDeclaration( - node: csstree.CssNode, -): node is DeclarationWithValue { +export function isDeclaration(node: CssNode): node is DeclarationWithValue { return node.type === 'Declaration'; } export function getDeclarationValue(node: DeclarationWithValue) { - return (node.value.children.first as csstree.Identifier).name; + return (node.value.children.first as Identifier).name; } export interface StyleData { @@ -51,9 +59,9 @@ export interface StyleData { export const POSITION_ANCHOR_PROPERTY = `--position-anchor-${INSTANCE_UUID}`; -export function splitCommaList(list: csstree.List) { +export function splitCommaList(list: List) { return list.toArray().reduce( - (acc: csstree.Identifier[][], child) => { + (acc: Identifier[][], child) => { if (child.type === 'Operator' && child.value === ',') { acc.push([]); return acc; @@ -68,15 +76,15 @@ export function splitCommaList(list: csstree.List) { ); } -export function getSelectors(rule: csstree.SelectorList | undefined) { +export function getSelectors(rule: SelectorList | undefined) { if (!rule) return []; - return (rule.children as csstree.List) + return (rule.children as List) .map((selector) => { let pseudoElementPart: string | undefined; if (selector.children.last?.type === 'PseudoElementSelector') { - selector = csstree.clone(selector) as csstree.Selector; + selector = clone(selector) as CssTreeSelector; pseudoElementPart = generateCSS(selector.children.last!); selector.children.pop(); } diff --git a/vite.config.ts b/vite.config.ts index bd1b8343..3ea0600e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,7 @@ /// import { resolve } from 'path'; +import { bundleStats } from 'rollup-plugin-bundle-stats'; import { defineConfig } from 'vite'; export default defineConfig({ @@ -38,6 +39,7 @@ export default defineConfig({ target: 'es6', sourcemap: true, }, + plugins: [bundleStats()], /** * @see https://vitest.dev/config/#configuration */ From 2ba65a4f11e0d74e4f138e4da175de527d35af66 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Fri, 22 Nov 2024 09:04:25 -0500 Subject: [PATCH 2/6] Add css-tree module types --- src/@types/css-tree.d.ts | 19 +++++++++++++++++++ src/cascade.ts | 2 +- src/fallback.ts | 2 +- src/utils.ts | 6 +++--- 4 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/@types/css-tree.d.ts diff --git a/src/@types/css-tree.d.ts b/src/@types/css-tree.d.ts new file mode 100644 index 00000000..c3a8bded --- /dev/null +++ b/src/@types/css-tree.d.ts @@ -0,0 +1,19 @@ +declare module 'css-tree/walker' { + import { walk } from 'css-tree'; + + export default walk; +} +declare module 'css-tree/utils' { + export { clone, List } from 'css-tree'; +} + +declare module 'css-tree/generator' { + import { generate } from 'css-tree'; + + export default generate; +} +declare module 'css-tree/parser' { + import { parse } from 'css-tree'; + + export default parse; +} diff --git a/src/cascade.ts b/src/cascade.ts index f58220f9..9477c4de 100644 --- a/src/cascade.ts +++ b/src/cascade.ts @@ -1,4 +1,4 @@ -import { type Block, type CssNode, } from 'css-tree'; +import { type Block, type CssNode } from 'css-tree'; import walk from 'css-tree/walker'; import { diff --git a/src/fallback.ts b/src/fallback.ts index f2ebcbe4..563645ec 100644 --- a/src/fallback.ts +++ b/src/fallback.ts @@ -9,8 +9,8 @@ import { type SelectorList, type Value, } from 'css-tree'; +import { clone, List } from 'css-tree/utils'; import walk from 'css-tree/walker'; -import {clone, List} from 'css-tree/utils'; import { nanoid } from 'nanoid/non-secure'; import { getCSSPropertyValue } from './dom.js'; diff --git a/src/utils.ts b/src/utils.ts index fa3aad07..150ea9b0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -8,9 +8,9 @@ import { type SelectorList, type Value, } from 'css-tree'; -import {clone} from 'css-tree/utils'; -import parse from 'css-tree/parser'; import generate from 'css-tree/generator'; +import parse from 'css-tree/parser'; +import { clone } from 'css-tree/utils'; import { nanoid } from 'nanoid/non-secure'; import type { Selector } from './dom.js'; @@ -18,7 +18,7 @@ import type { Selector } from './dom.js'; export const INSTANCE_UUID = nanoid(); // https://github.com/import-js/eslint-plugin-import/issues/3019 - + export interface DeclarationWithValue extends Declaration { value: Value; } From 074c470b5edaf84af1ec574555556889d0a9e902 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Fri, 22 Nov 2024 09:18:48 -0500 Subject: [PATCH 3/6] Exclude source-map-js lib from bundle --- vite.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vite.config.ts b/vite.config.ts index 3ea0600e..7ea1c614 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -38,8 +38,12 @@ export default defineConfig({ emptyOutDir: !process.env.BUILD_FN, target: 'es6', sourcemap: true, + rollupOptions: { + external: [/source-map-js/], + }, }, plugins: [bundleStats()], + /** * @see https://vitest.dev/config/#configuration */ From 702caa680bb80b88ce09c13e3380066faa66cec6 Mon Sep 17 00:00:00 2001 From: James Stuckey Weber Date: Fri, 22 Nov 2024 09:23:22 -0500 Subject: [PATCH 4/6] Serve demo from dist --- index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index c092eb69..2d9305cd 100644 --- a/index.html +++ b/index.html @@ -61,7 +61,8 @@ }