diff --git a/CHANGELOG.md b/CHANGELOG.md index be14a565c..a6885b1e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,48 @@ # Changelog +# v1.6.5 + +## New + +- [x] Added fine-grained minification parameters: + - [x] RenderOptions#minifyValues: minify CSS values such as numbers and dimension tokens + - [x] ParseOptions#minifyAST: minify the AST. + +## Improvement + +```css + .footer{ + grid-row:4; + grid-column:1; + grid-column-end:2; + } +``` + +is now computed as + +```css +.footer { + grid-area: 4/1/auto/2 +} +``` + +## Fixes + +- [x] fix a98-rgb, hwb color color space handling in color-mix() +- [x] fix percentage handling in relative rgb color + +```css + .c { +color: rgb(from rgb(20% 40% 60% / 80%) r g b / calc(alpha / 2)); +``` +is now computed as + +```css +.c { + color: #3696 +} +``` + # v1.6.4 ## New diff --git a/README.md b/README.md index 640f02dd4..25f767c47 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,49 @@ A sample result: On the [complete benchmark suite](https://tbela99.github.io/css-parser/benchmark/index.html), css-parser generated a total output size of 2,158,698 bytes, compared to 2,494,113 bytes for Lightning CSS and larger outputs for all other tested minifiers. While some tools prioritize raw execution speed, css-parser focuses on maximizing compression while preserving stylesheet semantics, resulting in consistently smaller production bundles. +## Minification performance vs execution speed + +`css-parser` is designed for maximum minification performance, but the optimal configuration depends on what matters most for your workload. + +The parser provides settings that let you choose the balance between minification performance and execution speed: + +- Minification performance: prioritize the quality and efficiency of the minification process, allowing the parser to perform additional work when generating the minimized output. + +- Execution speed: minimize the amount of work performed during parsing and minification to achieve the fastest possible execution time. + +However, the available settings allow you to shift the balance toward execution speed when minimizing runtime is more important than performing every available minification optimization. + +The example below demonstrates a balanced configuration that improves execution speed by disabling advanced minification features. + +```ts + +import {transformSync} from "@tbela99/css-parser"; + +const css = `...`; + +const result = transformSync({ + input: css, + minify: false, + beautify: false, + removeEmpty: true, + removeComments: true, + convertColor: true, + minifyValues: true, + }); + +console.debug(result.code); +console.debug(result.stats); +``` + +Performance vs execution speed comparison + + +| File: tailwind.css | Speed optimization | Minification optimization | +| --------------------- | ------------------ | ------------------------- | +| Size: 2,380,419 bytes | 1,890,728 bytes | 1,633,188 bytes | +| Time | 205.91 ms | 471.89 ms | +| Size reduction | -20.6% | -31.4% | + ## Playground Try it [online](https://tbela99.github.io/css-parser/playground/) @@ -196,3 +239,64 @@ Try it [online](https://tbela99.github.io/css-parser/playground/) ## Performance - [x] Bundle file referenced by the @import statement. + +# Architecture + +```mermaid +flowchart TD + %% --- Transform --- + Input(["CSS input"]) + + + %% The Grouped Container + subgraph Group10["Transform step"] + + transform["transform()/transformSync()"] + + + %% The Grouped Container + subgraph Group1 ["Parse step"] + + %% --- Parse step --- + parse["parse()/parseSync()"] + tokenize(["tokenize()"]) + parseNode(["parse and validate token stream"]) + visitors(["visitors"]) + minify(["minify AST"]) + cssModules(["generate CSS module"]) + parseResult["Parse result"] + end + + %% The Grouped Container + subgraph Group2 ["Render step"] + + %% --- Render step --- + renderAst(["Render AST"]) + sourcemap([Sourcemap generation]) + + end + + %% --- Result step --- + transformResult["Transform result"] + end + + %% --- Routing step --- + Input --> transform + transform --> parse + parse --> tokenize + tokenize --> parseNode + parseNode -- "Visitors set?" --> visitors + visitors -- "Minify AST?" --> minify + minify -- "CSS module?" --> cssModules + visitors -- "CSS module?" --> cssModules + cssModules --> parseResult + parseNode -- "CSS module?" --> cssModules + parseNode -- "Minify AST?" --> minify + parseNode --> parseResult + visitors --> parseResult + minify --> parseResult + parseResult --> renderAst + renderAst -- "Sourcemap?" --> sourcemap + renderAst --> transformResult + sourcemap --> transformResult +``` \ No newline at end of file diff --git a/benchmark/package.json b/benchmark/package.json index 5d81be43d..4e75aa7c0 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -10,8 +10,8 @@ "all": "npm run sizes && npm run bench; npm run report" }, "dependencies": { - "@tbela99/css-parser": "^1.6.3", - "@tbela99/css-parser2": "github:tbela99/css-parser#04832c9", + "@tbela99/css-parser": "^1.6.5", + "@tbela99/css-parser2": "github:tbela99/css-parser#b74aa264", "clean-css": "^5.3.3", "css-tree": "^3.2.1", "cssnano": "^9.0.5", @@ -21,4 +21,4 @@ "postcss": "^8.5.28", "vitest": "^5.0.1" } -} \ No newline at end of file +} diff --git a/benchmark/src/generate-report.js b/benchmark/src/generate-report.js index 8effbf060..422cd9a8b 100644 --- a/benchmark/src/generate-report.js +++ b/benchmark/src/generate-report.js @@ -72,7 +72,7 @@ for (const m of minifiers) { totalRow += `\n`; const headerCells = minifiers - .map((m) => `${m.url != null ? `${m.label}` : m.label}`) + .map((m) => `${m.url != null ? `${m.label}` : m.label}`) .join("\n"); const html = ` diff --git a/benchmark/src/minifiers.js b/benchmark/src/minifiers.js index 57ee284ed..a8d829865 100644 --- a/benchmark/src/minifiers.js +++ b/benchmark/src/minifiers.js @@ -10,9 +10,9 @@ import cssnano from "cssnano"; import * as csso from "csso"; import * as csstree from "css-tree"; import * as esbuild from "esbuild"; -import { transform as lightningTransform } from "lightningcss"; -import { transform as tbelaTransform } from "@tbela99/css-parser"; -import {transformSync as tbelaDevTransform} from "@tbela99/css-parser2"; +import { transform } from "lightningcss"; +import { transformSync as tbelaTransform } from "@tbela99/css-parser"; +import { transformSync as tbelaDevTransform } from "@tbela99/css-parser2"; function pkgVersion(name, pathToPkgJson) { const { version, repository } = JSON.parse( @@ -39,16 +39,14 @@ function pkgVersion(name, pathToPkgJson) { const githubShorthand = url.match(/^github:([^/]+\/[^/]+)$/); if (githubShorthand) { url = `https://github.com/${githubShorthand[1]}`; - } - - else { + } else { url = url .replace(/^git\+/, "") .replace(/^git@github\.com:/, "https://github.com/") .replace(/^ssh:\/\/git@github\.com\//, "https://github.com/") .replace(/\.git$/, ""); } - + if (!url.match(/[a-zA-Z]+:/)) { url = "https://github.com/" + url; } @@ -99,15 +97,15 @@ export const minifiers = [ minify: (css) => csso.minify(css).css, }, // infinite loop bug - // { - // id: "css-tree", - // url: versions["css-tree"].url, - // label: `css-tree - ${versions["css-tree"].version}`, - // // css-tree has no dedicated minifier API; parse+generate already - // // drops whitespace/comments, which is how the official benchmark - // // treats it too (no property-level optimization, just compact output). - // minify: (css) => csstree.generate(csstree.parse(css)), - // }, + { + id: "css-tree", + url: versions["css-tree"].url, + label: `css-tree - ${versions["css-tree"].version}`, + // css-tree has no dedicated minifier API; parse+generate already + // drops whitespace/comments, which is how the official benchmark + // treats it too (no property-level optimization, just compact output). + minify: (css) => csstree.generate(csstree.parse(css)), + }, { id: "esbuild", url: versions.esbuild.url, @@ -118,19 +116,28 @@ export const minifiers = [ id: "lightningcss", url: versions.lightningcss.url, label: `lightningcss - ${versions.lightningcss.version}`, - minify: (css) => - lightningTransform({ filename: "style.css", code: Buffer.from(css), minify: true }).code.toString(), + minify: (css) => transform({ filename: "style.css", code: Buffer.from(css), minify: true }).code.toString(), }, { id: "css-parser", url: versions["css-parser"].url, - label: `@tbela99/css-parser - ${versions["css-parser"].version}`, - minify: async (css) => (await tbelaTransform(css, { minify: true })).code, + label: `@tbela99/css-parser (speed) - ${versions["css-parser"].version}`, + title: `settings: { minify: false, beautify: false, removeEmpty: true, removeComments: true, convertColor: true }`, + minify: async (css) => + tbelaTransform({ + input: css, + minify: false, + beautify: false, + removeEmpty: true, + removeComments: true, + convertColor: true, + // minifyValues: true, + }).code, }, { id: "css-parser-dev", url: versions["css-parser-dev"].url, - label: `@tbela99/css-parser-dev - ${versions["css-parser-dev"].version}`, - minify: async (css) => (await tbelaDevTransform(css, { minify: true })).code, + label: `@tbela99/css-parser-dev (default) - ${versions["css-parser-dev"].version}`, + minify: async (css) => tbelaDevTransform({ input: css }).code, }, ]; diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index c42387449..e8505ba55 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -6429,6 +6429,11 @@ * Color range definitions */ const colorRange = { + rgb: { + r: [0, 255], + g: [0, 255], + b: [0, 255], + }, lab: { l: [0, 100], a: [-125, 125], @@ -6898,13 +6903,6 @@ } function getColorComponents(token) { - // if (token.typ === EnumToken.IdenTokenType) { - // if (isColor(token)) { - // parseColor(token); - // } else { - // return null; - // } - // } if (token.kin == exports.ColorType.HEX || token.kin == exports.ColorType.LIT) { if (equalsIgnoreCase("currentcolor", token.val)) { return null; @@ -6928,25 +6926,12 @@ ].includes(child.typ)) { continue; } - // if (child.typ === EnumToken.IdenTokenType && isColor(child)) { - // parseColor(child); - // } if (child.typ === exports.EnumToken.FunctionTokenType || child.typ === exports.EnumToken.WildCardFunctionTokenType || child.typ === exports.EnumToken.MathFunctionTokenType) { if ("var" == child.val.toLowerCase()) { return null; } - // else { - // for (const { value } of walkValues((child as FunctionToken).chi)) { - // if ( - // value.typ == EnumToken.WildCardFunctionTokenDefType && - // "var" === (value as FunctionToken).val.toLowerCase() - // ) { - // return null; - // } - // } - // } } if (child.typ == exports.EnumToken.ColorTokenType && equalsIgnoreCase("currentcolor", child.val)) { return null; @@ -8242,7 +8227,10 @@ if (value == null) { return null; } - return hexToken(value.reduce((acc, curr) => acc + srgb2rgb(curr + Number.EPSILON).toString(16).padStart(2, "0"), "#")); + return hexToken(value.reduce((acc, curr) => acc + + srgb2rgb(curr + Number.EPSILON) + .toString(16) + .padStart(2, "0"), "#")); } function oklab2HexToken(token) { let value = oklab2srgbvalues(token); @@ -9091,7 +9079,7 @@ // convert an array of linear-light a98-rgb in the range 0.0-1.0 // to gamma corrected form // negative values are also now accepted - return [r, b, g] + return [r, g, b] .map(function (val) { let sign = val < 0 ? -1 : 1; let abs = Math.abs(val); @@ -9227,6 +9215,9 @@ if (values == null) { return null; } + if (colorSpace == "hwb") { + colorSpace = "srgb"; + } switch (colorSpace) { case "srgb": break; @@ -9256,17 +9247,17 @@ values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); break; - case "rgb": - for (let j = 0; j < values.length; j++) { - values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); - } - break; + // case "rgb": + // for (let j = 0; j < values.length; j++) { + // values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + // } + // break; case "hsl": values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; - case "hwb": - values = srgb2hwb(values[0], values[1], values[2], values[3]); - break; + // case "hwb": + // values = srgb2hwb(values[0], values[1], values[2], values[3]); + // break; case "lab": values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; @@ -9465,14 +9456,14 @@ kin: exports.ColorType.COLOR, cal: "col", }; - case "rgb": + // case "rgb": case "hsl": - case "hwb": + // case "hwb": case "lab": case "lch": case "oklab": case "oklch": - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore if (values[2] < 0) { // @ts-ignore @@ -9502,7 +9493,7 @@ }), kin: exports.ColorType[colorSpace.toUpperCase().replaceAll("-", "_")], }; - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore result.chi[0] = { typ: exports.EnumToken.AngleTokenType, val: result.chi[0].val * 360 }; // @ts-ignore @@ -10097,6 +10088,7 @@ [LOCSRCID]: nodes[0][LOCSRCID], [LOCSTA]: nodes[0][LOCSTA], [LOCEND]: nodes[0][LOCEND], + [PARENT]: nodes[0][PARENT], }, ]; } @@ -10119,6 +10111,7 @@ [LOCSRCID]: nodes[i][LOCSRCID], [LOCSTA]: nodes[i][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }; } else { @@ -10128,6 +10121,7 @@ [LOCSRCID]: nodes[i + 1][LOCSRCID], [LOCSTA]: nodes[i + 1][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }, exports.EnumToken.Mul); } i++; @@ -10148,12 +10142,14 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, { ...token, val: -token.val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); return acc; } @@ -10164,6 +10160,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); } acc.push(token); @@ -10185,6 +10182,7 @@ [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -10257,6 +10255,7 @@ [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: exports.EnumToken.NumberTokenType, @@ -10264,6 +10263,7 @@ [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -10276,6 +10276,7 @@ [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: exports.EnumToken.NumberTokenType, @@ -10283,6 +10284,7 @@ [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -10309,6 +10311,7 @@ [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (token.typ == exports.EnumToken.IdenTokenType) { // @ts-ignore @@ -10489,6 +10492,7 @@ [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], } : { typ: token.val == "sign" ? exports.EnumToken.NumberTokenType : value[0].typ, @@ -10496,6 +10500,7 @@ [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], }, ]; } @@ -10518,6 +10523,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10591,6 +10597,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10605,6 +10612,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10615,6 +10623,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10654,6 +10663,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10696,6 +10706,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10723,6 +10734,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); for (const child of inlineExpression$1(token.r)) { result.push(child); @@ -10802,6 +10814,7 @@ [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }; // @ts-ignore delete token.val; @@ -10843,6 +10856,7 @@ [LOCSRCID]: tokens[i - 1][LOCSRCID], [LOCSTA]: tokens[i - 1][LOCSTA], [LOCEND]: tokens[i + 1][LOCEND], + [PARENT]: tokens[i + 1][PARENT], }); i--; } @@ -10888,20 +10902,20 @@ continue; } if (component.typ == exports.EnumToken.IdenTokenType) { - val = component.val.toLowerCase(); + val = component.val; if ( // @ts-expect-error typeof Math[val.toUpperCase()] !== "number" && - val != "in" && - val != "hue" && - val != "from" && - val != "alpha" && - val != "none" && - val != "shorter" && - val != "longer" && - val != "increasing" && - val != "decreasing" && - !colorsFunc.includes(val) && + !equalsIgnoreCase(val, "in") && + !equalsIgnoreCase(val, "hue") && + !equalsIgnoreCase(val, "from") && + !equalsIgnoreCase(val, "alpha") && + !equalsIgnoreCase(val, "none") && + !equalsIgnoreCase(val, "shorter") && + !equalsIgnoreCase(val, "longer") && + !equalsIgnoreCase(val, "increasing") && + !equalsIgnoreCase(val, "decreasing") && + !colorsFunc.some((t) => equalsIgnoreCase(t, val)) && !colorFuncColorSpace.includes(val) && !validKeys.includes(val)) { return null; @@ -12805,7 +12819,8 @@ for (let i = index; i < syntaxes.length; i++) { if (syntaxes[i].typ == ValidationTokenEnum.Whitespace || syntaxes[i].isOptional || - syntaxes[i].isRepeatable) { + syntaxes[i].isRepeatable || + syntaxes[i].match?.min?.val === 0) { continue; } return { @@ -14510,7 +14525,6 @@ } let components = getColorComponents(color); if (alpha.typ === exports.EnumToken.MathFunctionTokenType) { - const originalAlpha = cloneNode(alpha, true); for (const { value } of walkValues(alpha.chi, alpha)) { if (value.typ === exports.EnumToken.IdenTokenType) { if (equalsIgnoreCase(value.val, "alpha")) { @@ -14522,22 +14536,22 @@ }); // continue; } - else if (equalsIgnoreCase(value.val, "none")) { - Object.assign(value, { - typ: exports.EnumToken.NumberTokenType, - val: 0, - }); - } + // else if (equalsIgnoreCase((value as IdentToken).val, "none")) { + // Object.assign(value, { + // typ: EnumToken.NumberTokenType, + // val: 0, + // }); + // } } } const result = evaluate([alpha]); if (result.length == 1) { alpha = result[0]; } - else { - // @ts-expect-error - alpha = originalAlpha; - } + // else { + // // @ts-expect-error + // alpha = originalAlpha; + // } } // console.error({ alpha }); if (alpha.typ !== exports.EnumToken.IdenTokenType && @@ -14563,17 +14577,17 @@ return null; } if (alpha?.typ === exports.EnumToken.IdenTokenType) { - if (equalsIgnoreCase(alpha.val, "alpha")) { - alpha = components[3] ?? { - typ: exports.EnumToken.NumberTokenType, - val: 1, - }; - } - else if (equalsIgnoreCase(alpha.val, "node")) { - alpha = { + // if (equalsIgnoreCase((alpha as IdentToken).val, "alpha")) { + // alpha = components[3] ?? { + // typ: EnumToken.NumberTokenType, + // val: 1, + // }; + // } else + if (equalsIgnoreCase(alpha.val, "none")) { + Object.assign(alpha, { typ: exports.EnumToken.NumberTokenType, val: 0, - }; + }); } } return makeColor(color.kin, components, alpha); @@ -15294,12 +15308,12 @@ // '\\' const REVERSE_SOLIDUS = 0x5c; const flexUnits = ["fr"]; - const frequencyUnits = ["hz", "khz"]; + const frequencyUnits = ["Hz", "kHz"]; const timeUnits = ["ms", "s"]; const angleUnits = ["rad", "turn", "deg", "grad"]; const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; const dimensionUnits = [ - "q", + "Q", "cap", "ch", "cm", @@ -16983,7 +16997,7 @@ } class ComputePrefixFeature { get ordering() { - return 2; + return 0; } get processMode() { return exports.FeatureWalkMode.Pre; @@ -17427,10 +17441,10 @@ class InlineCssVariablesFeature { accept = new Set([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType]); get ordering() { - return 0; + return 2; } get processMode() { - return exports.FeatureWalkMode.Pre; + return exports.FeatureWalkMode.Post; } static register(options) { if (options.inlineCssVariables) { @@ -19680,8 +19694,8 @@ const propertiesConfig = getConfig(); class PropertyMap { - config; declarations; + config; requiredCount; pattern; constructor(config) { @@ -19695,7 +19709,7 @@ } add(declaration) { if (declaration.nam == this.config.shorthand) { - this.declarations = new Map(); + this.declarations.clear(); this.declarations.set(declaration.nam, declaration); this.matchTypes(declaration); } @@ -19711,23 +19725,17 @@ if (this.declarations.has(this.config.shorthand)) { const tokens = {}; const values = []; - // @ts-ignore - this.declarations - .get(this.config.shorthand) - // @ts-ignore - .val.slice() - .reduce((acc, curr) => { + const val = [[]]; + for (const curr of this.declarations.get(this.config.shorthand).val) { // @ts-ignore // @ts-ignore if (separator != null && separator.typ == curr.typ && separator.val == curr.val) { - acc.push([]); - return acc; + val.push([]); + continue; } // @ts-ignore - acc.at(-1).push(curr); - return acc; - }, [[]]) - // @ts-ignore - .reduce((acc, list, current) => { + val.at(-1).push(curr); + } + for (let current = 0; current < val.length; current++) { values.push(...this.pattern.reduce((acc, property) => { // let current: number = 0; const props = this.config.properties[property]; @@ -19742,9 +19750,7 @@ // @ts-ignore acc[i][PROPERTYNAME] == property || matchType(acc[i], props)) { - if ("prefix" in props && - props.previous != null && - !(props.previous in tokens)) { + if ("prefix" in props && props.previous != null && !(props.previous in tokens)) { return acc; } if (!(property in tokens)) { @@ -19809,9 +19815,8 @@ } } return acc; - }, list)); - return values; - }, []); + }, val[current])); + } if (values.length == 0) { this.declarations = Object.entries(tokens).reduce((acc, curr) => { acc.set(curr[0], { @@ -19871,17 +19876,40 @@ } if (hasMapping) { const mapped = {}; - for (const key of declarations.keys()) { - const value = declarations.get(key); + let key; + for (const value of declarations.values()) { + key = value.nam; if (value instanceof PropertyMap) { for (const [k, v] of value.declarations) { - mapped[k] = v; + if (k == value.config.shorthand) { + for (const [key, val] of Object.entries(value.config.properties)) { + mapped[key] = cloneNode(v); + for (let i = 0; i < v.val.length; i++) { + // @ts-ignore + if (key == v.val[i][PROPERTYNAME]) { + if (mapped[key].val.length > 0) { + mapped[key].val.push({ + typ: exports.EnumToken.WhitespaceTokenType, + }); + } + mapped[key].val.push(v.val[i]); + } + } + if (mapped[key].val.length == 0) { + mapped[key].val.push(...parseString(value.config.properties[key].default[0])); + } + } + } + else { + mapped[k] = v; + } } } else { mapped[key] = value; } } + // console.error(mapped); if (patterns.length === Object.keys(mapped).length) { declarations = new Map(); for (const key of patterns) { @@ -20337,8 +20365,6 @@ } return acc; }, []); - // console.error({hasMapping, shorthand: this.config.shorthand, requiredCount, isShorthand, - // declarations: declarations.values(), values}); if (this.config.mapping != null) { const val = values.reduce((acc, curr) => acc + renderValue(curr, { @@ -20375,6 +20401,7 @@ } } const iterators = []; + // @ts-ignore return { // @ts-ignore next() { @@ -20627,6 +20654,9 @@ } const config = getConfig(); + /** + * Represents a list of property declarations, compute shorthand and remove duplicate declarations. + */ class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; @@ -20701,28 +20731,35 @@ // @ts-ignore shorthand = config.property[propertyName]; } - // console.error({shortHandType, propertyName, config: config.map[propertyName], map: config.map[shorthand].properties[propertyName]}); // @ts-ignore if (shortHandType == "map") { let owner = this; + const mapName = // @ts-ignore - const mapName = config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; + config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; if (typeof mapName === "string") { if (!this.declarations.has(mapName)) { // @ts-ignore this.declarations.set(mapName, new PropertyMap(config.map[mapName])); } owner = this.declarations.get(mapName); - // console.error({mapName}); } - // @ts-ignore - if (!owner.declarations.has(shorthand)) { + else if (!this.declarations.has(shorthand)) { // @ts-ignore - owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + this.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + if (owner == this) { + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); + } + else { + if (!owner.declarations.has(shorthand)) { + // @ts-ignore + owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); } - // console.error({propertyName,mapName, owned: owner == this}); - // @ts-ignore - owner.declarations.get(shorthand).add(declaration); } // @ts-ignore else if (shortHandType == "set") { @@ -20809,7 +20846,7 @@ [Symbol.iterator]() { let iterator = this.declarations.values(); const iterators = []; - // console.error(this); + // @ts-ignore return { next() { let value = iterator.next(); @@ -20840,7 +20877,7 @@ exports.EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 10; + return 5; } get processMode() { return exports.FeatureWalkMode.Post; @@ -20859,7 +20896,6 @@ const j = ast.chi.length; let k = 0; let l; - // let properties: PropertyList = new PropertyList(options); const rules = []; const declarations = []; // @ts-ignore @@ -20880,7 +20916,6 @@ if (node.typ == exports.EnumToken.DeclarationNodeType) { for (let m = k; m <= l; m++) { declarations.push(ast.chi[m]); - // properties.add(ast.chi![m]); } } else { @@ -20890,7 +20925,6 @@ } k = l; } - // console.error([...new PropertyList(options).add(declarations)]); if (declarations.length > 0) { ast.chi.length = 0; // @ts-expect-error @@ -21001,7 +21035,7 @@ class ComputeCalcExpressionFeature { accept = new Set([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType]); get ordering() { - return 1; + return 3; } get processMode() { return exports.FeatureWalkMode.Post; @@ -21026,8 +21060,20 @@ continue; } if (value.typ == exports.EnumToken.BinaryExpressionTokenType) { - // @ts-ignore - replaceNodeOrValue(parent, value, evaluate([value])); + const result = evaluate([value]); + try { + // @ts-ignore + replaceNodeOrValue(parent, value, result); + } + catch (e) { + // @ts-ignore + if (Array.isArray(parent.chi)) { + // @ts-ignore + parent.chi.length = 0; + // @ts-ignore + parent.chi.push(...result); + } + } continue; } if (value != null && tokensfuncSet.has(value.typ)) { @@ -21045,7 +21091,7 @@ ? value.val : value.chi; const values = evaluate(cp); - // fix a + -b to a - b + // fix a + -b into a - b for (const { value, parent: p } of walkValues(values)) { if (value.typ === exports.EnumToken.BinaryExpressionTokenType) { if (value.op === exports.EnumToken.Add && @@ -22311,7 +22357,7 @@ exports.EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 3; + return 4; } get processMode() { return exports.FeatureWalkMode.Post; @@ -22714,7 +22760,7 @@ class ExpandIfFeature { accept = new Set([exports.EnumToken.DeclarationNodeType]); get ordering() { - return 4; + return 1; } get processMode() { return exports.FeatureWalkMode.Pre; @@ -23516,7 +23562,8 @@ previous = node; nodeIndex = i; } - if (recursive && node != null && "chi" in node) { + // @ts-ignore + if (recursive && node != null && node.chi != null) { if (node.typ == exports.EnumToken.KeyframesAtRuleNodeType || !node.chi.some((n) => n.typ == exports.EnumToken.DeclarationNodeType)) { if (!(node.typ == exports.EnumToken.AtRuleNodeType && node.nam != "font-face")) { @@ -25349,6 +25396,7 @@ removeEmpty: false, removeComments: false, }), + minifyValues: true, sourcemap: false, convertColor: true, expandNestingRules: false, @@ -25588,7 +25636,7 @@ const indentSub = indents[level + 1]; switch (data.typ) { case exports.EnumToken.DeclarationNodeType: - return `${data.nam}:${options.indent}${(options.minify + return `${data.nam}:${options.indent}${(options.minifyValues ? filterValues(data.val) : data.val).reduce(reducer, "")}`; case exports.EnumToken.CommentNodeType: @@ -25643,7 +25691,7 @@ : node.val; } else if (node.typ == exports.EnumToken.DeclarationNodeType) { - str = `${node.nam}:${options.indent}${(options.minify + str = `${node.nam}:${options.indent}${(options.minifyValues ? filterValues(node.val) : node.val) .reduce(reducer, "") @@ -25711,9 +25759,10 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, errors) { if (token.typ === exports.EnumToken.WhenElseFunctionTokenType && equalsIgnoreCase(token.val, "supports")) { - options = { ...options, minify: false, convertColor: false }; + options = { ...options, minifyValues: false, minify: false, convertColor: false }; reducer = null; } + options.minifyValues ??= options.minify; if (reducer == null) { reducer = function (acc, curr) { if (curr.typ == exports.EnumToken.CommentTokenType && options.removeComments) { @@ -25870,7 +25919,7 @@ ")"); } case exports.EnumToken.UrlFunctionTokenType: - if (options.minify && token.typ === exports.EnumToken.UrlFunctionTokenType) { + if (options.minifyValues && token.typ === exports.EnumToken.UrlFunctionTokenType) { if (token.chi[0]?.typ === exports.EnumToken.BadUrlTokenType) { return "url()"; } @@ -25891,7 +25940,7 @@ case exports.EnumToken.FunctionTokenType: case exports.EnumToken.MathFunctionTokenType: case exports.EnumToken.ImageFunctionTokenType: - if (options.minify && token.typ === exports.EnumToken.ImageFunctionTokenType) { + if (options.minifyValues && token.typ === exports.EnumToken.ImageFunctionTokenType) { const slice = token.chi.slice(); switch (token.val) { case "linear-gradient": @@ -26377,37 +26426,7 @@ renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + ")"); } - return ( - /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + - "(" + - token.chi.reduce(reducer, "") + - ")"); - // case EnumToken.MatchExpressionTokenType: - // return ( - // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + - // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") - // ); - // case EnumToken.NameSpaceAttributeTokenType: - // return ( - // ((token as NameSpaceAttributeToken).l == null - // ? "" - // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + - // "|" + - // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) - // ); - // case EnumToken.ComposesSelectorNodeType: - // return ( - // (token as ComposesSelectorToken).l.reduce( - // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), - // "", - // ) + - // ((token as ComposesSelectorToken).r == null - // ? "" - // : " from " + - // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) - // ); + return (token.val ?? "") + "(" + token.chi.reduce(reducer, "") + ")"; case exports.EnumToken.BlockStartTokenType: return "{"; case exports.EnumToken.BlockEndTokenType: @@ -26556,7 +26575,11 @@ const perc = token.val.typ == exports.EnumToken.FractionTokenType ? renderValue(token.val, options, cache) : minifyNumber(token.val); - return options.minify && perc == "0" ? "0" : perc.includes("/") ? perc.replace("/", uni + "/") : perc + uni; + return options.minifyValues && perc == "0" + ? "0" + : perc.includes("/") + ? perc.replace("/", uni + "/") + : perc + uni; case exports.EnumToken.NumberTokenType: return token.val.typ == exports.EnumToken.FractionTokenType ? renderValue(token.val, options, cache) @@ -26621,7 +26644,7 @@ case exports.EnumToken.DeclarationNodeType: return (token.nam + ":" + - (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + (options.minifyValues ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); case exports.EnumToken.MediaQueryUnaryFeatureTokenType: return (renderValue(token.l, options, cache, reducer) + " " + @@ -26695,6 +26718,7 @@ } const SymbolsMapTokens = Object.create(null); + const SymbolsMapTokensLower = Object.create(null); // Regex for escape sequence decoding - compile once, reuse many times const ESCAPE_SEQUENCE_REGEX = /\\((\n|\r|\f|\v|\u2028|\u2029|([0-9a-fA-F]{1,6})) ?)/gms; function decodeEscapeSequences(value) { @@ -26723,7 +26747,9 @@ } function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { for (const entry of entries) { - SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + const key = (lowercase ? entry.toLowerCase() : entry) + suffix; + SymbolsMapTokens[key] = tokenType; + SymbolsMapTokensLower[key.toLowerCase()] = tokenType; } } SymbolsMapTokens[""] = exports.EnumToken.DelimTokenType; @@ -26823,20 +26849,24 @@ })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { const len = end - start; - const keysLength = SymbolsMapTokensKeys.length; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; + const value = parseInfo.stream.slice(start, end); + // Direct lookup handles the hottest punctuation and keyword cases without + // scanning the entire symbol table on every token. + const match = SymbolsMapTokens[value] ?? SymbolsMapTokensLower[value.toLowerCase()]; + if (match != null) { + return match; + } + const keysLength = SymbolsMapTokensKeys.length; for (let i = 0; i < keysLength; i++) { const key = SymbolsMapTokensKeys[i]; if (key.length !== len) continue; - // Match character by character let match = true; for (let j = 0; j < len; j++) { let ca = key.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let cb = value.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) @@ -26854,32 +26884,29 @@ } function searchArray(array, parseInfo, start, end) { const len = end - start; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; - // Use a simple linear search optimized with length pre-filtering - let i = array.length; - while (i--) { - if (array[i].length !== len) + let match; + let item; + for (let i = 0; i < array.length; i++) { + item = array[i]; + if (item.length !== len) continue; - // Match character by character - let match = true; - const arrayItem = array[i]; + match = true; for (let j = 0; j < len; j++) { - let ca = arrayItem.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let ca = parseInfo.stream.charCodeAt(start + j); + let cb = item.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) cb += 32; - if (ca != cb) { + if (ca !== cb) { match = false; break; } } if (match) { - return arrayItem; + return item; } } return null; @@ -27817,23 +27844,6 @@ } return true; } - /** - * - * @param parseInfo - * @returns - */ - // isPseudo(parseInfo: ParseInfo): boolean { - // let position: number = parseInfo.currentPosition - parseInfo.offset; - // let endPosition: number = parseInfo.currentPosition - parseInfo.offset; - // return (parseInfo.stream.charAt(position) == ":" && - // parseInfo.stream.charAt(endPosition - 1) == "(" && - // (parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2, -1) - // : this.isIdentToken(parseInfo, 1, -1))) || - // parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2) - // : this.isIdentToken(parseInfo, 1); - // } /** * * @param parseInfo @@ -27964,28 +27974,28 @@ // EOF switch (charCode) { case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); - if (isDigit(charCode)) { - tokensCount = this.consumeNumericToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { - slice: this.slice, - sign: "+", - }); - } - } + // if (isDigit(charCode)) { + // tokensCount = this.consumeNumericToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + // slice: this.slice, + // sign: "+", + // }); + // } + // } return this.makeToken(parseInfo, exports.EnumToken.Plus); case 45 /* TokenMap.MINUS */: if (parseInfo.position == parseInfo.currentPosition) { @@ -27995,15 +28005,17 @@ this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.Sub); } - if (charCode == 45 /* TokenMap.MINUS */ && - (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.advance(parseInfo); - tokensCount = this.consumeIdentToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); - } - } + // if ( + // charCode == TokenMap.MINUS && + // (nextCharCode == TokenMap.MINUS || isIdentStart(nextCharCode)) + // ) { + // this.advance(parseInfo); + // tokensCount = this.consumeIdentToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, EnumToken.IdenTokenType); + // } + // } } this.advance(parseInfo); break; @@ -28056,28 +28068,28 @@ return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); @@ -28109,15 +28121,15 @@ } return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "$=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); @@ -28125,9 +28137,9 @@ this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "~=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); @@ -28136,9 +28148,9 @@ return this.makeToken(parseInfo, exports.EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "^=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); @@ -28146,9 +28158,9 @@ this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "*=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); @@ -28162,9 +28174,9 @@ this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } // '||' if (this.match(parseInfo, "||")) { this.advance(parseInfo, 2); @@ -28187,9 +28199,9 @@ this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (!this.match(parseInfo, "/*")) { this.advance(parseInfo); return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); @@ -28208,9 +28220,9 @@ } break; case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, ">=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); @@ -28249,20 +28261,11 @@ this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } this.advance(parseInfo); // EOF - if (!this.peek(parseInfo)) { - // if (!yieldEOFToken) { - // break; - // } - // end of stream ignore \\ - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } - break; + // end of stream ignore \\ + if (!this.peek(parseInfo) && parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } this.advance(parseInfo); break; @@ -28275,9 +28278,9 @@ case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { @@ -28285,27 +28288,22 @@ return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); } } - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - this.makeToken(parseInfo); - this.advance(parseInfo, 2); - return this; - } + // if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + // this.makeToken(parseInfo); + // this.advance(parseInfo, 2); + // return this; + // } this.advance(parseInfo); break; default: this.advance(parseInfo); break; } - // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } } - // if (yieldEOFToken) { if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo); } return this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); - // } } /** * tokenize readable stream @@ -31079,6 +31077,7 @@ if (options.expandNestingRules) { options.nestingRules = false; } + options.minifyAST ??= options.minify; const startTime = performance.now(); const errors = []; const stack = []; @@ -31458,7 +31457,7 @@ } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { @@ -31998,6 +31997,7 @@ lenient: true, ...options, }; + options.minifyAST ??= options.minify; if (typeof options.validation !== "boolean") { options.validation = !!options.validation; } @@ -32452,7 +32452,7 @@ } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { @@ -34842,6 +34842,7 @@ }); } + exports.PropertyList = PropertyList; exports.SourceMap = SourceMap; exports.cloneNode = cloneNode; exports.convertColor = convertColor; diff --git a/dist/index.cjs b/dist/index.cjs index c9475aa67..1c95d5ec5 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -6432,6 +6432,11 @@ const anglePrecision = 3; * Color range definitions */ const colorRange = { + rgb: { + r: [0, 255], + g: [0, 255], + b: [0, 255], + }, lab: { l: [0, 100], a: [-125, 125], @@ -6901,13 +6906,6 @@ function equalsIgnoreCase(a, b) { } function getColorComponents(token) { - // if (token.typ === EnumToken.IdenTokenType) { - // if (isColor(token)) { - // parseColor(token); - // } else { - // return null; - // } - // } if (token.kin == exports.ColorType.HEX || token.kin == exports.ColorType.LIT) { if (equalsIgnoreCase("currentcolor", token.val)) { return null; @@ -6931,25 +6929,12 @@ function getColorComponents(token) { ].includes(child.typ)) { continue; } - // if (child.typ === EnumToken.IdenTokenType && isColor(child)) { - // parseColor(child); - // } if (child.typ === exports.EnumToken.FunctionTokenType || child.typ === exports.EnumToken.WildCardFunctionTokenType || child.typ === exports.EnumToken.MathFunctionTokenType) { if ("var" == child.val.toLowerCase()) { return null; } - // else { - // for (const { value } of walkValues((child as FunctionToken).chi)) { - // if ( - // value.typ == EnumToken.WildCardFunctionTokenDefType && - // "var" === (value as FunctionToken).val.toLowerCase() - // ) { - // return null; - // } - // } - // } } if (child.typ == exports.EnumToken.ColorTokenType && equalsIgnoreCase("currentcolor", child.val)) { return null; @@ -8245,7 +8230,10 @@ function color2HexToken(token) { if (value == null) { return null; } - return hexToken(value.reduce((acc, curr) => acc + srgb2rgb(curr + Number.EPSILON).toString(16).padStart(2, "0"), "#")); + return hexToken(value.reduce((acc, curr) => acc + + srgb2rgb(curr + Number.EPSILON) + .toString(16) + .padStart(2, "0"), "#")); } function oklab2HexToken(token) { let value = oklab2srgbvalues(token); @@ -9094,7 +9082,7 @@ function la98rgb2a98rgb(r, g, b, a = null) { // convert an array of linear-light a98-rgb in the range 0.0-1.0 // to gamma corrected form // negative values are also now accepted - return [r, b, g] + return [r, g, b] .map(function (val) { let sign = val < 0 ? -1 : 1; let abs = Math.abs(val); @@ -9230,6 +9218,9 @@ function colorMix(...args) { if (values == null) { return null; } + if (colorSpace == "hwb") { + colorSpace = "srgb"; + } switch (colorSpace) { case "srgb": break; @@ -9259,17 +9250,17 @@ function colorMix(...args) { values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); break; - case "rgb": - for (let j = 0; j < values.length; j++) { - values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); - } - break; + // case "rgb": + // for (let j = 0; j < values.length; j++) { + // values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + // } + // break; case "hsl": values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; - case "hwb": - values = srgb2hwb(values[0], values[1], values[2], values[3]); - break; + // case "hwb": + // values = srgb2hwb(values[0], values[1], values[2], values[3]); + // break; case "lab": values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; @@ -9468,14 +9459,14 @@ function colorMix(...args) { kin: exports.ColorType.COLOR, cal: "col", }; - case "rgb": + // case "rgb": case "hsl": - case "hwb": + // case "hwb": case "lab": case "lch": case "oklab": case "oklch": - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore if (values[2] < 0) { // @ts-ignore @@ -9505,7 +9496,7 @@ function colorMix(...args) { }), kin: exports.ColorType[colorSpace.toUpperCase().replaceAll("-", "_")], }; - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore result.chi[0] = { typ: exports.EnumToken.AngleTokenType, val: result.chi[0].val * 360 }; // @ts-ignore @@ -10100,6 +10091,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[0][LOCSRCID], [LOCSTA]: nodes[0][LOCSTA], [LOCEND]: nodes[0][LOCEND], + [PARENT]: nodes[0][PARENT], }, ]; } @@ -10122,6 +10114,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[i][LOCSRCID], [LOCSTA]: nodes[i][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }; } else { @@ -10131,6 +10124,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[i + 1][LOCSRCID], [LOCSTA]: nodes[i + 1][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }, exports.EnumToken.Mul); } i++; @@ -10151,12 +10145,14 @@ function evaluate(tokens) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, { ...token, val: -token.val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); return acc; } @@ -10167,6 +10163,7 @@ function evaluate(tokens) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); } acc.push(token); @@ -10188,6 +10185,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -10260,6 +10258,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: exports.EnumToken.NumberTokenType, @@ -10267,6 +10266,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -10279,6 +10279,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: exports.EnumToken.NumberTokenType, @@ -10286,6 +10287,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -10312,6 +10314,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (token.typ == exports.EnumToken.IdenTokenType) { // @ts-ignore @@ -10492,6 +10495,7 @@ function evaluateFunc(token) { [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], } : { typ: token.val == "sign" ? exports.EnumToken.NumberTokenType : value[0].typ, @@ -10499,6 +10503,7 @@ function evaluateFunc(token) { [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], }, ]; } @@ -10521,6 +10526,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10594,6 +10600,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10608,6 +10615,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10618,6 +10626,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10657,6 +10666,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10699,6 +10709,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -10726,6 +10737,7 @@ function inlineExpression$1(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); for (const child of inlineExpression$1(token.r)) { result.push(child); @@ -10805,6 +10817,7 @@ function factorToken(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }; // @ts-ignore delete token.val; @@ -10846,6 +10859,7 @@ function factor(tokens, ops) { [LOCSRCID]: tokens[i - 1][LOCSRCID], [LOCSTA]: tokens[i - 1][LOCSTA], [LOCEND]: tokens[i + 1][LOCEND], + [PARENT]: tokens[i + 1][PARENT], }); i--; } @@ -10891,20 +10905,20 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, continue; } if (component.typ == exports.EnumToken.IdenTokenType) { - val = component.val.toLowerCase(); + val = component.val; if ( // @ts-expect-error typeof Math[val.toUpperCase()] !== "number" && - val != "in" && - val != "hue" && - val != "from" && - val != "alpha" && - val != "none" && - val != "shorter" && - val != "longer" && - val != "increasing" && - val != "decreasing" && - !colorsFunc.includes(val) && + !equalsIgnoreCase(val, "in") && + !equalsIgnoreCase(val, "hue") && + !equalsIgnoreCase(val, "from") && + !equalsIgnoreCase(val, "alpha") && + !equalsIgnoreCase(val, "none") && + !equalsIgnoreCase(val, "shorter") && + !equalsIgnoreCase(val, "longer") && + !equalsIgnoreCase(val, "increasing") && + !equalsIgnoreCase(val, "decreasing") && + !colorsFunc.some((t) => equalsIgnoreCase(t, val)) && !colorFuncColorSpace.includes(val) && !validKeys.includes(val)) { return null; @@ -12808,7 +12822,8 @@ function matchAllSyntaxes(syntaxes, context, options) { for (let i = index; i < syntaxes.length; i++) { if (syntaxes[i].typ == ValidationTokenEnum.Whitespace || syntaxes[i].isOptional || - syntaxes[i].isRepeatable) { + syntaxes[i].isRepeatable || + syntaxes[i].match?.min?.val === 0) { continue; } return { @@ -14513,7 +14528,6 @@ function alpha(color, alpha) { } let components = getColorComponents(color); if (alpha.typ === exports.EnumToken.MathFunctionTokenType) { - const originalAlpha = cloneNode(alpha, true); for (const { value } of walkValues(alpha.chi, alpha)) { if (value.typ === exports.EnumToken.IdenTokenType) { if (equalsIgnoreCase(value.val, "alpha")) { @@ -14525,22 +14539,22 @@ function alpha(color, alpha) { }); // continue; } - else if (equalsIgnoreCase(value.val, "none")) { - Object.assign(value, { - typ: exports.EnumToken.NumberTokenType, - val: 0, - }); - } + // else if (equalsIgnoreCase((value as IdentToken).val, "none")) { + // Object.assign(value, { + // typ: EnumToken.NumberTokenType, + // val: 0, + // }); + // } } } const result = evaluate([alpha]); if (result.length == 1) { alpha = result[0]; } - else { - // @ts-expect-error - alpha = originalAlpha; - } + // else { + // // @ts-expect-error + // alpha = originalAlpha; + // } } // console.error({ alpha }); if (alpha.typ !== exports.EnumToken.IdenTokenType && @@ -14566,17 +14580,17 @@ function alpha(color, alpha) { return null; } if (alpha?.typ === exports.EnumToken.IdenTokenType) { - if (equalsIgnoreCase(alpha.val, "alpha")) { - alpha = components[3] ?? { - typ: exports.EnumToken.NumberTokenType, - val: 1, - }; - } - else if (equalsIgnoreCase(alpha.val, "node")) { - alpha = { + // if (equalsIgnoreCase((alpha as IdentToken).val, "alpha")) { + // alpha = components[3] ?? { + // typ: EnumToken.NumberTokenType, + // val: 1, + // }; + // } else + if (equalsIgnoreCase(alpha.val, "none")) { + Object.assign(alpha, { typ: exports.EnumToken.NumberTokenType, val: 0, - }; + }); } } return makeColor(color.kin, components, alpha); @@ -15297,12 +15311,12 @@ function getColorSpace(color) { // '\\' const REVERSE_SOLIDUS = 0x5c; const flexUnits = ["fr"]; -const frequencyUnits = ["hz", "khz"]; +const frequencyUnits = ["Hz", "kHz"]; const timeUnits = ["ms", "s"]; const angleUnits = ["rad", "turn", "deg", "grad"]; const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; const dimensionUnits = [ - "q", + "Q", "cap", "ch", "cm", @@ -16986,7 +17000,7 @@ function replaceAstNodes(tokens, root) { } class ComputePrefixFeature { get ordering() { - return 2; + return 0; } get processMode() { return exports.FeatureWalkMode.Pre; @@ -17430,10 +17444,10 @@ function replace(node, variableScope) { class InlineCssVariablesFeature { accept = new Set([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType]); get ordering() { - return 0; + return 2; } get processMode() { - return exports.FeatureWalkMode.Pre; + return exports.FeatureWalkMode.Post; } static register(options) { if (options.inlineCssVariables) { @@ -19683,8 +19697,8 @@ function matchType(val, properties) { const propertiesConfig = getConfig(); class PropertyMap { - config; declarations; + config; requiredCount; pattern; constructor(config) { @@ -19698,7 +19712,7 @@ class PropertyMap { } add(declaration) { if (declaration.nam == this.config.shorthand) { - this.declarations = new Map(); + this.declarations.clear(); this.declarations.set(declaration.nam, declaration); this.matchTypes(declaration); } @@ -19714,23 +19728,17 @@ class PropertyMap { if (this.declarations.has(this.config.shorthand)) { const tokens = {}; const values = []; - // @ts-ignore - this.declarations - .get(this.config.shorthand) - // @ts-ignore - .val.slice() - .reduce((acc, curr) => { + const val = [[]]; + for (const curr of this.declarations.get(this.config.shorthand).val) { // @ts-ignore // @ts-ignore if (separator != null && separator.typ == curr.typ && separator.val == curr.val) { - acc.push([]); - return acc; + val.push([]); + continue; } // @ts-ignore - acc.at(-1).push(curr); - return acc; - }, [[]]) - // @ts-ignore - .reduce((acc, list, current) => { + val.at(-1).push(curr); + } + for (let current = 0; current < val.length; current++) { values.push(...this.pattern.reduce((acc, property) => { // let current: number = 0; const props = this.config.properties[property]; @@ -19745,9 +19753,7 @@ class PropertyMap { // @ts-ignore acc[i][PROPERTYNAME] == property || matchType(acc[i], props)) { - if ("prefix" in props && - props.previous != null && - !(props.previous in tokens)) { + if ("prefix" in props && props.previous != null && !(props.previous in tokens)) { return acc; } if (!(property in tokens)) { @@ -19812,9 +19818,8 @@ class PropertyMap { } } return acc; - }, list)); - return values; - }, []); + }, val[current])); + } if (values.length == 0) { this.declarations = Object.entries(tokens).reduce((acc, curr) => { acc.set(curr[0], { @@ -19874,17 +19879,40 @@ class PropertyMap { } if (hasMapping) { const mapped = {}; - for (const key of declarations.keys()) { - const value = declarations.get(key); + let key; + for (const value of declarations.values()) { + key = value.nam; if (value instanceof PropertyMap) { for (const [k, v] of value.declarations) { - mapped[k] = v; + if (k == value.config.shorthand) { + for (const [key, val] of Object.entries(value.config.properties)) { + mapped[key] = cloneNode(v); + for (let i = 0; i < v.val.length; i++) { + // @ts-ignore + if (key == v.val[i][PROPERTYNAME]) { + if (mapped[key].val.length > 0) { + mapped[key].val.push({ + typ: exports.EnumToken.WhitespaceTokenType, + }); + } + mapped[key].val.push(v.val[i]); + } + } + if (mapped[key].val.length == 0) { + mapped[key].val.push(...parseString(value.config.properties[key].default[0])); + } + } + } + else { + mapped[k] = v; + } } } else { mapped[key] = value; } } + // console.error(mapped); if (patterns.length === Object.keys(mapped).length) { declarations = new Map(); for (const key of patterns) { @@ -20340,8 +20368,6 @@ class PropertyMap { } return acc; }, []); - // console.error({hasMapping, shorthand: this.config.shorthand, requiredCount, isShorthand, - // declarations: declarations.values(), values}); if (this.config.mapping != null) { const val = values.reduce((acc, curr) => acc + renderValue(curr, { @@ -20378,6 +20404,7 @@ class PropertyMap { } } const iterators = []; + // @ts-ignore return { // @ts-ignore next() { @@ -20630,6 +20657,9 @@ function syncHash(input, length = 6, algo) { } const config = getConfig(); +/** + * Represents a list of property declarations, compute shorthand and remove duplicate declarations. + */ class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; @@ -20704,28 +20734,35 @@ class PropertyList { // @ts-ignore shorthand = config.property[propertyName]; } - // console.error({shortHandType, propertyName, config: config.map[propertyName], map: config.map[shorthand].properties[propertyName]}); // @ts-ignore if (shortHandType == "map") { let owner = this; + const mapName = // @ts-ignore - const mapName = config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; + config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; if (typeof mapName === "string") { if (!this.declarations.has(mapName)) { // @ts-ignore this.declarations.set(mapName, new PropertyMap(config.map[mapName])); } owner = this.declarations.get(mapName); - // console.error({mapName}); } - // @ts-ignore - if (!owner.declarations.has(shorthand)) { + else if (!this.declarations.has(shorthand)) { // @ts-ignore - owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + this.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + if (owner == this) { + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); + } + else { + if (!owner.declarations.has(shorthand)) { + // @ts-ignore + owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); } - // console.error({propertyName,mapName, owned: owner == this}); - // @ts-ignore - owner.declarations.get(shorthand).add(declaration); } // @ts-ignore else if (shortHandType == "set") { @@ -20812,7 +20849,7 @@ class PropertyList { [Symbol.iterator]() { let iterator = this.declarations.values(); const iterators = []; - // console.error(this); + // @ts-ignore return { next() { let value = iterator.next(); @@ -20843,7 +20880,7 @@ class ComputeShorthandFeature { exports.EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 10; + return 5; } get processMode() { return exports.FeatureWalkMode.Post; @@ -20862,7 +20899,6 @@ class ComputeShorthandFeature { const j = ast.chi.length; let k = 0; let l; - // let properties: PropertyList = new PropertyList(options); const rules = []; const declarations = []; // @ts-ignore @@ -20883,7 +20919,6 @@ class ComputeShorthandFeature { if (node.typ == exports.EnumToken.DeclarationNodeType) { for (let m = k; m <= l; m++) { declarations.push(ast.chi[m]); - // properties.add(ast.chi![m]); } } else { @@ -20893,7 +20928,6 @@ class ComputeShorthandFeature { } k = l; } - // console.error([...new PropertyList(options).add(declarations)]); if (declarations.length > 0) { ast.chi.length = 0; // @ts-expect-error @@ -21004,7 +21038,7 @@ function trimWhiteSpaceTokens(tokens) { class ComputeCalcExpressionFeature { accept = new Set([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType]); get ordering() { - return 1; + return 3; } get processMode() { return exports.FeatureWalkMode.Post; @@ -21029,8 +21063,20 @@ class ComputeCalcExpressionFeature { continue; } if (value.typ == exports.EnumToken.BinaryExpressionTokenType) { - // @ts-ignore - replaceNodeOrValue(parent, value, evaluate([value])); + const result = evaluate([value]); + try { + // @ts-ignore + replaceNodeOrValue(parent, value, result); + } + catch (e) { + // @ts-ignore + if (Array.isArray(parent.chi)) { + // @ts-ignore + parent.chi.length = 0; + // @ts-ignore + parent.chi.push(...result); + } + } continue; } if (value != null && tokensfuncSet.has(value.typ)) { @@ -21048,7 +21094,7 @@ class ComputeCalcExpressionFeature { ? value.val : value.chi; const values = evaluate(cp); - // fix a + -b to a - b + // fix a + -b into a - b for (const { value, parent: p } of walkValues(values)) { if (value.typ === exports.EnumToken.BinaryExpressionTokenType) { if (value.op === exports.EnumToken.Add && @@ -22314,7 +22360,7 @@ class TransformCssFeature { exports.EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 3; + return 4; } get processMode() { return exports.FeatureWalkMode.Post; @@ -22717,7 +22763,7 @@ function processNode(declarationNode, cache) { class ExpandIfFeature { accept = new Set([exports.EnumToken.DeclarationNodeType]); get ordering() { - return 4; + return 1; } get processMode() { return exports.FeatureWalkMode.Pre; @@ -23519,7 +23565,8 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, previous = node; nodeIndex = i; } - if (recursive && node != null && "chi" in node) { + // @ts-ignore + if (recursive && node != null && node.chi != null) { if (node.typ == exports.EnumToken.KeyframesAtRuleNodeType || !node.chi.some((n) => n.typ == exports.EnumToken.DeclarationNodeType)) { if (!(node.typ == exports.EnumToken.AtRuleNodeType && node.nam != "font-face")) { @@ -25352,6 +25399,7 @@ function doRender(data, options = {}, mapping) { removeEmpty: false, removeComments: false, }), + minifyValues: true, sourcemap: false, convertColor: true, expandNestingRules: false, @@ -25591,7 +25639,7 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro const indentSub = indents[level + 1]; switch (data.typ) { case exports.EnumToken.DeclarationNodeType: - return `${data.nam}:${options.indent}${(options.minify + return `${data.nam}:${options.indent}${(options.minifyValues ? filterValues(data.val) : data.val).reduce(reducer, "")}`; case exports.EnumToken.CommentNodeType: @@ -25646,7 +25694,7 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro : node.val; } else if (node.typ == exports.EnumToken.DeclarationNodeType) { - str = `${node.nam}:${options.indent}${(options.minify + str = `${node.nam}:${options.indent}${(options.minifyValues ? filterValues(node.val) : node.val) .reduce(reducer, "") @@ -25714,9 +25762,10 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro function renderValue(token, options = {}, cache = Object.create(null), reducer, errors) { if (token.typ === exports.EnumToken.WhenElseFunctionTokenType && equalsIgnoreCase(token.val, "supports")) { - options = { ...options, minify: false, convertColor: false }; + options = { ...options, minifyValues: false, minify: false, convertColor: false }; reducer = null; } + options.minifyValues ??= options.minify; if (reducer == null) { reducer = function (acc, curr) { if (curr.typ == exports.EnumToken.CommentTokenType && options.removeComments) { @@ -25873,7 +25922,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, ")"); } case exports.EnumToken.UrlFunctionTokenType: - if (options.minify && token.typ === exports.EnumToken.UrlFunctionTokenType) { + if (options.minifyValues && token.typ === exports.EnumToken.UrlFunctionTokenType) { if (token.chi[0]?.typ === exports.EnumToken.BadUrlTokenType) { return "url()"; } @@ -25894,7 +25943,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, case exports.EnumToken.FunctionTokenType: case exports.EnumToken.MathFunctionTokenType: case exports.EnumToken.ImageFunctionTokenType: - if (options.minify && token.typ === exports.EnumToken.ImageFunctionTokenType) { + if (options.minifyValues && token.typ === exports.EnumToken.ImageFunctionTokenType) { const slice = token.chi.slice(); switch (token.val) { case "linear-gradient": @@ -26380,37 +26429,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + ")"); } - return ( - /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + - "(" + - token.chi.reduce(reducer, "") + - ")"); - // case EnumToken.MatchExpressionTokenType: - // return ( - // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + - // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") - // ); - // case EnumToken.NameSpaceAttributeTokenType: - // return ( - // ((token as NameSpaceAttributeToken).l == null - // ? "" - // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + - // "|" + - // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) - // ); - // case EnumToken.ComposesSelectorNodeType: - // return ( - // (token as ComposesSelectorToken).l.reduce( - // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), - // "", - // ) + - // ((token as ComposesSelectorToken).r == null - // ? "" - // : " from " + - // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) - // ); + return (token.val ?? "") + "(" + token.chi.reduce(reducer, "") + ")"; case exports.EnumToken.BlockStartTokenType: return "{"; case exports.EnumToken.BlockEndTokenType: @@ -26559,7 +26578,11 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, const perc = token.val.typ == exports.EnumToken.FractionTokenType ? renderValue(token.val, options, cache) : minifyNumber(token.val); - return options.minify && perc == "0" ? "0" : perc.includes("/") ? perc.replace("/", uni + "/") : perc + uni; + return options.minifyValues && perc == "0" + ? "0" + : perc.includes("/") + ? perc.replace("/", uni + "/") + : perc + uni; case exports.EnumToken.NumberTokenType: return token.val.typ == exports.EnumToken.FractionTokenType ? renderValue(token.val, options, cache) @@ -26624,7 +26647,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, case exports.EnumToken.DeclarationNodeType: return (token.nam + ":" + - (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + (options.minifyValues ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); case exports.EnumToken.MediaQueryUnaryFeatureTokenType: return (renderValue(token.l, options, cache, reducer) + " " + @@ -26698,6 +26721,7 @@ function filterValues(values) { } const SymbolsMapTokens = Object.create(null); +const SymbolsMapTokensLower = Object.create(null); // Regex for escape sequence decoding - compile once, reuse many times const ESCAPE_SEQUENCE_REGEX = /\\((\n|\r|\f|\v|\u2028|\u2029|([0-9a-fA-F]{1,6})) ?)/gms; function decodeEscapeSequences(value) { @@ -26726,7 +26750,9 @@ function decodeEscapeSequences(value) { } function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { for (const entry of entries) { - SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + const key = (lowercase ? entry.toLowerCase() : entry) + suffix; + SymbolsMapTokens[key] = tokenType; + SymbolsMapTokensLower[key.toLowerCase()] = tokenType; } } SymbolsMapTokens[""] = exports.EnumToken.DelimTokenType; @@ -26826,20 +26852,24 @@ var TokenMap; })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { const len = end - start; - const keysLength = SymbolsMapTokensKeys.length; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; + const value = parseInfo.stream.slice(start, end); + // Direct lookup handles the hottest punctuation and keyword cases without + // scanning the entire symbol table on every token. + const match = SymbolsMapTokens[value] ?? SymbolsMapTokensLower[value.toLowerCase()]; + if (match != null) { + return match; + } + const keysLength = SymbolsMapTokensKeys.length; for (let i = 0; i < keysLength; i++) { const key = SymbolsMapTokensKeys[i]; if (key.length !== len) continue; - // Match character by character let match = true; for (let j = 0; j < len; j++) { let ca = key.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let cb = value.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) @@ -26857,32 +26887,29 @@ function getSymbolHint(parseInfo, start, end) { } function searchArray(array, parseInfo, start, end) { const len = end - start; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; - // Use a simple linear search optimized with length pre-filtering - let i = array.length; - while (i--) { - if (array[i].length !== len) + let match; + let item; + for (let i = 0; i < array.length; i++) { + item = array[i]; + if (item.length !== len) continue; - // Match character by character - let match = true; - const arrayItem = array[i]; + match = true; for (let j = 0; j < len; j++) { - let ca = arrayItem.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let ca = parseInfo.stream.charCodeAt(start + j); + let cb = item.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) cb += 32; - if (ca != cb) { + if (ca !== cb) { match = false; break; } } if (match) { - return arrayItem; + return item; } } return null; @@ -27820,23 +27847,6 @@ class Tokenizer { } return true; } - /** - * - * @param parseInfo - * @returns - */ - // isPseudo(parseInfo: ParseInfo): boolean { - // let position: number = parseInfo.currentPosition - parseInfo.offset; - // let endPosition: number = parseInfo.currentPosition - parseInfo.offset; - // return (parseInfo.stream.charAt(position) == ":" && - // parseInfo.stream.charAt(endPosition - 1) == "(" && - // (parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2, -1) - // : this.isIdentToken(parseInfo, 1, -1))) || - // parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2) - // : this.isIdentToken(parseInfo, 1); - // } /** * * @param parseInfo @@ -27967,28 +27977,28 @@ class Tokenizer { // EOF switch (charCode) { case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); - if (isDigit(charCode)) { - tokensCount = this.consumeNumericToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { - slice: this.slice, - sign: "+", - }); - } - } + // if (isDigit(charCode)) { + // tokensCount = this.consumeNumericToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + // slice: this.slice, + // sign: "+", + // }); + // } + // } return this.makeToken(parseInfo, exports.EnumToken.Plus); case 45 /* TokenMap.MINUS */: if (parseInfo.position == parseInfo.currentPosition) { @@ -27998,15 +28008,17 @@ class Tokenizer { this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.Sub); } - if (charCode == 45 /* TokenMap.MINUS */ && - (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.advance(parseInfo); - tokensCount = this.consumeIdentToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); - } - } + // if ( + // charCode == TokenMap.MINUS && + // (nextCharCode == TokenMap.MINUS || isIdentStart(nextCharCode)) + // ) { + // this.advance(parseInfo); + // tokensCount = this.consumeIdentToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, EnumToken.IdenTokenType); + // } + // } } this.advance(parseInfo); break; @@ -28059,28 +28071,28 @@ class Tokenizer { return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); @@ -28112,15 +28124,15 @@ class Tokenizer { } return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "$=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); @@ -28128,9 +28140,9 @@ class Tokenizer { this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "~=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); @@ -28139,9 +28151,9 @@ class Tokenizer { return this.makeToken(parseInfo, exports.EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "^=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); @@ -28149,9 +28161,9 @@ class Tokenizer { this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "*=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); @@ -28165,9 +28177,9 @@ class Tokenizer { this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } // '||' if (this.match(parseInfo, "||")) { this.advance(parseInfo, 2); @@ -28190,9 +28202,9 @@ class Tokenizer { this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (!this.match(parseInfo, "/*")) { this.advance(parseInfo); return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); @@ -28211,9 +28223,9 @@ class Tokenizer { } break; case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, ">=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); @@ -28252,20 +28264,11 @@ class Tokenizer { this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } this.advance(parseInfo); // EOF - if (!this.peek(parseInfo)) { - // if (!yieldEOFToken) { - // break; - // } - // end of stream ignore \\ - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } - break; + // end of stream ignore \\ + if (!this.peek(parseInfo) && parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } this.advance(parseInfo); break; @@ -28278,9 +28281,9 @@ class Tokenizer { case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { @@ -28288,27 +28291,22 @@ class Tokenizer { return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); } } - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - this.makeToken(parseInfo); - this.advance(parseInfo, 2); - return this; - } + // if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + // this.makeToken(parseInfo); + // this.advance(parseInfo, 2); + // return this; + // } this.advance(parseInfo); break; default: this.advance(parseInfo); break; } - // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } } - // if (yieldEOFToken) { if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo); } return this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); - // } } /** * tokenize readable stream @@ -31082,6 +31080,7 @@ function doParseSync(tokenizer, options = {}) { if (options.expandNestingRules) { options.nestingRules = false; } + options.minifyAST ??= options.minify; const startTime = performance.now(); const errors = []; const stack = []; @@ -31461,7 +31460,7 @@ function doParseSync(tokenizer, options = {}) { } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { @@ -32001,6 +32000,7 @@ async function doParse(iter, options = {}) { lenient: true, ...options, }; + options.minifyAST ??= options.minify; if (typeof options.validation !== "boolean") { options.validation = !!options.validation; } @@ -32455,7 +32455,7 @@ async function doParse(iter, options = {}) { } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { diff --git a/dist/index.d.ts b/dist/index.d.ts index 096b023d7..5c17e370e 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -5217,6 +5217,12 @@ interface MinifyOptions { * Enable minification */ minify?: boolean; + + /** + * enable ast minification + */ + minifyAST?: boolean; + /** * Parse color tokens */ @@ -5294,7 +5300,8 @@ export declare type LoadResult = | Promise> | ReadableStream | string - | Promise | object; + | Promise + | object; /** * CSS module parser options @@ -5792,9 +5799,15 @@ export declare interface RenderOptions { src?: string; /** - * Minify css values. + * strip comments and whitespace. */ minify?: boolean; + + /** + * Minify values + */ + minifyValues?: boolean; + /** * Pretty print css * diff --git a/dist/lib/ast/features/calc.js b/dist/lib/ast/features/calc.js index 9ac0aa9c5..67a32fefd 100644 --- a/dist/lib/ast/features/calc.js +++ b/dist/lib/ast/features/calc.js @@ -8,7 +8,7 @@ import { replaceNodeOrValue } from '../../parser/utils/token.js'; class ComputeCalcExpressionFeature { accept = new Set([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType]); get ordering() { - return 1; + return 3; } get processMode() { return FeatureWalkMode.Post; @@ -33,8 +33,20 @@ class ComputeCalcExpressionFeature { continue; } if (value.typ == EnumToken.BinaryExpressionTokenType) { - // @ts-ignore - replaceNodeOrValue(parent, value, evaluate([value])); + const result = evaluate([value]); + try { + // @ts-ignore + replaceNodeOrValue(parent, value, result); + } + catch (e) { + // @ts-ignore + if (Array.isArray(parent.chi)) { + // @ts-ignore + parent.chi.length = 0; + // @ts-ignore + parent.chi.push(...result); + } + } continue; } if (value != null && tokensfuncSet.has(value.typ)) { @@ -52,7 +64,7 @@ class ComputeCalcExpressionFeature { ? value.val : value.chi; const values = evaluate(cp); - // fix a + -b to a - b + // fix a + -b into a - b for (const { value, parent: p } of walkValues(values)) { if (value.typ === EnumToken.BinaryExpressionTokenType) { if (value.op === EnumToken.Add && diff --git a/dist/lib/ast/features/if.js b/dist/lib/ast/features/if.js index cbf4cb516..0acfa25c5 100644 --- a/dist/lib/ast/features/if.js +++ b/dist/lib/ast/features/if.js @@ -174,7 +174,7 @@ function processNode(declarationNode, cache) { class ExpandIfFeature { accept = new Set([EnumToken.DeclarationNodeType]); get ordering() { - return 4; + return 1; } get processMode() { return FeatureWalkMode.Pre; diff --git a/dist/lib/ast/features/inlinecssvariables.js b/dist/lib/ast/features/inlinecssvariables.js index 0c7716bea..9dc33e0ce 100644 --- a/dist/lib/ast/features/inlinecssvariables.js +++ b/dist/lib/ast/features/inlinecssvariables.js @@ -57,10 +57,10 @@ function replace(node, variableScope) { class InlineCssVariablesFeature { accept = new Set([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType]); get ordering() { - return 0; + return 2; } get processMode() { - return FeatureWalkMode.Pre; + return FeatureWalkMode.Post; } static register(options) { if (options.inlineCssVariables) { diff --git a/dist/lib/ast/features/prefix.js b/dist/lib/ast/features/prefix.js index fa2aa3c71..5b551497f 100644 --- a/dist/lib/ast/features/prefix.js +++ b/dist/lib/ast/features/prefix.js @@ -109,7 +109,7 @@ function replaceAstNodes(tokens, root) { } class ComputePrefixFeature { get ordering() { - return 2; + return 0; } get processMode() { return FeatureWalkMode.Pre; diff --git a/dist/lib/ast/features/shorthand.js b/dist/lib/ast/features/shorthand.js index 149ed4e87..684f0e747 100644 --- a/dist/lib/ast/features/shorthand.js +++ b/dist/lib/ast/features/shorthand.js @@ -9,7 +9,7 @@ class ComputeShorthandFeature { EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 10; + return 5; } get processMode() { return FeatureWalkMode.Post; @@ -28,7 +28,6 @@ class ComputeShorthandFeature { const j = ast.chi.length; let k = 0; let l; - // let properties: PropertyList = new PropertyList(options); const rules = []; const declarations = []; // @ts-ignore @@ -49,7 +48,6 @@ class ComputeShorthandFeature { if (node.typ == EnumToken.DeclarationNodeType) { for (let m = k; m <= l; m++) { declarations.push(ast.chi[m]); - // properties.add(ast.chi![m]); } } else { @@ -59,7 +57,6 @@ class ComputeShorthandFeature { } k = l; } - // console.error([...new PropertyList(options).add(declarations)]); if (declarations.length > 0) { ast.chi.length = 0; // @ts-expect-error diff --git a/dist/lib/ast/features/transform.js b/dist/lib/ast/features/transform.js index 2f59e3910..97503a60b 100644 --- a/dist/lib/ast/features/transform.js +++ b/dist/lib/ast/features/transform.js @@ -12,7 +12,7 @@ class TransformCssFeature { EnumToken.KeyframesRuleNodeType, ]); get ordering() { - return 3; + return 4; } get processMode() { return FeatureWalkMode.Post; diff --git a/dist/lib/ast/math/expression.js b/dist/lib/ast/math/expression.js index 1a372b279..5a04f657e 100644 --- a/dist/lib/ast/math/expression.js +++ b/dist/lib/ast/math/expression.js @@ -1,5 +1,5 @@ import { equalsIgnoreCase } from '../../parser/utils/text.js'; -import { mathFuncs, LOCEND, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; +import { mathFuncs, PARENT, LOCEND, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; import { EnumToken } from '../types.js'; import { rem, compute } from './math.js'; @@ -64,6 +64,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[0][LOCSRCID], [LOCSTA]: nodes[0][LOCSTA], [LOCEND]: nodes[0][LOCEND], + [PARENT]: nodes[0][PARENT], }, ]; } @@ -86,6 +87,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[i][LOCSRCID], [LOCSTA]: nodes[i][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }; } else { @@ -95,6 +97,7 @@ function evaluate(tokens) { [LOCSRCID]: nodes[i + 1][LOCSRCID], [LOCSTA]: nodes[i + 1][LOCSTA], [LOCEND]: nodes[i + 1][LOCEND], + [PARENT]: nodes[i + 1][PARENT], }, EnumToken.Mul); } i++; @@ -115,12 +118,14 @@ function evaluate(tokens) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, { ...token, val: -token.val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); return acc; } @@ -131,6 +136,7 @@ function evaluate(tokens) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); } acc.push(token); @@ -152,6 +158,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -224,6 +231,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: EnumToken.NumberTokenType, @@ -231,6 +239,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -243,6 +252,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: l[LOCEND], + [PARENT]: l[PARENT], }, r: { typ: EnumToken.NumberTokenType, @@ -250,6 +260,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: r[LOCSRCID], [LOCSTA]: r[LOCSTA], [LOCEND]: r[LOCEND], + [PARENT]: r[PARENT], }, }; } @@ -276,6 +287,7 @@ function doEvaluate(l, r, op) { [LOCSRCID]: l[LOCSRCID], [LOCSTA]: l[LOCSTA], [LOCEND]: r?.[LOCEND] ?? l[LOCEND], + [PARENT]: l[PARENT], }; if (token.typ == EnumToken.IdenTokenType) { // @ts-ignore @@ -456,6 +468,7 @@ function evaluateFunc(token) { [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], } : { typ: token.val == "sign" ? EnumToken.NumberTokenType : value[0].typ, @@ -463,6 +476,7 @@ function evaluateFunc(token) { [LOCSRCID]: value[0][LOCSRCID], [LOCSTA]: value[0][LOCSTA], [LOCEND]: value[0][LOCEND], + [PARENT]: value[0][PARENT], }, ]; } @@ -485,6 +499,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -558,6 +573,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -572,6 +588,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -582,6 +599,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -621,6 +639,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -663,6 +682,7 @@ function evaluateFunc(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }, ]; } @@ -690,6 +710,7 @@ function inlineExpression(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }); for (const child of inlineExpression(token.r)) { result.push(child); @@ -769,6 +790,7 @@ function factorToken(token) { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], + [PARENT]: token[PARENT], }; // @ts-ignore delete token.val; @@ -810,6 +832,7 @@ function factor(tokens, ops) { [LOCSRCID]: tokens[i - 1][LOCSRCID], [LOCSTA]: tokens[i - 1][LOCSTA], [LOCEND]: tokens[i + 1][LOCEND], + [PARENT]: tokens[i + 1][PARENT], }); i--; } diff --git a/dist/lib/ast/minify.js b/dist/lib/ast/minify.js index 54a57e2d7..6817fbf1d 100644 --- a/dist/lib/ast/minify.js +++ b/dist/lib/ast/minify.js @@ -787,7 +787,8 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, previous = node; nodeIndex = i; } - if (recursive && node != null && "chi" in node) { + // @ts-ignore + if (recursive && node != null && node.chi != null) { if (node.typ == EnumToken.KeyframesAtRuleNodeType || !node.chi.some((n) => n.typ == EnumToken.DeclarationNodeType)) { if (!(node.typ == EnumToken.AtRuleNodeType && node.nam != "font-face")) { diff --git a/dist/lib/parser/declaration/list.js b/dist/lib/parser/declaration/list.js index 40b326e84..205c01f68 100644 --- a/dist/lib/parser/declaration/list.js +++ b/dist/lib/parser/declaration/list.js @@ -10,6 +10,9 @@ import { objectHash } from '../utils/hash.js'; import { equalsIgnoreCase } from '../utils/text.js'; const config = getConfig(); +/** + * Represents a list of property declarations, compute shorthand and remove duplicate declarations. + */ class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; @@ -84,28 +87,35 @@ class PropertyList { // @ts-ignore shorthand = config.property[propertyName]; } - // console.error({shortHandType, propertyName, config: config.map[propertyName], map: config.map[shorthand].properties[propertyName]}); // @ts-ignore if (shortHandType == "map") { let owner = this; + const mapName = // @ts-ignore - const mapName = config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; + config.map[propertyName]?.map ?? config.map[shorthand]?.properties?.[propertyName]?.map; if (typeof mapName === "string") { if (!this.declarations.has(mapName)) { // @ts-ignore this.declarations.set(mapName, new PropertyMap(config.map[mapName])); } owner = this.declarations.get(mapName); - // console.error({mapName}); } - // @ts-ignore - if (!owner.declarations.has(shorthand)) { + else if (!this.declarations.has(shorthand)) { // @ts-ignore - owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + this.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + if (owner == this) { + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); + } + else { + if (!owner.declarations.has(shorthand)) { + // @ts-ignore + owner.declarations.set(shorthand, new PropertyMap(config.map[shorthand])); + } + // @ts-ignore + owner.declarations.get(shorthand).add(declaration); } - // console.error({propertyName,mapName, owned: owner == this}); - // @ts-ignore - owner.declarations.get(shorthand).add(declaration); } // @ts-ignore else if (shortHandType == "set") { @@ -192,7 +202,7 @@ class PropertyList { [Symbol.iterator]() { let iterator = this.declarations.values(); const iterators = []; - // console.error(this); + // @ts-ignore return { next() { let value = iterator.next(); diff --git a/dist/lib/parser/declaration/map.js b/dist/lib/parser/declaration/map.js index 30978bc29..91749665c 100644 --- a/dist/lib/parser/declaration/map.js +++ b/dist/lib/parser/declaration/map.js @@ -10,8 +10,8 @@ import { cloneNode } from '../../ast/clone.js'; const propertiesConfig = getConfig(); class PropertyMap { - config; declarations; + config; requiredCount; pattern; constructor(config) { @@ -25,7 +25,7 @@ class PropertyMap { } add(declaration) { if (declaration.nam == this.config.shorthand) { - this.declarations = new Map(); + this.declarations.clear(); this.declarations.set(declaration.nam, declaration); this.matchTypes(declaration); } @@ -41,23 +41,17 @@ class PropertyMap { if (this.declarations.has(this.config.shorthand)) { const tokens = {}; const values = []; - // @ts-ignore - this.declarations - .get(this.config.shorthand) - // @ts-ignore - .val.slice() - .reduce((acc, curr) => { + const val = [[]]; + for (const curr of this.declarations.get(this.config.shorthand).val) { // @ts-ignore // @ts-ignore if (separator != null && separator.typ == curr.typ && separator.val == curr.val) { - acc.push([]); - return acc; + val.push([]); + continue; } // @ts-ignore - acc.at(-1).push(curr); - return acc; - }, [[]]) - // @ts-ignore - .reduce((acc, list, current) => { + val.at(-1).push(curr); + } + for (let current = 0; current < val.length; current++) { values.push(...this.pattern.reduce((acc, property) => { // let current: number = 0; const props = this.config.properties[property]; @@ -72,9 +66,7 @@ class PropertyMap { // @ts-ignore acc[i][PROPERTYNAME] == property || matchType(acc[i], props)) { - if ("prefix" in props && - props.previous != null && - !(props.previous in tokens)) { + if ("prefix" in props && props.previous != null && !(props.previous in tokens)) { return acc; } if (!(property in tokens)) { @@ -139,9 +131,8 @@ class PropertyMap { } } return acc; - }, list)); - return values; - }, []); + }, val[current])); + } if (values.length == 0) { this.declarations = Object.entries(tokens).reduce((acc, curr) => { acc.set(curr[0], { @@ -201,17 +192,40 @@ class PropertyMap { } if (hasMapping) { const mapped = {}; - for (const key of declarations.keys()) { - const value = declarations.get(key); + let key; + for (const value of declarations.values()) { + key = value.nam; if (value instanceof PropertyMap) { for (const [k, v] of value.declarations) { - mapped[k] = v; + if (k == value.config.shorthand) { + for (const [key, val] of Object.entries(value.config.properties)) { + mapped[key] = cloneNode(v); + for (let i = 0; i < v.val.length; i++) { + // @ts-ignore + if (key == v.val[i][PROPERTYNAME]) { + if (mapped[key].val.length > 0) { + mapped[key].val.push({ + typ: EnumToken.WhitespaceTokenType, + }); + } + mapped[key].val.push(v.val[i]); + } + } + if (mapped[key].val.length == 0) { + mapped[key].val.push(...parseString(value.config.properties[key].default[0])); + } + } + } + else { + mapped[k] = v; + } } } else { mapped[key] = value; } } + // console.error(mapped); if (patterns.length === Object.keys(mapped).length) { declarations = new Map(); for (const key of patterns) { @@ -667,8 +681,6 @@ class PropertyMap { } return acc; }, []); - // console.error({hasMapping, shorthand: this.config.shorthand, requiredCount, isShorthand, - // declarations: declarations.values(), values}); if (this.config.mapping != null) { const val = values.reduce((acc, curr) => acc + renderValue(curr, { @@ -705,6 +717,7 @@ class PropertyMap { } } const iterators = []; + // @ts-ignore return { // @ts-ignore next() { diff --git a/dist/lib/parser/parse.js b/dist/lib/parser/parse.js index ab1e48152..d4ed48bb7 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -475,6 +475,7 @@ function doParseSync(tokenizer, options = {}) { if (options.expandNestingRules) { options.nestingRules = false; } + options.minifyAST ??= options.minify; const startTime = performance.now(); const errors = []; const stack = []; @@ -854,7 +855,7 @@ function doParseSync(tokenizer, options = {}) { } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { @@ -1394,6 +1395,7 @@ async function doParse(iter, options = {}) { lenient: true, ...options, }; + options.minifyAST ??= options.minify; if (typeof options.validation !== "boolean") { options.validation = !!options.validation; } @@ -1848,7 +1850,7 @@ async function doParse(iter, options = {}) { } } } - if (options.minify) { + if (options.minifyAST) { if (ast.chi.length > 0) { let passes = options.pass ?? 1; while (passes--) { diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index 3f0a70ba8..3abc35c43 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -4,6 +4,7 @@ import { isWhiteSpace, isNewLine, isDigit, isLetter, isIdentStart, isIdentCodepo import { SourceFile } from './source.js'; const SymbolsMapTokens = Object.create(null); +const SymbolsMapTokensLower = Object.create(null); // Regex for escape sequence decoding - compile once, reuse many times const ESCAPE_SEQUENCE_REGEX = /\\((\n|\r|\f|\v|\u2028|\u2029|([0-9a-fA-F]{1,6})) ?)/gms; function decodeEscapeSequences(value) { @@ -32,7 +33,9 @@ function decodeEscapeSequences(value) { } function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { for (const entry of entries) { - SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + const key = (lowercase ? entry.toLowerCase() : entry) + suffix; + SymbolsMapTokens[key] = tokenType; + SymbolsMapTokensLower[key.toLowerCase()] = tokenType; } } SymbolsMapTokens[""] = EnumToken.DelimTokenType; @@ -132,20 +135,24 @@ var TokenMap; })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { const len = end - start; - const keysLength = SymbolsMapTokensKeys.length; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; + const value = parseInfo.stream.slice(start, end); + // Direct lookup handles the hottest punctuation and keyword cases without + // scanning the entire symbol table on every token. + const match = SymbolsMapTokens[value] ?? SymbolsMapTokensLower[value.toLowerCase()]; + if (match != null) { + return match; + } + const keysLength = SymbolsMapTokensKeys.length; for (let i = 0; i < keysLength; i++) { const key = SymbolsMapTokensKeys[i]; if (key.length !== len) continue; - // Match character by character let match = true; for (let j = 0; j < len; j++) { let ca = key.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let cb = value.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) @@ -163,32 +170,29 @@ function getSymbolHint(parseInfo, start, end) { } function searchArray(array, parseInfo, start, end) { const len = end - start; - // Early exit for impossible lengths - if (len < 0) + if (len <= 0) return null; - // Use a simple linear search optimized with length pre-filtering - let i = array.length; - while (i--) { - if (array[i].length !== len) + let match; + let item; + for (let i = 0; i < array.length; i++) { + item = array[i]; + if (item.length !== len) continue; - // Match character by character - let match = true; - const arrayItem = array[i]; + match = true; for (let j = 0; j < len; j++) { - let ca = arrayItem.charCodeAt(j); - let cb = parseInfo.stream.charCodeAt(start + j); - // Normalize A-Z to a-z + let ca = parseInfo.stream.charCodeAt(start + j); + let cb = item.charCodeAt(j); if (ca >= 65 && ca <= 90) ca += 32; if (cb >= 65 && cb <= 90) cb += 32; - if (ca != cb) { + if (ca !== cb) { match = false; break; } } if (match) { - return arrayItem; + return item; } } return null; @@ -1126,23 +1130,6 @@ class Tokenizer { } return true; } - /** - * - * @param parseInfo - * @returns - */ - // isPseudo(parseInfo: ParseInfo): boolean { - // let position: number = parseInfo.currentPosition - parseInfo.offset; - // let endPosition: number = parseInfo.currentPosition - parseInfo.offset; - // return (parseInfo.stream.charAt(position) == ":" && - // parseInfo.stream.charAt(endPosition - 1) == "(" && - // (parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2, -1) - // : this.isIdentToken(parseInfo, 1, -1))) || - // parseInfo.stream.charAt(position + 1) == ":" - // ? this.isIdentToken(parseInfo, 2) - // : this.isIdentToken(parseInfo, 1); - // } /** * * @param parseInfo @@ -1273,28 +1260,28 @@ class Tokenizer { // EOF switch (charCode) { case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); - if (isDigit(charCode)) { - tokensCount = this.consumeNumericToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { - slice: this.slice, - sign: "+", - }); - } - } + // if (isDigit(charCode)) { + // tokensCount = this.consumeNumericToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + // slice: this.slice, + // sign: "+", + // }); + // } + // } return this.makeToken(parseInfo, EnumToken.Plus); case 45 /* TokenMap.MINUS */: if (parseInfo.position == parseInfo.currentPosition) { @@ -1304,15 +1291,17 @@ class Tokenizer { this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.Sub); } - if (charCode == 45 /* TokenMap.MINUS */ && - (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.advance(parseInfo); - tokensCount = this.consumeIdentToken(parseInfo); - if (tokensCount > 0) { - this.advance(parseInfo, tokensCount); - return this.makeToken(parseInfo, EnumToken.IdenTokenType); - } - } + // if ( + // charCode == TokenMap.MINUS && + // (nextCharCode == TokenMap.MINUS || isIdentStart(nextCharCode)) + // ) { + // this.advance(parseInfo); + // tokensCount = this.consumeIdentToken(parseInfo); + // if (tokensCount > 0) { + // this.advance(parseInfo, tokensCount); + // return this.makeToken(parseInfo, EnumToken.IdenTokenType); + // } + // } } this.advance(parseInfo); break; @@ -1365,28 +1354,28 @@ class Tokenizer { return this.makeToken(parseInfo, EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); @@ -1418,15 +1407,15 @@ class Tokenizer { } return this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "$=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, EnumToken.EndMatchTokenType); @@ -1434,9 +1423,9 @@ class Tokenizer { this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "~=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); @@ -1445,9 +1434,9 @@ class Tokenizer { return this.makeToken(parseInfo, EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "^=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, EnumToken.StartMatchTokenType); @@ -1455,9 +1444,9 @@ class Tokenizer { this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, "*=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); @@ -1471,9 +1460,9 @@ class Tokenizer { this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } // '||' if (this.match(parseInfo, "||")) { this.advance(parseInfo, 2); @@ -1496,9 +1485,9 @@ class Tokenizer { this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (!this.match(parseInfo, "/*")) { this.advance(parseInfo); return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); @@ -1517,9 +1506,9 @@ class Tokenizer { } break; case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } if (this.match(parseInfo, ">=")) { this.advance(parseInfo, 2); return this.makeToken(parseInfo, EnumToken.GteTokenType); @@ -1558,20 +1547,11 @@ class Tokenizer { this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } this.advance(parseInfo); // EOF - if (!this.peek(parseInfo)) { - // if (!yieldEOFToken) { - // break; - // } - // end of stream ignore \\ - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } - break; + // end of stream ignore \\ + if (!this.peek(parseInfo) && parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } this.advance(parseInfo); break; @@ -1584,9 +1564,9 @@ class Tokenizer { case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - if (parseInfo.position < parseInfo.currentPosition) { - return this.makeToken(parseInfo); - } + // if (parseInfo.position < parseInfo.currentPosition) { + // return this.makeToken(parseInfo); + // } this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { @@ -1594,27 +1574,22 @@ class Tokenizer { return this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); } } - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - this.makeToken(parseInfo); - this.advance(parseInfo, 2); - return this; - } + // if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + // this.makeToken(parseInfo); + // this.advance(parseInfo, 2); + // return this; + // } this.advance(parseInfo); break; default: this.advance(parseInfo); break; } - // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - // break; - // } } - // if (yieldEOFToken) { if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo); } return this.makeToken(parseInfo, EnumToken.EOFTokenType); - // } } /** * tokenize readable stream diff --git a/dist/lib/printer/render.js b/dist/lib/printer/render.js index cfa4dc5a5..75c27a5e7 100644 --- a/dist/lib/printer/render.js +++ b/dist/lib/printer/render.js @@ -42,6 +42,7 @@ function doRender(data, options = {}, mapping) { removeEmpty: false, removeComments: false, }), + minifyValues: true, sourcemap: false, convertColor: true, expandNestingRules: false, @@ -281,7 +282,7 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro const indentSub = indents[level + 1]; switch (data.typ) { case EnumToken.DeclarationNodeType: - return `${data.nam}:${options.indent}${(options.minify + return `${data.nam}:${options.indent}${(options.minifyValues ? filterValues(data.val) : data.val).reduce(reducer, "")}`; case EnumToken.CommentNodeType: @@ -336,7 +337,7 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro : node.val; } else if (node.typ == EnumToken.DeclarationNodeType) { - str = `${node.nam}:${options.indent}${(options.minify + str = `${node.nam}:${options.indent}${(options.minifyValues ? filterValues(node.val) : node.val) .reduce(reducer, "") @@ -404,9 +405,10 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro function renderValue(token, options = {}, cache = Object.create(null), reducer, errors) { if (token.typ === EnumToken.WhenElseFunctionTokenType && equalsIgnoreCase(token.val, "supports")) { - options = { ...options, minify: false, convertColor: false }; + options = { ...options, minifyValues: false, minify: false, convertColor: false }; reducer = null; } + options.minifyValues ??= options.minify; if (reducer == null) { reducer = function (acc, curr) { if (curr.typ == EnumToken.CommentTokenType && options.removeComments) { @@ -563,7 +565,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, ")"); } case EnumToken.UrlFunctionTokenType: - if (options.minify && token.typ === EnumToken.UrlFunctionTokenType) { + if (options.minifyValues && token.typ === EnumToken.UrlFunctionTokenType) { if (token.chi[0]?.typ === EnumToken.BadUrlTokenType) { return "url()"; } @@ -584,7 +586,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, case EnumToken.FunctionTokenType: case EnumToken.MathFunctionTokenType: case EnumToken.ImageFunctionTokenType: - if (options.minify && token.typ === EnumToken.ImageFunctionTokenType) { + if (options.minifyValues && token.typ === EnumToken.ImageFunctionTokenType) { const slice = token.chi.slice(); switch (token.val) { case "linear-gradient": @@ -1070,37 +1072,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, renderValue(curr, token.typ == EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + ")"); } - return ( - /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + - "(" + - token.chi.reduce(reducer, "") + - ")"); - // case EnumToken.MatchExpressionTokenType: - // return ( - // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + - // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") - // ); - // case EnumToken.NameSpaceAttributeTokenType: - // return ( - // ((token as NameSpaceAttributeToken).l == null - // ? "" - // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + - // "|" + - // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) - // ); - // case EnumToken.ComposesSelectorNodeType: - // return ( - // (token as ComposesSelectorToken).l.reduce( - // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), - // "", - // ) + - // ((token as ComposesSelectorToken).r == null - // ? "" - // : " from " + - // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) - // ); + return (token.val ?? "") + "(" + token.chi.reduce(reducer, "") + ")"; case EnumToken.BlockStartTokenType: return "{"; case EnumToken.BlockEndTokenType: @@ -1249,7 +1221,11 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, const perc = token.val.typ == EnumToken.FractionTokenType ? renderValue(token.val, options, cache) : minifyNumber(token.val); - return options.minify && perc == "0" ? "0" : perc.includes("/") ? perc.replace("/", uni + "/") : perc + uni; + return options.minifyValues && perc == "0" + ? "0" + : perc.includes("/") + ? perc.replace("/", uni + "/") + : perc + uni; case EnumToken.NumberTokenType: return token.val.typ == EnumToken.FractionTokenType ? renderValue(token.val, options, cache) @@ -1314,7 +1290,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, case EnumToken.DeclarationNodeType: return (token.nam + ":" + - (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + (options.minifyValues ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); case EnumToken.MediaQueryUnaryFeatureTokenType: return (renderValue(token.l, options, cache, reducer) + " " + diff --git a/dist/lib/syntax/color/a98rgb.js b/dist/lib/syntax/color/a98rgb.js index 87fd4de9d..1b5ada0af 100644 --- a/dist/lib/syntax/color/a98rgb.js +++ b/dist/lib/syntax/color/a98rgb.js @@ -37,7 +37,7 @@ function la98rgb2a98rgb(r, g, b, a = null) { // convert an array of linear-light a98-rgb in the range 0.0-1.0 // to gamma corrected form // negative values are also now accepted - return [r, b, g] + return [r, g, b] .map(function (val) { let sign = val < 0 ? -1 : 1; let abs = Math.abs(val); diff --git a/dist/lib/syntax/color/alpha.js b/dist/lib/syntax/color/alpha.js index 1f667d317..d85237b70 100644 --- a/dist/lib/syntax/color/alpha.js +++ b/dist/lib/syntax/color/alpha.js @@ -24,7 +24,6 @@ function alpha(color, alpha) { } let components = getColorComponents(color); if (alpha.typ === EnumToken.MathFunctionTokenType) { - const originalAlpha = cloneNode(alpha, true); for (const { value } of walkValues(alpha.chi, alpha)) { if (value.typ === EnumToken.IdenTokenType) { if (equalsIgnoreCase(value.val, "alpha")) { @@ -36,22 +35,22 @@ function alpha(color, alpha) { }); // continue; } - else if (equalsIgnoreCase(value.val, "none")) { - Object.assign(value, { - typ: EnumToken.NumberTokenType, - val: 0, - }); - } + // else if (equalsIgnoreCase((value as IdentToken).val, "none")) { + // Object.assign(value, { + // typ: EnumToken.NumberTokenType, + // val: 0, + // }); + // } } } const result = evaluate([alpha]); if (result.length == 1) { alpha = result[0]; } - else { - // @ts-expect-error - alpha = originalAlpha; - } + // else { + // // @ts-expect-error + // alpha = originalAlpha; + // } } // console.error({ alpha }); if (alpha.typ !== EnumToken.IdenTokenType && @@ -77,17 +76,17 @@ function alpha(color, alpha) { return null; } if (alpha?.typ === EnumToken.IdenTokenType) { - if (equalsIgnoreCase(alpha.val, "alpha")) { - alpha = components[3] ?? { - typ: EnumToken.NumberTokenType, - val: 1, - }; - } - else if (equalsIgnoreCase(alpha.val, "node")) { - alpha = { + // if (equalsIgnoreCase((alpha as IdentToken).val, "alpha")) { + // alpha = components[3] ?? { + // typ: EnumToken.NumberTokenType, + // val: 1, + // }; + // } else + if (equalsIgnoreCase(alpha.val, "none")) { + Object.assign(alpha, { typ: EnumToken.NumberTokenType, val: 0, - }; + }); } } return makeColor(color.kin, components, alpha); diff --git a/dist/lib/syntax/color/color-mix.js b/dist/lib/syntax/color/color-mix.js index 2478e5fcc..24febd95f 100644 --- a/dist/lib/syntax/color/color-mix.js +++ b/dist/lib/syntax/color/color-mix.js @@ -2,9 +2,7 @@ import { EnumToken, ColorType } from '../../ast/types.js'; import { minmax, getNumber } from './color.js'; import { srgbvalues, srgb2lsrgbvalues } from './srgb.js'; import { srgb2lch, xyz2lchvalues } from './lch.js'; -import { srgb2rgb } from './rgb.js'; import { srgb2hslvalues } from './hsl.js'; -import { srgb2hwb } from './hwb.js'; import { srgb2labvalues } from './lab.js'; import { srgb2lp3values, srgb2p3values } from './p3.js'; import { getColorComponents } from './utils/components.js'; @@ -121,6 +119,9 @@ function colorMix(...args) { if (values == null) { return null; } + if (colorSpace == "hwb") { + colorSpace = "srgb"; + } switch (colorSpace) { case "srgb": break; @@ -150,17 +151,17 @@ function colorMix(...args) { values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); break; - case "rgb": - for (let j = 0; j < values.length; j++) { - values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); - } - break; + // case "rgb": + // for (let j = 0; j < values.length; j++) { + // values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + // } + // break; case "hsl": values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; - case "hwb": - values = srgb2hwb(values[0], values[1], values[2], values[3]); - break; + // case "hwb": + // values = srgb2hwb(values[0], values[1], values[2], values[3]); + // break; case "lab": values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; @@ -359,14 +360,14 @@ function colorMix(...args) { kin: ColorType.COLOR, cal: "col", }; - case "rgb": + // case "rgb": case "hsl": - case "hwb": + // case "hwb": case "lab": case "lch": case "oklab": case "oklch": - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore if (values[2] < 0) { // @ts-ignore @@ -396,7 +397,7 @@ function colorMix(...args) { }), kin: ColorType[colorSpace.toUpperCase().replaceAll("-", "_")], }; - if (colorSpace == "hsl" || colorSpace == "hwb") { + if (colorSpace == "hsl") { // @ts-ignore result.chi[0] = { typ: EnumToken.AngleTokenType, val: result.chi[0].val * 360 }; // @ts-ignore diff --git a/dist/lib/syntax/color/hex.js b/dist/lib/syntax/color/hex.js index c21026b67..6fdc2bc42 100644 --- a/dist/lib/syntax/color/hex.js +++ b/dist/lib/syntax/color/hex.js @@ -70,7 +70,10 @@ function color2HexToken(token) { if (value == null) { return null; } - return hexToken(value.reduce((acc, curr) => acc + srgb2rgb(curr + Number.EPSILON).toString(16).padStart(2, "0"), "#")); + return hexToken(value.reduce((acc, curr) => acc + + srgb2rgb(curr + Number.EPSILON) + .toString(16) + .padStart(2, "0"), "#")); } function oklab2HexToken(token) { let value = oklab2srgbvalues(token); diff --git a/dist/lib/syntax/color/relative-color.js b/dist/lib/syntax/color/relative-color.js index 68e56a13d..b5b915146 100644 --- a/dist/lib/syntax/color/relative-color.js +++ b/dist/lib/syntax/color/relative-color.js @@ -44,20 +44,20 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, continue; } if (component.typ == EnumToken.IdenTokenType) { - val = component.val.toLowerCase(); + val = component.val; if ( // @ts-expect-error typeof Math[val.toUpperCase()] !== "number" && - val != "in" && - val != "hue" && - val != "from" && - val != "alpha" && - val != "none" && - val != "shorter" && - val != "longer" && - val != "increasing" && - val != "decreasing" && - !colorsFunc.includes(val) && + !equalsIgnoreCase(val, "in") && + !equalsIgnoreCase(val, "hue") && + !equalsIgnoreCase(val, "from") && + !equalsIgnoreCase(val, "alpha") && + !equalsIgnoreCase(val, "none") && + !equalsIgnoreCase(val, "shorter") && + !equalsIgnoreCase(val, "longer") && + !equalsIgnoreCase(val, "increasing") && + !equalsIgnoreCase(val, "decreasing") && + !colorsFunc.some((t) => equalsIgnoreCase(t, val)) && !colorFuncColorSpace.includes(val) && !validKeys.includes(val)) { return null; diff --git a/dist/lib/syntax/color/utils/components.js b/dist/lib/syntax/color/utils/components.js index 559d04785..2cd077053 100644 --- a/dist/lib/syntax/color/utils/components.js +++ b/dist/lib/syntax/color/utils/components.js @@ -4,13 +4,6 @@ import { expandHexValue } from '../hex.js'; import { equalsIgnoreCase } from '../../../parser/utils/text.js'; function getColorComponents(token) { - // if (token.typ === EnumToken.IdenTokenType) { - // if (isColor(token)) { - // parseColor(token); - // } else { - // return null; - // } - // } if (token.kin == ColorType.HEX || token.kin == ColorType.LIT) { if (equalsIgnoreCase("currentcolor", token.val)) { return null; @@ -34,25 +27,12 @@ function getColorComponents(token) { ].includes(child.typ)) { continue; } - // if (child.typ === EnumToken.IdenTokenType && isColor(child)) { - // parseColor(child); - // } if (child.typ === EnumToken.FunctionTokenType || child.typ === EnumToken.WildCardFunctionTokenType || child.typ === EnumToken.MathFunctionTokenType) { if ("var" == child.val.toLowerCase()) { return null; } - // else { - // for (const { value } of walkValues((child as FunctionToken).chi)) { - // if ( - // value.typ == EnumToken.WildCardFunctionTokenDefType && - // "var" === (value as FunctionToken).val.toLowerCase() - // ) { - // return null; - // } - // } - // } } if (child.typ == EnumToken.ColorTokenType && equalsIgnoreCase("currentcolor", child.val)) { return null; diff --git a/dist/lib/syntax/constants.js b/dist/lib/syntax/constants.js index 3297b2c0d..e92ac312b 100644 --- a/dist/lib/syntax/constants.js +++ b/dist/lib/syntax/constants.js @@ -67,6 +67,11 @@ const anglePrecision = 3; * Color range definitions */ const colorRange = { + rgb: { + r: [0, 255], + g: [0, 255], + b: [0, 255], + }, lab: { l: [0, 100], a: [-125, 125], diff --git a/dist/lib/syntax/syntax.js b/dist/lib/syntax/syntax.js index e44ba17e3..4690cf7ce 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -16,12 +16,12 @@ import { getSyntaxConfig } from '../validation/config.js'; // '\\' const REVERSE_SOLIDUS = 0x5c; const flexUnits = ["fr"]; -const frequencyUnits = ["hz", "khz"]; +const frequencyUnits = ["Hz", "kHz"]; const timeUnits = ["ms", "s"]; const angleUnits = ["rad", "turn", "deg", "grad"]; const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; const dimensionUnits = [ - "q", + "Q", "cap", "ch", "cm", diff --git a/dist/lib/validation/match.js b/dist/lib/validation/match.js index f865e4bf9..3ee9a31e4 100644 --- a/dist/lib/validation/match.js +++ b/dist/lib/validation/match.js @@ -643,7 +643,8 @@ function matchAllSyntaxes(syntaxes, context, options) { for (let i = index; i < syntaxes.length; i++) { if (syntaxes[i].typ == ValidationTokenEnum.Whitespace || syntaxes[i].isOptional || - syntaxes[i].isRepeatable) { + syntaxes[i].isRepeatable || + syntaxes[i].match?.min?.val === 0) { continue; } return { diff --git a/dist/web.js b/dist/web.js index f7e55bf76..e3e3363d2 100644 --- a/dist/web.js +++ b/dist/web.js @@ -17,6 +17,7 @@ export { isOkLabClose, okLabDistance } from './lib/syntax/color/utils/distance.j export { find, findAll, findByValue, findLast } from './lib/ast/find.js'; export { cloneNode } from './lib/ast/clone.js'; export { replaceNodeOrValue } from './lib/parser/utils/token.js'; +export { PropertyList } from './lib/parser/declaration/list.js'; export { SourceMap } from './lib/printer/sourcemap/sourcemap.js'; export { FeatureWalkMode } from './lib/ast/features/type.js'; export { getNodeProperty, setNodeProperty } from './lib/ast/node.js'; diff --git a/files/architecture.md b/files/architecture.md new file mode 100644 index 000000000..4ea848bcd --- /dev/null +++ b/files/architecture.md @@ -0,0 +1,69 @@ +--- +title: Architecture +group: Documents +category: Guides +--- + +# CSS parser architecture + +```mermaid +flowchart TD + %% --- Transform --- + Input(["CSS input"]) + + + %% The Grouped Container + subgraph Group10["Transform step"] + + transform["transform()/transformSync()"] + + + %% The Grouped Container + subgraph Group1 ["Parse step"] + + %% --- Parse step --- + parse["parse()/parseSync()"] + tokenize(["tokenize()"]) + parseNode(["parse and validate token stream"]) + visitors(["visitors"]) + minify(["minify AST"]) + cssModules(["generate CSS module"]) + parseResult["Parse result"] + end + + %% The Grouped Container + subgraph Group2 ["Render step"] + + %% --- Render step --- + renderAst(["Render AST"]) + sourcemap([Sourcemap generation]) + + end + + %% --- Result step --- + transformResult["Transform result"] + end + + %% --- Routing step --- + Input --> transform + transform --> parse + parse --> tokenize + tokenize --> parseNode + parseNode -- "Visitors set?" --> visitors + visitors -- "Minify AST?" --> minify + minify -- "CSS module?" --> cssModules + visitors -- "CSS module?" --> cssModules + cssModules --> parseResult + parseNode -- "CSS module?" --> cssModules + parseNode -- "Minify AST?" --> minify + parseNode --> parseResult + visitors --> parseResult + minify --> parseResult + parseResult --> renderAst + renderAst -- "Sourcemap?" --> sourcemap + renderAst --> transformResult + sourcemap --> transformResult +``` +------ +[← Usage](./usage.md) | [Validation →](./Guide.Validation.html) + diff --git a/files/assets/typedoc-custom.css b/files/assets/typedoc-custom.css index 2cb11e7ad..6c2a8a9ab 100644 --- a/files/assets/typedoc-custom.css +++ b/files/assets/typedoc-custom.css @@ -74,26 +74,54 @@ html[data-theme="dark"] { } } } + + table { + border-collapse: collapse; + margin-bottom: 15px; + + tr { + border-bottom: 1px solid #f0f0f0; + + th { + font-weight: 400; + } + + th, + td { + padding-bottom: 5px; + padding-top: 5px; + text-align: left; + } + } + + thead th { + text-align: left; + } + + tbody { + tr { + &:hover { + background-color: var(--transparent-blue) !important; + color: var(--blue-dark) !important; + } + } + td { + text-align: left; + } + } + } } } } -#main-function-differences ~ table tbody tr { - &:hover { - background-color: var(--transparent-blue) !important; - color: var(--blue-dark) !important; - } +#css-parser-architecture ~ .mermaid-block .mermaid { + min-height: 1745px; - td { - &:first-child { - text-align: left; - } - - text-align: center; + svg { + min-height: 1740px; } } - .tsd-kind-icon { - width: 16px; -} \ No newline at end of file + width: 16px; +} diff --git a/files/getting-started.md b/files/getting-started.md index 564ff7e4f..df6ac0b1e 100644 --- a/files/getting-started.md +++ b/files/getting-started.md @@ -62,7 +62,7 @@ It can be imported as an umd module. ```html + +