├── .github └── workflows │ ├── docs.yml │ ├── e2e-test.yml │ └── swc.yml ├── .gitignore ├── CHANGELOG.md ├── README.md ├── babel.commonjs.cjs ├── babel.config.cjs ├── babel ├── hash.cjs └── index.cjs ├── docs ├── .babelrc ├── .linariarc ├── build.js ├── next-env.d.ts ├── next.config.js ├── package.json ├── pages │ ├── CodeExample.tsx │ ├── Theme.tsx │ └── index.page.tsx ├── public │ └── static │ │ └── favicon.png └── tsconfig.json ├── examples └── styled-components │ ├── babel.config.js │ ├── next-env.d.ts │ ├── next.config.js │ ├── package.json │ ├── pages │ ├── gradient │ │ ├── index.page.tsx │ │ └── text-gradient.ts │ └── index.page.tsx │ └── tsconfig.json ├── jest.config.cjs ├── license ├── package.json ├── src └── index.ts ├── swc ├── Cargo.lock ├── Cargo.toml ├── README.md ├── package.json ├── swc-plugin-css-variable │ ├── Cargo.toml │ └── src │ │ └── lib.rs └── transform │ ├── Cargo.toml │ ├── benches │ ├── bench_main.rs │ ├── nested.js │ └── styledPage.tsx │ ├── src │ ├── hash.rs │ └── lib.rs │ └── tests │ └── __swc_snapshots__ │ └── src │ └── lib.rs │ ├── adds_camel_case_variable_name_with_display_name.js │ ├── adds_multiple_variable_names.js │ ├── adds_variable_name.js │ ├── adds_variable_name_for_renamed.js │ ├── adds_variable_name_with_display_name.js │ ├── adds_variable_name_with_value.js │ └── ignores_unknwon_modules.js ├── test ├── __snapshots__ │ └── babel.test.js.snap ├── babel.test.js ├── examples.js ├── fixtures │ ├── CSSVariable.js │ ├── createVar.js │ └── renamed.js ├── package.json ├── swc │ ├── jest.config.js │ └── swc.test.js └── without-babel.test.js └── tsconfig.json /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "docs/**" 9 | - ".github/workflows/docs.yml" 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [20] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v4 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | - name: RustUp 26 | run: rustup target add wasm32-wasip1 27 | - run: npm install 28 | - run: (cd docs && npm install) 29 | - run: npm run prepublishOnly 30 | env: 31 | CI: true 32 | - run: npm run docs 33 | - name: Deploy 34 | uses: peaceiris/actions-gh-pages@v3 35 | with: 36 | github_token: ${{ secrets.GITHUB_TOKEN }} 37 | publish_dir: ./docs/out 38 | -------------------------------------------------------------------------------- /.github/workflows/e2e-test.yml: -------------------------------------------------------------------------------- 1 | name: e2e test 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | strategy: 10 | matrix: 11 | node-version: [20] 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Use Node.js ${{ matrix.node-version }} 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: ${{ matrix.node-version }} 19 | - run: npm install 20 | - run: npm run build 21 | - run: npm test 22 | env: 23 | CI: true 24 | NODE_OPTIONS: --openssl-legacy-provider 25 | - run: npx bundlesize -f dist/index.min.mjs 26 | -------------------------------------------------------------------------------- /.github/workflows/swc.yml: -------------------------------------------------------------------------------- 1 | name: SWC validation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | rust: 14 | name: Rust tests & lints 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout sources 18 | uses: actions/checkout@v4 19 | - name: Install stable toolchain 20 | uses: dtolnay/rust-toolchain@stable 21 | - name: Enable caching 22 | uses: Swatinem/rust-cache@v2 23 | with: 24 | workspaces: swc 25 | - name: Run cargo check 26 | run: cargo check --manifest-path swc/Cargo.toml 27 | - name: Run cargo test 28 | run: cargo test --manifest-path swc/Cargo.toml 29 | - name: Run cargo fmt 30 | run: cargo fmt --manifest-path swc/Cargo.toml --all -- --check 31 | - name: Run cargo clippy 32 | run: cargo clippy --manifest-path swc/Cargo.toml -- -D warnings 33 | 34 | wasm: 35 | name: Wasm plugin tests 36 | strategy: 37 | fail-fast: false 38 | matrix: 39 | os: [ubuntu-latest, windows-latest] 40 | runs-on: ${{ matrix.os }} 41 | steps: 42 | - name: Checkout sources 43 | uses: actions/checkout@v4 44 | - name: Add wasm32-wasip1 target 45 | run: rustup target add wasm32-wasip1 46 | - name: Enable caching 47 | uses: Swatinem/rust-cache@v2 48 | with: 49 | workspaces: swc 50 | - name: Use Node.js 20 51 | uses: actions/setup-node@v4 52 | with: 53 | node-version: 20 54 | - name: Install NPM dependencies 55 | run: npm i 56 | - name: Build JS 57 | run: npm run build 58 | - name: Build SWC plugin 59 | run: npm run build:swc 60 | - name: Run tests 61 | run: npm run test:swc:jest 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | .swc 4 | .linaria-cache 5 | dist 6 | target 7 | package-lock.json 8 | yarn.lock 9 | yarn-error.log 10 | out 11 | *.tgz 12 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ## 6.0.0 (2025-02-27) 6 | 7 | 8 | ### ⚠ BREAKING CHANGES 9 | 10 | * **swc:** Update to swc_core 16.0.0 (compatible with @swc/core@1.11.1) 11 | 12 | ## 5.0.0 (2024-12-10) 13 | 14 | 15 | ### ⚠ BREAKING CHANGES 16 | 17 | * **swc** Update to swc_core 5.x (compatible with @swc/core@1.9.2) [#43](https://github.com/jantimon/css-variable/issues/43) 18 | 19 | ### Features 20 | 21 | * add support for Next.js 15.0.4 ([#43](https://github.com/jantimon/css-variable/issues/43)) ([0f9a5a6](https://github.com/jantimon/css-variable/commit/0f9a5a6e8b6ab586dad0460ae0ab4c09948e5aa0)) 22 | 23 | 24 | ## [4.0.0](https://github.com/jantimon/css-variable/compare/v3.10.2...v4.0.0) (2024-05-21) 25 | 26 | 27 | ### ⚠ BREAKING CHANGES 28 | 29 | * **swc:** Update to swc_core 0.90.x (compatible with @swc/core@1.4.x) (#34) 30 | 31 | ### Features 32 | 33 | * **swc:** Update to swc_core 0.90.x (compatible with @swc/core@1.4.x) ([#34](https://github.com/jantimon/css-variable/issues/34)) ([5daebad](https://github.com/jantimon/css-variable/commit/5daebadc893b77428da797b300f9037ab7482da6)) 34 | 35 | ### [3.10.2](https://github.com/jantimon/css-variable/compare/v3.10.1...v3.10.2) (2023-07-20) 36 | 37 | ### [3.10.1](https://github.com/jantimon/css-variable/compare/v3.10.0...v3.10.1) (2023-01-26) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * **swc:** include package.json properly ([#28](https://github.com/jantimon/css-variable/issues/28)) ([2077ec6](https://github.com/jantimon/css-variable/commit/2077ec6e01c9f9f58091326ddbe1dfdc2799e29f)) 43 | 44 | ## [3.10.0](https://github.com/jantimon/css-variable/compare/v3.9.0...v3.10.0) (2023-01-26) 45 | 46 | ### Features 47 | 48 | * faster hash generation with more readable hashes ([1a0006f](https://github.com/jantimon/css-variable/commit/1a0006f9f150231b319be74ccaf757eb257da764)) 49 | 50 | ### Bug Fixes 51 | 52 | * update dev dependencies ([d3dabe2](https://github.com/jantimon/css-variable/commit/d3dabe2c7ca948f080a67e9439074c40c71d13bc)) 53 | 54 | ### [3.9.1](https://github.com/jantimon/css-variable/compare/v3.9.0...v3.9.1) (2022-11-23) 55 | 56 | ### Features 57 | 58 | * add type declarations to exports field ([13e6696](https://github.com/jantimon/css-variable/commit/13e669626747d248d4f695ccf9d4f919f757bcf3)) in package.json. closes [#18] 59 | 60 | ### Bug Fixes 61 | 62 | * update dev dependencies ([9d6132e](https://github.com/jantimon/css-variable/commit/9d6132e06342d7e4aa17e746d920b5fc5f7d7f1b)) 63 | 64 | ## [3.9.0](https://github.com/jantimon/css-variable/compare/v3.8.0...v3.9.0) (2022-11-03) 65 | 66 | ### Features 67 | 68 | * improve css variable names ([2bd733f](https://github.com/jantimon/css-variable/commit/2bd733f793453bf1c954e87933a98b44998bd95f)) 69 | 70 | ## [3.8.0](https://github.com/jantimon/css-variable/compare/v3.7.0...v3.8.0) (2022-08-02) 71 | 72 | 73 | ### Features 74 | 75 | * update @swc/core ([9318847](https://github.com/jantimon/css-variable/commit/93188474cb7c6026a1f3458161f57c97d6b8b550)) 76 | 77 | # 3.7.0 (2022-07-15) 78 | 79 | 80 | ### Bug Fixes 81 | 82 | * **swc:** convert window paths to posix ([1f2fec0](https://github.com/jantimon/css-variable/commit/1f2fec0707f68ee6713dccb652bf733768e9b2a9)), closes [#6](https://github.com/jantimon/css-variable/issues/6) 83 | 84 | 85 | ### Features 86 | 87 | * add createVar, createGlobalTheme and assignVars ([7cde9d0](https://github.com/jantimon/css-variable/commit/7cde9d032bf3045484d8a9370cc5f414412bdf24)) 88 | * add displayName babel plugin option ([5843862](https://github.com/jantimon/css-variable/commit/58438622e3e58bfd0b199d9dc665db0211eae198)) 89 | * add full path to the dev variable name when using the swc plugin ([2af5985](https://github.com/jantimon/css-variable/commit/2af598512ce0596bb9a7890e32befacee9fb7708)) 90 | * add swc plugin ([#2](https://github.com/jantimon/css-variable/issues/2)) ([e7e09c7](https://github.com/jantimon/css-variable/commit/e7e09c717b505578089550e5a903c411fa1ae89e)) 91 | * reduze bundle size ([b726748](https://github.com/jantimon/css-variable/commit/b72674819369afc3f3cf6f95f5d19230c6e1ec79)) 92 | * replace random fallback id ([00c569d](https://github.com/jantimon/css-variable/commit/00c569df081f41463a64f3eadddc720b36d113d6)) 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # css-variable 2 | 3 | [![npm](https://img.shields.io/npm/v/css-variable)](npmjs.com/package/css-variable) [![e2e test](https://github.com/jantimon/css-variable/actions/workflows/e2e-test.yml/badge.svg)](https://github.com/jantimon/css-variable/actions/workflows/e2e-test.yml) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/css-variable) ![npm type definitions](https://img.shields.io/npm/types/css-variable) ![NPM](https://img.shields.io/npm/l/css-variable) 4 | 5 | Tiny ( ~0.3 kb ) treeshakable library to define CSS custom properties (variables) in JS. 6 | Compatible with 👩‍🎤 Emotion / 💅 StyledComponents / Linaria and similar CSS-in-JS solutions. 7 | 8 | ## Install 9 | 10 | ```bash 11 | npm i css-variable 12 | ``` 13 | 14 | ## Docs 15 | 16 | [http://css-variable.js.org](http://css-variable.js.org) 17 | 18 | 19 | ## License 20 | 21 | Licensed under MIT 22 | Crafted with <3 [@jantimon](https://twitter.com/jantimon) 23 | 24 | Special thanks to [@4alpine](https://twitter.com/4lpine) for donating the package name. -------------------------------------------------------------------------------- /babel.commonjs.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "presets": ["@babel/preset-typescript"], 3 | "plugins": [ 4 | ["@babel/plugin-transform-modules-commonjs", { 5 | "allowTopLevelThis": false, 6 | "importInterop": "none" 7 | }] 8 | ] 9 | } -------------------------------------------------------------------------------- /babel.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "presets": ["@babel/preset-typescript"], 3 | "plugins": [ 4 | ] 5 | } -------------------------------------------------------------------------------- /babel/hash.cjs: -------------------------------------------------------------------------------- 1 | /** 2 | * JS Implementation of MurmurHash2 3 | * 4 | * @author Gary Court 5 | * @see http://github.com/garycourt/murmurhash-js 6 | * @author Austin Appleby 7 | * @see http://sites.google.com/site/murmurhash/ 8 | * 9 | * @param {string} str ASCII only 10 | * @return {string} Base 36 encoded hash result 11 | */ 12 | function murmurhash2_32_gc(str) { 13 | let l = str.length 14 | let h = l 15 | let i = 0 16 | let k 17 | 18 | while (l >= 4) { 19 | k = 20 | (str.charCodeAt(i) & 0xff) | 21 | ((str.charCodeAt(++i) & 0xff) << 8) | 22 | ((str.charCodeAt(++i) & 0xff) << 16) | 23 | ((str.charCodeAt(++i) & 0xff) << 24) 24 | 25 | k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16) 26 | k ^= k >>> 24 27 | k = (k & 0xffff) * 0x5bd1e995 + ((((k >>> 16) * 0x5bd1e995) & 0xffff) << 16) 28 | 29 | h = 30 | ((h & 0xffff) * 0x5bd1e995 + 31 | ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16)) ^ 32 | k 33 | 34 | l -= 4 35 | ++i 36 | } // forgive existing code 37 | 38 | /* eslint-disable no-fallthrough */ switch (l) { 39 | case 3: 40 | h ^= (str.charCodeAt(i + 2) & 0xff) << 16 41 | case 2: 42 | h ^= (str.charCodeAt(i + 1) & 0xff) << 8 43 | case 1: 44 | h ^= str.charCodeAt(i) & 0xff 45 | h = 46 | (h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16) 47 | } 48 | /* eslint-enable no-fallthrough */ 49 | 50 | h ^= h >>> 13 51 | h = (h & 0xffff) * 0x5bd1e995 + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16) 52 | h ^= h >>> 15 53 | 54 | return (h >>> 0).toString(36) 55 | } 56 | 57 | module.exports = murmurhash2_32_gc; -------------------------------------------------------------------------------- /babel/index.cjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | const PACKAGE_NAME = "css-variable"; 3 | const hash = require("./hash.cjs"); 4 | const pathRelative = require("path").relative; 5 | 6 | /** @typedef {import("@babel/core")} babel */ 7 | 8 | /** 9 | * The context of a babel plugin run 10 | * @typedef {{ 11 | * minifyVariables: boolean, 12 | * varCount: number, 13 | * varPrefix: string, 14 | * isImportedInCurrentFile: boolean, 15 | * localVarNames: string[], 16 | * opts: babel.PluginOptions & { displayName?: boolean } 17 | * } & babel.PluginPass} PluginPass 18 | */ 19 | 20 | /** 21 | * @param {babel} babel 22 | * @returns {babel.PluginObj} 23 | */ 24 | module.exports = function (babel) { 25 | const { 26 | types: { stringLiteral }, 27 | } = babel; 28 | 29 | /** 30 | * @param {babel.NodePath | babel.NodePath} path; 31 | * @param {PluginPass} pluginPass 32 | */ 33 | const injectVariableName = (path, pluginPass) => { 34 | // Skip if no import statements where found 35 | if (!pluginPass.localVarNames.length) { 36 | return; 37 | } 38 | const callee = path.node.callee; 39 | if ( 40 | !("name" in callee) || 41 | !pluginPass.localVarNames.includes(callee.name) 42 | ) { 43 | return; 44 | } 45 | const readableName = 46 | !pluginPass.minifyVariables && dashed(getNameByUsage(path)); 47 | const readablePrefix = readableName ? `${readableName}--` : ""; 48 | // 49 | // Inject the variable prefix 50 | // 51 | // E.g. CSSVariable() -> CSSVariable("1isaui4-0") 52 | // E.g. CSSVariable({value: "10px"}) -> CSSVariable("1isaui4-0", {value: "10px"}) 53 | // 54 | const constructorArguments = path.node.arguments; 55 | const firstArg = constructorArguments[0]; 56 | if (!firstArg || firstArg.type !== "StringLiteral") { 57 | constructorArguments.unshift( 58 | stringLiteral( 59 | readablePrefix + getUniqueHash(pluginPass) + pluginPass.varCount++ 60 | ) 61 | ); 62 | } 63 | // 64 | // Inject @__PURE__ comment to tell terser that 65 | // creating s CSSVariable class instance will cause no 66 | // side effects and is save to be removed 67 | // 68 | path.addComment("leading", "@__PURE__"); 69 | }; 70 | 71 | return { 72 | name: `${PACKAGE_NAME} unique variable name injector`, 73 | pre() { 74 | this.isImportedInCurrentFile = false; 75 | this.varCount = 0; 76 | this.minifyVariables = 77 | this.opts.displayName !== undefined 78 | ? !this.opts.displayName 79 | : this.file.opts.envName !== "development"; 80 | this.localVarNames = []; 81 | }, 82 | visitor: { 83 | ImportDeclaration({ node }) { 84 | // Search for `import {CSSVariable} from "css-variable";` 85 | // Search for `import {CSSVariable as CustomName} from "css-variable";` 86 | const isLib = node.source.value === PACKAGE_NAME; 87 | if (!isLib) { 88 | return; 89 | } 90 | node.specifiers.forEach((specifier) => { 91 | const importSpecifier = "imported" in specifier && specifier.imported; 92 | if (!importSpecifier || !("name" in importSpecifier)) { 93 | return; 94 | } 95 | const localSpecifier = 96 | ("local" in specifier && specifier.local) || importSpecifier; 97 | if ( 98 | importSpecifier.name === "CSSVariable" || 99 | importSpecifier.name === "createVar" 100 | ) { 101 | this.localVarNames.push(localSpecifier.name); 102 | } 103 | }); 104 | this.isImportedInCurrentFile = this.localVarNames.length > 0; 105 | }, 106 | CallExpression(path) { 107 | return injectVariableName(path, this); 108 | }, 109 | NewExpression(path) { 110 | return injectVariableName(path, this); 111 | }, 112 | }, 113 | }; 114 | }; 115 | 116 | /** 117 | * Tries to extract the name for readable names in developments 118 | * e.g.: 119 | * 120 | * `const fontSize = createVar()` -> fontSize 121 | * `const theme = { primary: createVar() }` -> primary 122 | * 123 | * @param {babel.NodePath} path 124 | */ 125 | function getNameByUsage(path) { 126 | const parent = path.parent; 127 | if (!parent) return ""; 128 | if (parent.type === "ObjectProperty") { 129 | const key = parent.key; 130 | if (key && key.type === "Identifier" && key.name) { 131 | return key.name; 132 | } 133 | } 134 | if (parent.type === "VariableDeclarator") { 135 | const id = parent.id; 136 | if (id && id.type === "Identifier" && id.name) { 137 | return id.name; 138 | } 139 | } 140 | return ""; 141 | } 142 | 143 | /** @param {string} val*/ 144 | function dashed(val) { 145 | /** handle camelCase and CONSTANT_CASE */ 146 | return val 147 | .replace(/([0-9a-z])([A-Z])/g, "$1-$2") 148 | .toLowerCase() 149 | .replace(/_/g, "-"); 150 | } 151 | 152 | /** @type {WeakMap} */ 153 | const prefixCache = new WeakMap(); 154 | /** 155 | * Returns a unique name based on the processed filename 156 | * 157 | * @param {babel.PluginPass} pass 158 | */ 159 | function getUniqueHash(pass) { 160 | const fromCache = prefixCache.get(pass); 161 | if (fromCache) { 162 | return fromCache; 163 | } 164 | // Variables should keep the same generated name for 165 | // multiple builds. 166 | // 167 | // This is possible by hashing the source filename 168 | // which includes the CSSVariable. 169 | // 170 | // As an absolute file might be different from system to system 171 | // the relative filename is used instead 172 | const relativeFileName = pass.file.opts.filename 173 | ? pathRelative(__dirname, pass.file.opts.filename).replace(/\\/g, "/") 174 | : "jantimon"; 175 | const prefix = hash(relativeFileName); 176 | prefixCache.set(pass, prefix); 177 | return prefix; 178 | } 179 | -------------------------------------------------------------------------------- /docs/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "next/babel", 4 | "linaria/babel" 5 | ], 6 | "plugins": [ 7 | "css-variable/babel" 8 | ] 9 | } -------------------------------------------------------------------------------- /docs/.linariarc: -------------------------------------------------------------------------------- 1 | { 2 | babelOptions: { 3 | "presets": [ 4 | "next/babel", 5 | "linaria/babel" 6 | ], 7 | "plugins": [ 8 | "css-variable/babel" 9 | ] 10 | } 11 | } -------------------------------------------------------------------------------- /docs/build.js: -------------------------------------------------------------------------------- 1 | /// @ts-check 2 | /* 3 | * This script generates a static export for the docs 4 | */ 5 | const fs = require("fs"); 6 | const child_process = require("child_process"); 7 | 8 | async function run () { 9 | await spawnAsync("npm", ["install"], { cwd: __dirname, stdio: "inherit" }).promise; 10 | await spawnAsync("npm", ["run", "build"], { cwd: __dirname, stdio: "inherit" }).promise; 11 | await spawnAsync("npm", ["run", "export"], { cwd: __dirname, stdio: "inherit" }).promise; 12 | // CNAME for js.org 13 | fs.writeFileSync(__dirname + '/out/CNAME', 'css-variable.js.org'); 14 | } 15 | 16 | run(); 17 | function spawnAsync(command, args, options) { 18 | const child = child_process.spawn(command, args, options); 19 | return {child, promise: new Promise((resolve, reject) => { 20 | child.on("close", (code) => { 21 | if (code) { 22 | reject(new Error(`${command} failed - exit code: ${code}`)); 23 | } else { 24 | resolve(); 25 | } 26 | }); 27 | })}; 28 | } 29 | -------------------------------------------------------------------------------- /docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /docs/next.config.js: -------------------------------------------------------------------------------- 1 | const withLinaria = require('next-linaria'); 2 | 3 | module.exports = withLinaria({ 4 | pageExtensions: ['page.tsx'], 5 | webpack(config, options) { 6 | return config; 7 | }, 8 | }); -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "export": "next export" 10 | }, 11 | "dependencies": { 12 | "@babel/core": "7.15.5", 13 | "@babel/preset-env": "^7.15.4", 14 | "classnames": "2.3.1", 15 | "css-variable": "file:../", 16 | "linaria": "2.1.0", 17 | "next": "12.2.3", 18 | "next-linaria": "0.11.0", 19 | "react": "18.2.0", 20 | "react-dom": "18.2.0", 21 | "react-syntax-highlighter": "^15.4.4", 22 | "typescript": "^4.4.3" 23 | }, 24 | "devDependencies": { 25 | "@types/react": "^18.0.15", 26 | "@types/react-dom": "^18.0.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /docs/pages/CodeExample.tsx: -------------------------------------------------------------------------------- 1 | import { css } from "linaria"; 2 | import { styled } from "linaria/react"; 3 | import classnames from "classnames"; 4 | import { useState } from "react"; 5 | import SyntaxHighlighter from "react-syntax-highlighter"; 6 | import dark from "react-syntax-highlighter/dist/cjs/styles/hljs/a11y-dark"; 7 | 8 | const codeExampleStyles = css` 9 | margin: 0 auto; 10 | width: 100%; 11 | max-width: 600px; 12 | min-height: 50px; 13 | box-shadow: rgb(20 20 20 / 27%) 0.555556px 0.555556px 11.1111px; 14 | // Overrule react-syntax-highlighter style 15 | padding: 10px 20px !important; 16 | `; 17 | 18 | /** @param {{children, className?: string}} props */ 19 | export const CodeExample = ({ children, className }) => ( 20 | 25 | {children} 26 | 27 | ); 28 | 29 | const CodeExampleWrapper = styled.div` 30 | display: grid; 31 | max-width: 600px; 32 | margin: 0 auto; 33 | width: 100%; 34 | `; 35 | 36 | const gridOverlay = css` 37 | grid-column-start: 1; 38 | grid-column-end: 1; 39 | grid-row-start: 2; 40 | grid-row-end: 2; 41 | `; 42 | const invisble = css` 43 | opacity: 0; 44 | pointer-events: none; 45 | ` 46 | 47 | const CodeButtonWrapper = styled.div` 48 | grid-column-start: 1; 49 | grid-column-end: 1; 50 | grid-row-start: 1; 51 | grid-row-end: 1; 52 | justify-self: end; 53 | white-space: nowrap; 54 | margin-top: -5px; 55 | `; 56 | 57 | const MultiCodeButton = styled.button<{active?: boolean}>` 58 | background: #2b2b2b; 59 | transition: color 300ms; 60 | color: ${(props) => props.active ? 'rgba(230,230,230, 1)' : 'rgba(230,230,230, 0.7)'}; 61 | &:hover { 62 | color: rgba(230,230,230, 1); 63 | } 64 | position: relative; 65 | top: 5px; 66 | border: 0; 67 | margin: 0; 68 | padding: 5px 20px; 69 | cursor: pointer; 70 | & + & { 71 | box-shadow: -8px 0px 1px -7px white; 72 | } 73 | ` 74 | 75 | export const CodeExamples = ({ children }: {children: Record}) => { 76 | const keys = Object.keys(children); 77 | const [activeKey, setActiveKeys] = useState(keys[0]); 78 | return 79 | 80 | {keys.length > 1 && keys.map((key) => ( 81 | setActiveKeys(key)}>{key} 82 | ))} 83 | 84 | { 85 | keys.map((key) => ( 86 | {children[key]} 87 | )) 88 | } 89 | 90 | } -------------------------------------------------------------------------------- /docs/pages/Theme.tsx: -------------------------------------------------------------------------------- 1 | /// @ts-check 2 | import { createVar, createGlobalTheme } from "css-variable"; 3 | import { css } from "linaria"; 4 | import { styled } from "linaria/react"; 5 | 6 | export const theme = { 7 | fontSize: createVar("FontSize"), 8 | spacings: { 9 | s: createVar(), 10 | m: createVar(), 11 | l: createVar(), 12 | }, 13 | colors: { 14 | base: createVar("base"), 15 | primary: createVar("primary"), 16 | secondary: createVar("secondary"), 17 | backgroundPrimary: createVar(), 18 | backgroundSecondary: createVar(), 19 | }, 20 | }; 21 | 22 | export const Font = css` 23 | :global { 24 | @import url("https://fonts.googleapis.com/css?family=Noto%20Sans"); 25 | body { 26 | font-family: "Noto Sans"; 27 | } 28 | } 29 | `; 30 | 31 | export const Base = css` 32 | :global { 33 | * { box-sizing: inherit } 34 | body { 35 | min-width: min-content; 36 | margin: 0; 37 | padding: 0; 38 | background: ${theme.colors.backgroundPrimary.val}; 39 | box-sizing: border-box; 40 | } 41 | } 42 | `; 43 | 44 | const lightTheme = /*@__PURE__*/createGlobalTheme("", theme, { 45 | fontSize: "12px", 46 | spacings: { 47 | s: "10px", 48 | m: "20px", 49 | l: "30px", 50 | }, 51 | colors: { 52 | base: "#24292e", 53 | primary: "#6290C3", 54 | secondary: "#C2E7DA", 55 | backgroundPrimary: "#efefef", 56 | backgroundSecondary: "#e8e8e7", 57 | }, 58 | }); 59 | const darkTheme = /*@__PURE__*/createGlobalTheme("", theme, { 60 | fontSize: "12px", 61 | spacings: { 62 | s: "10px", 63 | m: "20px", 64 | l: "30px", 65 | }, 66 | colors: { 67 | base: "#efefef", 68 | primary: "#6290C3", 69 | secondary: "#C2E7DA", 70 | backgroundPrimary: "#24292e", 71 | backgroundSecondary: "#393939", 72 | }, 73 | }); 74 | 75 | const invertedTheme = css` 76 | ${darkTheme} 77 | @media (prefers-color-scheme: dark) { 78 | ${lightTheme} 79 | } 80 | `; 81 | 82 | const ThemeSwitchButton = styled.button` 83 | border: none; 84 | background: transparent; 85 | padding: 0; 86 | position: relative; 87 | overflow: hidden; 88 | font-size: 80%; 89 | cursor: pointer; 90 | :before { 91 | transition: transform 300ms ease-in-out; 92 | content: "🌙"; 93 | display: block; 94 | ${`.${invertedTheme}`} & { 95 | transform: translateY(-120%); 96 | } 97 | } 98 | :after { 99 | transition: transform 300ms ease-in-out; 100 | position: absolute; 101 | left: 0; 102 | top: 0; 103 | content: "☀️"; 104 | transform: translateY(240%); 105 | ${`.${invertedTheme}`} & { 106 | transform: translateY(0); 107 | } 108 | } 109 | `; 110 | 111 | export const ThemeSwitch = () => ( 112 | document.body.classList.toggle(invertedTheme)} 114 | title="Toggle Light/Dark Mode" 115 | /> 116 | ); 117 | 118 | export const DefaultTheme = css` 119 | :global() { 120 | :root { 121 | ${lightTheme} 122 | } 123 | @media (prefers-color-scheme: dark) { 124 | :root { 125 | ${darkTheme} 126 | } 127 | } 128 | } 129 | `; 130 | -------------------------------------------------------------------------------- /docs/pages/index.page.tsx: -------------------------------------------------------------------------------- 1 | import { styled } from "linaria/lib/react"; 2 | import Head from "next/head"; 3 | import { CodeExamples } from "./CodeExample"; 4 | import "./Theme"; 5 | import { theme, ThemeSwitch } from "./Theme"; 6 | 7 | const HeaderWrapper = styled.header` 8 | background: ${theme.colors.backgroundSecondary.val}; 9 | position: fixed; 10 | top: 0; 11 | width: 100%; 12 | padding: 5px 10px; 13 | z-index: 10; 14 | `; 15 | 16 | const Header = styled.div` 17 | display: grid; 18 | grid-template-columns: auto max-content max-content max-content; 19 | grid-template-rows: 1fr; 20 | gap: 10px; 21 | color: ${theme.colors.base.val}; 22 | align-items: end; 23 | max-width: 1200px; 24 | margin: 0 auto; 25 | `; 26 | 27 | const TextLogo = styled.h1` 28 | font-size: 18px; 29 | margin: 0; 30 | letter-spacing: -1px; 31 | `; 32 | 33 | const HeaderLink = styled.a` 34 | font-size: 14px; 35 | color: ${theme.colors.base.val}; 36 | text-decoration: none; 37 | `; 38 | 39 | const Main = styled.main` 40 | padding: 80px 50px 0px; 41 | width: 100%; 42 | max-width: 900px; 43 | margin: 0 auto; 44 | display: flex; 45 | flex-direction: column; 46 | gap: ${theme.spacings.m.val}; 47 | 48 | @media (min-width: 860px) { 49 | padding-left: 10px; 50 | padding-right: 10px; 51 | } 52 | `; 53 | 54 | const Section = styled.section<{ reverse?: boolean }>` 55 | display: flex; 56 | gap: 30px; 57 | flex-wrap: wrap; 58 | flex-direction: ${({ reverse }) => (reverse ? "row-reverse" : "row")}; 59 | margin-bottom: 80px; 60 | @media (min-width: 860px) { 61 | flex-wrap: nowrap; 62 | margin-bottom: 120px; 63 | } 64 | `; 65 | 66 | const SectionContent = styled.div` 67 | display: flex; 68 | max-width: 600px; 69 | margin: 0 auto; 70 | gap: ${theme.spacings.m.val}; 71 | flex-direction: column; 72 | flex-grow: 0; 73 | flex-shrink: 1; 74 | width: 100%; 75 | @media (min-width: 860px) { 76 | flex-wrap: nowrap; 77 | margin-bottom: 40px; 78 | } 79 | `; 80 | 81 | const SectionExample = styled.div` 82 | display: flex; 83 | gap: 10px; 84 | flex-direction: column; 85 | flex-grow: 0; 86 | flex-shrink: 0; 87 | width: 100%; 88 | @media (min-width: 860px) { 89 | width: 65%; 90 | } 91 | `; 92 | 93 | const Intro = styled.h2` 94 | font-size: 20px; 95 | color: ${theme.colors.base.val}; 96 | text-align: center; 97 | margin-bottom: 40px; 98 | `; 99 | 100 | const Headline = styled.h2` 101 | font-size: 18px; 102 | color: ${theme.colors.base.val}; 103 | margin: 0 0 5px 0; 104 | `; 105 | 106 | const Text = styled.p` 107 | font-size: 16px; 108 | color: ${theme.colors.base.val}; 109 | margin: 0 0 15px 0; 110 | `; 111 | 112 | const Footer = styled.footer` 113 | font-size: 14px; 114 | background: ${theme.colors.backgroundSecondary.val}; 115 | color: ${theme.colors.base.val}; 116 | padding: 20px; 117 | `; 118 | 119 | const FooterContent = styled.div` 120 | max-width: 1200px; 121 | width: 100%; 122 | margin: 0 auto; 123 | text-align: center; 124 | `; 125 | 126 | const Badges = styled.div` 127 | display: inline-flex; 128 | gap: 8px; 129 | margin-right: 8px; 130 | margin-bottom: 8px; 131 | line-height: 0; 132 | `; 133 | 134 | const Index = () => ( 135 | <> 136 | 137 | 138 | 139 | 140 |
141 | CSS Variable 142 | 143 | GitHub 144 | 145 | 146 |
147 |
148 |
149 | CSS Variables for your CSS-in-JS solution 150 | 151 |
152 | 153 | Built with high focus on performance 154 | 155 | ✨ better css minification 156 | 157 | 158 | ✨ smaller virtual DOM updates 159 | 160 | 161 | ✨ less crititcal SSR CSS 162 | 163 | 164 | ✨ unique variable names 165 | 166 | 167 | 168 | 169 | {{ 170 | base: ` 171 | import { createVar } from 'css-variable'; 172 | 173 | export const tokens = { 174 | primary: createVar(), 175 | secondary: createVar(), 176 | }; 177 | `, 178 | }} 179 | 180 | 181 | 182 | {{ 183 | "styled-components": ` 184 | import { createGlobalTheme } from 'css-variable'; 185 | import { createGlobalStyle } from 'styled-components'; 186 | import { tokens } from './tokens'; 187 | 188 | export const GlobalStyles = createGlobalStyle\` 189 | $\{createGlobalTheme(":root", tokens, { 190 | primary: '#3a5779', 191 | secondary: '#23374e', 192 | })} 193 | \`; 194 | `, 195 | 196 | emotion: ` 197 | import { createGlobalTheme } from 'css-variable'; 198 | import { Global, css } from '@emotion/react'; 199 | import { tokens } from './tokens'; 200 | 201 | export const GlobalStyles = () => 202 | ; 208 | `, 209 | 210 | linaria: ` 211 | import { createGlobalTheme } from 'css-variable'; 212 | import { css } from 'linaria'; 213 | import { tokens } from './tokens'; 214 | 215 | export const globalStyles = css\`:global() { 216 | $\{createGlobalTheme(":root", tokens, { 217 | primary: '#3a5779', 218 | secondary: '#23374e', 219 | }) 220 | }\`; 221 | `, 222 | }} 223 | 224 | 225 | 226 | {{ 227 | "js source": ` 228 | import { tokens } from './tokens'; 229 | 230 | export const Headline = styled.h1\` 231 | color: \${tokens.primary}; 232 | \`; 233 | `, 234 | "css result": ` 235 | .se7gjt0-headline { 236 | color: var(--primary--1isauia0); 237 | } 238 | `, 239 | }} 240 | 241 | 242 |
243 | 244 |
245 | 246 | Create themable CSS Snippets 247 | 248 | Define which parts of your reusable css are customizable without 249 | overwrites 250 | 251 | 252 | 253 | 254 | {{ 255 | base: ` 256 | export const startColor = createVar({value: '#238f97'}); 257 | export const endColor = createVar({value: '#5442bb'}); 258 | 259 | export const gradientHover = css\` 260 | background: linear-gradient(to right, 261 | \${gradientStartColor.val}, 262 | \${gradientEndColor.val}); 263 | 264 | background-size: 200% 200%; 265 | animation: rainbow 2s ease-in-out infinite; 266 | background-clip: text; 267 | 268 | :focus, :hover { 269 | color:rgba(0,0,0,0); 270 | } 271 | @keyframes rainbow { 272 | 0%{background-position:left} 273 | 50%{background-position:right} 274 | 100%{background-position:left} 275 | } 276 | \`; 277 | `, 278 | }} 279 | 280 | 281 | {{ 282 | "js source": ` 283 | import { startColor, endColor, gradientHover } from './gradient'; 284 | 285 | export const Button = styled.button\` 286 | \${startColor.toStyle('#f5ab35')} 287 | \${endColor.toStyle('#8d1d1d')} 288 | \${gradientHover} 289 | \`; 290 | `, 291 | "css result": ` 292 | .se7gjt0-button { 293 | --1isauia0: #f5ab35; 294 | --1isauia1: #8d1d1d; 295 | /* the css from gradientHover */ 296 | } 297 | `, 298 | }} 299 | 300 | 301 |
302 | 303 |
304 | 305 | Unique and consistent variable names 306 | 307 | The recommended babel plugin generates unique variable names during 308 | build time 309 | 310 |

