From 9a2d21d309df1f7ec39df06f94c471e8dde668e4 Mon Sep 17 00:00:00 2001 From: Stuart Robinson Date: Tue, 11 Nov 2025 19:05:10 +0700 Subject: [PATCH 1/5] fix: migrate to @eslint/css-tree to support CSS variables (var()) - Replace css-tree with @eslint/css-tree v3.6.6 - Add var() detection to skip validation for CSS custom properties - Update all imports across 8 files - Fix TypeScript types for walk() callbacks - Remove @types/css-tree dependency Resolves issue where properties containing var() would report validation errors even though expansion was successful. CSS variables are runtime values that cannot be validated at parse time. --- docs.llm/llm_src.txt | 61 +++++++++++++------- package.json | 5 +- pnpm-lock.yaml | 38 +++++------- src/core/validate.ts | 23 +++++++- src/handlers/animation/animation-layers.ts | 6 +- src/handlers/background/background-layers.ts | 6 +- src/handlers/grid/expand.ts | 6 +- src/handlers/mask/mask-layers.ts | 6 +- src/handlers/transition/transition-layers.ts | 6 +- src/internal/is-value-node.ts | 2 +- src/internal/layer-parser-utils.ts | 6 +- 11 files changed, 99 insertions(+), 66 deletions(-) diff --git a/docs.llm/llm_src.txt b/docs.llm/llm_src.txt index 4b60c42..d170def 100644 --- a/docs.llm/llm_src.txt +++ b/docs.llm/llm_src.txt @@ -924,7 +924,7 @@ export interface CollapseResult { * @since 1.0.0 */ -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { BStyleWarning, StylesheetValidation } from "./schema"; // Constants @@ -963,6 +963,21 @@ interface FormattedLine { adjustedColumn: number; } +/** + * Checks if a CSS value node contains var() function. + * CSS variables cannot be validated by css-tree as they are runtime values. + */ +function containsVar(node: csstree.CssNode): boolean { + if (!node) return false; + if (node.type === "Function" && node.name === "var") return true; + if ("children" in node && node.children) { + for (const child of node.children) { + if (containsVar(child)) return true; + } + } + return false; +} + /** * Validates a CSS stylesheet for syntax and property value errors. * @@ -1032,6 +1047,12 @@ export function validate(css: string): StylesheetValidation { } for (const decl of declarations) { + // Skip validation for declarations containing CSS variables (var()) + // as they cannot be validated at parse time + if (containsVar(decl.value)) { + continue; + } + const match = syntax.matchProperty(decl.property, decl.value); const error = match.error as csstree.SyntaxMatchError; @@ -1311,7 +1332,7 @@ function formatErrorDisplay( === File: src/handlers/animation/animation-layers.ts === // b_path:: src/handlers/animation/animation-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { AnimationLayer, AnimationResult } from "@/core/schema"; import isTime from "@/internal/is-time"; import isTimingFunction from "@/internal/is-timing-function"; @@ -1357,8 +1378,8 @@ function parseSingleLayer(layerValue: string): AnimationLayer | undefined { const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); @@ -2148,7 +2169,7 @@ export { default } from "./expand"; === File: src/handlers/background/background-layers.ts === // b_path:: src/handlers/background/background-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { BackgroundLayer, BackgroundResult } from "@/core/schema"; import isColor from "@/internal/is-color"; import { isPositionValueNode, isSizeValueNode } from "@/internal/is-value-node"; @@ -2252,8 +2273,8 @@ function parseSingleLayerWithCssTree(layerValue: string): BackgroundLayer & { co const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); @@ -5645,7 +5666,7 @@ export const gridCollapser: CollapseHandler = createCollapseHandler({ // named grid lines, track sizes, repeat() notation, area names, and multiple syntaxes // (template form, explicit-rows, explicit-columns). The parsing logic is preserved as-is. -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import { matchesType } from "@/internal/is-value-node"; import { createPropertyHandler, type PropertyHandler } from "@/internal/property-handler"; @@ -5674,8 +5695,8 @@ function parseValueAndGetSegments( csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { let index = 0; node.children.forEach((child) => { if (child.type === "Operator" && (child as csstree.Operator).value === "/") { @@ -6715,7 +6736,7 @@ export { default } from "./expand"; === File: src/handlers/mask/mask-layers.ts === // b_path:: src/handlers/mask/mask-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { MaskLayer, MaskResult } from "@/core/schema"; import { isPositionValueNode, isSizeValueNode } from "@/internal/is-value-node"; import { hasTopLevelCommas, parseLayersGeneric } from "@/internal/layer-parser-utils"; @@ -6766,8 +6787,8 @@ function parseSingleLayerWithCssTree(layerValue: string): MaskLayer | undefined const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); @@ -8944,7 +8965,7 @@ export { default } from "./expand"; === File: src/handlers/transition/transition-layers.ts === // b_path:: src/handlers/transition/transition-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { TransitionLayer, TransitionResult } from "@/core/schema"; import isTime from "@/internal/is-time"; import isTimingFunction from "@/internal/is-timing-function"; @@ -8986,8 +9007,8 @@ function parseSingleLayer(layerValue: string): TransitionLayer | undefined { const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); @@ -10402,7 +10423,7 @@ export default function isTimingFunction(value: string): boolean { === File: src/internal/is-value-node.ts === // b_path:: src/internal/is-value-node.ts -import type * as csstree from "css-tree"; +import type * as csstree from "@eslint/css-tree"; /** * CSS functions that represent colors, not numeric values. @@ -10532,7 +10553,7 @@ export function isSizeValueNode(node: csstree.CssNode, keywords?: string[]): boo === File: src/internal/layer-parser-utils.ts === // b_path:: src/internal/layer-parser-utils.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; /** * Shared utilities for parsing multi-layer CSS properties (background, mask, animation, transition). @@ -10688,8 +10709,8 @@ export function collectCssTreeChildren(ast: csstree.CssNode): csstree.CssNode[] // Walk the AST and collect children from Value nodes csstree.walk(ast, { visit: "Value", - enter: (node: { children?: Iterable }) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { for (const child of node.children) { children.push(child); } diff --git a/package.json b/package.json index 90271ec..32ebd96 100644 --- a/package.json +++ b/package.json @@ -115,13 +115,12 @@ "access": "public", "registry": "https://registry.npmjs.org/" }, - "peerDependencies": { - "css-tree": "^3.1.0" + "dependencies": { + "@eslint/css-tree": "^3.6.6" }, "devDependencies": { "@biomejs/biome": "2.3.4", "@size-limit/preset-small-lib": "^11.2.0", - "@types/css-tree": "^2.3.11", "@types/node": "^24.10.0", "@vitest/coverage-v8": "^4.0.8", "husky": "^9.1.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66b0a6c..3b2c283 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,9 +8,9 @@ importers: .: dependencies: - css-tree: - specifier: ^3.1.0 - version: 3.1.0 + '@eslint/css-tree': + specifier: ^3.6.6 + version: 3.6.6 devDependencies: '@biomejs/biome': specifier: 2.3.4 @@ -18,9 +18,6 @@ importers: '@size-limit/preset-small-lib': specifier: ^11.2.0 version: 11.2.0(size-limit@11.2.0) - '@types/css-tree': - specifier: ^2.3.11 - version: 2.3.11 '@types/node': specifier: ^24.10.0 version: 24.10.0 @@ -281,6 +278,10 @@ packages: cpu: [x64] os: [win32] + '@eslint/css-tree@3.6.6': + resolution: {integrity: sha512-C3YiJMY9OZyZ/3vEMFWJIesdGaRY6DmIYvmtyxMT934CbrOKqRs+Iw7NWSRlJQEaK4dPYy2lZ2y1zkaj8z0p5A==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -435,9 +436,6 @@ packages: '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/css-tree@2.3.11': - resolution: {integrity: sha512-aEokibJOI77uIlqoBOkVbaQGC9zII0A+JH1kcTNKW2CwyYWD8KM6qdo+4c77wD3wZOQfJuNWAr9M4hdk+YhDIg==} - '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -566,10 +564,6 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -707,8 +701,8 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdn-data@2.23.0: + resolution: {integrity: sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==} minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} @@ -1182,6 +1176,11 @@ snapshots: '@esbuild/win32-x64@0.25.12': optional: true + '@eslint/css-tree@3.6.6': + dependencies: + mdn-data: 2.23.0 + source-map-js: 1.2.1 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -1297,8 +1296,6 @@ snapshots: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - '@types/css-tree@2.3.11': {} - '@types/deep-eql@4.0.2': {} '@types/estree@1.0.8': {} @@ -1424,11 +1421,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-tree@3.1.0: - dependencies: - mdn-data: 2.12.2 - source-map-js: 1.2.1 - debug@4.4.3: dependencies: ms: 2.1.3 @@ -1574,7 +1566,7 @@ snapshots: dependencies: semver: 7.7.3 - mdn-data@2.12.2: {} + mdn-data@2.23.0: {} minimatch@9.0.5: dependencies: diff --git a/src/core/validate.ts b/src/core/validate.ts index 0292532..336a850 100644 --- a/src/core/validate.ts +++ b/src/core/validate.ts @@ -25,7 +25,7 @@ * @since 1.0.0 */ -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { BStyleWarning, StylesheetValidation } from "./schema"; // Constants @@ -64,6 +64,21 @@ interface FormattedLine { adjustedColumn: number; } +/** + * Checks if a CSS value node contains var() function. + * CSS variables cannot be validated by css-tree as they are runtime values. + */ +function containsVar(node: csstree.CssNode): boolean { + if (!node) return false; + if (node.type === "Function" && node.name === "var") return true; + if ("children" in node && node.children) { + for (const child of node.children) { + if (containsVar(child)) return true; + } + } + return false; +} + /** * Validates a CSS stylesheet for syntax and property value errors. * @@ -133,6 +148,12 @@ export function validate(css: string): StylesheetValidation { } for (const decl of declarations) { + // Skip validation for declarations containing CSS variables (var()) + // as they cannot be validated at parse time + if (containsVar(decl.value)) { + continue; + } + const match = syntax.matchProperty(decl.property, decl.value); const error = match.error as csstree.SyntaxMatchError; diff --git a/src/handlers/animation/animation-layers.ts b/src/handlers/animation/animation-layers.ts index e2e825c..3b76aba 100644 --- a/src/handlers/animation/animation-layers.ts +++ b/src/handlers/animation/animation-layers.ts @@ -1,6 +1,6 @@ // b_path:: src/handlers/animation/animation-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { AnimationLayer, AnimationResult } from "@/core/schema"; import isTime from "@/internal/is-time"; import isTimingFunction from "@/internal/is-timing-function"; @@ -46,8 +46,8 @@ function parseSingleLayer(layerValue: string): AnimationLayer | undefined { const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); diff --git a/src/handlers/background/background-layers.ts b/src/handlers/background/background-layers.ts index e564adc..185b368 100644 --- a/src/handlers/background/background-layers.ts +++ b/src/handlers/background/background-layers.ts @@ -1,6 +1,6 @@ // b_path:: src/handlers/background/background-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { BackgroundLayer, BackgroundResult } from "@/core/schema"; import isColor from "@/internal/is-color"; import { isPositionValueNode, isSizeValueNode } from "@/internal/is-value-node"; @@ -104,8 +104,8 @@ function parseSingleLayerWithCssTree(layerValue: string): BackgroundLayer & { co const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); diff --git a/src/handlers/grid/expand.ts b/src/handlers/grid/expand.ts index 7481a3e..59b1877 100644 --- a/src/handlers/grid/expand.ts +++ b/src/handlers/grid/expand.ts @@ -5,7 +5,7 @@ // named grid lines, track sizes, repeat() notation, area names, and multiple syntaxes // (template form, explicit-rows, explicit-columns). The parsing logic is preserved as-is. -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import { matchesType } from "@/internal/is-value-node"; import { createPropertyHandler, type PropertyHandler } from "@/internal/property-handler"; @@ -34,8 +34,8 @@ function parseValueAndGetSegments( csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { let index = 0; node.children.forEach((child) => { if (child.type === "Operator" && (child as csstree.Operator).value === "/") { diff --git a/src/handlers/mask/mask-layers.ts b/src/handlers/mask/mask-layers.ts index 4f7c690..c280e65 100644 --- a/src/handlers/mask/mask-layers.ts +++ b/src/handlers/mask/mask-layers.ts @@ -1,6 +1,6 @@ // b_path:: src/handlers/mask/mask-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { MaskLayer, MaskResult } from "@/core/schema"; import { isPositionValueNode, isSizeValueNode } from "@/internal/is-value-node"; import { hasTopLevelCommas, parseLayersGeneric } from "@/internal/layer-parser-utils"; @@ -51,8 +51,8 @@ function parseSingleLayerWithCssTree(layerValue: string): MaskLayer | undefined const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); diff --git a/src/handlers/transition/transition-layers.ts b/src/handlers/transition/transition-layers.ts index d5c8efb..d012374 100644 --- a/src/handlers/transition/transition-layers.ts +++ b/src/handlers/transition/transition-layers.ts @@ -1,6 +1,6 @@ // b_path:: src/handlers/transition/transition-layers.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; import type { TransitionLayer, TransitionResult } from "@/core/schema"; import isTime from "@/internal/is-time"; import isTimingFunction from "@/internal/is-timing-function"; @@ -42,8 +42,8 @@ function parseSingleLayer(layerValue: string): TransitionLayer | undefined { const children: csstree.CssNode[] = []; csstree.walk(ast, { visit: "Value", - enter: (node: csstree.Value) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { node.children.forEach((child) => { children.push(child); }); diff --git a/src/internal/is-value-node.ts b/src/internal/is-value-node.ts index 3ebec8e..48f807f 100644 --- a/src/internal/is-value-node.ts +++ b/src/internal/is-value-node.ts @@ -1,5 +1,5 @@ // b_path:: src/internal/is-value-node.ts -import type * as csstree from "css-tree"; +import type * as csstree from "@eslint/css-tree"; /** * CSS functions that represent colors, not numeric values. diff --git a/src/internal/layer-parser-utils.ts b/src/internal/layer-parser-utils.ts index 035620c..1fb34c3 100644 --- a/src/internal/layer-parser-utils.ts +++ b/src/internal/layer-parser-utils.ts @@ -1,5 +1,5 @@ // b_path:: src/internal/layer-parser-utils.ts -import * as csstree from "css-tree"; +import * as csstree from "@eslint/css-tree"; /** * Shared utilities for parsing multi-layer CSS properties (background, mask, animation, transition). @@ -155,8 +155,8 @@ export function collectCssTreeChildren(ast: csstree.CssNode): csstree.CssNode[] // Walk the AST and collect children from Value nodes csstree.walk(ast, { visit: "Value", - enter: (node: { children?: Iterable }) => { - if (node.children) { + enter: (node: csstree.CssNode) => { + if (node.type === "Value" && node.children) { for (const child of node.children) { children.push(child); } From 784b8be0f6ecee1d36ea16878e576461c3926ea8 Mon Sep 17 00:00:00 2001 From: Stuart Robinson Date: Tue, 11 Nov 2025 19:12:54 +0700 Subject: [PATCH 2/5] docs: update bundle sizes and dependencies in README - Update bundle size: ~68KB (ESM), ~73KB (CJS) minified + brotli - Remove css-tree from installation (now bundled dependency) - Update test count: 973 tests - Update acknowledgments to @eslint/css-tree - Add accurate performance metrics --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b9be258..deb9fc9 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,18 @@ ## Why b_short? -- **📦 Tiny**: ~16KB compressed +- **📦 Tiny**: ~68KB minified + brotli (ESM), ~73KB (CJS) with all dependencies - **⚡ Fast**: Optimized TypeScript with smart caching - **🎯 Complete**: 35+ CSS shorthands including modern features - **🔒 Type-Safe**: Full TypeScript support -- **✅ Tested**: 970 tests ensuring 100% accuracy +- **✅ Tested**: 973 tests ensuring 100% accuracy - **🎨 Flexible**: CSS strings or JS objects (camelCase for React) - **🔄 Bidirectional**: Both expand and collapse APIs ## Quick Start ```bash -npm install b_short css-tree +npm install b_short ``` ```typescript @@ -240,8 +240,8 @@ if (!result.ok) { ## Performance - **Fast**: Optimized for performance with LRU caching -- **Small**: ~16KB compressed (brotli) -- **Efficient**: Handles 808 test cases in <1 second +- **Small**: 89KB unminified, ~68KB minified + brotli (ESM) +- **Efficient**: Handles 973 test cases in <2 seconds ## TypeScript Support @@ -276,7 +276,7 @@ MIT © [alphabio](https://github.com/alphabio) ## Acknowledgments - [TypeScript](https://www.typescriptlang.org/) -- [css-tree](https://github.com/csstree/csstree) - CSS parsing +- [@eslint/css-tree](https://github.com/eslint/css-tree) - CSS parsing and validation - [Vitest](https://vitest.dev/) - Testing - [Biome](https://biomejs.dev/) - Code quality From 1e6fff789fc60a294496755fab56baee1453b27b Mon Sep 17 00:00:00 2001 From: Stuart Robinson Date: Tue, 11 Nov 2025 19:14:52 +0700 Subject: [PATCH 3/5] docs: update comment to reference @eslint/css-tree --- src/core/validate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/validate.ts b/src/core/validate.ts index 336a850..460a2f9 100644 --- a/src/core/validate.ts +++ b/src/core/validate.ts @@ -66,7 +66,7 @@ interface FormattedLine { /** * Checks if a CSS value node contains var() function. - * CSS variables cannot be validated by css-tree as they are runtime values. + * CSS variables cannot be validated by @eslint/css-tree as they are runtime values. */ function containsVar(node: csstree.CssNode): boolean { if (!node) return false; From ea8615cad7534e55a3b79d6776de7405da5dd962 Mon Sep 17 00:00:00 2001 From: Stuart Robinson Date: Tue, 11 Nov 2025 19:15:38 +0700 Subject: [PATCH 4/5] docs: link to b_values fork in acknowledgments --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index deb9fc9..fa3e04b 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,7 @@ MIT © [alphabio](https://github.com/alphabio) ## Acknowledgments - [TypeScript](https://www.typescriptlang.org/) -- [@eslint/css-tree](https://github.com/eslint/css-tree) - CSS parsing and validation +- [@eslint/css-tree](https://github.com/alphabio/b_values) - CSS parsing and validation - [Vitest](https://vitest.dev/) - Testing - [Biome](https://biomejs.dev/) - Code quality From 5a573ef34dd44cdcc36e4002cf2977b16a8c464a Mon Sep 17 00:00:00 2001 From: Stuart Robinson Date: Tue, 11 Nov 2025 19:16:50 +0700 Subject: [PATCH 5/5] docs: add separate acknowledgment for b_values - Keep @eslint/css-tree link to upstream repo - Add b_values link for CSS value expansion/validation work --- README.md | 3 ++- docs.llm/llm_src.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa3e04b..ebfaf8c 100644 --- a/README.md +++ b/README.md @@ -276,7 +276,8 @@ MIT © [alphabio](https://github.com/alphabio) ## Acknowledgments - [TypeScript](https://www.typescriptlang.org/) -- [@eslint/css-tree](https://github.com/alphabio/b_values) - CSS parsing and validation +- [@eslint/css-tree](https://github.com/eslint/css-tree) - CSS parsing +- [b_values](https://github.com/alphabio/b_values) - CSS value expansion and validation - [Vitest](https://vitest.dev/) - Testing - [Biome](https://biomejs.dev/) - Code quality diff --git a/docs.llm/llm_src.txt b/docs.llm/llm_src.txt index d170def..bec9660 100644 --- a/docs.llm/llm_src.txt +++ b/docs.llm/llm_src.txt @@ -965,7 +965,7 @@ interface FormattedLine { /** * Checks if a CSS value node contains var() function. - * CSS variables cannot be validated by css-tree as they are runtime values. + * CSS variables cannot be validated by @eslint/css-tree as they are runtime values. */ function containsVar(node: csstree.CssNode): boolean { if (!node) return false;