311 | Automatic DX 312 | 313 | All babel generated variable names will have human readable names 314 | during development 315 | 316 |
317 | 318 | 319 | {{ 320 | babel: ` 321 | { 322 | "plugins": [ 323 | "css-variable/babel" 324 | ] 325 | } 326 | `, 327 | swc: ` 328 | { 329 | "plugins": [ 330 | "css-variable/swc", { "basePath": __dirname }, 331 | ] 332 | } 333 | `, 334 | withOptions: ` 335 | { 336 | "plugins": [ 337 | ["css-variable/babel", { 338 | // Prefix vairables with a readable name e.g. 'primary--1isauia0' 339 | // Default for production: false 340 | // Default for development: true 341 | displayName: true 342 | }] 343 | ] 344 | } 345 | `, 346 | }} 347 | 348 | 349 | {{ 350 | original: ` 351 | import { createVar } from 'css-variable'; 352 | 353 | export const theme = { 354 | primary: createVar(), 355 | secondary: createVar(), 356 | }; 357 | `, 358 | "transpiled dev": ` 359 | import { createVar } from 'css-variable'; 360 | 361 | export const theme = { 362 | primary: /*@__PURE__*/createVar("primary--1isauia0"), 363 | secondary: /*@__PURE__*/createVar("secondary--1isauia1"), 364 | }; 365 | `, 366 | "transpiled prod": ` 367 | import { createVar } from 'css-variable'; 368 | 369 | export const theme = { 370 | primary: /*@__PURE__*/createVar("1isauia0"), 371 | secondary: /*@__PURE__*/createVar("1isauia1"), 372 | }; 373 | `, 374 | }} 375 | 376 | 377 |
378 | 379 |
380 | 381 | Typed Contracts 382 | 383 | By default any string is a valid value for a CSSVariable. 384 |
385 |
386 | But it doesn't end here - the generic interface allows to define 387 | explicitly which values are assignable 388 |
389 |
390 | 391 | 392 | {{ 393 | base: ` 394 | import { createVar } from 'css-variable'; 395 | import type { CSSHexColor, CSSPixelValue } from 'css-variable'; 396 | 397 | export const tokens = { 398 | colors: { 399 | primary: createVar(), 400 | secondary: createVar(), 401 | }, 402 | spacing: { 403 | large: createVar() 404 | } 405 | }; 406 | `, 407 | }} 408 | 409 | 410 |
411 |
412 | 459 | 460 | ); 461 | 462 | export default Index; 463 | -------------------------------------------------------------------------------- /docs/public/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jantimon/css-variable/ef9b6c8e8998a5c31ad8764e1771d892b1d373fc/docs/public/static/favicon.png -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "incremental": true 21 | }, 22 | "include": [ 23 | "next-env.d.ts", 24 | "**/*.ts", 25 | "**/*.tsx" 26 | ], 27 | "exclude": [ 28 | "node_modules" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /examples/styled-components/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function (api) { 2 | api.cache(true); 3 | return { 4 | presets: ["next/babel"], 5 | plugins: [ 6 | ["css-variable/babel", { async: false }], 7 | ["babel-plugin-styled-components", { ssr: true }], 8 | ], 9 | }; 10 | }; 11 | -------------------------------------------------------------------------------- /examples/styled-components/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /examples/styled-components/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pageExtensions: ["page.tsx"], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/styled-components/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@example/styled-components", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "@types/react": "17.0.20", 12 | "@types/react-dom": "17.0.9", 13 | "@types/styled-components": "5.1.14", 14 | "babel-plugin-styled-components": "^1.13.2", 15 | "css-variable": "file:../../", 16 | "next": "^14.2.3", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0", 19 | "styled-components": "^6.1.11", 20 | "typescript": "5.4.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/styled-components/pages/gradient/index.page.tsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { 3 | gradientEndColor, 4 | gradientHover, 5 | gradientStartColor, 6 | } from "./text-gradient"; 7 | 8 | const Link = styled.a` 9 | font-family: Arial, Helvetica, sans-serif; 10 | font-size: 20px; 11 | ${gradientStartColor.toStyle("#5610a5")}; 12 | ${gradientEndColor.toStyle("#2286ad")}; 13 | ${gradientHover}; 14 | `; 15 | 16 | const Page = () => Click me; 17 | 18 | export default Page; 19 | -------------------------------------------------------------------------------- /examples/styled-components/pages/gradient/text-gradient.ts: -------------------------------------------------------------------------------- 1 | import { createVar, CSSHexColor } from "css-variable"; 2 | import { css } from "styled-components"; 3 | 4 | export const fontColor = createVar({value: "currentColor"}); 5 | /** The linear gradient start color during hover */ 6 | export const gradientStartColor = createVar(); 7 | /** The linear gradient end color during hover */ 8 | export const gradientEndColor = createVar(); 9 | 10 | export const gradientHover = css` 11 | color: ${fontColor.val}; 12 | background: linear-gradient(to right, ${gradientStartColor.val}, ${gradientEndColor.val}); 13 | background-size: 200% 200%; 14 | animation: rainbow 2s ease-in-out infinite; 15 | background-clip: text; 16 | -webkit-background-clip:text; 17 | transition: color .2s ease-in-out; 18 | } 19 | :focus, 20 | :hover{ 21 | color:rgba(0,0,0,0); 22 | } 23 | @keyframes rainbow { 24 | 0%{background-position:left} 25 | 50%{background-position:right} 26 | 100%{background-position:left} 27 | } 28 | `; 29 | 30 | -------------------------------------------------------------------------------- /examples/styled-components/pages/index.page.tsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { CSSPixelValue, createVar, createGlobalTheme } from "css-variable"; 3 | 4 | const theme = { 5 | fontSize: createVar("FontSize"), 6 | spacings: { 7 | s: createVar(), 8 | m: createVar(), 9 | l: createVar(), 10 | }, 11 | colors: { 12 | primary: createVar("primary"), 13 | secondary: createVar("secondary"), 14 | }, 15 | }; 16 | 17 | const ThemeA = styled.div` 18 | ${createGlobalTheme("", theme, { 19 | fontSize: "12px", 20 | spacings: { 21 | s: "10px", 22 | m: "20px", 23 | l: "30px", 24 | }, 25 | colors: { 26 | primary: "#6290C3", 27 | secondary: "#C2E7DA", 28 | }, 29 | })} 30 | `; 31 | 32 | const ThemeB = styled.div` 33 | ${createGlobalTheme("", theme, { 34 | fontSize: "24px", 35 | spacings: { 36 | s: "20px", 37 | m: "40px", 38 | l: "60px", 39 | }, 40 | colors: { 41 | primary: "#7C9EB2", 42 | secondary: "#52528C", 43 | }, 44 | })} 45 | `; 46 | 47 | const colorVar = createVar({ value: theme.colors.primary }); 48 | const xVar = createVar({ value: "0" }); 49 | 50 | const StyledHeadline = styled.h1` 51 | font-family: Arial, Helvetica, sans-serif; 52 | font-size: ${theme.fontSize.val}; 53 | color: ${colorVar.val}; 54 | transform: translateX(${xVar.val}); 55 | width: calc(100% - 1 * ${xVar.val}); 56 | `; 57 | 58 | const FancyComponent: React.FunctionComponent<{color?:string}> = ({ color, children }) => { 59 | return ( 60 | 61 | {children} 62 | 63 | ); 64 | }; 65 | 66 | const BigBox = styled.div` 67 | background: ${theme.colors.secondary.val}; 68 | padding: ${theme.spacings.m.val}; 69 | 70 | ${colorVar.toStyle("grey")} 71 | ${xVar.toStyle('20px')} 72 | 73 | @media (min-width: 500px) { 74 | ${xVar.toStyle('250px')}; 75 | } 76 | `; 77 | 78 | const Demo = () => ( 79 | <> 80 | Demo 81 |
82 | xOffset 83 |
84 | 85 | Inside Box 86 | 87 | 88 | ); 89 | 90 | const Index = () => ( 91 | <> 92 | 93 | 94 | 95 |
96 |
97 | 98 | 99 | 100 | 101 | ); 102 | 103 | export default Index; 104 | -------------------------------------------------------------------------------- /examples/styled-components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "strict": false, 12 | "forceConsistentCasingInFileNames": true, 13 | "noEmit": true, 14 | "esModuleInterop": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "jsx": "preserve", 20 | "incremental": true 21 | }, 22 | "include": [ 23 | "next-env.d.ts", 24 | "**/*.ts", 25 | "**/*.tsx" 26 | ], 27 | "exclude": [ 28 | "node_modules" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /jest.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "testPathIgnorePatterns" : [ 3 | // don't run swc tests during babel jest runs 4 | "/test/swc/*.*" 5 | ] 6 | }; -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Jan Nicklas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-variable", 3 | "version": "6.0.0", 4 | "description": "define CSS custom properties (variables) in JS", 5 | "main": "./dist/index.cjs", 6 | "module": "./dist/index.mjs", 7 | "type": "module", 8 | "exports": { 9 | ".": { 10 | "types": "./dist/index.d.ts", 11 | "import": "./dist/index.mjs", 12 | "require": "./dist/index.cjs" 13 | }, 14 | "./babel": "./babel/index.cjs", 15 | "./swc": "./swc/target/wasm32-wasip1/release/swc_plugin_css_variable.wasm" 16 | }, 17 | "types": "./dist/index.d.ts", 18 | "files": [ 19 | "src", 20 | "dist", 21 | "babel", 22 | "swc/package.json", 23 | "swc/target/wasm32-wasip1/release/swc_plugin_css_variable.wasm" 24 | ], 25 | "sideEffects": false, 26 | "scripts": { 27 | "prepublishOnly": "npm run build && npm run build:swc", 28 | "build": "npm run build:types && npm run build:commonjs && npm run build:module && npm run build:modulemin", 29 | "build:commonjs": "babel --config-file=./babel.commonjs.cjs -o dist/index.cjs src/index.ts", 30 | "build:module": "babel --config-file=./babel.config.cjs -o dist/index.mjs src/index.ts", 31 | "build:types": "tsc --skipLibCheck --emitDeclarationOnly --declaration --target ESNext --outDir dist src/index.ts", 32 | "build:modulemin": "terser ./dist/index.mjs -o ./dist/index.min.mjs -m --ecma 2017 --module --toplevel -b -c", 33 | "build:swc": "cargo build --manifest-path ./swc/Cargo.toml --release --target=wasm32-wasip1", 34 | "changelog": "npx standard-version", 35 | "test": "npm run test:e2e && npm run test:jest", 36 | "test:e2e": "node ./test/examples.js", 37 | "test:jest": "jest", 38 | "test:swc": "npm run test:swc:cargo && npm run build:swc && npm run test:swc:jest", 39 | "test:swc:jest": "jest --config test/swc/jest.config.js", 40 | "test:swc:cargo": "cargo test --manifest-path ./swc/Cargo.toml", 41 | "docs": "node ./docs/build.js" 42 | }, 43 | "repository": { 44 | "type": "git", 45 | "url": "git+https://github.com/jantimon/css-variable.git" 46 | }, 47 | "release": { 48 | "branches": [ 49 | "main" 50 | ] 51 | }, 52 | "keywords": [ 53 | "css" 54 | ], 55 | "author": "Jan Nicklas", 56 | "license": "MIT", 57 | "bugs": { 58 | "url": "https://github.com/jantimon/css-variable/issues" 59 | }, 60 | "homepage": "https://css-variable.js.org/", 61 | "devDependencies": { 62 | "@babel/cli": "7.19.3", 63 | "@babel/core": "7.22.0", 64 | "@babel/plugin-transform-modules-commonjs": "^7.19.6", 65 | "@babel/preset-typescript": "^7.18.6", 66 | "@babel/runtime": "^7.20.1", 67 | "@babel/types": "^7.22.0", 68 | "@swc/core": "1.11.1", 69 | "@swc/jest": "^0.2.37", 70 | "@types/jest": "^29.2.3", 71 | "jest": "^29.3.1", 72 | "terser": "5.15.1", 73 | "typescript": "^5.4.5" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export type CSSPixelValue = '0' | `${string}px`; 2 | export type CSSLengthValue = '0' | `${string}${| "%" 3 | | "ch" 4 | | "cm" 5 | | "em" 6 | | "ex" 7 | | "in" 8 | | "mm" 9 | | "pc" 10 | | "pt" 11 | | "px" 12 | | "rem" 13 | | "vh" 14 | | "vmax" 15 | | "vmin" 16 | | "vw" 17 | }`; 18 | export type CSSAngleValue = `${string}${| "deg" 19 | | "grad" 20 | | "rad" 21 | | "turn" 22 | }`; 23 | export type CSSHexColor = `#${string}`; 24 | 25 | type CSSVariableOptions = { value: TValue | CSSVariable }; 26 | 27 | /** 28 | * Usually css-variable should always be used with its babel plugin 29 | * 30 | * However in some scenarios e.g. storybook / jest it might be difficult 31 | * to setup. 32 | * For those cases this counter provides a very basic fallback to generate 33 | * different ids. 34 | */ 35 | let fallbackId = 9 ** 9; 36 | 37 | export class CSSVariable extends ( 38 | // Inherit from String to be compatible to most CSS-in-JS solutions 39 | // Hacky cast to any for reduced autocomplete 40 | String as any as { new(base: string): { toString: () => string } } 41 | ) { 42 | /** Name e.g. `--baseSize` */ 43 | readonly name: string; 44 | /** Value e.g. `var(--baseSize, 12px)` */ 45 | readonly val: string; 46 | /** 47 | * Creates a new CSS Variable with a unique autogenerated name 48 | * 49 | * E.g. `var(--1isaui4-0)` 50 | */ 51 | constructor(); 52 | /** 53 | * Creates a new CSS Variable with a custom defined name 54 | * 55 | * E.g. `var(--baseSize)` 56 | */ 57 | constructor(uniqueName: string); 58 | /** 59 | * Creates a new CSS Variable with a unique autogenerated name 60 | * and a fallback value 61 | * 62 | * E.g. `var(--1isaui4-0, 12px)` 63 | */ 64 | constructor(options: CSSVariableOptions); 65 | /** 66 | * Creates a new CSS Variable with a unique autogenerated name 67 | * and a fallback value 68 | * 69 | * E.g. `var(--baseSize, 12px)` 70 | */ 71 | constructor(uniqueName: string, options: CSSVariableOptions); 72 | /*#__PURE__*/ 73 | constructor( 74 | ...args: Array> 75 | ) { 76 | const optionArg = args.find( 77 | (arg): arg is CSSVariableOptions => typeof arg === "object" 78 | ); 79 | const name = 80 | "--" + 81 | (args.filter((arg): arg is string => typeof arg === "string").join('-').toLowerCase() || 82 | // Fallback if babel plugin is missing 83 | (fallbackId++).toString(16)); 84 | const val = `var(${name}${optionArg ? `, ${optionArg.value}` : ""})`; 85 | super(val); 86 | this.val = val; 87 | this.name = name; 88 | } 89 | /** Returns the variable name e.g. `--baseSize` */ 90 | getName() { 91 | return this.name; 92 | } 93 | /** Create a CSS Object e.g. `{ "--baseSize": '12px' }` */ 94 | toStyle(newValue: TValue | CSSVariable) { 95 | return { [this.name]: (`${newValue}` as unknown as TValue) }; 96 | } 97 | /** Create a CSS String e.g. `--baseSize:12px;` */ 98 | toCSS(newValue: TValue | CSSVariable) { 99 | return `${this.name}:${newValue};`; 100 | } 101 | } 102 | 103 | 104 | type ICreateVar = { 105 | /** 106 | * Creates a new CSS Variable with a unique autogenerated name 107 | * 108 | * E.g. `var(--1isaui4-0)` 109 | */ 110 | (): CSSVariable; 111 | /** 112 | * Creates a new CSS Variable with a custom defined name 113 | * 114 | * E.g. `var(--baseSize)` 115 | */ 116 | (uniqueName: string): CSSVariable; 117 | /** 118 | * Creates a new CSS Variable with a unique autogenerated name 119 | * and a fallback value 120 | * 121 | * E.g. `var(--1isaui4-0, 12px)` 122 | */ 123 | (options: CSSVariableOptions): CSSVariable; 124 | /** 125 | * Creates a new CSS Variable with a unique autogenerated name 126 | * and a fallback value 127 | * 128 | * E.g. `var(--baseSize, 12px)` 129 | */ 130 | (uniqueName: string, options: CSSVariableOptions): CSSVariable; 131 | } 132 | export const createVar: ICreateVar = (...args: any[]) => new (CSSVariable as any)(...args); 133 | 134 | /** 135 | * A theme structure groups multiple CSSVariable instances 136 | * in a nested object structure e.g.: 137 | * 138 | * ```ts 139 | * const theme = { 140 | * colors: { 141 | * primary: createVar(), 142 | * secondary: createVar() 143 | * }, 144 | * spacings: { 145 | * small: createVar(), 146 | * large: createVar() 147 | * } 148 | * } 149 | * ``` 150 | */ 151 | type ThemeStructure = { [key: string]: CSSVariable | ThemeStructure }; 152 | 153 | /** The allowed value type for the given CSSVariable */ 154 | export type CSSVariableValueArgument = T extends CSSVariable ? U : T 155 | /** 156 | * The ThemeValues type is a helper to map a ThemeStructure to a value type 157 | * to guarantee that the structure and values in createGlobalTheme match 158 | */ 159 | type ThemeValues = { 160 | [Property in keyof TThemeStructure]: TThemeStructure[Property] extends CSSVariable 161 | ? CSSVariableValueArgument | CSSVariable> 162 | : TThemeStructure[Property] extends ThemeStructure 163 | ? ThemeValues 164 | : never; 165 | }; 166 | 167 | type DeepPartial = T extends Function ? T : (T extends object ? { [P in keyof T]?: DeepPartial; } : T); 168 | 169 | /** 170 | * Assign multiple CSSVariables for a given flat or nested Theme Contract 171 | * 172 | * @example 173 | * ```js 174 | * const theme = { 175 | * colors: { 176 | * primary: createVar(), 177 | * secondary: createVar(), 178 | * } 179 | * } 180 | * 181 | * const brightThemeCSS = assignVars(theme, { 182 | * colors: { 183 | * primary: "#6290C3", 184 | * } 185 | * }) 186 | * 187 | * console.log(brightThemeCSS) // -> `--1isaui4-0:#6290C3;` 188 | * ``` 189 | */ 190 | export const assignVars = ( 191 | cssVariables: TTheme, 192 | cssVariableValues: DeepPartial> 193 | ): string => 194 | Object.keys(cssVariableValues) 195 | .map((key) => 196 | typeof cssVariableValues[key] === "string" 197 | ? (cssVariables[key] as CSSVariable).toCSS(cssVariableValues[key] as string) 198 | : assignVars( 199 | cssVariables[key] as ThemeStructure, 200 | cssVariableValues[key] as ThemeValues 201 | ) 202 | ) 203 | .join(""); 204 | 205 | /** 206 | * Serialize all CSS Variable values for an entire nested or flat Theme Contract 207 | * 208 | * @example 209 | * ```js 210 | * const theme = { 211 | * colors: { 212 | * primary: createVar(), 213 | * secondary: createVar(), 214 | * } 215 | * } 216 | * 217 | * const brightThemeCSS = createGlobalTheme(":root", theme, { 218 | * colors: { 219 | * primary: "#6290C3", 220 | * secondary: "#C2E7DA", 221 | * } 222 | * }) 223 | * 224 | * console.log(brightThemeCSS) // -> `:root { --1isaui4-0:#6290C3; --1isaui4-1:#C2E7DA; }` 225 | * ``` 226 | */ 227 | export const createGlobalTheme = (scope: string | undefined | null, 228 | cssVariables: TTheme, 229 | cssVariableValues: ThemeValues): string => `${scope ? `${scope}{` : ''}${assignVars(cssVariables, cssVariableValues as DeepPartial>)}${scope ? '}' : ''}`; -------------------------------------------------------------------------------- /swc/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "once_cell", 13 | "version_check", 14 | "zerocopy", 15 | ] 16 | 17 | [[package]] 18 | name = "aho-corasick" 19 | version = "1.1.3" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 22 | dependencies = [ 23 | "memchr", 24 | ] 25 | 26 | [[package]] 27 | name = "allocator-api2" 28 | version = "0.2.21" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 31 | 32 | [[package]] 33 | name = "anes" 34 | version = "0.1.6" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" 37 | 38 | [[package]] 39 | name = "ansi_term" 40 | version = "0.12.1" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 43 | dependencies = [ 44 | "winapi", 45 | ] 46 | 47 | [[package]] 48 | name = "anstyle" 49 | version = "1.0.10" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" 52 | 53 | [[package]] 54 | name = "anyhow" 55 | version = "1.0.97" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" 58 | 59 | [[package]] 60 | name = "ascii" 61 | version = "1.1.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" 64 | 65 | [[package]] 66 | name = "ast_node" 67 | version = "3.0.0" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "91fb5864e2f5bf9fd9797b94b2dfd1554d4c3092b535008b27d7e15c86675a2f" 70 | dependencies = [ 71 | "proc-macro2", 72 | "quote", 73 | "swc_macros_common", 74 | "syn", 75 | ] 76 | 77 | [[package]] 78 | name = "autocfg" 79 | version = "1.4.0" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 82 | 83 | [[package]] 84 | name = "base62" 85 | version = "2.2.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "10e52a7bcb1d6beebee21fb5053af9e3cbb7a7ed1a4909e534040e676437ab1f" 88 | dependencies = [ 89 | "rustversion", 90 | ] 91 | 92 | [[package]] 93 | name = "base64" 94 | version = "0.22.1" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 97 | 98 | [[package]] 99 | name = "base64-simd" 100 | version = "0.7.0" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" 103 | dependencies = [ 104 | "simd-abstraction", 105 | ] 106 | 107 | [[package]] 108 | name = "better_scoped_tls" 109 | version = "1.0.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "50fd297a11c709be8348aec039c8b91de16075d2b2bdaee1bd562c0875993664" 112 | dependencies = [ 113 | "scoped-tls", 114 | ] 115 | 116 | [[package]] 117 | name = "bitflags" 118 | version = "2.9.0" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 121 | 122 | [[package]] 123 | name = "bitvec" 124 | version = "1.0.1" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 127 | dependencies = [ 128 | "funty", 129 | "radium", 130 | "tap", 131 | "wyz", 132 | ] 133 | 134 | [[package]] 135 | name = "block-buffer" 136 | version = "0.10.4" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 139 | dependencies = [ 140 | "generic-array", 141 | ] 142 | 143 | [[package]] 144 | name = "bumpalo" 145 | version = "3.17.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 148 | dependencies = [ 149 | "allocator-api2", 150 | ] 151 | 152 | [[package]] 153 | name = "bytecheck" 154 | version = "0.8.1" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3" 157 | dependencies = [ 158 | "bytecheck_derive", 159 | "ptr_meta", 160 | "rancor", 161 | "simdutf8", 162 | ] 163 | 164 | [[package]] 165 | name = "bytecheck_derive" 166 | version = "0.8.1" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71" 169 | dependencies = [ 170 | "proc-macro2", 171 | "quote", 172 | "syn", 173 | ] 174 | 175 | [[package]] 176 | name = "bytes" 177 | version = "1.10.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" 180 | 181 | [[package]] 182 | name = "camino" 183 | version = "1.1.9" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" 186 | dependencies = [ 187 | "serde", 188 | ] 189 | 190 | [[package]] 191 | name = "cargo-platform" 192 | version = "0.1.9" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" 195 | dependencies = [ 196 | "serde", 197 | ] 198 | 199 | [[package]] 200 | name = "cargo_metadata" 201 | version = "0.18.1" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" 204 | dependencies = [ 205 | "camino", 206 | "cargo-platform", 207 | "semver 1.0.26", 208 | "serde", 209 | "serde_json", 210 | "thiserror 1.0.69", 211 | ] 212 | 213 | [[package]] 214 | name = "cargo_metadata" 215 | version = "0.19.2" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" 218 | dependencies = [ 219 | "camino", 220 | "cargo-platform", 221 | "semver 1.0.26", 222 | "serde", 223 | "serde_json", 224 | "thiserror 2.0.12", 225 | ] 226 | 227 | [[package]] 228 | name = "cast" 229 | version = "0.3.0" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 232 | 233 | [[package]] 234 | name = "castaway" 235 | version = "0.2.3" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 238 | dependencies = [ 239 | "rustversion", 240 | ] 241 | 242 | [[package]] 243 | name = "cc" 244 | version = "1.2.16" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" 247 | dependencies = [ 248 | "shlex", 249 | ] 250 | 251 | [[package]] 252 | name = "cfg-if" 253 | version = "1.0.0" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 256 | 257 | [[package]] 258 | name = "ciborium" 259 | version = "0.2.2" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" 262 | dependencies = [ 263 | "ciborium-io", 264 | "ciborium-ll", 265 | "serde", 266 | ] 267 | 268 | [[package]] 269 | name = "ciborium-io" 270 | version = "0.2.2" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" 273 | 274 | [[package]] 275 | name = "ciborium-ll" 276 | version = "0.2.2" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" 279 | dependencies = [ 280 | "ciborium-io", 281 | "half", 282 | ] 283 | 284 | [[package]] 285 | name = "clap" 286 | version = "4.5.31" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" 289 | dependencies = [ 290 | "clap_builder", 291 | ] 292 | 293 | [[package]] 294 | name = "clap_builder" 295 | version = "4.5.31" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" 298 | dependencies = [ 299 | "anstyle", 300 | "clap_lex", 301 | ] 302 | 303 | [[package]] 304 | name = "clap_lex" 305 | version = "0.7.4" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" 308 | 309 | [[package]] 310 | name = "compact_str" 311 | version = "0.7.1" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" 314 | dependencies = [ 315 | "castaway", 316 | "cfg-if", 317 | "itoa", 318 | "ryu", 319 | "static_assertions", 320 | ] 321 | 322 | [[package]] 323 | name = "cpufeatures" 324 | version = "0.2.17" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 327 | dependencies = [ 328 | "libc", 329 | ] 330 | 331 | [[package]] 332 | name = "criterion" 333 | version = "0.5.1" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" 336 | dependencies = [ 337 | "anes", 338 | "cast", 339 | "ciborium", 340 | "clap", 341 | "criterion-plot", 342 | "is-terminal", 343 | "itertools", 344 | "num-traits", 345 | "once_cell", 346 | "oorandom", 347 | "regex", 348 | "serde", 349 | "serde_derive", 350 | "serde_json", 351 | "tinytemplate", 352 | "walkdir", 353 | ] 354 | 355 | [[package]] 356 | name = "criterion-plot" 357 | version = "0.5.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" 360 | dependencies = [ 361 | "cast", 362 | "itertools", 363 | ] 364 | 365 | [[package]] 366 | name = "crunchy" 367 | version = "0.2.3" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" 370 | 371 | [[package]] 372 | name = "crypto-common" 373 | version = "0.1.6" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 376 | dependencies = [ 377 | "generic-array", 378 | "typenum", 379 | ] 380 | 381 | [[package]] 382 | name = "darling" 383 | version = "0.20.10" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 386 | dependencies = [ 387 | "darling_core", 388 | "darling_macro", 389 | ] 390 | 391 | [[package]] 392 | name = "darling_core" 393 | version = "0.20.10" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 396 | dependencies = [ 397 | "fnv", 398 | "ident_case", 399 | "proc-macro2", 400 | "quote", 401 | "strsim", 402 | "syn", 403 | ] 404 | 405 | [[package]] 406 | name = "darling_macro" 407 | version = "0.20.10" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 410 | dependencies = [ 411 | "darling_core", 412 | "quote", 413 | "syn", 414 | ] 415 | 416 | [[package]] 417 | name = "data-encoding" 418 | version = "2.8.0" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" 421 | 422 | [[package]] 423 | name = "debugid" 424 | version = "0.8.0" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" 427 | dependencies = [ 428 | "serde", 429 | "uuid", 430 | ] 431 | 432 | [[package]] 433 | name = "derive_builder" 434 | version = "0.20.2" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" 437 | dependencies = [ 438 | "derive_builder_macro", 439 | ] 440 | 441 | [[package]] 442 | name = "derive_builder_core" 443 | version = "0.20.2" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" 446 | dependencies = [ 447 | "darling", 448 | "proc-macro2", 449 | "quote", 450 | "syn", 451 | ] 452 | 453 | [[package]] 454 | name = "derive_builder_macro" 455 | version = "0.20.2" 456 | source = "registry+https://github.com/rust-lang/crates.io-index" 457 | checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" 458 | dependencies = [ 459 | "derive_builder_core", 460 | "syn", 461 | ] 462 | 463 | [[package]] 464 | name = "diff" 465 | version = "0.1.13" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" 468 | 469 | [[package]] 470 | name = "difference" 471 | version = "2.0.0" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 474 | 475 | [[package]] 476 | name = "digest" 477 | version = "0.10.7" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 480 | dependencies = [ 481 | "block-buffer", 482 | "crypto-common", 483 | ] 484 | 485 | [[package]] 486 | name = "displaydoc" 487 | version = "0.2.5" 488 | source = "registry+https://github.com/rust-lang/crates.io-index" 489 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 490 | dependencies = [ 491 | "proc-macro2", 492 | "quote", 493 | "syn", 494 | ] 495 | 496 | [[package]] 497 | name = "either" 498 | version = "1.14.0" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" 501 | 502 | [[package]] 503 | name = "equivalent" 504 | version = "1.0.2" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 507 | 508 | [[package]] 509 | name = "errno" 510 | version = "0.3.10" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 513 | dependencies = [ 514 | "libc", 515 | "windows-sys", 516 | ] 517 | 518 | [[package]] 519 | name = "fastrand" 520 | version = "2.3.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" 523 | 524 | [[package]] 525 | name = "fnv" 526 | version = "1.0.7" 527 | source = "registry+https://github.com/rust-lang/crates.io-index" 528 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 529 | 530 | [[package]] 531 | name = "form_urlencoded" 532 | version = "1.2.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 535 | dependencies = [ 536 | "percent-encoding", 537 | ] 538 | 539 | [[package]] 540 | name = "from_variant" 541 | version = "2.0.0" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "8d7ccf961415e7aa17ef93dcb6c2441faaa8e768abe09e659b908089546f74c5" 544 | dependencies = [ 545 | "proc-macro2", 546 | "swc_macros_common", 547 | "syn", 548 | ] 549 | 550 | [[package]] 551 | name = "funty" 552 | version = "2.0.0" 553 | source = "registry+https://github.com/rust-lang/crates.io-index" 554 | checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 555 | 556 | [[package]] 557 | name = "generic-array" 558 | version = "0.14.7" 559 | source = "registry+https://github.com/rust-lang/crates.io-index" 560 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 561 | dependencies = [ 562 | "typenum", 563 | "version_check", 564 | ] 565 | 566 | [[package]] 567 | name = "getrandom" 568 | version = "0.3.1" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" 571 | dependencies = [ 572 | "cfg-if", 573 | "libc", 574 | "wasi", 575 | "windows-targets", 576 | ] 577 | 578 | [[package]] 579 | name = "glob" 580 | version = "0.3.2" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" 583 | 584 | [[package]] 585 | name = "half" 586 | version = "2.4.1" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 589 | dependencies = [ 590 | "cfg-if", 591 | "crunchy", 592 | ] 593 | 594 | [[package]] 595 | name = "hashbrown" 596 | version = "0.14.5" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 599 | dependencies = [ 600 | "ahash", 601 | "allocator-api2", 602 | ] 603 | 604 | [[package]] 605 | name = "hashbrown" 606 | version = "0.15.2" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 609 | 610 | [[package]] 611 | name = "heck" 612 | version = "0.5.0" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 615 | 616 | [[package]] 617 | name = "hermit-abi" 618 | version = "0.3.9" 619 | source = "registry+https://github.com/rust-lang/crates.io-index" 620 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 621 | 622 | [[package]] 623 | name = "hermit-abi" 624 | version = "0.4.0" 625 | source = "registry+https://github.com/rust-lang/crates.io-index" 626 | checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" 627 | 628 | [[package]] 629 | name = "hex" 630 | version = "0.4.3" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 633 | 634 | [[package]] 635 | name = "hstr" 636 | version = "1.0.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "71399f53a92ef72ee336a4b30201c6e944827e14e0af23204c291aad9c24cc85" 639 | dependencies = [ 640 | "hashbrown 0.14.5", 641 | "new_debug_unreachable", 642 | "once_cell", 643 | "phf", 644 | "rustc-hash 2.1.1", 645 | "triomphe", 646 | ] 647 | 648 | [[package]] 649 | name = "icu_collections" 650 | version = "1.5.0" 651 | source = "registry+https://github.com/rust-lang/crates.io-index" 652 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 653 | dependencies = [ 654 | "displaydoc", 655 | "yoke", 656 | "zerofrom", 657 | "zerovec", 658 | ] 659 | 660 | [[package]] 661 | name = "icu_locid" 662 | version = "1.5.0" 663 | source = "registry+https://github.com/rust-lang/crates.io-index" 664 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 665 | dependencies = [ 666 | "displaydoc", 667 | "litemap", 668 | "tinystr", 669 | "writeable", 670 | "zerovec", 671 | ] 672 | 673 | [[package]] 674 | name = "icu_locid_transform" 675 | version = "1.5.0" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 678 | dependencies = [ 679 | "displaydoc", 680 | "icu_locid", 681 | "icu_locid_transform_data", 682 | "icu_provider", 683 | "tinystr", 684 | "zerovec", 685 | ] 686 | 687 | [[package]] 688 | name = "icu_locid_transform_data" 689 | version = "1.5.0" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" 692 | 693 | [[package]] 694 | name = "icu_normalizer" 695 | version = "1.5.0" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 698 | dependencies = [ 699 | "displaydoc", 700 | "icu_collections", 701 | "icu_normalizer_data", 702 | "icu_properties", 703 | "icu_provider", 704 | "smallvec", 705 | "utf16_iter", 706 | "utf8_iter", 707 | "write16", 708 | "zerovec", 709 | ] 710 | 711 | [[package]] 712 | name = "icu_normalizer_data" 713 | version = "1.5.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" 716 | 717 | [[package]] 718 | name = "icu_properties" 719 | version = "1.5.1" 720 | source = "registry+https://github.com/rust-lang/crates.io-index" 721 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 722 | dependencies = [ 723 | "displaydoc", 724 | "icu_collections", 725 | "icu_locid_transform", 726 | "icu_properties_data", 727 | "icu_provider", 728 | "tinystr", 729 | "zerovec", 730 | ] 731 | 732 | [[package]] 733 | name = "icu_properties_data" 734 | version = "1.5.0" 735 | source = "registry+https://github.com/rust-lang/crates.io-index" 736 | checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" 737 | 738 | [[package]] 739 | name = "icu_provider" 740 | version = "1.5.0" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 743 | dependencies = [ 744 | "displaydoc", 745 | "icu_locid", 746 | "icu_provider_macros", 747 | "stable_deref_trait", 748 | "tinystr", 749 | "writeable", 750 | "yoke", 751 | "zerofrom", 752 | "zerovec", 753 | ] 754 | 755 | [[package]] 756 | name = "icu_provider_macros" 757 | version = "1.5.0" 758 | source = "registry+https://github.com/rust-lang/crates.io-index" 759 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 760 | dependencies = [ 761 | "proc-macro2", 762 | "quote", 763 | "syn", 764 | ] 765 | 766 | [[package]] 767 | name = "ident_case" 768 | version = "1.0.1" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 771 | 772 | [[package]] 773 | name = "idna" 774 | version = "1.0.3" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 777 | dependencies = [ 778 | "idna_adapter", 779 | "smallvec", 780 | "utf8_iter", 781 | ] 782 | 783 | [[package]] 784 | name = "idna_adapter" 785 | version = "1.2.0" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 788 | dependencies = [ 789 | "icu_normalizer", 790 | "icu_properties", 791 | ] 792 | 793 | [[package]] 794 | name = "if_chain" 795 | version = "1.0.2" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" 798 | 799 | [[package]] 800 | name = "indexmap" 801 | version = "2.7.1" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" 804 | dependencies = [ 805 | "equivalent", 806 | "hashbrown 0.15.2", 807 | ] 808 | 809 | [[package]] 810 | name = "is-macro" 811 | version = "0.3.7" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "1d57a3e447e24c22647738e4607f1df1e0ec6f72e16182c4cd199f647cdfb0e4" 814 | dependencies = [ 815 | "heck", 816 | "proc-macro2", 817 | "quote", 818 | "syn", 819 | ] 820 | 821 | [[package]] 822 | name = "is-terminal" 823 | version = "0.4.15" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" 826 | dependencies = [ 827 | "hermit-abi 0.4.0", 828 | "libc", 829 | "windows-sys", 830 | ] 831 | 832 | [[package]] 833 | name = "itertools" 834 | version = "0.10.5" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 837 | dependencies = [ 838 | "either", 839 | ] 840 | 841 | [[package]] 842 | name = "itoa" 843 | version = "1.0.15" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 846 | 847 | [[package]] 848 | name = "lazy_static" 849 | version = "1.5.0" 850 | source = "registry+https://github.com/rust-lang/crates.io-index" 851 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 852 | 853 | [[package]] 854 | name = "libc" 855 | version = "0.2.170" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" 858 | 859 | [[package]] 860 | name = "linux-raw-sys" 861 | version = "0.4.15" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 864 | 865 | [[package]] 866 | name = "litemap" 867 | version = "0.7.5" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" 870 | 871 | [[package]] 872 | name = "lock_api" 873 | version = "0.4.12" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 876 | dependencies = [ 877 | "autocfg", 878 | "scopeguard", 879 | ] 880 | 881 | [[package]] 882 | name = "log" 883 | version = "0.4.26" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" 886 | 887 | [[package]] 888 | name = "matchers" 889 | version = "0.1.0" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" 892 | dependencies = [ 893 | "regex-automata 0.1.10", 894 | ] 895 | 896 | [[package]] 897 | name = "memchr" 898 | version = "2.7.4" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 901 | 902 | [[package]] 903 | name = "miette" 904 | version = "7.5.0" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "1a955165f87b37fd1862df2a59547ac542c77ef6d17c666f619d1ad22dd89484" 907 | dependencies = [ 908 | "cfg-if", 909 | "miette-derive", 910 | "owo-colors", 911 | "textwrap", 912 | "thiserror 1.0.69", 913 | "unicode-width 0.1.14", 914 | ] 915 | 916 | [[package]] 917 | name = "miette-derive" 918 | version = "7.5.0" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "bf45bf44ab49be92fd1227a3be6fc6f617f1a337c06af54981048574d8783147" 921 | dependencies = [ 922 | "proc-macro2", 923 | "quote", 924 | "syn", 925 | ] 926 | 927 | [[package]] 928 | name = "munge" 929 | version = "0.4.3" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7" 932 | dependencies = [ 933 | "munge_macro", 934 | ] 935 | 936 | [[package]] 937 | name = "munge_macro" 938 | version = "0.4.3" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459" 941 | dependencies = [ 942 | "proc-macro2", 943 | "quote", 944 | "syn", 945 | ] 946 | 947 | [[package]] 948 | name = "new_debug_unreachable" 949 | version = "1.0.6" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" 952 | 953 | [[package]] 954 | name = "nu-ansi-term" 955 | version = "0.46.0" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 958 | dependencies = [ 959 | "overload", 960 | "winapi", 961 | ] 962 | 963 | [[package]] 964 | name = "num-bigint" 965 | version = "0.4.6" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 968 | dependencies = [ 969 | "num-integer", 970 | "num-traits", 971 | "serde", 972 | ] 973 | 974 | [[package]] 975 | name = "num-integer" 976 | version = "0.1.46" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 979 | dependencies = [ 980 | "num-traits", 981 | ] 982 | 983 | [[package]] 984 | name = "num-traits" 985 | version = "0.2.19" 986 | source = "registry+https://github.com/rust-lang/crates.io-index" 987 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 988 | dependencies = [ 989 | "autocfg", 990 | ] 991 | 992 | [[package]] 993 | name = "num_cpus" 994 | version = "1.16.0" 995 | source = "registry+https://github.com/rust-lang/crates.io-index" 996 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 997 | dependencies = [ 998 | "hermit-abi 0.3.9", 999 | "libc", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "once_cell" 1004 | version = "1.20.3" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" 1007 | 1008 | [[package]] 1009 | name = "oorandom" 1010 | version = "11.1.4" 1011 | source = "registry+https://github.com/rust-lang/crates.io-index" 1012 | checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" 1013 | 1014 | [[package]] 1015 | name = "outref" 1016 | version = "0.1.0" 1017 | source = "registry+https://github.com/rust-lang/crates.io-index" 1018 | checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" 1019 | 1020 | [[package]] 1021 | name = "overload" 1022 | version = "0.1.1" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1025 | 1026 | [[package]] 1027 | name = "owo-colors" 1028 | version = "4.2.0" 1029 | source = "registry+https://github.com/rust-lang/crates.io-index" 1030 | checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" 1031 | 1032 | [[package]] 1033 | name = "parking_lot" 1034 | version = "0.12.3" 1035 | source = "registry+https://github.com/rust-lang/crates.io-index" 1036 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 1037 | dependencies = [ 1038 | "lock_api", 1039 | "parking_lot_core", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "parking_lot_core" 1044 | version = "0.9.10" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 1047 | dependencies = [ 1048 | "cfg-if", 1049 | "libc", 1050 | "redox_syscall", 1051 | "smallvec", 1052 | "windows-targets", 1053 | ] 1054 | 1055 | [[package]] 1056 | name = "pathdiff" 1057 | version = "0.2.3" 1058 | source = "registry+https://github.com/rust-lang/crates.io-index" 1059 | checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" 1060 | 1061 | [[package]] 1062 | name = "percent-encoding" 1063 | version = "2.3.1" 1064 | source = "registry+https://github.com/rust-lang/crates.io-index" 1065 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1066 | 1067 | [[package]] 1068 | name = "phf" 1069 | version = "0.11.3" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" 1072 | dependencies = [ 1073 | "phf_macros", 1074 | "phf_shared", 1075 | ] 1076 | 1077 | [[package]] 1078 | name = "phf_generator" 1079 | version = "0.11.3" 1080 | source = "registry+https://github.com/rust-lang/crates.io-index" 1081 | checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 1082 | dependencies = [ 1083 | "phf_shared", 1084 | "rand", 1085 | ] 1086 | 1087 | [[package]] 1088 | name = "phf_macros" 1089 | version = "0.11.3" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" 1092 | dependencies = [ 1093 | "phf_generator", 1094 | "phf_shared", 1095 | "proc-macro2", 1096 | "quote", 1097 | "syn", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "phf_shared" 1102 | version = "0.11.3" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" 1105 | dependencies = [ 1106 | "siphasher 1.0.1", 1107 | ] 1108 | 1109 | [[package]] 1110 | name = "pin-project-lite" 1111 | version = "0.2.16" 1112 | source = "registry+https://github.com/rust-lang/crates.io-index" 1113 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1114 | 1115 | [[package]] 1116 | name = "pretty_assertions" 1117 | version = "1.4.1" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" 1120 | dependencies = [ 1121 | "diff", 1122 | "yansi", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "proc-macro2" 1127 | version = "1.0.94" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 1130 | dependencies = [ 1131 | "unicode-ident", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "psm" 1136 | version = "0.1.25" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" 1139 | dependencies = [ 1140 | "cc", 1141 | ] 1142 | 1143 | [[package]] 1144 | name = "ptr_meta" 1145 | version = "0.3.0" 1146 | source = "registry+https://github.com/rust-lang/crates.io-index" 1147 | checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" 1148 | dependencies = [ 1149 | "ptr_meta_derive", 1150 | ] 1151 | 1152 | [[package]] 1153 | name = "ptr_meta_derive" 1154 | version = "0.3.0" 1155 | source = "registry+https://github.com/rust-lang/crates.io-index" 1156 | checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" 1157 | dependencies = [ 1158 | "proc-macro2", 1159 | "quote", 1160 | "syn", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "quote" 1165 | version = "1.0.39" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" 1168 | dependencies = [ 1169 | "proc-macro2", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "radium" 1174 | version = "0.7.0" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 1177 | 1178 | [[package]] 1179 | name = "rancor" 1180 | version = "0.1.0" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" 1183 | dependencies = [ 1184 | "ptr_meta", 1185 | ] 1186 | 1187 | [[package]] 1188 | name = "rand" 1189 | version = "0.8.5" 1190 | source = "registry+https://github.com/rust-lang/crates.io-index" 1191 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1192 | dependencies = [ 1193 | "rand_core", 1194 | ] 1195 | 1196 | [[package]] 1197 | name = "rand_core" 1198 | version = "0.6.4" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1201 | 1202 | [[package]] 1203 | name = "redox_syscall" 1204 | version = "0.5.10" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" 1207 | dependencies = [ 1208 | "bitflags", 1209 | ] 1210 | 1211 | [[package]] 1212 | name = "regex" 1213 | version = "1.11.1" 1214 | source = "registry+https://github.com/rust-lang/crates.io-index" 1215 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 1216 | dependencies = [ 1217 | "aho-corasick", 1218 | "memchr", 1219 | "regex-automata 0.4.9", 1220 | "regex-syntax 0.8.5", 1221 | ] 1222 | 1223 | [[package]] 1224 | name = "regex-automata" 1225 | version = "0.1.10" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 1228 | dependencies = [ 1229 | "regex-syntax 0.6.29", 1230 | ] 1231 | 1232 | [[package]] 1233 | name = "regex-automata" 1234 | version = "0.4.9" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 1237 | dependencies = [ 1238 | "aho-corasick", 1239 | "memchr", 1240 | "regex-syntax 0.8.5", 1241 | ] 1242 | 1243 | [[package]] 1244 | name = "regex-syntax" 1245 | version = "0.6.29" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" 1248 | 1249 | [[package]] 1250 | name = "regex-syntax" 1251 | version = "0.8.5" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1254 | 1255 | [[package]] 1256 | name = "relative-path" 1257 | version = "1.9.3" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" 1260 | 1261 | [[package]] 1262 | name = "rend" 1263 | version = "0.5.2" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215" 1266 | dependencies = [ 1267 | "bytecheck", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "rkyv" 1272 | version = "0.8.10" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" 1275 | dependencies = [ 1276 | "bytecheck", 1277 | "bytes", 1278 | "hashbrown 0.15.2", 1279 | "indexmap", 1280 | "munge", 1281 | "ptr_meta", 1282 | "rancor", 1283 | "rend", 1284 | "rkyv_derive", 1285 | "tinyvec", 1286 | "uuid", 1287 | ] 1288 | 1289 | [[package]] 1290 | name = "rkyv_derive" 1291 | version = "0.8.10" 1292 | source = "registry+https://github.com/rust-lang/crates.io-index" 1293 | checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" 1294 | dependencies = [ 1295 | "proc-macro2", 1296 | "quote", 1297 | "syn", 1298 | ] 1299 | 1300 | [[package]] 1301 | name = "rustc-hash" 1302 | version = "1.1.0" 1303 | source = "registry+https://github.com/rust-lang/crates.io-index" 1304 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1305 | 1306 | [[package]] 1307 | name = "rustc-hash" 1308 | version = "2.1.1" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 1311 | 1312 | [[package]] 1313 | name = "rustc_version" 1314 | version = "0.2.3" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1317 | dependencies = [ 1318 | "semver 0.9.0", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "rustix" 1323 | version = "0.38.44" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 1326 | dependencies = [ 1327 | "bitflags", 1328 | "errno", 1329 | "libc", 1330 | "linux-raw-sys", 1331 | "windows-sys", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "rustversion" 1336 | version = "1.0.20" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1339 | 1340 | [[package]] 1341 | name = "ryu" 1342 | version = "1.0.20" 1343 | source = "registry+https://github.com/rust-lang/crates.io-index" 1344 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1345 | 1346 | [[package]] 1347 | name = "ryu-js" 1348 | version = "1.0.2" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" 1351 | 1352 | [[package]] 1353 | name = "same-file" 1354 | version = "1.0.6" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1357 | dependencies = [ 1358 | "winapi-util", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "scoped-tls" 1363 | version = "1.0.1" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" 1366 | 1367 | [[package]] 1368 | name = "scopeguard" 1369 | version = "1.2.0" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1372 | 1373 | [[package]] 1374 | name = "semver" 1375 | version = "0.9.0" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1378 | dependencies = [ 1379 | "semver-parser", 1380 | ] 1381 | 1382 | [[package]] 1383 | name = "semver" 1384 | version = "1.0.26" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 1387 | dependencies = [ 1388 | "serde", 1389 | ] 1390 | 1391 | [[package]] 1392 | name = "semver-parser" 1393 | version = "0.7.0" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1396 | 1397 | [[package]] 1398 | name = "serde" 1399 | version = "1.0.218" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" 1402 | dependencies = [ 1403 | "serde_derive", 1404 | ] 1405 | 1406 | [[package]] 1407 | name = "serde_derive" 1408 | version = "1.0.218" 1409 | source = "registry+https://github.com/rust-lang/crates.io-index" 1410 | checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" 1411 | dependencies = [ 1412 | "proc-macro2", 1413 | "quote", 1414 | "syn", 1415 | ] 1416 | 1417 | [[package]] 1418 | name = "serde_json" 1419 | version = "1.0.140" 1420 | source = "registry+https://github.com/rust-lang/crates.io-index" 1421 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1422 | dependencies = [ 1423 | "itoa", 1424 | "memchr", 1425 | "ryu", 1426 | "serde", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "sha2" 1431 | version = "0.10.8" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1434 | dependencies = [ 1435 | "cfg-if", 1436 | "cpufeatures", 1437 | "digest", 1438 | ] 1439 | 1440 | [[package]] 1441 | name = "sharded-slab" 1442 | version = "0.1.7" 1443 | source = "registry+https://github.com/rust-lang/crates.io-index" 1444 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1445 | dependencies = [ 1446 | "lazy_static", 1447 | ] 1448 | 1449 | [[package]] 1450 | name = "shlex" 1451 | version = "1.3.0" 1452 | source = "registry+https://github.com/rust-lang/crates.io-index" 1453 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1454 | 1455 | [[package]] 1456 | name = "simd-abstraction" 1457 | version = "0.7.1" 1458 | source = "registry+https://github.com/rust-lang/crates.io-index" 1459 | checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" 1460 | dependencies = [ 1461 | "outref", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "simdutf8" 1466 | version = "0.1.5" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" 1469 | 1470 | [[package]] 1471 | name = "siphasher" 1472 | version = "0.3.11" 1473 | source = "registry+https://github.com/rust-lang/crates.io-index" 1474 | checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" 1475 | 1476 | [[package]] 1477 | name = "siphasher" 1478 | version = "1.0.1" 1479 | source = "registry+https://github.com/rust-lang/crates.io-index" 1480 | checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" 1481 | 1482 | [[package]] 1483 | name = "smallvec" 1484 | version = "1.14.0" 1485 | source = "registry+https://github.com/rust-lang/crates.io-index" 1486 | checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" 1487 | 1488 | [[package]] 1489 | name = "smartstring" 1490 | version = "1.0.1" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" 1493 | dependencies = [ 1494 | "autocfg", 1495 | "static_assertions", 1496 | "version_check", 1497 | ] 1498 | 1499 | [[package]] 1500 | name = "sourcemap" 1501 | version = "9.1.2" 1502 | source = "registry+https://github.com/rust-lang/crates.io-index" 1503 | checksum = "27c4ea7042fd1a155ad95335b5d505ab00d5124ea0332a06c8390d200bb1a76a" 1504 | dependencies = [ 1505 | "base64-simd", 1506 | "bitvec", 1507 | "data-encoding", 1508 | "debugid", 1509 | "if_chain", 1510 | "rustc-hash 1.1.0", 1511 | "rustc_version", 1512 | "serde", 1513 | "serde_json", 1514 | "unicode-id-start", 1515 | "url", 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "stable_deref_trait" 1520 | version = "1.2.0" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1523 | 1524 | [[package]] 1525 | name = "stacker" 1526 | version = "0.1.19" 1527 | source = "registry+https://github.com/rust-lang/crates.io-index" 1528 | checksum = "d9156ebd5870ef293bfb43f91c7a74528d363ec0d424afe24160ed5a4343d08a" 1529 | dependencies = [ 1530 | "cc", 1531 | "cfg-if", 1532 | "libc", 1533 | "psm", 1534 | "windows-sys", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "static_assertions" 1539 | version = "1.1.0" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1542 | 1543 | [[package]] 1544 | name = "string_enum" 1545 | version = "1.0.0" 1546 | source = "registry+https://github.com/rust-lang/crates.io-index" 1547 | checksum = "c9fe66b8ee349846ce2f9557a26b8f1e74843c4a13fb381f9a3d73617a5f956a" 1548 | dependencies = [ 1549 | "proc-macro2", 1550 | "quote", 1551 | "swc_macros_common", 1552 | "syn", 1553 | ] 1554 | 1555 | [[package]] 1556 | name = "strsim" 1557 | version = "0.11.1" 1558 | source = "registry+https://github.com/rust-lang/crates.io-index" 1559 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1560 | 1561 | [[package]] 1562 | name = "swc-plugin-css-variable" 1563 | version = "0.1.0" 1564 | dependencies = [ 1565 | "lazy_static", 1566 | "pathdiff", 1567 | "regex", 1568 | "serde_json", 1569 | "swc_core", 1570 | "transform", 1571 | ] 1572 | 1573 | [[package]] 1574 | name = "swc_allocator" 1575 | version = "4.0.0" 1576 | source = "registry+https://github.com/rust-lang/crates.io-index" 1577 | checksum = "cc6b926f0d94bbb34031fe5449428cfa1268cdc0b31158d6ad9c97e0fc1e79dd" 1578 | dependencies = [ 1579 | "allocator-api2", 1580 | "bumpalo", 1581 | "hashbrown 0.14.5", 1582 | "ptr_meta", 1583 | "rustc-hash 2.1.1", 1584 | "triomphe", 1585 | ] 1586 | 1587 | [[package]] 1588 | name = "swc_atoms" 1589 | version = "5.0.0" 1590 | source = "registry+https://github.com/rust-lang/crates.io-index" 1591 | checksum = "9d7077ba879f95406459bc0c81f3141c529b34580bc64d7ab7bd15e7118a0391" 1592 | dependencies = [ 1593 | "bytecheck", 1594 | "hstr", 1595 | "once_cell", 1596 | "rancor", 1597 | "rkyv", 1598 | "rustc-hash 2.1.1", 1599 | "serde", 1600 | ] 1601 | 1602 | [[package]] 1603 | name = "swc_common" 1604 | version = "8.0.0" 1605 | source = "registry+https://github.com/rust-lang/crates.io-index" 1606 | checksum = "26fbd21a1179166b5635d4b7a6b5930cf34b803a7361e0297b04f84dc820db04" 1607 | dependencies = [ 1608 | "anyhow", 1609 | "ast_node", 1610 | "better_scoped_tls", 1611 | "bytecheck", 1612 | "cfg-if", 1613 | "either", 1614 | "from_variant", 1615 | "new_debug_unreachable", 1616 | "num-bigint", 1617 | "once_cell", 1618 | "parking_lot", 1619 | "rancor", 1620 | "rkyv", 1621 | "rustc-hash 2.1.1", 1622 | "serde", 1623 | "siphasher 0.3.11", 1624 | "sourcemap", 1625 | "swc_allocator", 1626 | "swc_atoms", 1627 | "swc_eq_ignore_macros", 1628 | "swc_visit", 1629 | "termcolor", 1630 | "tracing", 1631 | "unicode-width 0.1.14", 1632 | "url", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "swc_core" 1637 | version = "16.3.1" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "f653564e81bd21b1fe89c433e83cc9bdefc84992ad4df0654af3c345b4fdb71e" 1640 | dependencies = [ 1641 | "once_cell", 1642 | "swc_allocator", 1643 | "swc_atoms", 1644 | "swc_common", 1645 | "swc_ecma_ast", 1646 | "swc_ecma_parser", 1647 | "swc_ecma_transforms_base", 1648 | "swc_ecma_transforms_testing", 1649 | "swc_ecma_visit", 1650 | "swc_plugin", 1651 | "swc_plugin_macro", 1652 | "swc_plugin_proxy", 1653 | "vergen", 1654 | ] 1655 | 1656 | [[package]] 1657 | name = "swc_ecma_ast" 1658 | version = "8.0.0" 1659 | source = "registry+https://github.com/rust-lang/crates.io-index" 1660 | checksum = "c66db1e9b31f0f91ee0964aba014b4d2dfdc6c558732d106d762b43bedad2c4a" 1661 | dependencies = [ 1662 | "bitflags", 1663 | "bytecheck", 1664 | "is-macro", 1665 | "num-bigint", 1666 | "phf", 1667 | "rancor", 1668 | "rkyv", 1669 | "scoped-tls", 1670 | "string_enum", 1671 | "swc_atoms", 1672 | "swc_common", 1673 | "swc_visit", 1674 | "unicode-id-start", 1675 | ] 1676 | 1677 | [[package]] 1678 | name = "swc_ecma_codegen" 1679 | version = "8.0.2" 1680 | source = "registry+https://github.com/rust-lang/crates.io-index" 1681 | checksum = "92103aa982740f265d6850bb3ffffbf6c3c1dee30ab0ed25117ca553f0d7467d" 1682 | dependencies = [ 1683 | "ascii", 1684 | "compact_str", 1685 | "memchr", 1686 | "num-bigint", 1687 | "once_cell", 1688 | "regex", 1689 | "rustc-hash 2.1.1", 1690 | "serde", 1691 | "sourcemap", 1692 | "swc_allocator", 1693 | "swc_atoms", 1694 | "swc_common", 1695 | "swc_ecma_ast", 1696 | "swc_ecma_codegen_macros", 1697 | "tracing", 1698 | ] 1699 | 1700 | [[package]] 1701 | name = "swc_ecma_codegen_macros" 1702 | version = "1.0.1" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "4ac2ff0957329e0dfcde86a1ac465382e189bf42a5989720d3476bea78eaa31a" 1705 | dependencies = [ 1706 | "proc-macro2", 1707 | "quote", 1708 | "swc_macros_common", 1709 | "syn", 1710 | ] 1711 | 1712 | [[package]] 1713 | name = "swc_ecma_parser" 1714 | version = "10.0.0" 1715 | source = "registry+https://github.com/rust-lang/crates.io-index" 1716 | checksum = "f9e336f2b460882df2c132328b3c29ab3e680e1db681a05ec3e406940d98320a" 1717 | dependencies = [ 1718 | "either", 1719 | "new_debug_unreachable", 1720 | "num-bigint", 1721 | "num-traits", 1722 | "phf", 1723 | "rustc-hash 2.1.1", 1724 | "serde", 1725 | "smallvec", 1726 | "smartstring", 1727 | "stacker", 1728 | "swc_atoms", 1729 | "swc_common", 1730 | "swc_ecma_ast", 1731 | "tracing", 1732 | "typed-arena", 1733 | ] 1734 | 1735 | [[package]] 1736 | name = "swc_ecma_testing" 1737 | version = "8.0.0" 1738 | source = "registry+https://github.com/rust-lang/crates.io-index" 1739 | checksum = "5e72a43b7acd904fa0c6d244a72aeda66febbc5a9720975481cb836d6804b604" 1740 | dependencies = [ 1741 | "anyhow", 1742 | "hex", 1743 | "sha2", 1744 | "testing", 1745 | "tracing", 1746 | ] 1747 | 1748 | [[package]] 1749 | name = "swc_ecma_transforms_base" 1750 | version = "11.2.0" 1751 | source = "registry+https://github.com/rust-lang/crates.io-index" 1752 | checksum = "39889063ff4819eae414dfe6426aa5cd72ebb0f9f48739a1fa1e7eb82d0adc78" 1753 | dependencies = [ 1754 | "better_scoped_tls", 1755 | "bitflags", 1756 | "indexmap", 1757 | "once_cell", 1758 | "phf", 1759 | "rustc-hash 2.1.1", 1760 | "serde", 1761 | "smallvec", 1762 | "swc_atoms", 1763 | "swc_common", 1764 | "swc_ecma_ast", 1765 | "swc_ecma_parser", 1766 | "swc_ecma_utils", 1767 | "swc_ecma_visit", 1768 | "swc_parallel", 1769 | "tracing", 1770 | ] 1771 | 1772 | [[package]] 1773 | name = "swc_ecma_transforms_testing" 1774 | version = "11.0.1" 1775 | source = "registry+https://github.com/rust-lang/crates.io-index" 1776 | checksum = "13c4d8c48a36ad5d02626f853edcf52ae82b65d238389e7e76270ddf564b69ab" 1777 | dependencies = [ 1778 | "ansi_term", 1779 | "anyhow", 1780 | "base64", 1781 | "hex", 1782 | "serde", 1783 | "serde_json", 1784 | "sha2", 1785 | "sourcemap", 1786 | "swc_allocator", 1787 | "swc_common", 1788 | "swc_ecma_ast", 1789 | "swc_ecma_codegen", 1790 | "swc_ecma_parser", 1791 | "swc_ecma_testing", 1792 | "swc_ecma_transforms_base", 1793 | "swc_ecma_utils", 1794 | "swc_ecma_visit", 1795 | "tempfile", 1796 | "testing", 1797 | ] 1798 | 1799 | [[package]] 1800 | name = "swc_ecma_utils" 1801 | version = "11.0.0" 1802 | source = "registry+https://github.com/rust-lang/crates.io-index" 1803 | checksum = "721dc779e7de200da96ac4002c710bc32c988e3e1ebf62b39d32bf99f14d9765" 1804 | dependencies = [ 1805 | "indexmap", 1806 | "num_cpus", 1807 | "once_cell", 1808 | "rustc-hash 2.1.1", 1809 | "ryu-js", 1810 | "swc_atoms", 1811 | "swc_common", 1812 | "swc_ecma_ast", 1813 | "swc_ecma_visit", 1814 | "swc_parallel", 1815 | "tracing", 1816 | "unicode-id", 1817 | ] 1818 | 1819 | [[package]] 1820 | name = "swc_ecma_visit" 1821 | version = "8.0.0" 1822 | source = "registry+https://github.com/rust-lang/crates.io-index" 1823 | checksum = "2f7a65fa06d0c0f709f1df4e820ccdc4eca7b3db7f9d131545e20c2ac2f1cd23" 1824 | dependencies = [ 1825 | "new_debug_unreachable", 1826 | "num-bigint", 1827 | "swc_atoms", 1828 | "swc_common", 1829 | "swc_ecma_ast", 1830 | "swc_visit", 1831 | "tracing", 1832 | ] 1833 | 1834 | [[package]] 1835 | name = "swc_eq_ignore_macros" 1836 | version = "1.0.0" 1837 | source = "registry+https://github.com/rust-lang/crates.io-index" 1838 | checksum = "e96e15288bf385ab85eb83cff7f9e2d834348da58d0a31b33bdb572e66ee413e" 1839 | dependencies = [ 1840 | "proc-macro2", 1841 | "quote", 1842 | "syn", 1843 | ] 1844 | 1845 | [[package]] 1846 | name = "swc_error_reporters" 1847 | version = "9.0.0" 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" 1849 | checksum = "10ad5f4690758cedc202cf0f4c9d2369372c6692307f65bd40031de494662cfa" 1850 | dependencies = [ 1851 | "anyhow", 1852 | "miette", 1853 | "once_cell", 1854 | "parking_lot", 1855 | "swc_common", 1856 | ] 1857 | 1858 | [[package]] 1859 | name = "swc_macros_common" 1860 | version = "1.0.0" 1861 | source = "registry+https://github.com/rust-lang/crates.io-index" 1862 | checksum = "a509f56fca05b39ba6c15f3e58636c3924c78347d63853632ed2ffcb6f5a0ac7" 1863 | dependencies = [ 1864 | "proc-macro2", 1865 | "quote", 1866 | "syn", 1867 | ] 1868 | 1869 | [[package]] 1870 | name = "swc_parallel" 1871 | version = "1.2.0" 1872 | source = "registry+https://github.com/rust-lang/crates.io-index" 1873 | checksum = "e5f75f1094d69174ef628e3665fff0f81d58e9f568802e3c90d332c72b0b6026" 1874 | dependencies = [ 1875 | "once_cell", 1876 | ] 1877 | 1878 | [[package]] 1879 | name = "swc_plugin" 1880 | version = "1.0.0" 1881 | source = "registry+https://github.com/rust-lang/crates.io-index" 1882 | checksum = "6b45099a38ed45528bef939d0eac1a0c1347749d0c67d3dd744d545316c5fd05" 1883 | dependencies = [ 1884 | "once_cell", 1885 | ] 1886 | 1887 | [[package]] 1888 | name = "swc_plugin_macro" 1889 | version = "1.0.0" 1890 | source = "registry+https://github.com/rust-lang/crates.io-index" 1891 | checksum = "0917ccfdcd3fa6cf41bdacef2388702a3b274f9ea708d930e1e8db37c7c3e1c6" 1892 | dependencies = [ 1893 | "proc-macro2", 1894 | "quote", 1895 | "syn", 1896 | ] 1897 | 1898 | [[package]] 1899 | name = "swc_plugin_proxy" 1900 | version = "8.0.0" 1901 | source = "registry+https://github.com/rust-lang/crates.io-index" 1902 | checksum = "a18c199683d9f946db8dfca444212a3551e74a7c563196b154d5ac30f3bf9de6" 1903 | dependencies = [ 1904 | "better_scoped_tls", 1905 | "bytecheck", 1906 | "rancor", 1907 | "rkyv", 1908 | "rustc-hash 2.1.1", 1909 | "swc_common", 1910 | "swc_ecma_ast", 1911 | "swc_trace_macro", 1912 | "tracing", 1913 | ] 1914 | 1915 | [[package]] 1916 | name = "swc_trace_macro" 1917 | version = "2.0.0" 1918 | source = "registry+https://github.com/rust-lang/crates.io-index" 1919 | checksum = "4c78717a841565df57f811376a3d19c9156091c55175e12d378f3a522de70cef" 1920 | dependencies = [ 1921 | "proc-macro2", 1922 | "quote", 1923 | "syn", 1924 | ] 1925 | 1926 | [[package]] 1927 | name = "swc_visit" 1928 | version = "2.0.0" 1929 | source = "registry+https://github.com/rust-lang/crates.io-index" 1930 | checksum = "9138b6a36bbe76dd6753c4c0794f7e26480ea757bee499738bedbbb3ae3ec5f3" 1931 | dependencies = [ 1932 | "either", 1933 | "new_debug_unreachable", 1934 | ] 1935 | 1936 | [[package]] 1937 | name = "syn" 1938 | version = "2.0.99" 1939 | source = "registry+https://github.com/rust-lang/crates.io-index" 1940 | checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" 1941 | dependencies = [ 1942 | "proc-macro2", 1943 | "quote", 1944 | "unicode-ident", 1945 | ] 1946 | 1947 | [[package]] 1948 | name = "synstructure" 1949 | version = "0.13.1" 1950 | source = "registry+https://github.com/rust-lang/crates.io-index" 1951 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1952 | dependencies = [ 1953 | "proc-macro2", 1954 | "quote", 1955 | "syn", 1956 | ] 1957 | 1958 | [[package]] 1959 | name = "tap" 1960 | version = "1.0.1" 1961 | source = "registry+https://github.com/rust-lang/crates.io-index" 1962 | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 1963 | 1964 | [[package]] 1965 | name = "tempfile" 1966 | version = "3.17.1" 1967 | source = "registry+https://github.com/rust-lang/crates.io-index" 1968 | checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" 1969 | dependencies = [ 1970 | "cfg-if", 1971 | "fastrand", 1972 | "getrandom", 1973 | "once_cell", 1974 | "rustix", 1975 | "windows-sys", 1976 | ] 1977 | 1978 | [[package]] 1979 | name = "termcolor" 1980 | version = "1.4.1" 1981 | source = "registry+https://github.com/rust-lang/crates.io-index" 1982 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1983 | dependencies = [ 1984 | "winapi-util", 1985 | ] 1986 | 1987 | [[package]] 1988 | name = "testing" 1989 | version = "8.0.0" 1990 | source = "registry+https://github.com/rust-lang/crates.io-index" 1991 | checksum = "8d32ddc0e2ebd072cbffe7424087267da990708a5bc3ae29e075904468450275" 1992 | dependencies = [ 1993 | "ansi_term", 1994 | "cargo_metadata 0.18.1", 1995 | "difference", 1996 | "once_cell", 1997 | "pretty_assertions", 1998 | "regex", 1999 | "rustc-hash 2.1.1", 2000 | "serde", 2001 | "serde_json", 2002 | "swc_common", 2003 | "swc_error_reporters", 2004 | "testing_macros", 2005 | "tracing", 2006 | "tracing-subscriber", 2007 | ] 2008 | 2009 | [[package]] 2010 | name = "testing_macros" 2011 | version = "1.0.0" 2012 | source = "registry+https://github.com/rust-lang/crates.io-index" 2013 | checksum = "a2d27bf245b90a80d5aa231133418ae7db98f032855ce5292e12071ab29c4b26" 2014 | dependencies = [ 2015 | "anyhow", 2016 | "glob", 2017 | "once_cell", 2018 | "proc-macro2", 2019 | "quote", 2020 | "regex", 2021 | "relative-path", 2022 | "syn", 2023 | ] 2024 | 2025 | [[package]] 2026 | name = "textwrap" 2027 | version = "0.16.2" 2028 | source = "registry+https://github.com/rust-lang/crates.io-index" 2029 | checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" 2030 | dependencies = [ 2031 | "unicode-linebreak", 2032 | "unicode-width 0.2.0", 2033 | ] 2034 | 2035 | [[package]] 2036 | name = "thiserror" 2037 | version = "1.0.69" 2038 | source = "registry+https://github.com/rust-lang/crates.io-index" 2039 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 2040 | dependencies = [ 2041 | "thiserror-impl 1.0.69", 2042 | ] 2043 | 2044 | [[package]] 2045 | name = "thiserror" 2046 | version = "2.0.12" 2047 | source = "registry+https://github.com/rust-lang/crates.io-index" 2048 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 2049 | dependencies = [ 2050 | "thiserror-impl 2.0.12", 2051 | ] 2052 | 2053 | [[package]] 2054 | name = "thiserror-impl" 2055 | version = "1.0.69" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 2058 | dependencies = [ 2059 | "proc-macro2", 2060 | "quote", 2061 | "syn", 2062 | ] 2063 | 2064 | [[package]] 2065 | name = "thiserror-impl" 2066 | version = "2.0.12" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 2069 | dependencies = [ 2070 | "proc-macro2", 2071 | "quote", 2072 | "syn", 2073 | ] 2074 | 2075 | [[package]] 2076 | name = "thread_local" 2077 | version = "1.1.8" 2078 | source = "registry+https://github.com/rust-lang/crates.io-index" 2079 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 2080 | dependencies = [ 2081 | "cfg-if", 2082 | "once_cell", 2083 | ] 2084 | 2085 | [[package]] 2086 | name = "tinystr" 2087 | version = "0.7.6" 2088 | source = "registry+https://github.com/rust-lang/crates.io-index" 2089 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2090 | dependencies = [ 2091 | "displaydoc", 2092 | "zerovec", 2093 | ] 2094 | 2095 | [[package]] 2096 | name = "tinytemplate" 2097 | version = "1.2.1" 2098 | source = "registry+https://github.com/rust-lang/crates.io-index" 2099 | checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" 2100 | dependencies = [ 2101 | "serde", 2102 | "serde_json", 2103 | ] 2104 | 2105 | [[package]] 2106 | name = "tinyvec" 2107 | version = "1.9.0" 2108 | source = "registry+https://github.com/rust-lang/crates.io-index" 2109 | checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" 2110 | dependencies = [ 2111 | "tinyvec_macros", 2112 | ] 2113 | 2114 | [[package]] 2115 | name = "tinyvec_macros" 2116 | version = "0.1.1" 2117 | source = "registry+https://github.com/rust-lang/crates.io-index" 2118 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2119 | 2120 | [[package]] 2121 | name = "tracing" 2122 | version = "0.1.41" 2123 | source = "registry+https://github.com/rust-lang/crates.io-index" 2124 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2125 | dependencies = [ 2126 | "pin-project-lite", 2127 | "tracing-attributes", 2128 | "tracing-core", 2129 | ] 2130 | 2131 | [[package]] 2132 | name = "tracing-attributes" 2133 | version = "0.1.28" 2134 | source = "registry+https://github.com/rust-lang/crates.io-index" 2135 | checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" 2136 | dependencies = [ 2137 | "proc-macro2", 2138 | "quote", 2139 | "syn", 2140 | ] 2141 | 2142 | [[package]] 2143 | name = "tracing-core" 2144 | version = "0.1.33" 2145 | source = "registry+https://github.com/rust-lang/crates.io-index" 2146 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2147 | dependencies = [ 2148 | "once_cell", 2149 | "valuable", 2150 | ] 2151 | 2152 | [[package]] 2153 | name = "tracing-log" 2154 | version = "0.2.0" 2155 | source = "registry+https://github.com/rust-lang/crates.io-index" 2156 | checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" 2157 | dependencies = [ 2158 | "log", 2159 | "once_cell", 2160 | "tracing-core", 2161 | ] 2162 | 2163 | [[package]] 2164 | name = "tracing-subscriber" 2165 | version = "0.3.19" 2166 | source = "registry+https://github.com/rust-lang/crates.io-index" 2167 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 2168 | dependencies = [ 2169 | "matchers", 2170 | "nu-ansi-term", 2171 | "once_cell", 2172 | "regex", 2173 | "sharded-slab", 2174 | "smallvec", 2175 | "thread_local", 2176 | "tracing", 2177 | "tracing-core", 2178 | "tracing-log", 2179 | ] 2180 | 2181 | [[package]] 2182 | name = "transform" 2183 | version = "0.1.0" 2184 | dependencies = [ 2185 | "base62", 2186 | "criterion", 2187 | "serde", 2188 | "swc_core", 2189 | "xxhash-rust", 2190 | ] 2191 | 2192 | [[package]] 2193 | name = "triomphe" 2194 | version = "0.1.14" 2195 | source = "registry+https://github.com/rust-lang/crates.io-index" 2196 | checksum = "ef8f7726da4807b58ea5c96fdc122f80702030edc33b35aff9190a51148ccc85" 2197 | dependencies = [ 2198 | "serde", 2199 | "stable_deref_trait", 2200 | ] 2201 | 2202 | [[package]] 2203 | name = "typed-arena" 2204 | version = "2.0.2" 2205 | source = "registry+https://github.com/rust-lang/crates.io-index" 2206 | checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" 2207 | 2208 | [[package]] 2209 | name = "typenum" 2210 | version = "1.18.0" 2211 | source = "registry+https://github.com/rust-lang/crates.io-index" 2212 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 2213 | 2214 | [[package]] 2215 | name = "unicode-id" 2216 | version = "0.3.5" 2217 | source = "registry+https://github.com/rust-lang/crates.io-index" 2218 | checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561" 2219 | 2220 | [[package]] 2221 | name = "unicode-id-start" 2222 | version = "1.3.1" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b" 2225 | 2226 | [[package]] 2227 | name = "unicode-ident" 2228 | version = "1.0.18" 2229 | source = "registry+https://github.com/rust-lang/crates.io-index" 2230 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 2231 | 2232 | [[package]] 2233 | name = "unicode-linebreak" 2234 | version = "0.1.5" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" 2237 | 2238 | [[package]] 2239 | name = "unicode-width" 2240 | version = "0.1.14" 2241 | source = "registry+https://github.com/rust-lang/crates.io-index" 2242 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2243 | 2244 | [[package]] 2245 | name = "unicode-width" 2246 | version = "0.2.0" 2247 | source = "registry+https://github.com/rust-lang/crates.io-index" 2248 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 2249 | 2250 | [[package]] 2251 | name = "url" 2252 | version = "2.5.4" 2253 | source = "registry+https://github.com/rust-lang/crates.io-index" 2254 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2255 | dependencies = [ 2256 | "form_urlencoded", 2257 | "idna", 2258 | "percent-encoding", 2259 | ] 2260 | 2261 | [[package]] 2262 | name = "utf16_iter" 2263 | version = "1.0.5" 2264 | source = "registry+https://github.com/rust-lang/crates.io-index" 2265 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2266 | 2267 | [[package]] 2268 | name = "utf8_iter" 2269 | version = "1.0.4" 2270 | source = "registry+https://github.com/rust-lang/crates.io-index" 2271 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2272 | 2273 | [[package]] 2274 | name = "uuid" 2275 | version = "1.15.1" 2276 | source = "registry+https://github.com/rust-lang/crates.io-index" 2277 | checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" 2278 | 2279 | [[package]] 2280 | name = "valuable" 2281 | version = "0.1.1" 2282 | source = "registry+https://github.com/rust-lang/crates.io-index" 2283 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 2284 | 2285 | [[package]] 2286 | name = "vergen" 2287 | version = "9.0.4" 2288 | source = "registry+https://github.com/rust-lang/crates.io-index" 2289 | checksum = "e0d2f179f8075b805a43a2a21728a46f0cc2921b3c58695b28fa8817e103cd9a" 2290 | dependencies = [ 2291 | "anyhow", 2292 | "cargo_metadata 0.19.2", 2293 | "derive_builder", 2294 | "regex", 2295 | "rustversion", 2296 | "vergen-lib", 2297 | ] 2298 | 2299 | [[package]] 2300 | name = "vergen-lib" 2301 | version = "0.1.6" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" 2304 | dependencies = [ 2305 | "anyhow", 2306 | "derive_builder", 2307 | "rustversion", 2308 | ] 2309 | 2310 | [[package]] 2311 | name = "version_check" 2312 | version = "0.9.5" 2313 | source = "registry+https://github.com/rust-lang/crates.io-index" 2314 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2315 | 2316 | [[package]] 2317 | name = "walkdir" 2318 | version = "2.5.0" 2319 | source = "registry+https://github.com/rust-lang/crates.io-index" 2320 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 2321 | dependencies = [ 2322 | "same-file", 2323 | "winapi-util", 2324 | ] 2325 | 2326 | [[package]] 2327 | name = "wasi" 2328 | version = "0.13.3+wasi-0.2.2" 2329 | source = "registry+https://github.com/rust-lang/crates.io-index" 2330 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 2331 | dependencies = [ 2332 | "wit-bindgen-rt", 2333 | ] 2334 | 2335 | [[package]] 2336 | name = "winapi" 2337 | version = "0.3.9" 2338 | source = "registry+https://github.com/rust-lang/crates.io-index" 2339 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2340 | dependencies = [ 2341 | "winapi-i686-pc-windows-gnu", 2342 | "winapi-x86_64-pc-windows-gnu", 2343 | ] 2344 | 2345 | [[package]] 2346 | name = "winapi-i686-pc-windows-gnu" 2347 | version = "0.4.0" 2348 | source = "registry+https://github.com/rust-lang/crates.io-index" 2349 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2350 | 2351 | [[package]] 2352 | name = "winapi-util" 2353 | version = "0.1.9" 2354 | source = "registry+https://github.com/rust-lang/crates.io-index" 2355 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 2356 | dependencies = [ 2357 | "windows-sys", 2358 | ] 2359 | 2360 | [[package]] 2361 | name = "winapi-x86_64-pc-windows-gnu" 2362 | version = "0.4.0" 2363 | source = "registry+https://github.com/rust-lang/crates.io-index" 2364 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2365 | 2366 | [[package]] 2367 | name = "windows-sys" 2368 | version = "0.59.0" 2369 | source = "registry+https://github.com/rust-lang/crates.io-index" 2370 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2371 | dependencies = [ 2372 | "windows-targets", 2373 | ] 2374 | 2375 | [[package]] 2376 | name = "windows-targets" 2377 | version = "0.52.6" 2378 | source = "registry+https://github.com/rust-lang/crates.io-index" 2379 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2380 | dependencies = [ 2381 | "windows_aarch64_gnullvm", 2382 | "windows_aarch64_msvc", 2383 | "windows_i686_gnu", 2384 | "windows_i686_gnullvm", 2385 | "windows_i686_msvc", 2386 | "windows_x86_64_gnu", 2387 | "windows_x86_64_gnullvm", 2388 | "windows_x86_64_msvc", 2389 | ] 2390 | 2391 | [[package]] 2392 | name = "windows_aarch64_gnullvm" 2393 | version = "0.52.6" 2394 | source = "registry+https://github.com/rust-lang/crates.io-index" 2395 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2396 | 2397 | [[package]] 2398 | name = "windows_aarch64_msvc" 2399 | version = "0.52.6" 2400 | source = "registry+https://github.com/rust-lang/crates.io-index" 2401 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2402 | 2403 | [[package]] 2404 | name = "windows_i686_gnu" 2405 | version = "0.52.6" 2406 | source = "registry+https://github.com/rust-lang/crates.io-index" 2407 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2408 | 2409 | [[package]] 2410 | name = "windows_i686_gnullvm" 2411 | version = "0.52.6" 2412 | source = "registry+https://github.com/rust-lang/crates.io-index" 2413 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2414 | 2415 | [[package]] 2416 | name = "windows_i686_msvc" 2417 | version = "0.52.6" 2418 | source = "registry+https://github.com/rust-lang/crates.io-index" 2419 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2420 | 2421 | [[package]] 2422 | name = "windows_x86_64_gnu" 2423 | version = "0.52.6" 2424 | source = "registry+https://github.com/rust-lang/crates.io-index" 2425 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2426 | 2427 | [[package]] 2428 | name = "windows_x86_64_gnullvm" 2429 | version = "0.52.6" 2430 | source = "registry+https://github.com/rust-lang/crates.io-index" 2431 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2432 | 2433 | [[package]] 2434 | name = "windows_x86_64_msvc" 2435 | version = "0.52.6" 2436 | source = "registry+https://github.com/rust-lang/crates.io-index" 2437 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2438 | 2439 | [[package]] 2440 | name = "wit-bindgen-rt" 2441 | version = "0.33.0" 2442 | source = "registry+https://github.com/rust-lang/crates.io-index" 2443 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 2444 | dependencies = [ 2445 | "bitflags", 2446 | ] 2447 | 2448 | [[package]] 2449 | name = "write16" 2450 | version = "1.0.0" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2453 | 2454 | [[package]] 2455 | name = "writeable" 2456 | version = "0.5.5" 2457 | source = "registry+https://github.com/rust-lang/crates.io-index" 2458 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2459 | 2460 | [[package]] 2461 | name = "wyz" 2462 | version = "0.5.1" 2463 | source = "registry+https://github.com/rust-lang/crates.io-index" 2464 | checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 2465 | dependencies = [ 2466 | "tap", 2467 | ] 2468 | 2469 | [[package]] 2470 | name = "xxhash-rust" 2471 | version = "0.8.15" 2472 | source = "registry+https://github.com/rust-lang/crates.io-index" 2473 | checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" 2474 | 2475 | [[package]] 2476 | name = "yansi" 2477 | version = "1.0.1" 2478 | source = "registry+https://github.com/rust-lang/crates.io-index" 2479 | checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 2480 | 2481 | [[package]] 2482 | name = "yoke" 2483 | version = "0.7.5" 2484 | source = "registry+https://github.com/rust-lang/crates.io-index" 2485 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2486 | dependencies = [ 2487 | "serde", 2488 | "stable_deref_trait", 2489 | "yoke-derive", 2490 | "zerofrom", 2491 | ] 2492 | 2493 | [[package]] 2494 | name = "yoke-derive" 2495 | version = "0.7.5" 2496 | source = "registry+https://github.com/rust-lang/crates.io-index" 2497 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2498 | dependencies = [ 2499 | "proc-macro2", 2500 | "quote", 2501 | "syn", 2502 | "synstructure", 2503 | ] 2504 | 2505 | [[package]] 2506 | name = "zerocopy" 2507 | version = "0.7.35" 2508 | source = "registry+https://github.com/rust-lang/crates.io-index" 2509 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 2510 | dependencies = [ 2511 | "zerocopy-derive", 2512 | ] 2513 | 2514 | [[package]] 2515 | name = "zerocopy-derive" 2516 | version = "0.7.35" 2517 | source = "registry+https://github.com/rust-lang/crates.io-index" 2518 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 2519 | dependencies = [ 2520 | "proc-macro2", 2521 | "quote", 2522 | "syn", 2523 | ] 2524 | 2525 | [[package]] 2526 | name = "zerofrom" 2527 | version = "0.1.6" 2528 | source = "registry+https://github.com/rust-lang/crates.io-index" 2529 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2530 | dependencies = [ 2531 | "zerofrom-derive", 2532 | ] 2533 | 2534 | [[package]] 2535 | name = "zerofrom-derive" 2536 | version = "0.1.6" 2537 | source = "registry+https://github.com/rust-lang/crates.io-index" 2538 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2539 | dependencies = [ 2540 | "proc-macro2", 2541 | "quote", 2542 | "syn", 2543 | "synstructure", 2544 | ] 2545 | 2546 | [[package]] 2547 | name = "zerovec" 2548 | version = "0.10.4" 2549 | source = "registry+https://github.com/rust-lang/crates.io-index" 2550 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2551 | dependencies = [ 2552 | "yoke", 2553 | "zerofrom", 2554 | "zerovec-derive", 2555 | ] 2556 | 2557 | [[package]] 2558 | name = "zerovec-derive" 2559 | version = "0.10.3" 2560 | source = "registry+https://github.com/rust-lang/crates.io-index" 2561 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2562 | dependencies = [ 2563 | "proc-macro2", 2564 | "quote", 2565 | "syn", 2566 | ] 2567 | -------------------------------------------------------------------------------- /swc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["swc-plugin-css-variable", "transform"] 3 | resolver = "2" 4 | 5 | [profile.release] 6 | # This profile results in small binary size with acceptable impact on 7 | # performance, but there may well be further optimizations to be had. 8 | strip = "debuginfo" 9 | codegen-units = 1 10 | lto = true 11 | opt-level = "z" 12 | -------------------------------------------------------------------------------- /swc/README.md: -------------------------------------------------------------------------------- 1 | # swc-plugin-css-variable 2 | 3 | This is the SWC counterpart to the babel plugin of this library. 4 | 5 | ## Structure 6 | 7 | This is a workspace with two crates: 8 | 9 | - `swc-plugin-css-variable` is the outer shell and only contains what's 10 | necessary to interface with SWC, which is essentially the main function that 11 | is decorated with `#[plugin_transform]` 12 | - `transform` has everything else, most importantly the visitor implementation 13 | 14 | The reason for the split is to enable benchmarking inside Wasm runtimes. If the 15 | code under test (the visitor) were in the same crate as `#[plugin_transform]`, 16 | code would be generated that requires functions to be linked in for accessing 17 | the environment and emitting diagnostics. Normally these are provided at 18 | runtime by SWC, but for only running benchmarks we don't want to have to 19 | fake them. 20 | 21 | ## Benchmarking 22 | 23 | The benchmarks can be run easily with `cargo bench`. Note that this builds and 24 | runs native code on your machine, which may not exhibit the exact same 25 | performance characteristics as a Wasm module in a runtime, as is the case for 26 | SWC transformations. 27 | 28 | To account for this, it's also possible to build a benchmark executable in Wasm 29 | format and execute it in your runtime of choice. Since SWC internally uses 30 | [Wasmer](https://wasmer.io), it makes sense to install this one. Then, it's 31 | just a matter of 32 | 33 | ```console 34 | $ cargo build --bench bench_main --release --target wasm32-wasip1 35 | # Get the name of the Wasm module we just built 36 | $ ls -t target/wasm32-wasip1/release/deps/*.wasm | head -n 1 37 | target/wasm32-wasip1/release/deps/bench_main-9530540cc15e2e67.wasm 38 | # Execute the benchmark 39 | $ wasmer target/wasm32-wasip1/release/deps/bench_main-9530540cc15e2e67.wasm -- --bench 40 | ``` 41 | 42 | With this you get the most accurate runtime behavior and can observe the 43 | difference to native code. However, you'll most likely find it negligible, with 44 | Wasm being just slightly slower and everything else scaling mostly linearly. A 45 | typical example: 46 | 47 | - `wasmer: visitor styledPage time: [6.6177 µs 6.6316 µs 6.6495 µs]` 48 | - `native: visitor styledPage time: [5.4191 µs 5.4736 µs 5.5150 µs]` 49 | 50 | For most changes that aren't Wasm-specific, it's therefore often good enough to 51 | just run the benchmarks normally with `cargo bench`. 52 | -------------------------------------------------------------------------------- /swc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swc-plugin-css-variable", 3 | "version": "0.1.0", 4 | "description": "", 5 | "author": "", 6 | "license": "MIT", 7 | "keywords": [ 8 | "swc-plugin" 9 | ], 10 | "main": "target/wasm32-wasip1/release/swc_plugin_css_variable.wasm", 11 | "scripts": { 12 | "prepublishOnly": "cargo build --release" 13 | }, 14 | "files": [] 15 | } 16 | -------------------------------------------------------------------------------- /swc/swc-plugin-css-variable/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "swc-plugin-css-variable" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [lib] 7 | # cdylib is for dynamic system library and necessary to produce the Wasm plugin 8 | crate-type = ["cdylib"] 9 | 10 | [dependencies] 11 | lazy_static = "1.4.0" 12 | pathdiff = "0.2.1" 13 | regex = "1.10.3" 14 | serde_json = "1.0.111" 15 | swc_core = { version = "16.0.0", features = ["ecma_plugin_transform"] } 16 | 17 | transform = { path = "../transform" } 18 | -------------------------------------------------------------------------------- /swc/swc-plugin-css-variable/src/lib.rs: -------------------------------------------------------------------------------- 1 | use pathdiff::diff_paths; 2 | use swc_core::{ 3 | ecma::{ast::*, visit::visit_mut_pass}, 4 | plugin::{ 5 | metadata::TransformPluginMetadataContextKind, plugin_transform, 6 | proxies::TransformPluginProgramMetadata, 7 | }, 8 | }; 9 | 10 | use transform::{hash, Config, TransformVisitor}; 11 | 12 | use regex::Regex; 13 | #[macro_use] 14 | extern crate lazy_static; 15 | 16 | /// Transforms a [`Program`]. 17 | #[plugin_transform] 18 | pub fn process_transform(program: Program, metadata: TransformPluginProgramMetadata) -> Program { 19 | let config: Config = serde_json::from_str( 20 | &metadata 21 | .get_transform_plugin_config() 22 | .expect("failed to get plugin config for swc-plugin-css-variable"), 23 | ) 24 | .expect("failed to parse plugin config"); 25 | 26 | let file_name = metadata 27 | .get_context(&TransformPluginMetadataContextKind::Filename) 28 | .expect("failed to get filename"); 29 | let deterministic_path = relative_posix_path(&config.base_path, &file_name); 30 | let hashed_filename = hash(&deterministic_path); 31 | 32 | program.apply(visit_mut_pass(&mut TransformVisitor::new( 33 | config, 34 | hashed_filename, 35 | ))) 36 | } 37 | 38 | /// Returns a relative POSIX path from the `base_path` to the filename. 39 | /// 40 | /// For example: 41 | /// - "/foo/", "/bar/baz.txt" -> "../bar/baz.txt" 42 | /// - "C:\foo\", "C:\foo\baz.txt" -> "../bar/baz.txt" 43 | /// 44 | /// The format of `base_path` and `filename` must match the current OS. 45 | fn relative_posix_path(base_path: &str, filename: &str) -> String { 46 | let normalized_base_path = convert_path_to_posix(base_path); 47 | let normalized_filename = convert_path_to_posix(filename); 48 | let relative_filename = diff_paths(normalized_filename, normalized_base_path) 49 | .expect("Could not create relative path"); 50 | let path_parts = relative_filename 51 | .components() 52 | .map(|component| component.as_os_str().to_str().unwrap()) 53 | .collect::>(); 54 | 55 | path_parts.join("/") 56 | } 57 | 58 | /// Returns the path converted to a POSIX path (naive approach). 59 | /// 60 | /// For example: 61 | /// - "C:\foo\bar" -> "c/foo/bar" 62 | /// - "/foo/bar" -> "/foo/bar" 63 | fn convert_path_to_posix(path: &str) -> String { 64 | lazy_static! { 65 | static ref PATH_REPLACEMENT_REGEX: Regex = Regex::new(r":\\|\\|:/").unwrap(); 66 | } 67 | 68 | PATH_REPLACEMENT_REGEX.replace_all(path, "/").to_string() 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | use super::*; 74 | 75 | #[test] 76 | fn test_relative_path_unix() { 77 | assert_eq!( 78 | relative_posix_path("/foo/", "/bar/baz.txt"), 79 | "../bar/baz.txt" 80 | ); 81 | } 82 | 83 | #[test] 84 | fn test_relative_path_windows() { 85 | assert_eq!( 86 | relative_posix_path(r"C:\foo\", r"C:\bar\baz.txt"), 87 | "../bar/baz.txt" 88 | ); 89 | } 90 | 91 | #[test] 92 | fn test_relative_path_windows_forward_slash() { 93 | assert_eq!( 94 | relative_posix_path(r"E:\foo", "E:/foo/bar/file.tsx"), 95 | "bar/file.tsx" 96 | ); 97 | } 98 | 99 | #[test] 100 | fn test_convert_unix_path() { 101 | assert_eq!(convert_path_to_posix(r"/foo/bar"), "/foo/bar"); 102 | } 103 | 104 | #[test] 105 | fn test_convert_windows_path() { 106 | assert_eq!(convert_path_to_posix(r"C:\foo\bar"), "C/foo/bar"); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /swc/transform/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "transform" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | base62 = "2.0.2" 8 | serde = { version = "1.0.195", features = ["derive"] } 9 | swc_core = "16.0.0" 10 | xxhash-rust = { version = "0.8.8", features = ["xxh32"] } 11 | 12 | [dev-dependencies] 13 | criterion = { version = "0.5.1", default-features = false } 14 | swc_core = { version = "16.0.0", features = ["ecma_parser", "ecma_plugin_transform"] } 15 | 16 | [[bench]] 17 | name = "bench_main" 18 | harness = false 19 | -------------------------------------------------------------------------------- /swc/transform/benches/bench_main.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; 2 | use swc_core::{ 3 | common::{sync::Lrc, FileName, SourceMap}, 4 | ecma::{parser, visit::VisitMutWith}, 5 | }; 6 | 7 | use transform::{Config, TransformVisitor}; 8 | 9 | pub fn styled_page(c: &mut Criterion) { 10 | let source_map: Lrc = Default::default(); 11 | let source_file = source_map.new_source_file( 12 | Lrc::new(FileName::Custom("styledPage.tsx".into())), 13 | include_str!("styledPage.tsx").into(), 14 | ); 15 | 16 | let program = parser::parse_file_as_program( 17 | &source_file, 18 | Default::default(), 19 | Default::default(), 20 | None, 21 | &mut vec![], 22 | ) 23 | .unwrap(); 24 | 25 | c.bench_function("visitor styledPage", |b| { 26 | b.iter_batched( 27 | || { 28 | ( 29 | program.clone(), 30 | TransformVisitor::new(Default::default(), String::from("hashed")), 31 | ) 32 | }, 33 | |(mut program, mut visitor)| program.visit_mut_with(&mut visitor), 34 | BatchSize::SmallInput, 35 | ) 36 | }); 37 | 38 | c.bench_function("visitor styledPage display_name", |b| { 39 | b.iter_batched( 40 | || { 41 | ( 42 | program.clone(), 43 | TransformVisitor::new( 44 | Config { 45 | display_name: true, 46 | ..Default::default() 47 | }, 48 | String::from("hashed"), 49 | ), 50 | ) 51 | }, 52 | |(mut program, mut visitor)| program.visit_mut_with(&mut visitor), 53 | BatchSize::SmallInput, 54 | ) 55 | }); 56 | } 57 | 58 | pub fn nested(c: &mut Criterion) { 59 | let source_map: Lrc = Default::default(); 60 | let source_file = source_map.new_source_file( 61 | Lrc::new(FileName::Custom("nested.js".into())), 62 | include_str!("nested.js").into(), 63 | ); 64 | 65 | let program = parser::parse_file_as_program( 66 | &source_file, 67 | Default::default(), 68 | Default::default(), 69 | None, 70 | &mut vec![], 71 | ) 72 | .unwrap(); 73 | 74 | c.bench_function("visitor nested", |b| { 75 | b.iter_batched( 76 | || { 77 | ( 78 | program.clone(), 79 | TransformVisitor::new(Default::default(), String::from("hashed")), 80 | ) 81 | }, 82 | |(mut program, mut visitor)| program.visit_mut_with(&mut visitor), 83 | BatchSize::SmallInput, 84 | ) 85 | }); 86 | 87 | c.bench_function("visitor nested display_name", |b| { 88 | b.iter_batched( 89 | || { 90 | ( 91 | program.clone(), 92 | TransformVisitor::new( 93 | Config { 94 | display_name: true, 95 | ..Default::default() 96 | }, 97 | String::from("hashed"), 98 | ), 99 | ) 100 | }, 101 | |(mut program, mut visitor)| program.visit_mut_with(&mut visitor), 102 | BatchSize::SmallInput, 103 | ) 104 | }); 105 | } 106 | 107 | pub fn short_hash(c: &mut Criterion) { 108 | c.bench_function("short filename hash", |b| { 109 | b.iter(|| transform::hash(black_box("fileName.ts"))) 110 | }); 111 | } 112 | 113 | pub fn longer_hash(c: &mut Criterion) { 114 | c.bench_function("longer filename hash", |b| { 115 | b.iter(|| { 116 | transform::hash( 117 | black_box("some/slightly/somewhat/much/very/much/longer/harder/better/faster/stronger/convoluted/fileName.ts") 118 | ) 119 | }) 120 | }); 121 | } 122 | 123 | criterion_group!(benches, styled_page, nested, short_hash, longer_hash); 124 | criterion_main!(benches); 125 | -------------------------------------------------------------------------------- /swc/transform/benches/nested.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | 3 | export const tokens = { 4 | one: { 5 | two: { 6 | three: { 7 | four: { 8 | five: { 9 | six: { 10 | seven: { 11 | eight: { 12 | nine: { 13 | ten: { 14 | eleven: { 15 | twelve: { 16 | thirteen: { 17 | fourteen: { 18 | fifteen: { 19 | sixteen: { 20 | seventeen: { 21 | eighteen: { 22 | nineteen: { 23 | twenty: createVar(), 24 | }, 25 | }, 26 | }, 27 | }, 28 | }, 29 | }, 30 | }, 31 | }, 32 | }, 33 | }, 34 | }, 35 | }, 36 | }, 37 | }, 38 | }, 39 | }, 40 | }, 41 | }, 42 | }, 43 | }; 44 | -------------------------------------------------------------------------------- /swc/transform/benches/styledPage.tsx: -------------------------------------------------------------------------------- 1 | /// @ts-check 2 | import { CSSPixelValue, createVar, createGlobalTheme } from "css-variable"; 3 | import { styled } from "linaria/react"; 4 | 5 | const theme = { 6 | fontSize: createVar(), 7 | spacings: { 8 | s: createVar(), 9 | m: createVar(), 10 | l: createVar(), 11 | }, 12 | colors: { 13 | primary: createVar(), 14 | secondary: createVar(), 15 | }, 16 | }; 17 | 18 | const ThemeA = styled.div` 19 | ${createGlobalTheme("", theme, { 20 | fontSize: "12px", 21 | spacings: { 22 | s: "10px", 23 | m: "20px", 24 | l: "30px", 25 | }, 26 | colors: { 27 | primary: "#6290C3", 28 | secondary: "#C2E7DA", 29 | }, 30 | })} 31 | `; 32 | 33 | const ThemeB = styled.div` 34 | ${createGlobalTheme("", theme, { 35 | fontSize: "24px", 36 | spacings: { 37 | s: "20px", 38 | m: "40px", 39 | l: "60px", 40 | }, 41 | colors: { 42 | primary: "#7C9EB2", 43 | secondary: "#52528C", 44 | }, 45 | })} 46 | `; 47 | 48 | const colorVar = createVar({ value: theme.colors.primary }); 49 | const xVar = createVar({ value: "0" }); 50 | 51 | const StyledHeadline = styled.h1` 52 | font-family: Arial, Helvetica, sans-serif; 53 | font-size: ${theme.fontSize.val}; 54 | color: ${colorVar.val}; 55 | transform: translateX(${xVar.val}); 56 | width: calc(100% - 1 * ${xVar.val}); 57 | `; 58 | -------------------------------------------------------------------------------- /swc/transform/src/hash.rs: -------------------------------------------------------------------------------- 1 | use xxhash_rust::xxh32::xxh32; 2 | 3 | /// Creates a CSS identifier using xxHash (https://cyan4973.github.io/xxHash/). 4 | /// Shortened to base62 (https://en.wikipedia.org/wiki/Base62) to avoid invalid characters. 5 | pub fn hash(data: &str) -> String { 6 | let hash = xxh32(data.as_bytes(), 0); 7 | base62::encode(hash) 8 | } 9 | 10 | #[cfg(test)] 11 | mod tests { 12 | use super::*; 13 | 14 | #[test] 15 | fn short() { 16 | assert_eq!(hash("hey"), "2Hy69D"); 17 | } 18 | 19 | #[test] 20 | fn longer() { 21 | assert_eq!(hash("hey how are you doing?"), "34D1Ek"); 22 | } 23 | 24 | #[test] 25 | fn longest() { 26 | assert_eq!( 27 | hash("hey how are you doing? I am doing fine, thanks for asking."), 28 | "1XQ5hm" 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /swc/transform/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::Deserialize; 2 | use std::{collections::HashSet, fmt::Write}; 3 | use swc_core::{ 4 | common::DUMMY_SP, 5 | ecma::{ 6 | ast::*, 7 | visit::{VisitMut, VisitMutWith}, 8 | }, 9 | }; 10 | 11 | mod hash; 12 | 13 | pub use hash::hash; 14 | 15 | /// Static plugin configuration. 16 | #[derive(Default, Deserialize)] 17 | #[serde(rename_all = "camelCase")] 18 | #[serde(deny_unknown_fields)] 19 | pub struct Config { 20 | /// Prefix variables with a readable name, e.g. `primary--2Hy69D0`. 21 | #[serde(default = "bool::default")] 22 | pub display_name: bool, 23 | /// The hash for a css-variable depends on the file name including createVar(). 24 | /// To ensure that the hash is consistent accross multiple systems the relative path 25 | /// from the base dir to the source file is used. 26 | #[serde()] 27 | pub base_path: String, 28 | } 29 | 30 | pub struct TransformVisitor { 31 | config: Config, 32 | filename_hash: String, 33 | local_idents: HashSet, 34 | variable_count: u32, 35 | current_var_declarator: Option, 36 | current_object_prop_declarators: Vec, 37 | } 38 | 39 | impl TransformVisitor { 40 | pub fn new(config: Config, filename_hash: String) -> Self { 41 | Self { 42 | config, 43 | filename_hash, 44 | local_idents: HashSet::new(), 45 | variable_count: 0, 46 | current_var_declarator: None, 47 | current_object_prop_declarators: vec![], 48 | } 49 | } 50 | } 51 | 52 | impl VisitMut for TransformVisitor { 53 | /// Searches all local names for `createVar`. 54 | /// 55 | /// For example: 56 | /// ```javascript 57 | /// import { createVar } from "css-variable"; 58 | /// import { createVar as x} from "css-variable"; 59 | /// import { foo as x, createVar as y } from "css-variable"; 60 | /// ``` 61 | fn visit_mut_import_decl(&mut self, import_decl: &mut ImportDecl) { 62 | if &import_decl.src.value != "css-variable" { 63 | return; 64 | } 65 | 66 | for specifier in &import_decl.specifiers { 67 | if let ImportSpecifier::Named(local) = specifier { 68 | let imported_ident = match &local.imported { 69 | Some(ModuleExportName::Ident(module_export)) => &module_export.sym, 70 | // import {createVar} from "css-variable"; 71 | _ => &local.local.sym, 72 | }; 73 | 74 | if imported_ident == "createVar" { 75 | self.local_idents.insert(String::from(&*local.local.sym)); 76 | } 77 | } 78 | } 79 | } 80 | 81 | fn visit_mut_var_declarator(&mut self, var_declarator: &mut VarDeclarator) { 82 | self.current_var_declarator = 83 | if let Pat::Ident(BindingIdent { id, .. }) = &var_declarator.name { 84 | Some(id.sym.to_string()) 85 | } else { 86 | None 87 | }; 88 | 89 | var_declarator.visit_mut_children_with(self); 90 | 91 | self.current_var_declarator = None; 92 | } 93 | 94 | fn visit_mut_key_value_prop(&mut self, key_value: &mut KeyValueProp) { 95 | if let PropName::Ident(id) = &key_value.key { 96 | self.current_object_prop_declarators 97 | .push(id.sym.to_string()); 98 | } 99 | 100 | key_value.visit_mut_children_with(self); 101 | 102 | self.current_object_prop_declarators.pop(); 103 | } 104 | 105 | fn visit_mut_call_expr(&mut self, call_expr: &mut CallExpr) { 106 | // Skip entire execution if no import call was found, see visit_mut_import_decl 107 | if self.local_idents.is_empty() { 108 | return; 109 | } 110 | 111 | call_expr.visit_mut_children_with(self); 112 | 113 | if let Callee::Expr(expr) = &call_expr.callee { 114 | if let Expr::Ident(id) = &**expr { 115 | if self.local_idents.contains(&*id.sym) { 116 | let mut variable_name = String::new(); 117 | 118 | if self.config.display_name { 119 | for object_prop_declarator in 120 | self.current_object_prop_declarators.iter().rev() 121 | { 122 | write!(&mut variable_name, "{object_prop_declarator}--").unwrap(); 123 | } 124 | 125 | if let Some(var_declarator) = &self.current_var_declarator { 126 | write!(&mut variable_name, "{var_declarator}--").unwrap(); 127 | } 128 | } 129 | 130 | write!( 131 | &mut variable_name, 132 | "{}{}", 133 | self.filename_hash, self.variable_count 134 | ) 135 | .unwrap(); 136 | self.variable_count += 1; 137 | 138 | call_expr.args.insert( 139 | 0, 140 | ExprOrSpread { 141 | spread: None, 142 | expr: Box::new(Expr::Lit(Lit::Str(Str { 143 | span: DUMMY_SP, 144 | value: variable_name.into(), 145 | raw: None, 146 | }))), 147 | }, 148 | ); 149 | } 150 | } 151 | } 152 | } 153 | } 154 | 155 | #[cfg(test)] 156 | mod tests { 157 | use swc_core::ecma::{ 158 | transforms::testing::test, 159 | visit::{visit_mut_pass, VisitMutPass}, 160 | }; 161 | 162 | use super::*; 163 | 164 | fn transform_visitor(config: Config) -> VisitMutPass { 165 | visit_mut_pass(TransformVisitor::new(config, String::from("hashed"))) 166 | } 167 | 168 | test!( 169 | Default::default(), 170 | |_| transform_visitor(Default::default()), 171 | adds_variable_name, 172 | r#"import {createVar} from "css-variable"; 173 | createVar();"# 174 | ); 175 | 176 | test!( 177 | Default::default(), 178 | |_| transform_visitor(Default::default()), 179 | adds_multiple_variable_names, 180 | r#"import {createVar} from "css-variable"; 181 | createVar(); 182 | createVar(); 183 | createVar();"# 184 | ); 185 | 186 | test!( 187 | Default::default(), 188 | |_| transform_visitor(Default::default()), 189 | ignores_unknwon_modules, 190 | r#"import {createVar} from "unknown"; 191 | createVar();"# 192 | ); 193 | 194 | test!( 195 | Default::default(), 196 | |_| transform_visitor(Default::default()), 197 | adds_variable_name_with_value, 198 | r#"import {createVar} from "css-variable"; 199 | createVar({ value: '0px' });"# 200 | ); 201 | 202 | test!( 203 | Default::default(), 204 | |_| transform_visitor(Default::default()), 205 | adds_variable_name_for_renamed, 206 | r#"import {createVar as create} from "css-variable"; 207 | create("hello world");"# 208 | ); 209 | 210 | test!( 211 | Default::default(), 212 | |_| transform_visitor(Config { 213 | display_name: true, 214 | base_path: "/".to_owned() 215 | }), 216 | adds_camel_case_variable_name_with_display_name, 217 | r#"import {createVar} from "css-variable"; 218 | const camelCase = createVar();"# 219 | ); 220 | 221 | test!( 222 | Default::default(), 223 | |_| transform_visitor(Config { 224 | display_name: true, 225 | base_path: "/".to_owned() 226 | }), 227 | adds_variable_name_with_display_name, 228 | r#"import {createVar} from "css-variable"; 229 | const primary = createVar(); 230 | const theme = { 231 | colors: { 232 | primary: createVar(), 233 | secondary: { 234 | inner: createVar() 235 | } 236 | } 237 | };"# 238 | ); 239 | } 240 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_camel_case_variable_name_with_display_name.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | const camelCase = createVar("camelCase--hashed0"); 3 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_multiple_variable_names.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | createVar("hashed0"); 3 | createVar("hashed1"); 4 | createVar("hashed2"); 5 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_variable_name.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | createVar("hashed0"); 3 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_variable_name_for_renamed.js: -------------------------------------------------------------------------------- 1 | import { createVar as create } from "css-variable"; 2 | create("hashed0", "hello world"); 3 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_variable_name_with_display_name.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | const primary = createVar("primary--hashed0"); 3 | const theme = { 4 | colors: { 5 | primary: createVar("primary--colors--theme--hashed1"), 6 | secondary: { 7 | inner: createVar("inner--secondary--colors--theme--hashed2"), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/adds_variable_name_with_value.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | createVar("hashed0", { 3 | value: '0px' 4 | }); 5 | -------------------------------------------------------------------------------- /swc/transform/tests/__swc_snapshots__/src/lib.rs/ignores_unknwon_modules.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "unknown"; 2 | createVar(); 3 | -------------------------------------------------------------------------------- /test/__snapshots__/babel.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`development transform CSSVariable 1`] = ` 4 | "import { CSSVariable } from "css-variable"; 5 | const primary = /*@__PURE__*/new CSSVariable("primary--mobtag0"); 6 | const secondary = /*@__PURE__*/new CSSVariable("secondary--mobtag1", { 7 | value: '#fff' 8 | }); 9 | const theme = { 10 | colors: { 11 | primary: /*@__PURE__*/new CSSVariable("primary--mobtag2") 12 | } 13 | }; 14 | const generated = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag3", color)); 15 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag4", color, { 16 | value: '#000' 17 | }));" 18 | `; 19 | 20 | exports[`development transform createVar 1`] = ` 21 | "import { createVar } from "css-variable"; 22 | const primary = /*@__PURE__*/createVar("primary--1c6m1ot0"); 23 | const secondary = /*@__PURE__*/createVar("secondary--1c6m1ot1", { 24 | value: '#fff' 25 | }); 26 | const theme = { 27 | colors: { 28 | primary: /*@__PURE__*/createVar("primary--1c6m1ot2") 29 | } 30 | }; 31 | const generated = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot3", color)); 32 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot4", color, { 33 | value: '#000' 34 | }));" 35 | `; 36 | 37 | exports[`development transform renamed 1`] = ` 38 | "import { CSSVariable as CSSVar, createVar as createVariable } from "css-variable"; 39 | const primary = /*@__PURE__*/new CSSVar("primary--1ynmbls0"); 40 | const secondary = /*@__PURE__*/createVariable("secondary--1ynmbls1");" 41 | `; 42 | 43 | exports[`production transform CSSVariable 1`] = ` 44 | "import { CSSVariable } from "css-variable"; 45 | const primary = /*@__PURE__*/new CSSVariable("mobtag0"); 46 | const secondary = /*@__PURE__*/new CSSVariable("mobtag1", { 47 | value: '#fff' 48 | }); 49 | const theme = { 50 | colors: { 51 | primary: /*@__PURE__*/new CSSVariable("mobtag2") 52 | } 53 | }; 54 | const generated = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag3", color)); 55 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag4", color, { 56 | value: '#000' 57 | }));" 58 | `; 59 | 60 | exports[`production transform createVar 1`] = ` 61 | "import { createVar } from "css-variable"; 62 | const primary = /*@__PURE__*/createVar("1c6m1ot0"); 63 | const secondary = /*@__PURE__*/createVar("1c6m1ot1", { 64 | value: '#fff' 65 | }); 66 | const theme = { 67 | colors: { 68 | primary: /*@__PURE__*/createVar("1c6m1ot2") 69 | } 70 | }; 71 | const generated = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot3", color)); 72 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot4", color, { 73 | value: '#000' 74 | }));" 75 | `; 76 | 77 | exports[`production transform renamed 1`] = ` 78 | "import { CSSVariable as CSSVar, createVar as createVariable } from "css-variable"; 79 | const primary = /*@__PURE__*/new CSSVar("1ynmbls0"); 80 | const secondary = /*@__PURE__*/createVariable("1ynmbls1");" 81 | `; 82 | 83 | exports[`production transform with displayName CSSVariable 1`] = ` 84 | "import { CSSVariable } from "css-variable"; 85 | const primary = /*@__PURE__*/new CSSVariable("primary--mobtag0"); 86 | const secondary = /*@__PURE__*/new CSSVariable("secondary--mobtag1", { 87 | value: '#fff' 88 | }); 89 | const theme = { 90 | colors: { 91 | primary: /*@__PURE__*/new CSSVariable("primary--mobtag2") 92 | } 93 | }; 94 | const generated = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag3", color)); 95 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/new CSSVariable("mobtag4", color, { 96 | value: '#000' 97 | }));" 98 | `; 99 | 100 | exports[`production transform with displayName createVar 1`] = ` 101 | "import { createVar } from "css-variable"; 102 | const primary = /*@__PURE__*/createVar("primary--1c6m1ot0"); 103 | const secondary = /*@__PURE__*/createVar("secondary--1c6m1ot1", { 104 | value: '#fff' 105 | }); 106 | const theme = { 107 | colors: { 108 | primary: /*@__PURE__*/createVar("primary--1c6m1ot2") 109 | } 110 | }; 111 | const generated = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot3", color)); 112 | const generatedWithFallback = allColors.map(color => /*@__PURE__*/createVar("1c6m1ot4", color, { 113 | value: '#000' 114 | }));" 115 | `; 116 | 117 | exports[`production transform with displayName renamed 1`] = ` 118 | "import { CSSVariable as CSSVar, createVar as createVariable } from "css-variable"; 119 | const primary = /*@__PURE__*/new CSSVar("primary--1ynmbls0"); 120 | const secondary = /*@__PURE__*/createVariable("secondary--1ynmbls1");" 121 | `; 122 | -------------------------------------------------------------------------------- /test/babel.test.js: -------------------------------------------------------------------------------- 1 | const transformFileSync = require("@babel/core").transformFileSync; 2 | const path = require("path"); 3 | const plugin = require("../babel"); 4 | 5 | describe("production transform", () => { 6 | it("CSSVariable", () => { 7 | const { code } = transformFileSync( 8 | path.join(__dirname, "fixtures/CSSVariable.js"), 9 | { 10 | plugins: [[plugin]], 11 | babelrc: false, 12 | } 13 | ); 14 | expect(code).toMatchSnapshot(); 15 | }); 16 | it("createVar", () => { 17 | const { code } = transformFileSync( 18 | path.join(__dirname, "fixtures/createVar.js"), 19 | { 20 | plugins: [[plugin]], 21 | babelrc: false, 22 | } 23 | ); 24 | expect(code).toMatchSnapshot(); 25 | }); 26 | it("renamed", () => { 27 | const { code } = transformFileSync( 28 | path.join(__dirname, "fixtures/renamed.js"), 29 | { 30 | plugins: [[plugin]], 31 | babelrc: false, 32 | } 33 | ); 34 | expect(code).toMatchSnapshot(); 35 | }); 36 | }); 37 | 38 | describe("development transform", () => { 39 | it("CSSVariable", () => { 40 | const { code } = transformFileSync( 41 | path.join(__dirname, "fixtures/CSSVariable.js"), 42 | { 43 | plugins: [[plugin]], 44 | babelrc: false, 45 | envName: "development" 46 | } 47 | ); 48 | expect(code).toMatchSnapshot(); 49 | }); 50 | it("createVar", () => { 51 | const { code } = transformFileSync( 52 | path.join(__dirname, "fixtures/createVar.js"), 53 | { 54 | plugins: [[plugin]], 55 | babelrc: false, 56 | envName: "development" 57 | } 58 | ); 59 | expect(code).toMatchSnapshot(); 60 | }); 61 | it("renamed", () => { 62 | const { code } = transformFileSync( 63 | path.join(__dirname, "fixtures/renamed.js"), 64 | { 65 | plugins: [[plugin]], 66 | babelrc: false, 67 | envName: "development" 68 | } 69 | ); 70 | expect(code).toMatchSnapshot(); 71 | }); 72 | }); 73 | 74 | describe("production transform with displayName", () => { 75 | it("CSSVariable", () => { 76 | const { code } = transformFileSync( 77 | path.join(__dirname, "fixtures/CSSVariable.js"), 78 | { 79 | plugins: [[plugin, { displayName: true }]], 80 | babelrc: false, 81 | } 82 | ); 83 | expect(code).toMatchSnapshot(); 84 | }); 85 | it("createVar", () => { 86 | const { code } = transformFileSync( 87 | path.join(__dirname, "fixtures/createVar.js"), 88 | { 89 | plugins: [[plugin, { displayName: true }]], 90 | babelrc: false, 91 | } 92 | ); 93 | expect(code).toMatchSnapshot(); 94 | }); 95 | it("renamed", () => { 96 | const { code } = transformFileSync( 97 | path.join(__dirname, "fixtures/renamed.js"), 98 | { 99 | plugins: [[plugin, { displayName: true }]], 100 | babelrc: false, 101 | } 102 | ); 103 | expect(code).toMatchSnapshot(); 104 | }); 105 | }); -------------------------------------------------------------------------------- /test/examples.js: -------------------------------------------------------------------------------- 1 | /// @ts-check 2 | const path = require("path"); 3 | const child_process = require("child_process"); 4 | const assert = require("assert"); 5 | let port = 47841; 6 | let runningChildren = new Set(); 7 | 8 | runTest().then( 9 | () => { 10 | console.log("\n\n✅ Next integration tests passed"); 11 | process.exit(0); 12 | }, 13 | (e) => { 14 | console.error("🤷‍♂️ Test failed because of ", e); 15 | process.exit(1); 16 | } 17 | ); 18 | 19 | async function runTest() { 20 | console.log("📦 install puppeteer"); 21 | await spawnAsync("npm", ["install"], { cwd: __dirname, stdio: "inherit" }).promise; 22 | console.log("🚀 test next <-> styled-component integration"); 23 | await launchExample(path.resolve(__dirname, "../examples/styled-components")); 24 | } 25 | 26 | /** @param {string} url */ 27 | async function testExample(url) { 28 | 29 | console.log("💻 start browser and open nextjs app"); 30 | const puppeteer = require('puppeteer'); 31 | const browser = await puppeteer.launch(); 32 | const page = await browser.newPage(); 33 | await page.goto(url, { 34 | waitUntil: 'networkidle2', 35 | }); 36 | const {fontSize,color} = await page.evaluate(() => { 37 | const styles = window.getComputedStyle(document.querySelector("h1")); 38 | return { 39 | fontSize: styles.fontSize, 40 | color: styles.color, 41 | }; 42 | }); 43 | 44 | assert(fontSize, '12px'); 45 | assert(color, 'rgb(255, 165, 0)'); 46 | 47 | console.log("✅ fontSize and color match"); 48 | 49 | await browser.close(); 50 | } 51 | 52 | /** @param {string} cwd */ 53 | async function launchExample(cwd) { 54 | const testPort = port++ 55 | console.log(`🧹 remove ${path.join(cwd, 'node_modules')}`); 56 | await removeDir(path.join(cwd, '.next')); 57 | await removeDir(path.join(cwd, 'node_modules')); 58 | await removeDir(path.join(cwd, '.linaria-cache')); 59 | console.log("📦 install example dependencies"); 60 | await spawnAsync("npm", ["install"], { cwd, stdio: "inherit" }).promise; 61 | console.log("🚀 build & launch nextjs"); 62 | await spawnAsync("npm", ["run", "build"], { cwd, stdio: "inherit" }).promise; 63 | const {child: server, promise: serverClosed} = spawnAsync("npm", ["start", "--", "-p", String(testPort)], { cwd, stdio: "inherit" }); 64 | await new Promise((resolve) => setTimeout(resolve, 500)); 65 | await Promise.race([ 66 | testExample(`http://localhost:${testPort}`), 67 | serverClosed 68 | ]); 69 | server.kill(); 70 | } 71 | 72 | function removeDir(directory) { 73 | return new Promise((resolve) => { 74 | require("rimraf")(directory, () => { 75 | resolve(true); 76 | }); 77 | }); 78 | } 79 | 80 | function spawnAsync(command, args, options) { 81 | const child = child_process.spawn(command, args, options); 82 | runningChildren.add(child); 83 | return {child, promise: new Promise((resolve, reject) => { 84 | child.on("close", (code) => { 85 | runningChildren.delete(child); 86 | if (code) { 87 | reject(new Error(`${command} failed - exit code: ${code}`)); 88 | } else { 89 | resolve(); 90 | } 91 | }); 92 | })}; 93 | } 94 | 95 | process.stdin.resume(); 96 | function exitHandler(exitCode) { 97 | Array.from(runningChildren).forEach((child) => { 98 | child.kill(); 99 | }); 100 | process.exit(exitCode || 0); 101 | } 102 | process.on('exit', exitHandler.bind(null)); 103 | process.on('SIGINT', exitHandler.bind(null)); 104 | process.on('SIGUSR1', exitHandler.bind(null)); 105 | process.on('SIGUSR2', exitHandler.bind(null)); 106 | process.on('uncaughtException', exitHandler.bind(null)); -------------------------------------------------------------------------------- /test/fixtures/CSSVariable.js: -------------------------------------------------------------------------------- 1 | import { CSSVariable } from "css-variable"; 2 | 3 | const primary = new CSSVariable(); 4 | const secondary = new CSSVariable({ value: '#fff' }); 5 | 6 | const theme = { 7 | colors: { 8 | primary: new CSSVariable() 9 | } 10 | }; 11 | 12 | const generated = allColors.map((color) => new CSSVariable(color)); 13 | 14 | const generatedWithFallback = allColors.map((color) => new CSSVariable(color, { value: '#000' })); 15 | -------------------------------------------------------------------------------- /test/fixtures/createVar.js: -------------------------------------------------------------------------------- 1 | import { createVar } from "css-variable"; 2 | 3 | const primary = createVar(); 4 | const secondary = createVar({ value: '#fff' }); 5 | 6 | const theme = { 7 | colors: { 8 | primary: createVar() 9 | } 10 | }; 11 | 12 | const generated = allColors.map((color) => createVar(color)); 13 | 14 | const generatedWithFallback = allColors.map((color) => createVar(color, { value: '#000' })); 15 | -------------------------------------------------------------------------------- /test/fixtures/renamed.js: -------------------------------------------------------------------------------- 1 | import { CSSVariable as CSSVar, createVar as createVariable } from "css-variable"; 2 | 3 | const primary = new CSSVar(); 4 | const secondary = createVariable(); -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "test": "node ./examples.js" 7 | }, 8 | "dependencies": { 9 | "puppeteer": "^10.2.0", 10 | "rimraf": "3.0.2" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/swc/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rootDir: __dirname, 3 | moduleNameMapper: { 4 | "css-variable$": "../../", 5 | }, 6 | transform: { 7 | "^.+\\.(t|j)sx?$": [ 8 | "@swc/jest", 9 | { 10 | jsc: { 11 | experimental: { 12 | plugins: [ 13 | [ 14 | require.resolve( 15 | "../../swc/target/wasm32-wasip1/release/swc_plugin_css_variable.wasm" 16 | ), 17 | { 18 | basePath: __dirname, 19 | displayName: true, 20 | }, 21 | ], 22 | ], 23 | }, 24 | }, 25 | }, 26 | ], 27 | }, 28 | }; 29 | -------------------------------------------------------------------------------- /test/swc/swc.test.js: -------------------------------------------------------------------------------- 1 | import {createVar} from "css-variable"; 2 | 3 | describe("createVar", () => { 4 | it("generates a variable name with swc plugin", () => { 5 | const foo = createVar(); 6 | const bar = createVar(); 7 | const baz = createVar(); 8 | expect(foo.name).toMatchInlineSnapshot(`"--foo--2hzhhy0"`); 9 | expect(bar.name).toMatchInlineSnapshot( `"--bar--2hzhhy1"`); 10 | expect(baz.name).toMatchInlineSnapshot( `"--baz--2hzhhy2"`); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /test/without-babel.test.js: -------------------------------------------------------------------------------- 1 | const {createVar} = require("../"); 2 | 3 | describe("createVar", () => { 4 | it("generates a variable name automatically", () => { 5 | const foo = createVar(); 6 | const bar = createVar(); 7 | const baz = createVar(); 8 | expect(foo.name).toMatch("--17179149"); 9 | expect(bar.name).toMatch("--1717914a"); 10 | expect(baz.name).toMatch("--1717914b"); 11 | }); 12 | 13 | it("allows to define a fallback variable", () => { 14 | const foo = createVar({value: "red"}); 15 | expect(foo.val).toMatch("var(--1717914c, red)"); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Projects */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ 8 | // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ 9 | // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ 10 | // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ 11 | // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ 12 | 13 | /* Language and Environment */ 14 | "target": "ESNext", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ 15 | // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ 16 | // "jsx": "preserve", /* Specify what JSX code is generated. */ 17 | // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ 18 | // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 19 | // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ 20 | // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ 21 | // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ 22 | // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ 23 | // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ 24 | // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ 25 | 26 | /* Modules */ 27 | "module": "commonjs", /* Specify what module code is generated. */ 28 | // "rootDir": "./", /* Specify the root folder within your source files. */ 29 | // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ 30 | // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ 31 | // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ 32 | // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ 33 | // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ 34 | // "types": [], /* Specify type package names to be included without being referenced in a source file. */ 35 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 36 | // "resolveJsonModule": true, /* Enable importing .json files */ 37 | // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ 38 | 39 | /* JavaScript Support */ 40 | // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ 41 | // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ 42 | // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ 43 | 44 | /* Emit */ 45 | // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ 46 | // "declarationMap": true, /* Create sourcemaps for d.ts files. */ 47 | // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ 48 | // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ 49 | // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ 50 | // "outDir": "./", /* Specify an output folder for all emitted files. */ 51 | // "removeComments": true, /* Disable emitting comments. */ 52 | // "noEmit": true, /* Disable emitting files from a compilation. */ 53 | // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ 54 | // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ 55 | // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ 56 | // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ 59 | // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ 60 | // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ 61 | // "newLine": "crlf", /* Set the newline character for emitting files. */ 62 | // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ 63 | // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ 64 | // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ 65 | // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ 66 | // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ 67 | 68 | /* Interop Constraints */ 69 | // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ 70 | // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ 71 | "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ 72 | // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ 73 | "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ 74 | 75 | /* Type Checking */ 76 | "strict": true, /* Enable all strict type-checking options. */ 77 | // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ 78 | // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ 79 | // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ 80 | // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ 81 | // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ 82 | // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ 83 | // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ 84 | // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ 85 | // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ 86 | // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ 87 | // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ 88 | // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ 89 | // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ 90 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 91 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ 92 | // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ 93 | // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ 94 | // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ 95 | 96 | /* Completeness */ 97 | // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ 98 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 99 | }, 100 | } --------------------------------------------------------------------------------