diff --git a/.npmignore b/.npmignore index 644183ba..004919b9 100644 --- a/.npmignore +++ b/.npmignore @@ -11,6 +11,7 @@ /tsconfig.json /src /.idea +/llms.txt /package-lock.json /node_modules /coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index cf61c73f..5d676788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +# v1.6.0 + +- [x] added support for math function `tan()`. + +## Improvements +- [x] faster tokenizer +- [x] ensure transform: rotate(360deg) is not minified to transform: none +- [x] support input sourcemap from inline sourcemap file. This is only supported by the async parser. + +```css + +table.colortable { + width: 100%; + text-shadow: none; + border-collapse: collapse +} +table.colortable td { + text-align: center +} +table.colortable td.c { + text-transform: uppercase; + background: #ff0 +} +table.colortable th { + text-align: center; + color: green; + font-weight: 400; + padding: 2px 3px +} + +/*# sourceMappingURL=sourcemap.css.map */ +``` + # v1.5.0 ## Improvements diff --git a/README.md b/README.md index 660514be..673fc0ee 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,11 @@ Try it [online](https://tbela99.github.io/css-parser/playground/) - typ: number - val: string, the comment +### AtRuleStyleSheet + +- typ: number +- chi: array of children + ### Declaration - typ: number @@ -115,7 +120,7 @@ Try it [online](https://tbela99.github.io/css-parser/playground/) - state: EnumAstNodeStatus, validation state - errors: ErrorDescription[], validation errors -### AtRule +### AtRule and KeyframesAtRule - typ: number - nam: string. AtRule name @@ -123,12 +128,7 @@ Try it [online](https://tbela99.github.io/css-parser/playground/) - state: EnumAstNodeStatus, validation state - errors: ErrorDescription[], validation errors -### AtRuleStyleSheet - -- typ: number -- chi: array of children - -### KeyFrameRule +### KeyframesRule - typ: number - sel: string, css selector diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 08381ca2..28299453 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -2799,6 +2799,9 @@ "text-emphasis-style": { syntax: "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | " }, + "text-fit": { + syntax: "[ none | grow | shrink ] [consistent | per-line | per-line-all]? ?" + }, "text-indent": { syntax: " && hanging? && each-line?" }, @@ -6339,6 +6342,15 @@ mediaFeatures: mediaFeatures }; + /** + * Location source id + */ + const LOCSRCID = Symbol.for("locSrcId"); + const LOCSTA = Symbol.for("locSta"); + const LOCEND = Symbol.for("locEnd"); + /** + * Used by the validation parser + */ const LOC = Symbol.for("loc"); const RAW = Symbol.for("raw"); const STATE = Symbol.for("state"); @@ -6391,7 +6403,7 @@ /** * Angle precision */ - const anglePrecision = 0.001; + const anglePrecision = 3; /** * Color range definitions */ @@ -6447,6 +6459,7 @@ "acos", "atan", "atan2", + "tan", "pow", "sqrt", "hypot", @@ -6831,9 +6844,11 @@ function equalsIgnoreCase(a, b) { if (a.length !== b.length) return false; + let ca; + let cb; for (let i = 0; i < a.length; i++) { - let ca = a.charCodeAt(i); - let cb = b.charCodeAt(i); + ca = a.charCodeAt(i); + cb = b.charCodeAt(i); // Normalize A-Z to a-z if (ca >= 65 && ca <= 90) ca += 32; @@ -7025,41 +7040,41 @@ function hex2lchvalues(token) { const values = hex2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2lchvalues(token) { const values = rgb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2lchvalues(token) { const values = hsl2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2lchvalues(token) { const values = hwb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lab2lchvalues(token) { const values = getLABComponents(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2lch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2labvalues(r, g, blue, alpha)); + let values = srgb2labvalues(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2lchvalues(token) { const values = oklab2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2lchvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2lch(...values); + return values == null ? null : srgb2lch(values[0], values[1], values[2], values[3]); } function oklch2lchvalues(token) { const values = oklch2labvalues(token); @@ -7067,7 +7082,7 @@ return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function color2lchvalues(token) { const values = color2srgbvalues(token); @@ -7075,7 +7090,7 @@ return null; } // @ts-ignore - return srgb2lch(...values); + return srgb2lch(values[0], values[1], values[2], values[3]); } function labvalues2lchvalues(l, a, b, alpha = null) { let c = Math.sqrt(a * a + b * b); @@ -7089,8 +7104,8 @@ return alpha == null ? [l, c, h] : [l, c, h, alpha]; } function xyz2lchvalues(x, y, z, alpha) { - // @ts-ignore( - const lch = labvalues2lchvalues(...xyz2lab(x, y, z)); + const values = xyz2lab(x, y, z); + const lch = labvalues2lchvalues(values[0], values[1], values[2]); return alpha == null || alpha == 1 ? lch : lch.concat(alpha); } function getLCHComponents(token) { @@ -7130,8 +7145,8 @@ /* */ function xyzd502lch(x, y, z, alpha) { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + const values = XYZ_D50_to_D65(x, y, z); + const [l, a, b] = xyz2lab(values[0], values[1], values[2]); // L in range [0,100]. For use in CSS, add a percent return labvalues2lchvalues(l, a, b, alpha); } @@ -7199,8 +7214,8 @@ // xyz d50 function srgb2xyz_d65(r, g, b, alpha) { // xyx d65 - // @ts-ignore - let rgb = XYZ_D65_to_D50(...srgb2xyz(r, g, b)); + let values = srgb2xyz(r, g, b); + let rgb = XYZ_D65_to_D50(values[0], values[1], values[2]); if (alpha != null && alpha != 1) { rgb.push(alpha); } @@ -7209,7 +7224,7 @@ function hex2oklchToken(token) { const values = hex2oklchvalues(token); - return oklchToken(values); + return values == null ? null : oklchToken(values); } function rgb2oklchToken(token) { const values = rgb2oklchvalues(token); @@ -7265,8 +7280,7 @@ if (values == null) { return null; } - // @ts-ignore - return oklchToken(srgb2oklch(...values)); + return oklchToken(srgb2oklch(values[0], values[1], values[2], values[3])); } function oklchToken(values) { values[2] = values[2]; @@ -7289,29 +7303,27 @@ }; } function hex2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hex2oklabvalues(token)); + const values = hex2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2oklchvalues(token) { const values = rgb2oklabvalues(token); if (values == null) { return null; } - // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hsl2oklabvalues(token)); + const values = hsl2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hwb2oklabvalues(token)); + const values = hwb2oklabvalues(token); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2oklchvalues(token) { const values = cmyk2srgbvalues(token); - // @ts-ignore - return values == null ? null : srgb2oklch(...values); + return values == null ? null : srgb2oklch(values[0], values[1], values[2], values[3]); } function lab2oklchvalues(token) { const values = lab2oklabvalues(token); @@ -7319,7 +7331,7 @@ return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lch2oklchvalues(token) { const values = lch2oklabvalues(token); @@ -7327,7 +7339,7 @@ return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2oklchvalues(token) { const values = getOKLABComponents(token); @@ -7335,11 +7347,11 @@ return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2oklch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2oklab(r, g, blue, alpha)); + const values = srgb2oklab(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function getOKLCHComponents(token) { const components = getColorComponents(token); @@ -7463,15 +7475,14 @@ return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function rgb2oklabvalues(token) { const values = rgb2srgb(token); if (values == null) { return null; } - // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hsl2oklabvalues(token) { const values = hsl2srgb(token); @@ -7479,16 +7490,16 @@ return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hwb2oklabvalues(token) { - // @ts-ignore - return srgb2oklab(...hwb2srgbvalues(token)); + const values = hwb2srgbvalues(token); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function cmyk2oklabvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function lab2oklabvalues(token) { const values = lab2srgbvalues(token); @@ -7496,22 +7507,22 @@ return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function lch2oklabvalues(token) { const values = lch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function oklch2oklabvalues(token) { const values = getOKLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function color2oklabvalues(token) { const values = color2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function srgb2oklab(r, g, blue, alpha) { [r, g, blue] = srgb2lsrgbvalues(r, g, blue); @@ -7666,19 +7677,19 @@ // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 function hex2labvalues(token) { - const values = hex2srgbvalues(token); + let values = hex2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function rgb2labvalues(token) { const values = rgb2srgb(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function cmyk2labvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function hsl2labvalues(token) { const values = hsl2srgb(token); @@ -7686,7 +7697,7 @@ return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function hwb2labvalues(token) { const values = hwb2srgbvalues(token); @@ -7694,20 +7705,21 @@ return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function lch2labvalues(token) { const values = getLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function oklab2labvalues(token) { - const values = getOKLABComponents(token); + let values = getOKLABComponents(token); if (values == null) { return null; } - // @ts-ignore - return xyz2lab(...XYZ_D65_to_D50(...OKLab_to_XYZ(...values))); + values = OKLab_to_XYZ(values[0], values[1], values[2], values[3]); + values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); + return xyz2lab(values[0], values[1], values[2], values[3]); } function oklch2labvalues(token) { const values = oklch2srgbvalues(token); @@ -7715,19 +7727,18 @@ return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function color2labvalues(token) { const val = color2srgbvalues(token); if (val == null) { return null; } - // @ts-ignore - return srgb2labvalues(...val); + return srgb2labvalues(val[0], val[1], val[2], val[3]); } function srgb2labvalues(r, g, b, a) { - // @ts-ignore */ - const result = xyz2lab(...srgb2xyz_d65(r, g, b)); + let result = srgb2xyz_d65(r, g, b); + result = xyz2lab(result[0], result[1], result[2]); // Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors // and approximated computations in sRGB <-> CIELab. // See: https://github.com/d3/d3-color/pull/46 @@ -7809,9 +7820,9 @@ function Lab_to_sRGB(l, a, b) { const xyz_d50 = Lab_to_XYZ(l, a, b); // @ts-ignore - const xyz_d65 = XYZ_D50_to_D65(...xyz_d50); + const xyz_d65 = XYZ_D50_to_D65(xyz_d50[0], xyz_d50[1], xyz_d50[2]); // @ts-ignore - return xyz2srgb(...xyz_d65); + return xyz2srgb(xyz_d65[0], xyz_d65[1], xyz_d65[2]); } // from https://www.w3.org/TR/css-color-4/#color-conversion-code function Lab_to_XYZ(l, a, b) { @@ -7893,8 +7904,9 @@ } // xyz d65 input function xyz2srgb(x, y, z, alpha = null) { + let values = XYZ_to_lin_sRGB(x, y, z); // @ts-ignore - return lsrgb2srgbvalues(...XYZ_to_lin_sRGB(x, y, z, alpha)); + return lsrgb2srgbvalues(values[0], values[1], values[2], alpha); } function hwb2srgbvalues(token) { const { h: hue, s: white, l: black, a: alpha } = hslvalues(token) ?? {}; @@ -7965,8 +7977,8 @@ if (l == null || c == null || h == null) { return null; } - // @ts-ignore - const rgb = OKLab_to_sRGB(...lchvalues2labvalues(l, c, h)); + const values = lchvalues2labvalues(l, c, h); + const rgb = OKLab_to_sRGB(values[0], values[1], values[2]); if (alpha != 1) { rgb.push(alpha); } @@ -8067,7 +8079,7 @@ return null; } // @ts-ignore - const [l, a, b, alpha] = lchvalues2labvalues(...components); + const [l, a, b, alpha] = lchvalues2labvalues(components[0], components[1], components[2], components[3]); if (l == null || a == null || b == null) { return null; } @@ -8437,8 +8449,11 @@ } function hex2HslToken(token) { - // @ts-ignore - return hslToken(srgb2hslvalues(...hex2srgbvalues(token))); + let values = hex2srgbvalues(token); + if (values == null) { + return null; + } + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function rgb2HslToken(token) { const values = rgb2hslvalues(token); @@ -8494,8 +8509,7 @@ if (values == null) { return null; } - // @ts-ignore - return hslToken(srgb2hslvalues(...values)); + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function hslToken(values) { values[0] = values[0] * 360; @@ -8543,8 +8557,7 @@ if (a != null && a != 1) { values.push(a); } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } // https://gist.github.com/defims/0ca2ef8832833186ed396a2f8a204117#file-annotated-js function hsv2hsl(h, s, v, a) { @@ -8566,20 +8579,19 @@ } function cmyk2hslvalues(token) { const values = cmyk2rgbvalues(token); - // @ts-ignore - return values == null ? null : rgbvalues2hslvalues(...values); + return values == null ? null : rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function hwb2hslvalues(token) { - // @ts-ignore - return hsv2hsl(...hwb2hsv(...Object.values(hslvalues(token)))); + const hsla = hslvalues(token); + const hwba = hwb2hsv(hsla.h, hsla.s, hsla.l, hsla.a); + return hsv2hsl(hwba[0], hwba[1], hwba[2], hwba[3]); } function lab2hslvalues(token) { const values = lab2rgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function lch2hslvalues(token) { const values = lch2rgbvalues(token); @@ -8587,17 +8599,17 @@ return null; } // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function oklab2hslvalues(token) { const t = oklab2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function oklch2hslvalues(token) { const t = oklch2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function rgbvalues2hslvalues(r, g, b, a = null) { return srgb2hslvalues(r / 255, g / 255, b / 255, a); @@ -8699,7 +8711,7 @@ if (values.length == 4) { chi.push({ typ: exports.EnumToken.LiteralTokenType, val: "/" }, { typ: exports.EnumToken.PercentageTokenType, - val: values[3] * 100 + val: values[3] * 100, }); } return { @@ -8710,21 +8722,21 @@ }; } function rgb2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3) { return getNumber(t); } return getNumber(t) / 255; - })); + }); + // @ts-ignore + return srgb2hwb(values[0], values[1], values[2], values[3]); } function cmyk2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...cmyk2srgbvalues(token)); + const values = cmyk2srgbvalues(token); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function hsl2hwbvalues(token) { - // @ts-ignore - return hslvalues2hwbvalues(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3 && t.typ == exports.EnumToken.IdenTokenType && t.val == "none") { return 1; } @@ -8732,23 +8744,23 @@ return getAngle(t); } return getNumber(t); - })); + }); + // @ts-ignore + return hslvalues2hwbvalues(values[0], values[1], values[2], values[3]); } function lab2hwbvalues(token) { const values = lab2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function lch2hwbvalues(token) { const values = lch2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklab2hwbvalues(token) { const values = oklab2srgbvalues(token); @@ -8756,12 +8768,12 @@ return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklch2hwbvalues(token) { const values = oklch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2hwb(...values); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function rgb2hue(r, g, b, fallback = 0) { let value = rgb2value(r, g, b); @@ -8789,7 +8801,7 @@ return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function srgb2hwb(r, g, b, a = null, fallback = 0) { r *= 100; @@ -8813,69 +8825,72 @@ return result; } function hslvalues2hwbvalues(h, s, l, a = null) { + let values = hsl2hsv(h, s, l); // @ts-ignore - return hsv2hwb(...hsl2hsv(h, s, l, a)); + return hsv2hwb(values[0], values[1], values[2], a); } function prophotorgb2srgbvalues(r, g, b, a = null) { + let values = prophotorgb2xyz50(r, g, b); // @ts-ignore - return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); + return xyzd502srgb(values[0], values[1], values[2], a); } function srgb2prophotorgbvalues(r, g, b, a) { - // @ts-ignore - return xyz50_to_prophotorgb(...XYZ_D65_to_D50(...srgb2xyz(r, g, b, a))); + let values = srgb2xyz(r, g, b); + values = XYZ_D65_to_D50(values[0], values[1], values[2]); + values = xyz50_to_prophotorgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; } function prophotorgb2lin_ProPhoto(r, g, b, a = null) { - return [r, g, b].map(v => { + return [r, g, b] + .map((v) => { let abs = Math.abs(v); if (abs >= 16 / 512) { return Math.sign(v) * Math.pow(abs, 1.8); } return v / 16; - }).concat(a == null || a == 1 ? [] : [a]); + }) + .concat(a == null || a == 1 ? [] : [a]); } function prophotorgb2xyz50(r, g, b, a = null) { [r, g, b, a] = prophotorgb2lin_ProPhoto(r, g, b, a); const xyz = [ - 0.7977666449006423 * r + - 0.1351812974005331 * g + - 0.0313477341283922 * b, - 0.2880748288194013 * r + - 0.7118352342418731 * g + - 0.0000899369387256 * b, - 0.8251046025104602 * b + 0.7977666449006423 * r + 0.1351812974005331 * g + 0.0313477341283922 * b, + 0.2880748288194013 * r + 0.7118352342418731 * g + 0.0000899369387256 * b, + 0.8251046025104602 * b, ]; return xyz.concat(a == null || a == 1 ? [] : [a]); } function xyz50_to_prophotorgb(x, y, z, a) { // @ts-ignore - return gam_prophotorgb(...[ - x * 1.3457868816471585 - - y * 0.2555720873797946 - - 0.0511018649755453 * z, - x * -0.5446307051249019 + - y * 1.5082477428451466 + - 0.0205274474364214 * z, - 1.2119675456389452 * z - ].concat(a == null || a == 1 ? [] : [a])); + return gam_prophotorgb(x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z, x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z, 1.2119675456389452 * z); + } + function gam_prophotorgbvalue(v) { + let abs = Math.abs(v); + if (abs >= 1 / 512) { + return Math.sign(v) * Math.pow(abs, 1 / 1.8); + } + return 16 * v; } function gam_prophotorgb(r, g, b, a) { - return [r, g, b].map(v => { - let abs = Math.abs(v); - if (abs >= 1 / 512) { - return Math.sign(v) * Math.pow(abs, 1 / 1.8); - } - return 16 * v; - }).concat(a == null || a == 1 ? [] : [a]); + const values = [gam_prophotorgbvalue(r), gam_prophotorgbvalue(g), gam_prophotorgbvalue(b)]; + return values; } function rec20202srgb(r, g, b, a) { + let values = rec20202lrec2020(r, g, b); + values = lrec20202xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lrec20202xyz(...rec20202lrec2020(r, g, b)), a); + return xyz2srgb(values[0], values[1], values[2], a); } function srgb2rec2020values(r, g, b, a) { + let values = srgb2xyz(r, g, b); + values = xyz2lrec2020(values[0], values[1], values[2]); // @ts-ignore - return lrec20202rec2020(...xyz2lrec2020(...srgb2xyz(r, g, b)), a); + return lrec20202rec2020(values[0], values[1], values[2], a); } function rec20202lrec2020(r, g, b, a) { // convert an array of rec2020 RGB values in the range 0.0 - 1.0 @@ -8921,7 +8936,7 @@ [0, 19567812 / 697040785, 295819943 / 278816314], ]; // 0 is actually calculated as 4.994106574466076e-17 - return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [r, g, b]).concat([] ); } function xyz2lrec2020(x, y, z, a) { // convert XYZ to linear-light rec2020 @@ -8930,24 +8945,36 @@ [-19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200], [792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125], ]; - return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [x, y, z]).concat([] ); } function p32srgbvalues(r, g, b, alpha) { + let values = p32lp3(r, g, b); + values = lp32xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lp32xyz(...p32lp3(r, g, b, alpha))); + return xyz2srgb(values[0], values[1], values[2], alpha); } function srgb2p3values(r, g, b, alpha) { - // @ts-ignore - return lp32p3(...xyz2lp3(...srgb2xyz(r, g, b, alpha))); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + values = lp32p3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function srgb2lp3values(r, g, b, alpha) { - // @ts-ignore - return xyz2lp3(...srgb2xyz(r, g, b, alpha)); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function lp32srgbvalues(r, g, b, alpha) { + let values = lp32xyz(r, g, b); // @ts-ignore - return xyz2srgb(...lp32xyz(r, g, b, alpha)); + return xyz2srgb(values[0], values[1], values[2], alpha); } function p32lp3(r, g, b, alpha) { // convert an array of display-p3 RGB values in the range 0.0 - 1.0 @@ -8969,9 +8996,6 @@ [0, 32229 / 714400, 5220557 / 5000800], ]; const result = multiplyMatrices(M, [r, g, b]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } function xyz2lp3(x, y, z, alpha) { @@ -8982,12 +9006,77 @@ [11844 / 330415, -50337 / 660830, 316169 / 330415], ]; const result = multiplyMatrices(M, [x, y, z]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } + function a98rgb2srgbvalues(r, g, b, a = null) { + let values = a98rgb2la98(r, g, b); + values = la98rgb2xyz(values[0], values[1], values[2]); + values = xyz2srgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; + } + function srgb2a98values(r, g, b, a = null) { + let values = srgb2xyz(r, g, b); + values = xyz2la98rgb(values[0], values[1], values[2]); + values = la98rgb2a98rgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; + } + // a98-rgb functions + function a98rgb2la98(r, g, b, a = null) { + // convert an array of a98-rgb values in the range 0.0 - 1.0 + // to linear light (un-companded) form. + // negative values are also now accepted + return [r, g, b] + .map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = Math.abs(val); + return sign * Math.pow(abs, 563 / 256); + }) + .concat(a == null || a == 1 ? [] : [a]); + } + 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] + .map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = Math.abs(val); + return sign * Math.pow(abs, 256 / 563); + }) + .concat(a == null || a == 1 ? [] : [a]); + } + function la98rgb2xyz(r, g, b, a = null) { + // convert an array of linear-light a98-rgb values to CIE XYZ + // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + // has greater numerical precision than section 4.3.5.3 of + // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + // but the values below were calculated from first principles + // from the chromaticity coordinates of R G B W + // see matrixmaker.html + var M = [ + [573536 / 994567, 263643 / 1420810, 187206 / 994567], + [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835], + [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835], + ]; + return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); + } + function xyz2la98rgb(x, y, z, a = null) { + // convert XYZ to linear-light a98-rgb + var M = [ + [1829569 / 896150, -506331 / 896150, -308931 / 896150], + [-851781 / 878810, 1648619 / 878810, 36519 / 878810], + [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040], + ]; + return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); + } + function interpolateHue(interpolationMethod, h1, h2) { switch (interpolationMethod) { case "longer": @@ -9095,65 +9184,53 @@ case "srgb": break; case "display-p3": - // @ts-ignore - values = srgb2p3values(...values); + values = srgb2p3values(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = srgb2lp3values(...values); + values = srgb2lp3values(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = srgb2a98values(...values); + values = srgb2a98values(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = srgb2prophotorgbvalues(...values); + values = srgb2prophotorgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = srgb2lsrgbvalues(...values); + values = srgb2lsrgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = srgb2rec2020values(...values); + values = srgb2rec2020values(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = srgb2xyz_d65(...values); + values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = XYZ_D65_to_D50(...srgb2xyz_d65(...values)); + 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": - // @ts-ignore - values = srgb2rgb(...values); + for (let j = 0; j < values.length; j++) { + values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + } break; case "hsl": - // @ts-ignore - values = srgb2hslvalues(...values); + values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; case "hwb": - // @ts-ignore - values = srgb2hwb(...values); + values = srgb2hwb(values[0], values[1], values[2], values[3]); break; case "lab": - // @ts-ignore - values = srgb2labvalues(...values); + values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; case "lch": - // @ts-ignore - values = srgb2lch(...values); + values = srgb2lch(values[0], values[1], values[2], values[3]); break; case "oklab": - // @ts-ignore - values = srgb2oklab(...values); + values = srgb2oklab(values[0], values[1], values[2], values[3]); break; case "oklch": - // @ts-ignore - values = srgb2oklch(...values); + values = srgb2oklch(values[0], values[1], values[2], values[3]); break; default: return null; @@ -9302,12 +9379,10 @@ case "xyz-d65": case "xyz-d50": if (colorSpace == "xyz-d50") { - // @ts-ignore - values = xyzd502lch(...values); + values = xyzd502lch(values[0], values[1], values[2], values[3]); } else { - // @ts-ignore - values = xyz2lchvalues(...values); + values = xyz2lchvalues(values[0], values[1], values[2], values[3]); } // @ts-ignore return { @@ -9652,6 +9727,7 @@ (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value) ?? root, exports.WalkerEvent.Enter, // @ts-expect-error function* () { @@ -9674,8 +9750,13 @@ const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } @@ -9706,8 +9787,13 @@ const sliced = value.chi.slice(); for (const child of sliced) { map.set(child, value); + if (reverse) { + stack.unshift(child); + } + else { + stack.push(child); + } } - stack[reverse ? "push" : "unshift"](...sliced); } else { const values = []; @@ -9740,7 +9826,14 @@ } } if (values.length > 0) { - stack[reverse ? "push" : "unshift"](...values); + for (const v of values) { + if (reverse) { + stack.unshift(v); + } + else { + stack.push(v); + } + } } } } @@ -9750,14 +9843,20 @@ (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value), exports.WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } @@ -9898,7 +9997,9 @@ if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }); const result = evaluateFunc(tokens[0]); @@ -9928,7 +10029,9 @@ // @ts-ignore val: Math[nodes[0].val.toUpperCase()], typ: exports.EnumToken.NumberTokenType, - [LOC]: nodes[0][LOC], + [LOCSRCID]: nodes[0][LOCSRCID], + [LOCSTA]: nodes[0][LOCSTA], + [LOCEND]: nodes[0][LOCEND], }, ]; } @@ -9948,11 +10051,19 @@ token = { typ: exports.EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]], - [LOC]: { ...nodes[i][LOC], end: nodes[i + 1][LOC].end }, + [LOCSRCID]: nodes[i][LOCSRCID], + [LOCSTA]: nodes[i][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], }; } else { - token = doEvaluate(nodes[i + 1], { typ: exports.EnumToken.NumberTokenType, val: -1, [LOC]: nodes[i + 1][LOC] }, exports.EnumToken.Mul); + token = doEvaluate(nodes[i + 1], { + typ: exports.EnumToken.NumberTokenType, + val: -1, + [LOCSRCID]: nodes[i + 1][LOCSRCID], + [LOCSTA]: nodes[i + 1][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], + }, exports.EnumToken.Mul); } i++; } @@ -9967,16 +10078,28 @@ const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, exports.EnumToken.Add)); if (token.typ != exports.EnumToken.BinaryExpressionTokenType) { if ("val" in token && +token.val < 0) { - acc.push({ typ: exports.EnumToken.Sub, [LOC]: token[LOC] }, { + acc.push({ + typ: exports.EnumToken.Sub, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, { ...token, val: -token.val, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }); return acc; } } if (acc.length > 0 && curr[0] != exports.EnumToken.ListToken) { - acc.push({ typ: exports.EnumToken.Add, [LOC]: token[LOC] }); + acc.push({ + typ: exports.EnumToken.Add, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); } acc.push(token); return acc; @@ -9994,7 +10117,9 @@ op, l, r, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -10032,15 +10157,39 @@ if (typeof v1 == "number" && l.typ == exports.EnumToken.PercentageTokenType) { v1 = { typ: exports.EnumToken.FractionTokenType, - l: { typ: exports.EnumToken.NumberTokenType, val: v1, [LOC]: l[LOC] }, - r: { typ: exports.EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: exports.EnumToken.NumberTokenType, + val: v1, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: exports.EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } else if (typeof v2 == "number" && r.typ == exports.EnumToken.PercentageTokenType) { v2 = { typ: exports.EnumToken.FractionTokenType, - l: { typ: exports.EnumToken.NumberTokenType, val: v2, [LOC]: l[LOC] }, - r: { typ: exports.EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: exports.EnumToken.NumberTokenType, + val: v2, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: exports.EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } } @@ -10051,7 +10200,9 @@ ...(l.typ === exports.EnumToken.NumberTokenType || l.typ === exports.EnumToken.IdenTokenType ? r : l), typ, val /* : typeof val == 'number' ? minifyNumber(val) : val */, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l?.[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (token.typ == exports.EnumToken.IdenTokenType) { // @ts-ignore @@ -10080,25 +10231,64 @@ case "sign": case "sqrt": case "exp": { + if (token.val == "tan" || token.val == "atan") { + for (let i = 0; i < values.length; i++) { + if (values[i].typ == exports.EnumToken.NumberTokenType) { + values[i] = Object.assign(values[i], { typ: exports.EnumToken.AngleTokenType, unit: "rad" }); + } + else if (values[i].typ == exports.EnumToken.AngleTokenType && values[i].unit != "rad") { + switch (values[i].unit) { + case "deg": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (2 * Math.PI), + }); + break; + } + } + } + } const value = evaluate(values); // @ts-ignore - let val = value[0].typ == exports.EnumToken.NumberTokenType + let val = value[0].typ == exports.EnumToken.NumberTokenType || value[0].typ == exports.EnumToken.AngleTokenType ? +value[0].val : // @ts-expect-error value[0].l.val / value[0].r.val; return [ - { - typ: exports.EnumToken.NumberTokenType, - val: Math[token.val](val), - [LOC]: value[0][LOC], - }, + token.val == "tan" || token.val == "atan" + ? { + typ: exports.EnumToken.AngleTokenType, + val: Math[token.val](val), + unit: "rad", + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + } + : { + typ: exports.EnumToken.NumberTokenType, + val: Math[token.val](val), + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + }, ]; } case "hypot": { const chi = values.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType, exports.EnumToken.CommaTokenType].includes(t.typ)); let all = []; let ref = chi[0]; - let value = 0; for (let i = 0; i < chi.length; i++) { // @ts-ignore const val = getValue$1(chi[i]); @@ -10106,13 +10296,14 @@ return null; } all.push(val); - value += val * val; } return [ { ...ref, - val: +Math.sqrt(value).toFixed(rem(...all)), - [LOC]: token[LOC], + val: Math.hypot(...all), + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10121,6 +10312,35 @@ case "rem": case "mod": { const chi = values.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(t.typ)); + if (token.val == "atan2") { + for (let i = 0; i < chi.length; i++) { + if (chi[i].typ == exports.EnumToken.NumberTokenType) { + chi[i] = Object.assign(chi[i], { typ: exports.EnumToken.AngleTokenType, unit: "rad" }); + } + else if (chi[i].typ == exports.EnumToken.AngleTokenType && chi[i].unit != "rad") { + switch (chi[i].unit) { + case "deg": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (2 * Math.PI), + }); + break; + } + } + } + } // https://developer.mozilla.org/en-US/docs/Web/CSS/mod const v1 = evaluate([chi[0]]); const v2 = evaluate([chi[2]]); @@ -10141,7 +10361,9 @@ { ...v1[0], val: Math.pow(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10150,8 +10372,12 @@ { ...{}, ...v1[0], + typ: exports.EnumToken.AngleTokenType, + unit: "rad", val: Math.atan2(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10159,7 +10385,9 @@ { ...v1[0], val: val2 == 0 ? val1 : val1 - Math.floor(val1 / val2) * val2, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10196,7 +10424,9 @@ { ...values[0], val: Math.log(val1) / Math.log(val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10232,7 +10462,15 @@ : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOC]: token[LOC] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -10250,7 +10488,18 @@ result.push(token); } else { - result.push(...inlineExpression$1(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression$1(token.r)); + for (const child of inlineExpression$1(token.l)) { + result.push(child); + } + result.push({ + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); + for (const child of inlineExpression$1(token.r)) { + result.push(child); + } } } else { @@ -10313,7 +10562,13 @@ token.val == "calc")) { if ((token.typ == exports.EnumToken.MathFunctionTokenType || token.typ == exports.EnumToken.FunctionTokenType) && token.val == "calc") { - token = { ...token, typ: exports.EnumToken.ParensTokenType, [LOC]: token[LOC] }; + token = { + ...token, + typ: exports.EnumToken.ParensTokenType, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }; // @ts-ignore delete token.val; } @@ -10351,7 +10606,9 @@ : getArithmeticOperation(tokens[i].val), l: factorToken(tokens[i - 1]), r: factorToken(tokens[i + 1]), - [LOC]: { ...tokens[i - 1][LOC], end: tokens[i + 1][LOC]?.end }, + [LOCSRCID]: tokens[i - 1][LOCSRCID], + [LOCSTA]: tokens[i - 1][LOCSTA], + [LOCEND]: tokens[i + 1][LOCEND], }); i--; } @@ -10387,7 +10644,9 @@ const validKeys = names.split(""); let val = ""; if (components != null) { - allComponents.push(...components); + for (const component of components) { + allComponents.push(component); + } } // ensure all components are valid for the color space for (const component of allComponents) { @@ -10456,19 +10715,25 @@ ? { typ: exports.EnumToken.NumberTokenType, val: 1, - [LOC]: b[LOC], + [LOCSRCID]: b[LOCSRCID], + [LOCSTA]: b[LOCSTA], + [LOCEND]: b[LOCEND], } : alpha.typ == exports.EnumToken.IdenTokenType && alpha.val == "none" ? { typ: exports.EnumToken.NumberTokenType, val: 0, - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha.typ == exports.EnumToken.PercentageTokenType ? { typ: exports.EnumToken.NumberTokenType, val: getNumber(alpha), - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha, }; @@ -10481,13 +10746,17 @@ ? { typ: exports.EnumToken.NumberTokenType, val: 1, - [LOC]: bExp[LOC], + [LOCSRCID]: bExp[LOCSRCID], + [LOCSTA]: bExp[LOCSTA], + [LOCEND]: bExp[LOCEND], } : aExp.typ == exports.EnumToken.IdenTokenType && aExp.val == "none" ? { typ: exports.EnumToken.NumberTokenType, val: 0, - [LOC]: aExp[LOC], + [LOCSRCID]: aExp[LOCSRCID], + [LOCSTA]: aExp[LOCSTA], + [LOCEND]: aExp[LOCEND], } : aExp), }; @@ -10518,7 +10787,9 @@ return { typ: exports.EnumToken.NumberTokenType, val: value, - [LOC]: t[LOC], + [LOCSRCID]: t[LOCSRCID], + [LOCSTA]: t[LOCSTA], + [LOCEND]: t[LOCEND], }; } return t; @@ -10561,8 +10832,10 @@ { typ: exports.EnumToken.NumberTokenType, // @ts-ignore - val: "" + Math[value.val.toUpperCase()], - [LOC]: value[LOC], + val: Math[value.val.toUpperCase()], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], // @ts-ignore }); } @@ -10601,68 +10874,60 @@ } function rgb2cmykToken(token) { - const components = rgb2srgbvalues(token); + let components = rgb2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function hsl2cmykToken(token) { - const values = hsl2srgbvalues(token); + let values = hsl2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function hwb2cmykToken(token) { const values = hwb2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function lab2cmykToken(token) { const components = lab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function lch2cmykToken(token) { const components = lch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklab2cmyk(token) { const components = oklab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklch2cmykToken(token) { const components = oklch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function color2cmykToken(token) { const values = color2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function srgb2cmykvalues(r, g, b, a = null) { const k = 1 - Math.max(r, g, b); @@ -10703,64 +10968,6 @@ }; } - function a98rgb2srgbvalues(r, g, b, a = null) { - // @ts-ignore - return xyz2srgb(...la98rgb2xyz(...a98rgb2la98(r, g, b, a))); - } - function srgb2a98values$1(r, g, b, a = null) { - // @ts-ignore - return la98rgb2a98rgb(...xyz2la98rgb(...srgb2xyz(r, g, b, a))); - } - // a98-rgb functions - function a98rgb2la98(r, g, b, a = null) { - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - return [r, g, b] - .map(function (val) { - let sign = val < 0 ? -1 : 1; - let abs = Math.abs(val); - return sign * Math.pow(abs, 563 / 256); - }) - .concat(a == null || a == 1 ? [] : [a]); - } - 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] - .map(function (val) { - let sign = val < 0 ? -1 : 1; - let abs = Math.abs(val); - return sign * Math.pow(abs, 256 / 563); - }) - .concat(a == null || a == 1 ? [] : [a]); - } - function la98rgb2xyz(r, g, b, a = null) { - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - var M = [ - [573536 / 994567, 263643 / 1420810, 187206 / 994567], - [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835], - [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835], - ]; - return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); - } - function xyz2la98rgb(x, y, z, a = null) { - // convert XYZ to linear-light a98-rgb - var M = [ - [1829569 / 896150, -506331 / 896150, -308931 / 896150], - [-851781 / 878810, 1648619 / 878810, 36519 / 878810], - [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040], - ]; - return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); - } - var ValidationTokenEnum; (function (ValidationTokenEnum) { ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root"; @@ -10941,7 +11148,7 @@ [LOC]: pos, }; } - if (isPseudo$1(token)) { + if (isPseudo(token)) { return { typ: ValidationTokenEnum.PseudoClassToken, val: token, @@ -11731,11 +11938,8 @@ /** * @type {Array.} */ - const funcTypes = [ - ...tokensfuncDefMap.values(), - exports.EnumToken.FunctionTokenType, - exports.EnumToken.PseudoClassFuncTokenType, - ]; + const funcTypes = Array.from(tokensfuncDefMap.values()); + funcTypes.push(exports.EnumToken.FunctionTokenType, exports.EnumToken.PseudoClassFuncTokenType); /** * trim leading and trailing whitespace * @param tokens @@ -12058,7 +12262,7 @@ message: `Unexpected token ${exports.EnumToken[stream[i].typ]}`, node: stream[i], // @ts-expect-error - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }, ], }; @@ -12093,7 +12297,9 @@ if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } } @@ -12112,7 +12318,7 @@ message: `Nesting selector is not allowed`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12146,7 +12352,7 @@ message: `Unexpected combinator ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12190,7 +12396,7 @@ message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12241,7 +12447,7 @@ message: `Unexpected token ${exports.EnumToken[slice[0].typ]}`, node: slice[0], // @ts-expect-error - location: options.source.getSourceLocation(slice[0][LOC].sta), + location: options.source.getSourceLocation(slice[0][LOCSTA]), }, ], }; @@ -12253,8 +12459,8 @@ // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOC]!.sta.lin}:${ - // slice[0][LOC]!.sta.col + // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOCSTA].lin}:${ + // slice[0][LOCSTA].col // }`, // node: slice[0], // location: slice[0][LOC], @@ -12292,8 +12498,8 @@ // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -12325,8 +12531,8 @@ // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -12355,7 +12561,7 @@ message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12384,7 +12590,9 @@ if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } stack.pop(); @@ -12398,7 +12606,7 @@ message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12420,7 +12628,7 @@ message: `Unsupported selector token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12446,13 +12654,15 @@ message: `Unmatched token ${exports.EnumToken[stack.at(-1).typ]}`, node: stack.at(-1), // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)[LOCSTA]), }, ], }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** @@ -12493,7 +12703,7 @@ message: result.errors[0]?.message || "could not match syntax", node: result.token, syntax: result.syntaxToken, - location: options.source.getSourceLocation((result.token?.[LOC] ?? context.tokens.at(-1)?.[LOC]).sta), + location: options.source.getSourceLocation((result.token?.[LOCSTA] ?? context.tokens.at(-1)?.[LOCSTA])), }, ] : result.errors, @@ -12588,7 +12798,7 @@ action: "drop", message: "could not match syntax", node: context.peek(), - // location: options.source!.getSourceLocation(context.peek()?.[LOC]!.sta), + // location: options.source!.getSourceLocation(context.peek()?.[LOCSTA]), }, ], syntaxToken: null, @@ -14335,8 +14545,8 @@ if (args.at(-2)?.typ === exports.EnumToken.LiteralTokenType && "/" === args.at(-2)?.val) { args.splice(args.length - 2, 1); } - // @ts-expect-error - token = alpha(...trimArray(args.slice(1))); + let values = trimArray(args.slice(1)); + token = alpha(values[0], values[1]); if (token == null) { return null; } @@ -14371,10 +14581,15 @@ } let { cal, ...tk } = { ...token, - chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], + chi: token.val == "color" ? [chi[offset]] : [], kin: exports.ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + for (const t of Object.values(components)) { + tk.chi.push(t); + } + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } @@ -14725,46 +14940,28 @@ return values2colortoken(values, to); } function srgb2srgbcolorspace(val, to) { - const values = []; switch (to) { case exports.ColorType.SRGB: - values.push(...val); - break; + return val; case exports.ColorType.SRGB_LINEAR: - // @ts-ignore - values.push(...srgb2lsrgbvalues(...val)); - break; + return srgb2lsrgbvalues(val[0], val[1], val[2], val[3]); case exports.ColorType.DISPLAY_P3: - // @ts-ignore - values.push(...srgb2p3values(...val)); - break; + return srgb2p3values(val[0], val[1], val[2], val[3]); case exports.ColorType.DISPLAY_P3_LINEAR: - // @ts-ignore - values.push(...srgb2lp3values(...val)); - break; + return srgb2lp3values(val[0], val[1], val[2], val[3]); case exports.ColorType.PROPHOTO_RGB: - // @ts-ignore - values.push(...srgb2prophotorgbvalues(...val)); - break; + return srgb2prophotorgbvalues(val[0], val[1], val[2], val[3]); case exports.ColorType.A98_RGB: - // @ts-ignore - values.push(...srgb2a98values$1(...val)); - break; + return srgb2a98values(val[0], val[1], val[2], val[3]); case exports.ColorType.REC2020: - // @ts-ignore - values.push(...srgb2rec2020values(...val)); - break; + return srgb2rec2020values(val[0], val[1], val[2], val[3]); case exports.ColorType.XYZ: case exports.ColorType.XYZ_D65: - // @ts-ignore - values.push(...srgb2xyz(...val)); - break; + return srgb2xyz(val[0], val[1], val[2], val[3]); case exports.ColorType.XYZ_D50: - // @ts-ignore - values.push(...srgb2xyz_d65(...val)); - break; + return srgb2xyz_d65(val[0], val[1], val[2], val[3]); } - return values; + return null; } function minmax(value, min, max) { return value < min ? min : value > max ? max : value; @@ -14778,37 +14975,29 @@ let values = components.map((val) => getNumber(val)); switch (colorSpace.val) { case "display-p3": - // @ts-ignore - values = p32srgbvalues(...values); + values = p32srgbvalues(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = lp32srgbvalues(...values); + values = lp32srgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = lsrgb2srgbvalues(...values); + values = lsrgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = prophotorgb2srgbvalues(...values); + values = prophotorgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = a98rgb2srgbvalues(...values); + values = a98rgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = rec20202srgb(...values); + values = rec20202srgb(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = xyz2srgb(...values); + values = xyz2srgb(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = xyzd502srgb(...values); + values = xyzd502srgb(values[0], values[1], values[2], values[3]); break; } if (values.length == 4) { @@ -14817,7 +15006,11 @@ return values; } function values2colortoken(values, to) { + // @ts-expect-error values = srgb2srgbcolorspace(values, to); + if (values == null) { + return null; + } const chi = [ { typ: exports.EnumToken.NumberTokenType, val: values[0] }, { typ: exports.EnumToken.NumberTokenType, val: values[1] }, @@ -14915,7 +15108,7 @@ if (okLab1[3] != null || okLab2[3] != null) { diff.push((okLab1[3] ?? 1) - (okLab2[3] ?? 1)); } - return toPrecisionValue(Math.hypot(...diff)); + return toPrecisionValue(Math.hypot(diff[0], diff[1], diff[2], diff[3] ?? 0)); } /** * Check if two colors are close in okLab space. @@ -15043,7 +15236,12 @@ // https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token // '\\' const REVERSE_SOLIDUS = 0x5c; - const dimensionUnits = new Set([ + const flexUnits = ["fr"]; + const frequencyUnits = ["hz", "khz"]; + const timeUnits = ["ms", "s"]; + const angleUnits = ["rad", "turn", "deg", "grad"]; + const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; + const dimensionUnits = [ "q", "cap", "ch", @@ -15087,7 +15285,7 @@ "vmax", "vmin", "vw", - ]); + ]; // https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions // https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions const pseudoAliasMap = { @@ -15224,19 +15422,19 @@ // renamed standard properties const renamedStandardProperties = new Map([["color-adjust", "print-color-adjust"]]); function isLength(dimension) { - return "unit" in dimension && dimensionUnits.has(dimension.unit.toLowerCase()); + return "unit" in dimension && dimensionUnits.includes(dimension.unit.toLowerCase()); } function isResolution(dimension) { - return "unit" in dimension && ["dpi", "dpcm", "dppx", "x"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && resolutionUnits.includes(dimension.unit.toLowerCase()); } function isAngle(dimension) { - return "unit" in dimension && ["rad", "turn", "deg", "grad"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && angleUnits.includes(dimension.unit.toLowerCase()); } function isTime(dimension) { - return "unit" in dimension && ["ms", "s"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && timeUnits.includes(dimension.unit.toLowerCase()); } function isFrequency(dimension) { - return "unit" in dimension && ["hz", "khz"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && frequencyUnits.includes(dimension.unit.toLowerCase()); } /** * Reduce color stops @@ -15259,7 +15457,9 @@ if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.PercentageTokenType, val: ((k - 1) * 100) / n }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -15283,7 +15483,9 @@ if (stops.length > 0) { stops.push({ typ: exports.EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (let m = 0; m < parts[j].length; m++) { + stops.push(parts[j][m]); + } } } return stops; @@ -15381,7 +15583,9 @@ if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.AngleTokenType, val: ((k - 1) * 100) / n, unit: "deg" }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -15404,7 +15608,9 @@ if (stops.length > 0) { stops.push({ typ: exports.EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (const token of parts[j]) { + stops.push(token); + } } } return stops; @@ -15700,11 +15906,10 @@ return true; } else { - const keywords = ["from", "none"]; // @ts-ignore if (["rgb", "hsl", "hwb", "lab", "lch", "oklab", "oklch"].some((t) => equalsIgnoreCase(t, token.val))) { - // @ts-ignore - keywords.push("alpha", ...token.val.slice(-3).split("")); + for (const keyword of token.val.slice(-3).split("")) { + } } // @ts-ignore for (const v of token.chi) { @@ -15861,7 +16066,7 @@ codepoint == 0x7f || (codepoint >= 0xe && codepoint <= 0x1f)); } - function isPseudo$1(name) { + function isPseudo(name) { return (name.charAt(0) == ":" && ((name.endsWith("(") && isIdent(name.charAt(1) == ":" ? name.slice(2, -1) : name.slice(1, -1))) || isIdent(name.charAt(1) == ":" ? name.slice(2) : name.slice(1)))); @@ -15869,75 +16074,6 @@ function isHash(name) { return name.charAt(0) == "#" && isIdentStart(name.charCodeAt(1)); } - const isNumber = memoize(function (name) { - let codepoint = name.charCodeAt(0); - let i = 0; - const j = name.length; - if (j == 1 && !isDigit(codepoint)) { - return false; - } - // '+' '-' - if ([0x2b, 0x2d].includes(codepoint)) { - i++; - } - // consume digits - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // '.' 'E' 'e' - if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { - break; - } - return false; - } - // '.' - if (codepoint == 0x2e) { - if (!isDigit(name.charCodeAt(++i))) { - return false; - } - } - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - i++; - break; - } - return false; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - // if (i == j) { - // return false; - // } - codepoint = name.charCodeAt(i + 1); - // '+' '-' - // if ([0x2b, 0x2d].includes(codepoint)) { - // i++; - // } - codepoint = name.charCodeAt(i + 1); - if (!isDigit(codepoint)) { - return false; - } - } - // while (++i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isDigit(codepoint)) { - // return false; - // } - // } - return true; - }); - function isPercentage(name) { - return name.endsWith("%") && isNumber(name.slice(0, -1)); - } function isFlex(dimension) { return "unit" in dimension && "fr" == dimension.unit.toLowerCase(); } @@ -15978,9 +16114,9 @@ else if (isResolution(dimension)) { // @ts-ignore dimension.typ = exports.EnumToken.ResolutionTokenType; - if (dimension.unit == "dppx") { - dimension.unit = "x"; - } + // if (dimension.unit == "dppx") { + // dimension.unit = "x"; + // } } else if (isFrequency(dimension)) { // @ts-ignore @@ -15992,22 +16128,6 @@ } return dimension; } - function isHexColor(name) { - if (name.charAt(0) != "#" || ![4, 5, 7, 9].includes(name.length)) { - return false; - } - for (let chr of name.slice(1)) { - let codepoint = chr.charCodeAt(0); - if (!isDigit(codepoint) && - // A-F - !(codepoint >= 0x41 && codepoint <= 0x46) && - // a-f - !(codepoint >= 0x61 && codepoint <= 0x66)) { - return false; - } - } - return true; - } function isFunction(name) { return name.endsWith("(") && isIdent(name.slice(0, -1)); } @@ -16102,14 +16222,11 @@ value = Math.round(value * div) / div; return Math.abs(value) < epsilon ? 0 : value; } - function toPrecisionAngle(angle, precision = colorPrecision, correctValue = true) { + function toPrecisionAngle(angle, precision = anglePrecision, correctValue = true) { angle = toPrecisionValue(angle, precision); if (correctValue && Math.abs(angle) >= 360) { angle %= 360; } - if (Math.abs(angle) < anglePrecision) { - angle = 0; - } if (correctValue && angle < 0) { angle += 360; } @@ -16225,8 +16342,8 @@ // typ: EnumToken.ResolutionTokenType, // unit: "x", // }); - // } - // else + // } + // else if (isPseudClass && value.typ == exports.EnumToken.PseudoElementTokenType) { // @ts-ignore value.typ = exports.EnumToken.PseudoClassTokenType; @@ -16239,7 +16356,7 @@ const set = new Set(); const split = splitTokenList(tokens, [exports.EnumToken.CommaTokenType]); tokens.length = 0; - tokens.push(...split.reduce((acc, curr) => { + for (const token of split.reduce((acc, curr) => { const str = curr.reduce((acc, curr) => acc + renderValue(curr), ""); if (set.has(str)) { return acc; @@ -16251,7 +16368,9 @@ }); } return acc.concat(curr); - }, [])); + }, [])) { + tokens.push(token); + } } return result; } @@ -16469,52 +16588,28 @@ // right bottom → left top to top left const replacements = []; if (key === "left top left bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }); } else if (key === "left bottom left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }); } else if (key === "left top right top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } else if (key === "left top right bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } else if (key === "left bottom right top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right bottom left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } tokens.splice(0, i, ...replacements); let checkStop = true; @@ -16527,7 +16622,10 @@ } if (tokens[i].typ === exports.EnumToken.FunctionTokenType) { if (equalsIgnoreCase(tokens[i].val, "to")) { - colorStop.push(tokens[checkStopIndex], ...tokens[i].chi); + colorStop.push(tokens[checkStopIndex]); + for (const token of tokens[i].chi) { + colorStop.push(token); + } tokens.splice(checkStopIndex, i - checkStopIndex + 1); i = checkStopIndex; checkStop = false; @@ -16555,12 +16653,16 @@ } } if (colorStop.length > 0) { - tokens.push(...colorStop); + for (const t of colorStop) { + tokens.push(t); + } } if (type !== "") { token.val = type; token.chi.length = 0; - token.chi.push(...tokens); + for (const t of tokens) { + token.chi.push(t); + } } } /** @@ -16631,7 +16733,9 @@ i++; } } - colorStops.push(...tokens.slice(i)); + for (let m = i; m < tokens.length; m++) { + colorStops.push(tokens[m]); + } tokens.length = 0; if (form.length > 0 || size.length > 0) { if (form.length === 0) { @@ -16639,17 +16743,27 @@ } if (size.length > 0) { form.push({ typ: exports.EnumToken.WhitespaceTokenType }); - form.push(...size); + for (const token of size) { + form.push(token); + } } if (positions.length > 0) { - form.push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + form.push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const position of positions) { + form.push(position); + } + } + for (const token of form) { + tokens.push(token); } - tokens.push(...form, { typ: exports.EnumToken.CommaTokenType }); + tokens.push({ typ: exports.EnumToken.CommaTokenType }); } token.val = equalsIgnoreCase(token.val, "-webkit-repeating-radial-gradient") ? "repeating-radial-gradient" : "radial-gradient"; - tokens.push(...colorStops); + for (const colorStop of colorStops) { + tokens.push(colorStop); + } return tokens; } } @@ -16657,13 +16771,14 @@ function inlineExpression(token) { const result = []; if (token.typ == exports.EnumToken.BinaryExpressionTokenType) { + const chi = inlineExpression(token.l); + chi.push({ typ: token.op }); + for (const child of inlineExpression(token.r)) { + chi.push(child); + } result.push({ typ: exports.EnumToken.ParensTokenType, - chi: [ - ...inlineExpression(token.l), - { typ: token.op }, - ...inlineExpression(token.r), - ], + chi, }); } else { @@ -16975,7 +17090,9 @@ // @ts-ignore acc.push({ ...this.config.separator, typ: exports.EnumToken.LiteralTokenType }); } - acc.push(...curr); + for (const token of curr) { + acc.push(token); + } return acc; }, []), }, @@ -18697,10 +18814,17 @@ else { if (current == tokens[property].length) { tokens[property].push([]); - tokens[property][current].push(...defaults); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } else { - tokens[property][current].push({ typ: exports.EnumToken.WhitespaceTokenType }, ...defaults); + tokens[property][current].push({ + typ: exports.EnumToken.WhitespaceTokenType, + }); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } } } @@ -18717,7 +18841,9 @@ if (acc.length > 0) { acc.push({ ...separator }); } - acc.push(...curr); + for (let i = 0; i < curr.length; i++) { + acc.push(curr[i]); + } return acc; }, []), }); @@ -18852,7 +18978,9 @@ }; const values = [...this.declarations.values()].reduce((acc, curr) => { if (curr instanceof PropertySet) { - acc.push(...curr); + for (const declaration of curr) { + acc.push(declaration); + } } else { acc.push(curr); @@ -19074,7 +19202,7 @@ else if (acc[i].length > 0) { acc[i].push({ typ: exports.EnumToken.WhitespaceTokenType }); } - acc[i].push(...values.reduce((acc, curr) => { + for (const v of values.reduce((acc, curr) => { if (acc.length > 0) { // @ts-ignore acc.push({ @@ -19088,7 +19216,9 @@ // @ts-ignore acc.push(curr); return acc; - }, [])); + }, [])) { + acc[i].push(v); + } } } return acc; @@ -19106,7 +19236,9 @@ return acc; }, [])); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); if (this.config.mapping != null) { @@ -19174,10 +19306,13 @@ } matchTypes(declaration) { const patterns = this.pattern.slice(); - const values = [...declaration.val]; + const values = []; let i; let j; const map = new Map(); + for (i = 0; i < declaration.val.length; i++) { + values.push(declaration.val[i]); + } for (i = 0; i < patterns.length; i++) { for (j = 0; j < values.length; j++) { if (!map.has(patterns[i])) { @@ -19280,7 +19415,7 @@ chars.push(FIRST_ALPHABET[n % FIRST_ALPHABET.length]); // Remaining characters for (let i = 1; i < length; i++) { - n = (n + chars.length + i) % FULL_ALPHABET.length; + n = (n + chars.length * i) % FULL_ALPHABET.length; chars.push(FULL_ALPHABET[n]); } return chars.join(""); @@ -19311,13 +19446,13 @@ * @returns */ function objectHash(object) { - return hashId(toSortedString(object)); + return hashCode(toSortedString(object)).toString(16); } /** * convert input to hex * @param input */ - function toHex(input) { + function toHex(input, length) { let result = ""; if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) { for (const byte of Array.from(new Uint8Array(input))) { @@ -19391,6 +19526,7 @@ class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; + // ketsey = new Map; constructor(options = {}) { this.options = options; this.declarations = new Map(); @@ -19407,15 +19543,12 @@ let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != exports.EnumToken.DeclarationNodeType - ? null - : declaration.nam.toLowerCase(); + name = declaration.typ != exports.EnumToken.DeclarationNodeType ? null : declaration.nam; if (declaration[STATE] == exports.EnumAstNodeStatus.Invalid || declaration[STATE] == exports.EnumAstNodeStatus.Unknown || declaration[STATE] == exports.EnumAstNodeStatus.ValidationFailed || declaration.typ != exports.EnumToken.DeclarationNodeType || - "composes" === name || + equalsIgnoreCase("composes", name) || (typeof this.options.removeDuplicateDeclarations === "string" && this.options.removeDuplicateDeclarations === name) || (Array.isArray(this.options.removeDuplicateDeclarations) @@ -19443,7 +19576,21 @@ } // do not compute shorthand for invalid declarations if (declaration[STATE] !== exports.EnumAstNodeStatus.Validated) { - this.declarations.set(declaration.nam, declaration); + // const key = objectHash(declaration); + // if (!this.ketsey.has(key)) { + // this.ketsey.set(key, [declaration.nam]); + // console.error( + // `Adding declaration : ${(declaration).nam} with key : ${key}` + // ) + // } + // else { + // console.error( + // `Duplicate declaration found: ${(declaration).nam} with key : [ ${key} => ${this.ketsey.get(key)} ]` + // ) + // console.error(JSON.stringify(toSortedString(declaration))) + // this.ketsey.get(key).push(declaration.nam); + // } + this.declarations.set(objectHash(declaration), declaration); return this; } let propertyName = declaration.nam; @@ -19559,7 +19706,9 @@ } if (values != declaration.val) { declaration.val.length = 0; - declaration.val.push(...values); + for (const v of values) { + declaration.val.push(v); + } } } [Symbol.iterator]() { @@ -19606,7 +19755,7 @@ options.features.push(new ComputeShorthandFeature(options)); } } - run(ast, options = {}, parent, context) { + run(ast, options) { if (!("chi" in ast)) { return null; } @@ -19632,15 +19781,20 @@ // @ts-ignore const node = ast.chi[l]; if (node.typ == exports.EnumToken.DeclarationNodeType) { - properties.add(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + properties.add(ast.chi[m]); + } } else { - rules.push(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + rules.push(ast.chi[m]); + } } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi.length = 0; + // @ts-expect-error + ast.chi.push(...properties, ...rules); return ast; } } @@ -19668,57 +19822,15 @@ continue; } const set = new Set(); - for (const { value, parent } of walkValues(node.val, node, { - event: exports.WalkerEvent.Enter, - // @ts-ignore - fn(node, parent) { - if (parent != null && - // @ts-ignore - parent.typ == exports.EnumToken.DeclarationNodeType && - // @ts-ignore - parent.val.length == 1 && - (node.typ === exports.EnumToken.MathFunctionTokenType || node.typ === exports.EnumToken.FunctionTokenType) && - mathFuncs.includes(node.val) && - node.chi.length == 1 && - node.chi[0].typ == exports.EnumToken.IdenTokenType) { - return exports.WalkerOptionEnum.Ignore; - } - if ((node.typ === exports.EnumToken.WildCardFunctionTokenType && node.val == "var") || - (!mathFuncs.includes(parent.val) && - [ - exports.EnumToken.MathFunctionTokenType, - exports.EnumToken.ColorTokenType, - exports.EnumToken.DeclarationNodeType, - exports.EnumToken.ImageFunc, - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.StyleSheetNodeType, - ].includes(parent?.typ))) { - return null; - } + for (const { value, parent } of walkValues(node.val, node)) { + if (parent?.typ == exports.EnumToken.BinaryExpressionTokenType) { + continue; + } + if (value.typ == exports.EnumToken.BinaryExpressionTokenType) { // @ts-ignore - const slice = (node.typ == exports.EnumToken.FunctionTokenType || node.typ == exports.EnumToken.MathFunctionTokenType - ? node.chi - : node.typ == exports.EnumToken.DeclarationNodeType - ? node.val - : node.chi)?.slice(); - if (slice != null && - (node.typ === exports.EnumToken.MathFunctionTokenType || - (node.typ == exports.EnumToken.FunctionTokenType && - mathFuncs.includes(node.val)))) { - // @ts-ignore - const key = "chi" in node ? "chi" : "val"; - const str1 = renderValue({ ...node, [key]: slice }); - const str2 = renderValue(node); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); - if (str1.length < str2.length) { - // @ts-ignore - node[key] = slice; - } - return exports.WalkerOptionEnum.Ignore; - } - return null; - }, - })) { + replaceNodeOrValue(parent, value, evaluate([value])); + continue; + } if (value != null && tokensfuncSet.has(value.typ)) { if (!set.has(value)) { set.add(value); @@ -19765,7 +19877,9 @@ typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], } : values[0]); break; @@ -19779,7 +19893,9 @@ typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; } @@ -19795,8 +19911,9 @@ } } + const identityMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); function identity() { - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + return identityMatrix.slice(); } function normalize$1(point) { const [x, y, z] = point; @@ -19810,37 +19927,64 @@ return point1[0] * point2[0] + point1[1] * point2[1] + point1[2] * point2[2]; } function multiply(matrixA, matrixB) { - let result = new Array(16).fill(0); - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - for (let k = 0; k < 4; k++) { - // Utiliser l'indexation linéaire pour accéder aux éléments - // Pour une matrice 4x4, l'index est (row * 4 + col) - result[j * 4 + i] += matrixA[k * 4 + i] * matrixB[j * 4 + k]; - } - } - } + const result = new Float32Array(16); + result[0] = matrixA[0] * matrixB[0] + matrixA[4] * matrixB[1] + matrixA[8] * matrixB[2] + matrixA[12] * matrixB[3]; + result[1] = matrixA[1] * matrixB[0] + matrixA[5] * matrixB[1] + matrixA[9] * matrixB[2] + matrixA[13] * matrixB[3]; + result[2] = matrixA[2] * matrixB[0] + matrixA[6] * matrixB[1] + matrixA[10] * matrixB[2] + matrixA[14] * matrixB[3]; + result[3] = matrixA[3] * matrixB[0] + matrixA[7] * matrixB[1] + matrixA[11] * matrixB[2] + matrixA[15] * matrixB[3]; + result[4] = matrixA[0] * matrixB[4] + matrixA[4] * matrixB[5] + matrixA[8] * matrixB[6] + matrixA[12] * matrixB[7]; + result[5] = matrixA[1] * matrixB[4] + matrixA[5] * matrixB[5] + matrixA[9] * matrixB[6] + matrixA[13] * matrixB[7]; + result[6] = matrixA[2] * matrixB[4] + matrixA[6] * matrixB[5] + matrixA[10] * matrixB[6] + matrixA[14] * matrixB[7]; + result[7] = matrixA[3] * matrixB[4] + matrixA[7] * matrixB[5] + matrixA[11] * matrixB[6] + matrixA[15] * matrixB[7]; + result[8] = + matrixA[0] * matrixB[8] + matrixA[4] * matrixB[9] + matrixA[8] * matrixB[10] + matrixA[12] * matrixB[11]; + result[9] = + matrixA[1] * matrixB[8] + matrixA[5] * matrixB[9] + matrixA[9] * matrixB[10] + matrixA[13] * matrixB[11]; + result[10] = + matrixA[2] * matrixB[8] + matrixA[6] * matrixB[9] + matrixA[10] * matrixB[10] + matrixA[14] * matrixB[11]; + result[11] = + matrixA[3] * matrixB[8] + matrixA[7] * matrixB[9] + matrixA[11] * matrixB[10] + matrixA[15] * matrixB[11]; + result[12] = + matrixA[0] * matrixB[12] + matrixA[4] * matrixB[13] + matrixA[8] * matrixB[14] + matrixA[12] * matrixB[15]; + result[13] = + matrixA[1] * matrixB[12] + matrixA[5] * matrixB[13] + matrixA[9] * matrixB[14] + matrixA[13] * matrixB[15]; + result[14] = + matrixA[2] * matrixB[12] + matrixA[6] * matrixB[13] + matrixA[10] * matrixB[14] + matrixA[14] * matrixB[15]; + result[15] = + matrixA[3] * matrixB[12] + matrixA[7] * matrixB[13] + matrixA[11] * matrixB[14] + matrixA[15] * matrixB[15]; return result; } function inverse(matrix) { // Create augmented matrix [matrix | identity] let augmented = [ - ...matrix.slice(0, 4), + matrix[0], + matrix[1], + matrix[2], + matrix[3], 1, 0, 0, 0, - ...matrix.slice(4, 8), + matrix[4], + matrix[5], + matrix[6], + matrix[7], 0, 1, 0, 0, - ...matrix.slice(8, 12), + matrix[8], + matrix[9], + matrix[10], + matrix[11], 0, 0, 1, 0, - ...matrix.slice(12, 16), + matrix[12], + matrix[13], + matrix[14], + matrix[15], 0, 0, 0, @@ -19936,11 +20080,11 @@ row1[0] * row2[1] - row1[1] * row2[0], ]; // Compute scale - const scaleX = Math.hypot(...row0); + const scaleX = Math.hypot(row0[0], row0[1], row0[2]); const row0Norm = normalize$1(row0); const skewXY = dot(row0Norm, row1); const row1Proj = [row1[0] - skewXY * row0Norm[0], row1[1] - skewXY * row0Norm[1], row1[2] - skewXY * row0Norm[2]]; - const scaleY = Math.hypot(...row1Proj); + const scaleY = Math.hypot(row1Proj[0], row1Proj[1], row1Proj[2]); const row1Norm = normalize$1(row1Proj); const skewXZ = dot(row0Norm, row2); const skewYZ = dot(row1Norm, row2); @@ -19951,7 +20095,7 @@ ]; const row2Norm = normalize$1(row2Proj); const determinant = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2]; - const scaleZ = Math.hypot(...row2Proj) * (determinant < 0 ? -1 : 1); + const scaleZ = Math.hypot(row2Proj[0], row2Proj[1], row2Proj[2]) * (determinant < 0 ? -1 : 1); // Build rotation matrix from orthonormalized vectors const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0]; const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1]; @@ -20472,7 +20616,7 @@ function eqMatrix(a, b) { let mat = identity(); let tmp = identity(); - const data = (Array.isArray(a) ? a : parseMatrix(a)); + const data = (Array.isArray(a) || ArrayBuffer.isView(a) ? a : parseMatrix(a)); for (const transform of b) { tmp = computeMatrix([transform], identity()); if (tmp == null) { @@ -20494,7 +20638,7 @@ } function minifyTransformFunctions(transform) { const name = transform.val.toLowerCase(); - if ("skewx" == name) { + if ("skewX" == name) { transform.val = "skew"; return transform; } @@ -20534,10 +20678,10 @@ } const ignoredValue = name.startsWith("scale") ? 1 : 0; const t = new Set(["x", "y", "z"]); - let i = 3; - while (i--) { + for (let i = 0; i < 3; i++) { + const axis = i == 0 ? "x" : i == 1 ? "y" : "z"; if (values.length <= i || values[i].val == ignoredValue) { - t.delete(i == 0 ? "x" : i == 1 ? "y" : "z"); + t.delete(axis); } } if (name == "translate3d" || name == "translate") { @@ -20627,6 +20771,7 @@ stripCommaToken(transformLists); let matrix = identity(); let mat; + let transforms; const cumulative = []; for (const transformList of splitTransformList(transformLists)) { mat = computeMatrix(transformList, identity()); @@ -20634,7 +20779,10 @@ return null; } matrix = multiply(matrix, mat); - cumulative.push(...(minify$1(mat) ?? transformList)); + transforms = minify$1(mat) ?? transformList; + for (let i = 0; i < transforms.length; i++) { + cumulative.push(transforms[i]); + } } const serialized = serialize(matrix); if (cumulative.length > 0) { @@ -20650,11 +20798,66 @@ }); } } - return { + const result = { matrix: serialize(toZero(matrix)), cumulative, minified: minify$1(matrix) ?? [serialized], }; + // valid identity matrix + if ((result.minified.length == 1 && + result.minified[0].typ == exports.EnumToken.IdenTokenType && + result.minified[0].val == "none") || + (result.cumulative.length == 1 && + result.cumulative[0].typ == exports.EnumToken.IdenTokenType && + result.cumulative[0].val == "none") || + (result.matrix?.typ == exports.EnumToken.IdenTokenType && result.matrix.val == "none")) { + // all transform function arguments must be 0 or scale(1) + for (const transform of transformLists) { + switch (transform.val) { + case "translate": + case "translateX": + case "translateY": + case "translateZ": + case "translate3d": + case "rotate": + case "rotateX": + case "rotateY": + case "rotateZ": + case "rotate3d": + case "skew": + case "skewX": + case "skewY": + for (const child of transform.chi) { + if (child.typ == exports.EnumToken.WhitespaceTokenType || child.typ == exports.EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != exports.EnumToken.AngleTokenType && + child.typ != exports.EnumToken.NumberTokenType && + child.typ != exports.EnumToken.PercentageTokenType) || + getNumber(child) != 0) { + return null; + } + } + break; + case "scale": + case "scaleX": + case "scaleY": + case "scaleZ": + case "scale3d": + for (const child of transform.chi) { + if (child.typ == exports.EnumToken.WhitespaceTokenType || child.typ == exports.EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != exports.EnumToken.NumberTokenType && child.typ != exports.EnumToken.PercentageTokenType) || + getNumber(child) != 1) { + return null; + } + } + break; + } + } + } + return result; } function computeMatrix(transformList, matrixVar) { let values = []; @@ -20776,7 +20979,7 @@ if (values.length != 3) { return null; } - matrixVar = scale3d(...values, matrixVar); + matrixVar = scale3d(values[0], values[1], values[2], matrixVar); break; } if (transformList[i].val == "scale") { @@ -20953,7 +21156,7 @@ } } run(ast) { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } let i = 0; @@ -21256,7 +21459,9 @@ chi: [], }); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } atRule[TOKENS] = [{ typ: exports.EnumToken.ParensTokenType, chi: left.chi.slice() }]; const minify = atRule.nam !== "supports"; @@ -21281,7 +21486,9 @@ atRule[TOKENS] = [left]; atRule.val = atRule[TOKENS].reduce((acc, curr) => acc + renderValue(curr), ""); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } clonedDeclaration = cloneNode(declaration, true, nodeMap); replaceNodeOrValue(nodeMap.get(targetWrapper.typ === exports.EnumToken.WildCardFunctionTokenType ? targetParentWrapper : targetWrapper), nodeMap.get(targetWrapper.typ === exports.EnumToken.WildCardFunctionTokenType ? targetWrapper : node), node.r.at(-1)?.typ === exports.EnumToken.SemiColonTokenType @@ -21365,3364 +21572,2462 @@ TransformCssFeature: TransformCssFeature }); - // from https://github.com/Rich-Harris/vlq/tree/master - // credit: Rich Harris - const integer_to_char = {}; - const char_to_integer = {}; - let i = 0; - for (const char of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=') { - char_to_integer[char] = i; - integer_to_char[i++] = char; - } + const notEndingWith = ["(", "["].concat(combinators); + const rules = [ + exports.EnumToken.AtRuleNodeType, + exports.EnumToken.RuleNodeType, + exports.EnumToken.AtRuleTokenType, + exports.EnumToken.KeyframesRuleNodeType, + ]; + // @ts-ignore + const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering); /** - * @param {string} str + * Apply minification rules to the ast tree + * @param ast + * @param options + * @param recursive + * @param errors + * @param nestingContent + * + * @param context + * @private */ - function decode(str) { - /** @type {number[]} */ - let result = []; - let shift = 0; - let value = 0; - for (let i = 0; i < str.length; i += 1) { - let integer = char_to_integer[str[i]]; - // if (integer === undefined) { - // throw new Error('Invalid character (' + str[i] + ')'); - // } - const has_continuation_bit = integer & 32; - integer &= 31; - value += integer << shift; - if (has_continuation_bit) { - shift += 5; - } - else { - const should_negate = value & 1; - value >>>= 1; - if (should_negate) { - result.push(value === 0 ? -2147483648 : -value); - } - else { - result.push(value); - } - // reset - value = shift = 0; + function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { + let preprocess = false; + let postprocess = false; + let parents; + let replacement; + let { sourcemap, module, ...options2 } = options; + if (!(options2.features != null)) { + options2 = { + removeDuplicateDeclarations: true, + computeShorthand: true, + computeCalcExpression: true, + removePrefix: false, + features: [], + ...options2, + }; + for (const feature of features) { + feature.register(options2); } + options2.features.sort((a, b) => a.ordering - b.ordering); } - return result; - } - /** - * - * @param value - * @returns - */ - function encode(value) { - if (typeof value === 'number') { - return encode_integer(value); - } - let result = ''; - for (let i = 0; i < value.length; i += 1) { - result += encode_integer(value[i]); - } - return result; - } - function encode_integer(num) { - let result = ''; - if (num < 0) { - num = (-num << 1) | 1; - } - else { - num <<= 1; - } - do { - let clamped = num & 31; - num >>>= 5; - if (num > 0) { - clamped |= 32; + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Pre) { + preprocess = true; } - result += integer_to_char[clamped]; - } while (num > 0); - return result; - } - - /** - * Generate and parse source map - */ - class SourceMap { - /** - * - * @private - */ - keys = new Set(); - /** - * Last location - */ - lastLocation = null; - /** - * Version - * @private - */ - version = 3; - /** - * Sources map - * @private - */ - sourcesMap = []; - /** - * Sources content - * @private - */ - sourcesContent = []; - /** - * Sources - * @private - */ - sources = []; - /** - * Map - * @private - * - */ - map = new Map(); - /** - * Map - * @private - * - */ - reverseMap = new Map(); - /** - * Line - * @private - */ - line = -1; - /** - * - * @param sourcemaps - */ - constructor(sourcemaps) { - if (typeof sourcemaps === "string") { - if (sourcemaps.startsWith("data:")) { - let encoding = ""; - let offset = sourcemaps.indexOf(",") + 1; - if (offset == 0) { - offset = sourcemaps.lastIndexOf(";") + 1; + if (feature.processMode & exports.FeatureWalkMode.Post) { + postprocess = true; + } + } + if (preprocess) { + parents = new Set([ast]); + for (const parent of parents) { + if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { + continue; + } + replacement = parent; + for (const feature of options2.features) { + if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || + (feature.accept != null && !feature.accept.has(parent.typ))) { + continue; } - else { - encoding = sourcemaps.slice(sourcemaps.lastIndexOf(";") + 1, offset - 1); + if (rules.includes(replacement.typ) && !Array.isArray(replacement[TOKENS])) { + replacement[TOKENS] = parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ === exports.EnumToken.KeyframesRuleNodeType + ? replacement.sel + : // @ts-ignore + replacement.nam); } - if (encoding == "base64") { - sourcemaps = atob(sourcemaps.slice(offset)); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Pre); + if (result != null) { + replacement = result; } - else { - sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); + } + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); + } + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); } } - sourcemaps = JSON.parse(sourcemaps); } - if (sourcemaps != null) { - this.sources = sourcemaps.sources?.slice() ?? []; - this.sourcesContent = sourcemaps.sourcesContent?.slice() ?? []; - const decodedMappings = sourcemaps.mappings - .split(";") - .map((mapping) => mapping.split(",").map((mapping) => decode(mapping))); - this.line = decodedMappings.length - 1; - for (let index = 0; index < decodedMappings.length; index++) { - if (decodedMappings[index].length == 0 || - (decodedMappings[index].length == 1 && decodedMappings[index][0].length == 0)) { + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Pre && "cleanup" in feature) { + // @ts-ignore + feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Pre); + } + } + } + doMinify(ast, options2, recursive, errors, nestingContent, context); + parents = new Set([ast]); + for (const parent of parents) { + if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { + continue; + } + replacement = parent; + if (postprocess) { + for (const feature of options2.features) { + if ((feature.processMode & exports.FeatureWalkMode.Post) === 0 || + (feature.accept != null && !feature.accept.has(parent.typ))) { continue; } - this.map.set(index, decodedMappings[index]); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); + if (result != null) { + replacement = result; + } } - this.computePositions(); } - } - /** - * add source - * @param id - * @param fileName - * @param content - * @returns - */ - addSourceContent(id, fileName, content) { - if (this.sourcesMap.includes(id)) { - return; + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); } - this.sourcesMap[this.sourcesMap.length] = id; - this.sources[this.sources.length] = fileName || null; - this.sourcesContent[this.sourcesContent.length] = content || null; - } - /** - * Add all location - * @param maps - * @throws - */ - add(...maps) { - let srcIndex; - if (typeof maps[0] === "number") { - maps = [maps]; + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } } - for (let [newLine, newColumn, srcId, ln, col] of maps) { - const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; - if (this.keys.has(key)) { - continue; + } + if (postprocess) { + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Post && "cleanup" in feature) { + // @ts-ignore + feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Post); } - this.keys.add(key); - const line = newLine - 1; - let record; - if (line > this.line) { - this.line = line; - } - srcIndex = this.sourcesMap.indexOf(srcId); - if (srcIndex == -1) { - throw new Error(`Source file ${srcId} not added to sourcemap`); - } - if (!this.map.has(line)) { - record = [Math.max(0, newColumn - 1), srcIndex, ln - 1, col - 1]; - this.map.set(line, [record]); - } - else { - const arr = this.map.get(line); - record = [Math.max(0, newColumn - 1) - arr[0][0], srcIndex - arr[0][1], ln - 1, col - 1]; - arr.push(record); - } - if (this.lastLocation != null) { - record[2] -= this.lastLocation.ln - 1; - record[3] -= this.lastLocation.col - 1; - } - this.lastLocation ??= { ln, col }; - this.lastLocation.ln = ln; - this.lastLocation.col = col; } } - /** - * compute original positions - */ - computePositions() { - this.reverseMap.clear(); - let sourceFileIndex = 0; // second field - let sourceCodeLine = 0; // third field - let sourceCodeColumn = 0; // fourth field - // let nameIndex: number = 0; // fifth field - let generatedCodeColumn; - let result; - // mappings to original source - for (let [i, line] of this.map.entries()) { - if (line.length === 0 || (line.length === 1 && line[0].length === 0)) { - continue; - } - generatedCodeColumn = line[0][0]; // first field - reset each time - line = line - .map((segment, index, array) => { - if (segment.length === 0) { - return []; + return ast; + } + function transformAtRuleMediaPrelude(values) { + let hasUpdates = false; + for (let { value, parent, parents } of walkValues(values)) { + if (value.typ === exports.EnumToken.MediaQueryConditionTokenType) { + if (value.op.typ == exports.EnumToken.AndTokenType && + // @ts-ignore + value.l.typ === exports.EnumToken.IdenTokenType && + // @ts-ignore + value.l.val.toLowerCase() === "all") { + if (parent === null) { + // @ts-ignore + values[values.indexOf(value)] = value.l; } - generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; - result = [generatedCodeColumn]; - if (segment.length <= 1) { - return result; + else { + // @ts-ignore + replaceNodeOrValue(parent, value, value.l); + // @ts-ignore + value = value.l; } - sourceFileIndex = index == 0 ? segment[1] : segment[1] + array[0][1]; - sourceCodeLine += segment[2]; - sourceCodeColumn += segment[3]; - result.push(sourceFileIndex, sourceCodeLine, sourceCodeColumn); - // nameIndex not needed - // if (segment.length === 5) { - // nameIndex += segment[4]; - // result.push(nameIndex); - // } - return result; - }) - .sort((a, b) => { - if (a[1] !== b[1]) { - return a[1] - b[1]; + hasUpdates = true; + } + } + // range operator + if (parent != null && + parent.typ === exports.EnumToken.MediaQueryConditionTokenType && + parent.op.typ == exports.EnumToken.AndTokenType && + // @ts-ignore + parent.l.typ == exports.EnumToken.ParensTokenType) { + let token = parent.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + if (token?.typ === exports.EnumToken.ParensTokenType) { + // @ts-ignore + const node1 = parent.l.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const node2 = token.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + if (node1?.typ === exports.EnumToken.MediaQueryConditionTokenType && + node2?.typ === exports.EnumToken.MediaQueryConditionTokenType && + node1.op.typ == exports.EnumToken.ColonTokenType && + node2.op.typ == exports.EnumToken.ColonTokenType && + // @ts-ignore + node1.l.typ == exports.EnumToken.IdenTokenType && + // @ts-ignore + node2.l.typ == exports.EnumToken.IdenTokenType && + // @ts-ignore + node1.l.val.startsWith("min-") && + // @ts-ignore + node2.l.val.startsWith("max-") && + // @ts-ignore + node1.l.val.slice(4) == + // @ts-ignore + node2.l.val.slice(4)) { + const val1 = node1.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const val2 = node2.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const replacement = { + typ: exports.EnumToken.ParensTokenType, + chi: [ + // @ts-ignore + { + typ: exports.EnumToken.MediaRangeQueryTokenType, + op: { + typ: exports.EnumToken.IdenTokenType, + // @ts-ignore + val: node1.l.val.slice(4), + }, + l: val1, + r: val2, + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], + }, + ], + }; + // @ts-expect-error + const p = parents?.[parents?.indexOf?.(parent) + 1]; + if (p != null) { + // @ts-ignore + replaceNodeOrValue(p, parent, replacement); + } + else { + // @ts-ignore + values.splice(values.indexOf(parent), 1, replacement); + } + hasUpdates = true; + value = replacement; } - return a[0] - b[0]; - }); - if (line.length == 0 || (line.length == 1 && line[0].length == 0)) { - continue; } - this.reverseMap.set(i, line); } } - /** - * retrieve original sources, lines and columns - * @param line generated line - * @param column generated column - */ - find(line, column) { - if (this.reverseMap.size == 0) { - this.computePositions(); + return { hasUpdates, values: trimArray(values) }; + } + /** + * Minify at-rule media + * - remove redundant tokens + * - generate range queries + * + * @private + * @param tokens + */ + function minifyAtRuleMedia(tokens) { + let hasUpdates = false; + const sections = tokens + .reduce((acc, t) => { + if (t.typ === exports.EnumToken.CommaTokenType) { + acc.push([]); } - if (!this.reverseMap.has(--line)) { - return null; + else { + acc[acc.length - 1].push(t); } - column--; - const result = []; - for (const record of this.reverseMap.get(line)) { - if (record.length == 0 || record[0] < column) { - continue; - } - if (record[0] > column) { - break; - } - result.push([ - this.sources?.[record[1]] ?? null, - record[2] + 1, - record[3] + 1, - this.sourcesContent?.[record[1]] ?? null, - ]); + return acc; + }, [[]]) + .reduce((acc, values) => { + if (acc.has("all")) { + return acc; } - return result.length == 0 ? null : result; - } - /** - * Convert to URL encoded string - */ - toUrl() { - // /*# sourceMappingURL = ${url} */ - return `data:application/json;charset=utf-8;base64,${btoa(JSON.stringify(this.toJSON()))}`; + const result = transformAtRuleMediaPrelude(values); + if (result.values.length === 0) { + return acc; + } + if (result.hasUpdates) { + hasUpdates = true; + } + acc.set(values.reduce((acc, t) => acc + renderValue(t), ""), result.values); + return acc; + }, new Map()); + if (sections.has("all")) { + tokens.length = 0; } - /** - * Convert to JSON object - */ - toJSON() { - const mappings = []; - let i = 0; - for (; i <= this.line; i++) { - if (!this.map.has(i)) { - mappings.push(""); + else if (hasUpdates) { + tokens.length = 0; + tokens.push(...[...sections.values()].reduce((acc, t) => { + if (acc.length > 0) { + acc.push({ + typ: exports.EnumToken.CommaTokenType, + }); } - else { - mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); + for (const token of t) { + acc.push(token); } - } - return { - version: this.version, - sources: this.sources.slice(), - sourcesContent: this.sourcesContent?.slice(), - mappings: mappings.join(";"), - }; + return acc; + }, [])); } + // return ast; + return tokens; } - /** - * Compute line and column of the offset + * Reduce selectors + * @param acc + * @param curr + * + * @private */ - class LineMap { - /** - * line starts - */ - lineStarts; - /** - * Constructor - * @param lines - */ - constructor(lines = []) { - if (lines.length === 0) { - lines.push(0); - } - this.lineStarts = lines; - } - /** - * Compute line and column of the offset - * @param offset - * @returns - */ - getOffsets(offset) { - const line = this.search(offset); - // if (offset < 0 || line < 0) { - // return [1, 1]; - // } - // [line, column] - return [line + 1, offset - this.lineStarts[line] + 1]; - } - /** - * search the greatest index of the value less than or equal to offset - * @param offset - * @returns - */ - search(offset) { - // search lineStarts using binary search - let start = 0; - let end = this.lineStarts.length - 1; - let mid = 0; - let result = -1; - while (start <= end) { - mid = start + ((end - start) >>> 1); - if (this.lineStarts[mid] <= offset) { - result = mid; - start = mid + 1; - } - else if (this.lineStarts[mid] > offset) { - end = mid - 1; - } + function reduce(acc, curr) { + // trim :is() + if (curr[0] == "&") { + if (curr[1] == " " && !isIdent(curr[2]) && !isFunction(curr[2])) { + curr.splice(0, 2); } - return result; - } - /** - * get line starts - * @returns - */ - getLineStarts() { - return this.lineStarts; - } - /** - * add line start - */ - addLineStart(lineStart) { - this.lineStarts.push(lineStart); } + acc.push(curr.join("")); + return acc; } - /** - * Source file ID - */ - let sourceId = 0; - /** - * Source file helper class + * Apply minification rules to the ast tree + * @param ast + * @param options + * @param recursive + * @param errors + * @param nestingContent + * @param context + * + * @private */ - class SourceFile { - inputSourceMap = null; - /** - * Source file ID - */ - id; - /** - * Source file path - */ - file; - /** - * Line map - */ - lineStarts; - /** - * Source file content - */ - content; - /** - * Constructor - * @param content - * @param lines - * @param file - */ - constructor(content, lines, file = null) { - this.id = sourceId++; - this.content = content; - this.file = file; - this.lineStarts = new LineMap(lines); - } - /** - * Update source content - * @param content - */ - append(content) { - this.content += content; - } - /** - * get file name - * @returns - */ - getFileName() { - return this.file; - } - /** - * get content - * @returns - */ - getContent() { - return this.content; - } - /** - * get text - * @param start - * @param length - * @returns - */ - getText(start, length) { - return this.content.slice(start, start + length); - } - /** - * Compute line and column of the offset - * @param offset - * @returns - */ - getOffsets(offset) { - return this.lineStarts.getOffsets(offset); - } - /** - * get source location - * @param offset - * @returns - */ - getSourceLocation(offset) { - return [this.file, ...this.getOffsets(offset)]; - } - /** - * get line starts - * @returns - */ - getLineStarts() { - return this.lineStarts.getLineStarts(); - } - /** - * add line start - * @param lineStart - */ - addLineStart(lineStart) { - this.lineStarts.addLineStart(lineStart); - } - /** - * set input source map - * @param inputSourceMap - */ - setInputSourceMap(inputSourceMap) { - this.inputSourceMap = inputSourceMap == null ? null : new SourceMap(inputSourceMap); + function doMinify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { + if (!("nodes" in context)) { + context.nodes = new Set(); } - /** - * return input source map - * @returns - */ - getInputSourceMap() { - return this.inputSourceMap; + if (context.nodes.has(ast)) { + return ast; } - } - - const SymbolsMapTokens = { - "+": exports.EnumToken.Plus, - "=": exports.EnumToken.DelimTokenType, - "|": exports.EnumToken.Pipe, - "||": exports.EnumToken.ColumnCombinatorTokenType, - "|=": exports.EnumToken.DashMatchTokenType, - "&": exports.EnumToken.NestingSelectorTokenType, - "*": exports.EnumToken.Star, - "*=": exports.EnumToken.ContainMatchTokenType, - "~": exports.EnumToken.Tilda, - "~=": exports.EnumToken.IncludeMatchTokenType, - "^=": exports.EnumToken.StartMatchTokenType, - "$=": exports.EnumToken.EndMatchTokenType, - ",": exports.EnumToken.Comma, - ":": exports.EnumToken.ColonTokenType, - "::": exports.EnumToken.DoubleColonTokenType, - ";": exports.EnumToken.SemiColonTokenType, - "(": exports.EnumToken.StartParensTokenType, - ")": exports.EnumToken.EndParensTokenType, - "[": exports.EnumToken.AttrStartTokenType, - "]": exports.EnumToken.AttrEndTokenType, - "{": exports.EnumToken.BlockStartTokenType, - "}": exports.EnumToken.BlockEndTokenType, - "<=": exports.EnumToken.LteTokenType, - ">": exports.EnumToken.GtTokenType, - ">=": exports.EnumToken.GteTokenType, - " ": exports.EnumToken.Whitespace, - "\t": exports.EnumToken.Whitespace, - "\r": exports.EnumToken.Whitespace, - "\n": exports.EnumToken.Whitespace, - "\f": exports.EnumToken.Whitespace, - ...pseudoElements.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.PseudoElementTokenType; - return acc; - }, Object.create(null)), - ...containerFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ContainerFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...urlFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.UrlFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...gridTemplateFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.GridTemplateFuncTokenDefType; - return acc; - }, Object.create(null)), - ...imageFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ImageFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timelineFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.TimelineFunctionTokenDefType; - return acc; - }, Object.create(null)), - // ...generalEnclosedFunc.reduce((acc, curr: string) => { - // acc[curr + "("] = EnumToken.GeneralEnclosedFunctionTokenDefType; - // return acc; - // }, Object.create(null)), - ...supportFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.SupportsFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timingFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.TimingFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...colorsFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ColorFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...mathFuncs.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.MathFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...transformFunctions.reduce((acc, curr) => { - acc[curr.toLowerCase() + "("] = exports.EnumToken.TransformFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...whenElseFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.WhenElseFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...wildCardFuncs.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.WildCardFunctionTokenDefType; - return acc; - }, Object.create(null)), - }; - // do not capture the value - const hintsEnum = new Set([ - exports.EnumToken.CommaTokenType, - exports.EnumToken.ImportantTokenType, - exports.EnumToken.SemiColonTokenType, - exports.EnumToken.BlockStartTokenType, - exports.EnumToken.BlockEndTokenType, - exports.EnumToken.StartParensTokenType, - exports.EnumToken.EndParensTokenType, - exports.EnumToken.ColonTokenType, - exports.EnumToken.EOFTokenType, - ]); - var TokenMap; - (function (TokenMap) { - TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; - TokenMap[TokenMap["SLASH"] = 47] = "SLASH"; - TokenMap[TokenMap["LOWERTHAN"] = 60] = "LOWERTHAN"; - TokenMap[TokenMap["HASH"] = 35] = "HASH"; - TokenMap[TokenMap["REVERSE_SOLIDUS"] = 92] = "REVERSE_SOLIDUS"; - TokenMap[TokenMap["DOUBLE_QUOTE"] = 34] = "DOUBLE_QUOTE"; - TokenMap[TokenMap["SINGLE_QUOTE"] = 39] = "SINGLE_QUOTE"; - TokenMap[TokenMap["DOT"] = 46] = "DOT"; - TokenMap[TokenMap["AT"] = 64] = "AT"; - TokenMap[TokenMap["PIPE"] = 124] = "PIPE"; - TokenMap[TokenMap["EQUALS"] = 61] = "EQUALS"; - TokenMap[TokenMap["AMPERSAND"] = 38] = "AMPERSAND"; - TokenMap[TokenMap["STAR"] = 42] = "STAR"; - TokenMap[TokenMap["TILDA"] = 126] = "TILDA"; - TokenMap[TokenMap["CARET"] = 94] = "CARET"; - TokenMap[TokenMap["DOLLAR"] = 36] = "DOLLAR"; - TokenMap[TokenMap["COMMA"] = 44] = "COMMA"; - TokenMap[TokenMap["COLON"] = 58] = "COLON"; - TokenMap[TokenMap["SEMICOLON"] = 59] = "SEMICOLON"; - TokenMap[TokenMap["LEFT_PARENTHESIS"] = 40] = "LEFT_PARENTHESIS"; - TokenMap[TokenMap["RIGHT_PARENTHESIS"] = 41] = "RIGHT_PARENTHESIS"; - TokenMap[TokenMap["LEFT_BRACKETS"] = 91] = "LEFT_BRACKETS"; - TokenMap[TokenMap["RIGHT_BRACKETS"] = 93] = "RIGHT_BRACKETS"; - TokenMap[TokenMap["LEFT_BRACE"] = 123] = "LEFT_BRACE"; - TokenMap[TokenMap["RIGHT_BRACE"] = 125] = "RIGHT_BRACE"; - TokenMap[TokenMap["PLUS"] = 43] = "PLUS"; - TokenMap[TokenMap["MINUS"] = 45] = "MINUS"; - TokenMap[TokenMap["GREATERTHAN"] = 62] = "GREATERTHAN"; - })(TokenMap || (TokenMap = {})); - function consumeString(parseInfo) { - const quote = next(parseInfo).charCodeAt(0); - let charCode; - let decodeSegments = false; - const result = []; - while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { - if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { - next(parseInfo, 2); - continue; - } - const sequence = peek(parseInfo, 7); - let escapeSequence = ""; - let codepoint; - let i; - for (i = 1; i < sequence.length; i++) { - codepoint = sequence.charCodeAt(i); - if (codepoint == 0x20 || - (codepoint >= 0x61 && codepoint <= 0x66) || - (codepoint >= 0x41 && codepoint <= 0x46) || - (codepoint >= 0x30 && codepoint <= 0x39)) { - escapeSequence += sequence[i]; - if (codepoint == 0x20) { - break; - } - continue; - } - break; - } - if (escapeSequence.trimEnd().length > 0) { - // const codepoint = parseInt(escapeSequence, 16); - // TODO set decode flag ON - // if ( - // codepoint == 0 || - // // leading surrogate - // (0xd800 <= codepoint && codepoint <= 0xdbff) || - // // trailing surrogate - // (0xdc00 <= codepoint && codepoint <= 0xdfff) - // ) { - // buffer += String.fromCodePoint(0xfffd); - // } else { - // buffer += String.fromCodePoint(codepoint); - // } - const length = escapeSequence.length + - 1 + - (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) - ? 1 - : 0); - decodeSegments = true; - next(parseInfo, length); - continue; - } - next(parseInfo, 2); - continue; - } - if (charCode == quote) { - next(parseInfo); - result.push(yieldResult(parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null)); - return result; - } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BadStringTokenType)); - return result; - } - next(parseInfo); - } - // EOF - 'Unclosed-string' fixed - result.push(yieldResult(parseInfo, exports.EnumToken.StringTokenType)); - return result; - } - function yieldResult(parseInfo, hint, options) { - let val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); - let token = null; - let dimension; - if (options?.decodeSegments) { - val = val.replace(/\\([0-9a-fA-F]{1,6})(?:\s)?/g, (_, sequence) => { - const codepoint = parseInt(sequence, 16); - if (codepoint == 0 || - // leading surrogate - (0xd800 <= codepoint && codepoint <= 0xdbff) || - // trailing surrogate - (0xdc00 <= codepoint && codepoint <= 0xdfff) || - codepoint > 0x10ffff) { - return "\uFFFD"; - } - return String.fromCodePoint(codepoint); - }); - } - if (hint != null) { - let searchArray = null; - switch (hint) { - case exports.EnumToken.TransformFunctionTokenDefType: - searchArray = transformFunctions; - break; - case exports.EnumToken.ColorFunctionTokenDefType: - searchArray = colorsFunc; - break; - case exports.EnumToken.ContainerFunctionTokenDefType: - searchArray = containerFunc; - break; - case exports.EnumToken.UrlFunctionTokenDefType: - searchArray = urlFunc; - break; - case exports.EnumToken.GridTemplateFuncTokenDefType: - searchArray = gridTemplateFunc; - break; - case exports.EnumToken.ImageFunctionTokenDefType: - searchArray = imageFunc; - break; - case exports.EnumToken.TimelineFunctionTokenDefType: - searchArray = timelineFunc; - break; - // case EnumToken.GeneralEnclosedFunctionTokenDefType: - // searchArray = generalEnclosedFunc; - // break; - case exports.EnumToken.SupportsFunctionTokenDefType: - searchArray = supportFunc; - break; - case exports.EnumToken.TimingFunctionTokenDefType: - searchArray = timingFunc; - break; - case exports.EnumToken.MathFunctionTokenDefType: - searchArray = mathFuncs; - break; - case exports.EnumToken.WhenElseFunctionTokenDefType: - searchArray = whenElseFunc; - break; - case exports.EnumToken.WildCardFunctionTokenDefType: - searchArray = wildCardFuncs; - break; - } - if (searchArray != null) { - val = searchArray.find((v) => equalsIgnoreCase(v, val)); - } - token = hintsEnum.has(hint) ? { typ: hint } : { typ: hint, val }; - } - else { - let slice = val.slice(1); - const chr = val.charAt(0); - if (chr == "!" && equalsIgnoreCase("!important", val)) { - token = { - typ: exports.EnumToken.ImportantTokenType, - }; - } - else if (chr == "@" && isIdent(slice)) { - token = { - typ: exports.EnumToken.AtRuleTokenType, - nam: slice, - }; - } - else if (chr == "." && isIdent(slice)) { - token = { - typ: exports.EnumToken.ClassSelectorTokenType, - val, - }; - } - else if (chr == "#") { - if (isHexColor(val)) { - token = { - typ: exports.EnumToken.ColorTokenType, - val: val, - kin: exports.ColorType.HEX, - }; - } - else if (isHash(val)) { - token = { - typ: exports.EnumToken.HashTokenType, - val: val, - }; - } - } - else if ("\"'".includes(chr)) { - token = { - typ: exports.EnumToken.UnclosedStringTokenType, - val: val, - }; - } - else if (isNumber(val)) { - token = - val[0] === "-" || val[0] === "+" - ? { - typ: exports.EnumToken.NumberTokenType, - sign: val[0], - val: +val, - } - : { - typ: exports.EnumToken.NumberTokenType, - val: +val, - }; - } - else if (isPercentage(val)) { - token = { - typ: exports.EnumToken.PercentageTokenType, - val: +val.slice(0, -1), - }; - } - else if ((dimension = parseDimension(val))) { - token = dimension; - } - else if (isIdent(val)) { - token = { - typ: val.startsWith("--") ? exports.EnumToken.DashedIdenTokenType : exports.EnumToken.IdenTokenType, - val, - }; - } - } - if (token == null) { - token = { - typ: exports.EnumToken.LiteralTokenType, - val, - }; - } - // return token; - token[LOC] = { - srcId: parseInfo.source.id, - sta: parseInfo.position, - end: parseInfo.currentPosition, - }; - parseInfo.position = parseInfo.currentPosition; - return { token, bytesIn: parseInfo.currentPosition }; - } - function match(parseInfo, input) { - let position = parseInfo.currentPosition - parseInfo.offset; - for (let i = 0; i < input.length; i++) { - if (parseInfo.stream[position + i] != input.charAt(i)) { - return false; - } - } - return true; - } - function peek(parseInfo, count = 1) { - if (count == 1) { - return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); - } - const position = parseInfo.currentPosition - parseInfo.offset; - return parseInfo.stream.slice(position, position + count); - } - function next(parseInfo, count = 1) { - let position = parseInfo.currentPosition - parseInfo.offset; - let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); - let i = 0; - let codepoint; - for (; i < char.length; i++) { - codepoint = char[i].charCodeAt(0); - if (codepoint == 0xa || // \n - codepoint == 0xb || // \v - codepoint == 0xc || // \f - codepoint == 0xd || // \r - codepoint == 0x2028 || // \u2028 - codepoint == 0x2029 // \u2029 - ) { - // \r\n - if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; - else { - parseInfo.source.lineStarts.lineStarts.push(position + i); - } - } - } - parseInfo.currentPosition += char.length; - return char; - } - function isIdentToken(parseInfo, start, end) { - let j = parseInfo.currentPosition - parseInfo.offset; - let i = parseInfo.position - parseInfo.offset; - if (start != null) { - if (end == null) { - if (start < 0) { - j += start; - } - else { - i += start; - } + context.nodes.add(ast); + // @ts-ignore + if ("chi" in ast && ast.chi.length > 0) { + const reducer = reduce.bind(ast); + if (!nestingContent) { + nestingContent = options.nestingRules && ast.typ == exports.EnumToken.RuleNodeType; } - else { - if (end < 0) { - j += end; + let i = 0; + let previous = null; + let node = null; + let nodeIndex = -1; + for (; i < ast.chi.length; i++) { + if (ast.chi[i].typ === exports.EnumToken.CommentNodeType) { + continue; } - else { - j = parseInfo.position + end; + while (previous?.typ === exports.EnumToken.CommentNodeType) { + // @ts-ignore + previous = ast.chi[--nodeIndex]; } - } - } - j--; - let codepoint = parseInfo.stream.charCodeAt(i); - // - - if (codepoint == 0x2d) { - let nextCodepoint; - if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { - return false; - } - if (isDigit(nextCodepoint)) { - return false; - } - codepoint = nextCodepoint; - i++; - } - if (codepoint !== 0x2d && !isIdentStart(codepoint)) { - return false; - } - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - codepoint = parseInfo.stream.charCodeAt(i + 1); - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - i += String.fromCodePoint(codepoint).length; - // if (i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - // } - } - while (i < j) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - continue; - } - if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { - return false; - } - } - return true; - } - function isPseudo(parseInfo) { - let position = parseInfo.currentPosition - parseInfo.offset; - let endPosition = parseInfo.currentPosition - parseInfo.offset; - return (parseInfo.stream.charAt(position) == ":" && - parseInfo.stream.charAt(endPosition - 1) == "(" && - (parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2, -1) - : isIdentToken(parseInfo, 1, -1))) || - parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2) - : isIdentToken(parseInfo, 1); - } - function startsWith(parseInfo, input) { - let i = 0; - let j = input.length; - while (i < j) { - if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { - return false; - } - i++; - } - return true; - } - function isURLToken(parseInfo) { - let i = parseInfo.position - parseInfo.offset; - let c; - while (++i < parseInfo.currentPosition) { - c = parseInfo.stream.charCodeAt(i); - // single quote or double quote or start parenthesis or close parenthesis - if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { - return false; - } - // valid escape - if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i++; - if (i >= parseInfo.currentPosition) { - return false; + node = ast.chi[i]; + if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { + continue; } - c = parseInfo.stream.charCodeAt(i); - // c is not '\n' or '\r' or '\f' - if (c == 0x6e || c == 0x72 || c == 0x66) { - return false; + if (node.typ === exports.EnumToken.KeyframesAtRuleNodeType) { + if (previous?.typ === exports.EnumToken.KeyframesAtRuleNodeType && + node.nam === previous.nam && + node.val === previous.val) { + ast.chi?.splice(nodeIndex--, 1); + previous = ast?.chi?.[nodeIndex] ?? null; + i = nodeIndex; + continue; + } } - continue; - } - // is white space - if (c == 0x20 || c == 0x09) { - break; - } - } - return i == parseInfo.currentPosition; - } - /** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ - function tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } - let charCode; - let nextCharCode; - const startTime = performance.now(); - const result = []; - // allow 10 characters buffer for the streaming parser to avoid incomplete tokens - const endPosition = parseInfo.stream.length - 1; - // NaN is not equal to NaN - while ((charCode = peek(parseInfo).charCodeAt(0)) == charCode) { - switch (charCode) { - case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.DelimTokenType)); - break; - // '+' or '-' - case 43 /* TokenMap.PLUS */: - case 45 /* TokenMap.MINUS */: - nextCharCode = peek(parseInfo).charCodeAt(0); - // not a number - if (charCode === 43 /* TokenMap.PLUS */ && !(nextCharCode >= 0x30 && nextCharCode <= 0x39)) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + else if (node.typ === exports.EnumToken.KeyframesRuleNodeType) { + if (previous?.typ === exports.EnumToken.KeyframesRuleNodeType && + node.sel === previous.sel) { + // do not merge keyframes + // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates + for (const child of node.chi) { + previous.chi.push(child); } - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase()])); - break; - } - next(parseInfo); - break; - // '{' - case 123 /* TokenMap.LEFT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // @ts-ignore + ast.chi.splice(i, 1); + previous = ast?.chi?.[nodeIndex] ?? null; + i = nodeIndex; + continue; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockEndTokenType)); - break; - // '(' - case 40 /* TokenMap.LEFT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && isPseudo(parseInfo)) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType)); - break; - } - else if (isIdentToken(parseInfo)) { - const hint = startsWith(parseInfo, "--") - ? exports.EnumToken.CustomFunctionTokenDefType - : (SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase() + "("] ?? exports.EnumToken.FunctionTokenDefType); - result.push(yieldResult(parseInfo, hint)); - next(parseInfo); - // consume '(' - parseInfo.position = parseInfo.currentPosition; - if (hint === exports.EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(peek(parseInfo).charCodeAt(0))) { - next(parseInfo); - } - charCode = peek(parseInfo).charCodeAt(0); - let values = null; - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - values = consumeString(parseInfo); - } - else { - do { - next(parseInfo); - // value = peek(parseInfo); - charCode = peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); - } - if (values != null) { - // NaN is not equal to NaN - if ((charCode = peek(parseInfo).charCodeAt(0)) != charCode) { - for (let i = 0; i < values.length; i++) { - values[i].token.typ = exports.EnumToken.BadUrlTokenType; - } - } - result.push(...values); + let k; + for (k = 0; k < node.chi.length; k++) { + if (node.chi[k].typ == exports.EnumToken.DeclarationNodeType) { + let l = node.chi[k].val.length; + while (l--) { + if (node.chi[k].val[l].typ == + exports.EnumToken.ImportantTokenType) { + node.chi.splice(k--, 1); + break; } - else if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = peek(parseInfo).charCodeAt(0)) != charCode || !isURLToken(parseInfo) - ? exports.EnumToken.BadUrlTokenType - : exports.EnumToken.UrlTokenTokenType)); + if ([exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(node.chi[k].val[l].typ)) { + continue; } + break; } - break; } } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.StartParensTokenType)); - break; - // ')' - case 41 /* TokenMap.RIGHT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.EndParensTokenType)); - break; - // '[' - case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.AttrStartTokenType)); - break; - // ']' - case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.AttrEndTokenType)); - break; - case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.SemiColonTokenType)); - break; - case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - if (peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.DoubleColonTokenType)); - break; - } - result.push(yieldResult(parseInfo, exports.EnumToken.ColonTokenType)); - break; - // \n \r \f \v \t space - case 0x9: - case 0x20: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0x2028: - case 0x2029: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - while (nextCharCode == 0x20 || - (nextCharCode >= 0x9 && nextCharCode <= 0xd) || - nextCharCode == 0x2028 || - nextCharCode == 0x2029) { - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - } - result.push(yieldResult(parseInfo, exports.EnumToken.WhitespaceTokenType)); - break; - case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.CommaTokenType)); - break; - case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "$=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.EndMatchTokenType)); - break; - } - next(parseInfo); - break; - case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "~=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.IncludeMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Tilda)); - break; - // case '^': - case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "^=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.StartMatchTokenType)); - break; - } - next(parseInfo); - break; - case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "*=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.ContainMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Star)); - break; - case 38 /* TokenMap.AMPERSAND */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.NestingSelectorTokenType)); - break; - case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - // '||' - if (match(parseInfo, "||")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.ColumnCombinatorTokenType)); - break; - } - else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.DashMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Pipe)); - break; - case 33 /* TokenMap.EXCLAMATION */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "!important")) { - next(parseInfo, 10); - result.push(yieldResult(parseInfo, exports.EnumToken.ImportantTokenType)); - break; - } - next(parseInfo); - break; - case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (!match(parseInfo, "/*")) { - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream.slice(parseInfo.position, parseInfo.currentPosition)])); - break; + } + else if (node.typ == exports.EnumToken.AtRuleNodeType) { + if (node.nam == "media") { + if (Array.isArray(node[TOKENS])) { + const slice = node[TOKENS].slice(); + minifyAtRuleMedia(slice); + if (slice.length !== node[TOKENS].length) { + node[TOKENS].length = 0; + for (const token of slice) { + node[TOKENS].push(token); + } + node.val = slice.reduce((acc, curr, index, arr) => acc + + (curr.typ === exports.EnumToken.CommentTokenType || + (curr.typ === exports.EnumToken.WhitespaceTokenType && + arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && + (index + 3 < arr.length || + arr[index + 2]?.typ === exports.EnumToken.WhitespaceTokenType)) + ? "" + : renderValue(curr)), ""); + } + } + if (["all", "", null].includes(node.val)) { + ast.chi?.splice(i--, 1, ...node.chi); + continue; + } } - next(parseInfo, 2); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 42 /* TokenMap.STAR */) { - if (match(parseInfo, "/")) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.CommentTokenType)); + else if (node.nam === "import" && Array.isArray(node[TOKENS])) { + let l = 0; + let token; + for (; l < node[TOKENS].length; l++) { + token = node[TOKENS][l]; + if (token.typ === exports.EnumToken.ParensTokenType || + token.typ === exports.EnumToken.MediaQueryConditionTokenType || + (token.typ === exports.EnumToken.IdenTokenType && "layer" !== token.val)) { break; } } - // else { - // buffer += value; - // } - } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, exports.EnumToken.BadCommentTokenType)); - } - break; - case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (l < node[TOKENS].length) { + const slice = node[TOKENS]?.slice(l); + node[TOKENS].splice(l, slice.length, ...minifyAtRuleMedia(slice)); + node.val = trimArray(node[TOKENS]).reduce((acc, curr, index, arr) => acc + + (curr.typ === exports.EnumToken.CommentTokenType || + (curr.typ === exports.EnumToken.WhitespaceTokenType && + arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && + (index + 3 < arr.length || arr[index + 2].typ === exports.EnumToken.WhitespaceTokenType)) + ? "" + : renderValue(curr)), ""); + } } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.GteTokenType)); - break; + else if (ast.typ === node.typ && + ast.nam === node.nam && + ast.val === node.val) { + // @ts-ignore + replaceNodeOrValue(ast, node, node.chi); + i--; + continue; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.GtTokenType)); - break; - case 60 /* TokenMap.LOWERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (previous?.typ == exports.EnumToken.AtRuleNodeType && + node.nam != "font-face" && + previous.nam === node.nam && + previous.val === node.val) { + if ("chi" in node) { + for (const child of node.chi) { + previous.chi.push(child); + } + if (!hasDeclaration(previous)) { + context.nodes.delete(previous); + doMinify(previous, options, recursive, errors, nestingContent, context); + } + } + ast?.chi?.splice(i--, 1); + continue; } - if (match(parseInfo, "<=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.LteTokenType)); - break; + // if (!hasDeclaration(node as AstAtRule)) { + // doMinify(node, options, recursive, errors, nestingContent, context); + // } + if ("chi" in node) { + doMinify(node, options, recursive, errors, nestingContent, context); } - next(parseInfo); - if (match(parseInfo, "!--")) { - next(parseInfo, 3); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 45 /* TokenMap.MINUS */ && match(parseInfo, "->")) { - break; + previous = node; + nodeIndex = i; + continue; + } + // @ts-ignore + else if (node.typ === exports.EnumToken.RuleNodeType) { + reduceRuleSelector(node); + let wrapper = null; + let match; + if (options.nestingRules) { + if (previous?.typ == exports.EnumToken.RuleNodeType) { + reduceRuleSelector(previous); + // @ts-ignore + match = matchSelectors(previous[RAW], node[RAW]); + if (match != null) { + wrapper = wrapNodes(previous, node, match, ast, reducer, i, nodeIndex); + nodeIndex = i - 1; + previous = ast.chi[nodeIndex]; + } + } + if (wrapper != null) { + while (i < ast.chi.length) { + const nextNode = ast.chi[i]; + if (nextNode.typ != exports.EnumToken.RuleNodeType) { + break; + } + reduceRuleSelector(nextNode); + match = matchSelectors(wrapper[RAW], nextNode[RAW]); + if (match == null) { + break; + } + wrapper = wrapNodes(wrapper, nextNode, match, ast, reducer, i, nodeIndex); } + nodeIndex = --i; + previous = ast.chi[nodeIndex]; + doMinify(wrapper, options, recursive, errors, nestingContent, context); + continue; } - if (parseInfo.currentPosition >= endPosition) { - result.push(yieldResult(parseInfo, exports.EnumToken.BadCdoTokenType)); + // @ts-ignore + else if (node[OPTIMIZED] != null && + // @ts-ignore + node[OPTIMIZED].match && + // @ts-ignore + node[OPTIMIZED].selector.length > 1) { + // @ts-ignore + wrapper = { + ...node, + chi: [], + sel: node[OPTIMIZED].optimized[0], + [RAW]: [[node[OPTIMIZED].optimized[0]]], + }; + // @ts-ignore + node.sel = node[OPTIMIZED].selector.reduce(reducer, []).join(","); + // @ts-ignore + node[RAW] = node[OPTIMIZED].selector.slice(); + node[TOKENS] = null; + // @ts-ignore + wrapper.chi.push(node); + // @ts-ignore + ast.chi.splice(i, 1, wrapper); + node = wrapper; } - else { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.CDOCOMMTokenType)); + else if (node[OPTIMIZED]?.reducible) { + if (node[OPTIMIZED].optimized.length === 1) { + const sel1 = node[OPTIMIZED].optimized[0] + + ":is(" + + node[OPTIMIZED].selector.reduce(reducer, []).join(",") + + ")"; + const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => + // @ts-ignore + (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); + node.sel = sel1.length < sel2.length ? sel1 : sel2; + node[TOKENS] = null; + } + else if (node[OPTIMIZED].optimized.length === 0) { + const testIdent = /^[a-zA-Z]/; + node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + + (nestingContent && testIdent.test(curr[0]) ? "& " : "") + + curr.join(""), ""); + node[TOKENS] = null; + } } } - break; - case 35 /* TokenMap.HASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - break; - case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } - next(parseInfo); - // EOF - if (!peek(parseInfo)) { - if (!yieldEOFToken) { - break; + // @ts-ignore + else if (node[OPTIMIZED]?.match) { + let wrap = true; + // @ts-ignore + const selector = node[OPTIMIZED].selector.reduce((acc, curr) => { + if (curr[0] == "&" && curr.length > 1) { + if (curr[1] == " ") { + curr.splice(0, 2); + } + else { + curr.splice(0, 1); + } + } + else if (combinators.includes(curr[0])) { + curr.unshift("&"); + wrap = false; + } + acc.push(curr); + return acc; + }, []); + if (!wrap) { + wrap = selector.some((s) => s[0] != "&"); } - // end of stream ignore \\ - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + let rule = null; + const optimized = node[OPTIMIZED].optimized.slice(); + if (optimized.length > 1) { + const check = optimized.at(-2); + if (!combinators.includes(check)) { + let last = optimized.pop(); + wrap = false; + rule = + optimized.join("") + + `:is(${selector + .map((s) => { + if (s[0] == "&") { + s.splice(0, 1, last); + } + else { + s.unshift(last); + } + return s.join(""); + }) + .join(",")})`; + } + } + if (rule == null) { + rule = selector + .map((s) => { + if (s[0] == "&") { + s.splice(0, 1, ...node[OPTIMIZED].optimized); + } + return s.join(""); + }) + .join(","); + } + let sel = wrap ? node[OPTIMIZED].optimized.join("") + `:is(${rule})` : rule; + if (sel.length < node.sel.length) { + node.sel = sel; + node[TOKENS] = null; } - break; - } - next(parseInfo); - break; - case 39 /* TokenMap.SINGLE_QUOTE */: - case 34 /* TokenMap.DOUBLE_QUOTE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - result.push(...consumeString(parseInfo)); - break; - case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - next(parseInfo, 2); - break; } - next(parseInfo); - break; - default: - next(parseInfo); - break; + else if (node[OPTIMIZED]?.reducible) { + if (node[OPTIMIZED].optimized.length === 1) { + const sel1 = node[OPTIMIZED].optimized[0] + + ":is(" + + node[OPTIMIZED].selector.reduce(reducer, []).join(",") + + ")"; + const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => + // @ts-ignore + (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); + node.sel = sel1.length < sel2.length ? sel1 : sel2; + node[TOKENS] = null; + } + else if (node[OPTIMIZED].optimized.length === 0) { + const testIdent = /^[a-zA-Z]/; + node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + + (nestingContent && testIdent.test(curr[0]) ? "& " : "") + + curr.join(""), ""); + node[TOKENS] = null; + } + // @ts-ignore + } + else if (node[OPTIMIZED]?.optimized.length > 0) { + // @ts-ignore + const sel = node[OPTIMIZED].optimized.join(""); + if (sel.length < node.sel.length) { + node.sel = sel; + // @ts-ignore + node[RAW] = [node[OPTIMIZED].optimized.slice()]; + node[TOKENS] = null; + } + } + doMinify(node, options, recursive, errors, nestingContent, context); + } + if (previous != null) { + if ("chi" in previous && "chi" in node) { + if (previous.typ === node.typ) { + let shouldMerge = true; + let k = previous.chi.length; + while (k-- > 0) { + if (previous.chi[k].typ === exports.EnumToken.CommentNodeType || + previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType || + previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType) { + continue; + } + shouldMerge = previous.chi[k].typ === exports.EnumToken.DeclarationNodeType; + break; + } + if (shouldMerge) { + if (((node.typ === exports.EnumToken.RuleNodeType || + node.typ === exports.EnumToken.KeyframesRuleNodeType) && + node.sel === previous.sel) || + // @ts-ignore + (node.typ == exports.EnumToken.AtRuleNodeType && + node.nam !== "font-face" && + // @ts-ignore + node.nam === previous.nam)) { + const array = []; + for (let i = 0; i < previous.chi.length; i++) { + array.push(previous.chi[i]); + } + for (let i = 0; i < node.chi.length; i++) { + array.push(node.chi[i]); + } + // @ts-ignore + node.chi = array; + doMinify(node, options, recursive, errors, nestingContent, context); + ast.chi.splice(nodeIndex, 1); + previous = ast.chi[--i]; + nodeIndex = i; + continue; + } + else if (node.typ == previous?.typ && + [exports.EnumToken.KeyframesRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) { + const intersect = diff$1(previous, node, options); + if (intersect != null) { + if (intersect.node1.chi.length == 0) { + ast.chi.splice(i--, 1); + } + else { + ast.chi.splice(i--, 1, intersect.node1); + } + if (intersect.node2.chi.length == 0) { + if (intersect.result != null) { + ast.chi.splice(nodeIndex, 1, intersect.result); + } + else { + ast.chi.splice(nodeIndex, 1); + } + i--; + if (nodeIndex == i) { + nodeIndex = i; + } + } + else { + if (intersect.result != null) { + ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2); + } + else { + ast.chi.splice(nodeIndex, 1, intersect.node2); + } + i = (nodeIndex ?? 0) + 1; + } + if (node != ast.chi[i]) { + node = ast.chi[i]; + } + previous = intersect.result; + nodeIndex = i; + } + } + } + } + if (recursive && previous != null && previous != node) { + if (!hasDeclaration(previous)) { + doMinify(previous, options, recursive, errors, nestingContent, context); + } + } + } + } + if (!nestingContent && + previous != null && + previous.typ == exports.EnumToken.RuleNodeType && + previous.sel.includes("&")) { + fixSelector(previous); + } + previous = node; + nodeIndex = i; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + if (recursive && node != null && "chi" in node) { + 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")) { + doMinify(node, options, recursive, errors, nestingContent, context); + } + } } - } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (!nestingContent && + node != null && + node.typ == exports.EnumToken.RuleNodeType && + node.sel.includes("&")) { + fixSelector(node); } - result.push(yieldResult(parseInfo, exports.EnumToken.EOFTokenType)); } - parseInfo.time += performance.now() - startTime; - return result; + return ast; } /** - * tokenize readable stream - * @param input - * @param parseInfo + * Check if a rule has a declaration + * @param node + * + * @private */ - async function* tokenizeStream(input, parseInfo) { - const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); - parseInfo.stream = ""; - while (true) { - const { done, value } = await reader.read(); - const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; - if (!done) { - parseInfo.source.append(stream); - parseInfo.stream = (parseInfo.stream.slice(parseInfo.position - parseInfo.offset) + stream); - parseInfo.offset = parseInfo.offset = parseInfo.position; - } - else { - parseInfo.stream = ""; - } - yield* tokenize(parseInfo, done); - if (done) { - break; + function hasDeclaration(node) { + // @ts-ignore + for (let i = 0; i < node.chi?.length; i++) { + // @ts-ignore + if (node.chi[i].typ == exports.EnumToken.CommentNodeType) { + continue; } + // @ts-ignore + return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; } + return true; } - - const notEndingWith = ["(", "["].concat(combinators); - const rules = [ - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleTokenType, - exports.EnumToken.KeyframesRuleNodeType, - ]; - // @ts-ignore - const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering); /** - * Apply minification rules to the ast tree - * @param ast - * @param options - * @param recursive - * @param errors - * @param nestingContent + * Optimize selector + * @param selector * - * @param context * @private */ - function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { - let preprocess = false; - let postprocess = false; - let parents; - let replacement; - let { sourcemap, module, ...options2 } = options; - if (!(options2.features != null)) { - options2 = { - removeDuplicateDeclarations: true, - computeShorthand: true, - computeCalcExpression: true, - removePrefix: false, - features: [], - ...options2, - }; - for (const feature of features) { - feature.register(options2); - } - options2.features.sort((a, b) => a.ordering - b.ordering); - } - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Pre) { - preprocess = true; - } - if (feature.processMode & exports.FeatureWalkMode.Post) { - postprocess = true; - } - } - if (preprocess) { - parents = new Set([ast]); - for (const parent of parents) { - if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { - continue; - } - replacement = parent; - for (const feature of options2.features) { - if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || - (feature.accept != null && !feature.accept.has(parent.typ))) { - continue; - } - if (rules.includes(replacement.typ) && !Array.isArray(replacement[TOKENS])) { - replacement[TOKENS] = parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ === exports.EnumToken.KeyframesRuleNodeType - ? replacement.sel - : // @ts-ignore - replacement.nam); - } - const result = feature.run(replacement, options2, - // @ts-ignore - parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Pre); - if (result != null) { - replacement = result; - } - } - if (replacement != null && - (!Array.isArray(replacement) || replacement.length > 0) && - replacement != parent && - parent[PARENT] != null) { - // @ts-ignore - replaceNodeOrValue(parent[PARENT], parent, replacement); - } + function optimizeSelector(selector) { + const map = new Set(); + selector = selector + .reduce((acc, curr) => { + // @ts-ignore + if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { // @ts-ignore - if (replacement.chi != null) { - // @ts-ignore - for (const node of replacement.chi) { - node[PARENT] = replacement; - parents.add(node); + const rules = splitRule(curr.at(-1).slice(4, -1)).map((x) => { + if (x[0] == "&" && x.length > 1) { + return x.slice(x[1] == " " ? 2 : 1); } + return x; + }); + const part = curr.slice(0, -1); + for (const rule of rules) { + acc.push(part.concat(rule)); } + return acc; } - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Pre && "cleanup" in feature) { - // @ts-ignore - feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Pre); - } - } - } - doMinify(ast, options2, recursive, errors, nestingContent, context); - parents = new Set([ast]); - for (const parent of parents) { - if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { - continue; + acc.push(curr); + return acc; + }, []) + .filter((x) => { + const str = x.join(""); + if (map.has(str)) { + return false; } - replacement = parent; - if (postprocess) { - for (const feature of options2.features) { - if ((feature.processMode & exports.FeatureWalkMode.Post) === 0 || - (feature.accept != null && !feature.accept.has(parent.typ))) { - continue; - } - const result = feature.run(replacement, options2, - // @ts-ignore - parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); - if (result != null) { - replacement = result; - } + map.add(str); + return true; + }); + const optimized = []; + const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : curr.length == 0 ? acc : Math.min(acc, curr.length), 0); + let i = 0; + let j; + let match; + for (; i < k; i++) { + const item = selector[0][i]; + match = true; + for (j = 1; j < selector.length; j++) { + if (item != selector[j][i]) { + match = false; + break; } } - if (replacement != null && - (!Array.isArray(replacement) || replacement.length > 0) && - replacement != parent && - parent[PARENT] != null) { - // @ts-ignore - replaceNodeOrValue(parent[PARENT], parent, replacement); + if (!match) { + break; } - // @ts-ignore - if (replacement.chi != null) { - // @ts-ignore - for (const node of replacement.chi) { - node[PARENT] = replacement; - parents.add(node); - } + optimized.push(item); + } + while (optimized.length > 0) { + const last = optimized.at(-1); + if (last == " " || combinators.includes(last)) { + optimized.pop(); + continue; } + break; } - if (postprocess) { - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Post && "cleanup" in feature) { - // @ts-ignore - feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Post); - } + for (let i1 = 0; i1 < selector.length; i1++) { + selector[i1].splice(0, optimized.length); + } + let reducible = optimized.length == 1; + if (optimized[0] == "&") { + if (optimized[1] == " ") { + optimized.splice(0, 2); } } - return ast; - } - function transformAtRuleMediaPrelude(values) { - let hasUpdates = false; - for (let { value, parent, parents } of walkValues(values)) { - if (value.typ === exports.EnumToken.MediaQueryConditionTokenType) { - if (value.op.typ == exports.EnumToken.AndTokenType && - // @ts-ignore - value.l.typ === exports.EnumToken.IdenTokenType && - // @ts-ignore - value.l.val.toLowerCase() === "all") { - if (parent === null) { - // @ts-ignore - values[values.indexOf(value)] = value.l; - } - else { - // @ts-ignore - replaceNodeOrValue(parent, value, value.l); - // @ts-ignore - value = value.l; - } - hasUpdates = true; + if (optimized.length == 0 || optimized[0].charAt(0) == "&" || selector.length == 1) { + return { + match: false, + optimized, + selector: selector.map((selector) => selector[0] == "&" && selector[1] == " " ? selector.slice(2) : selector), + reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0])), + }; + } + return { + match: true, + optimized, + selector: selector.reduce((acc, curr) => { + let hasCompound = true; + if (hasCompound && curr.length > 0) { + hasCompound = !["&"].concat(combinators).includes(curr[0].charAt(0)); } - } - // range operator - if (parent != null && - parent.typ === exports.EnumToken.MediaQueryConditionTokenType && - parent.op.typ == exports.EnumToken.AndTokenType && // @ts-ignore - parent.l.typ == exports.EnumToken.ParensTokenType) { - let token = parent.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - if (token?.typ === exports.EnumToken.ParensTokenType) { + if (hasCompound && curr[0] == " ") { + hasCompound = false; + curr.unshift("&"); + } + if (curr.length == 0) { + curr.push("&"); + hasCompound = false; + } + if (reducible) { + const chr = curr[0].charAt(0); // @ts-ignore - const node1 = parent.l.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const node2 = token.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - if (node1?.typ === exports.EnumToken.MediaQueryConditionTokenType && - node2?.typ === exports.EnumToken.MediaQueryConditionTokenType && - node1.op.typ == exports.EnumToken.ColonTokenType && - node2.op.typ == exports.EnumToken.ColonTokenType && - // @ts-ignore - node1.l.typ == exports.EnumToken.IdenTokenType && - // @ts-ignore - node2.l.typ == exports.EnumToken.IdenTokenType && - // @ts-ignore - node1.l.val.startsWith("min-") && - // @ts-ignore - node2.l.val.startsWith("max-") && - // @ts-ignore - node1.l.val.slice(4) == - // @ts-ignore - node2.l.val.slice(4)) { - const val1 = node1.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const val2 = node2.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const replacement = { - typ: exports.EnumToken.ParensTokenType, - chi: [ - // @ts-ignore - { - typ: exports.EnumToken.MediaRangeQueryTokenType, - op: { - typ: exports.EnumToken.IdenTokenType, - // @ts-ignore - val: node1.l.val.slice(4), - }, - l: val1, - r: val2, - [LOC]: value[LOC], - }, - ], - }; - // @ts-expect-error - const p = parents?.[parents?.indexOf?.(parent) + 1]; - if (p != null) { - // @ts-ignore - replaceNodeOrValue(p, parent, replacement); - } - else { - // @ts-ignore - values.splice(values.indexOf(parent), 1, replacement); - } - hasUpdates = true; - value = replacement; - } + reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); } - } - } - return { hasUpdates, values: trimArray(values) }; + acc.push(hasCompound ? ["&"].concat(curr) : curr); + return acc; + }, []), + reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), + }; } /** - * Minify at-rule media - * - remove redundant tokens - * - generate range queries + * Split selector string + * @param buffer * - * @private - * @param tokens + * @internal */ - function minifyAtRuleMedia(tokens) { - let hasUpdates = false; - const sections = tokens - .reduce((acc, t) => { - if (t.typ === exports.EnumToken.CommaTokenType) { - acc.push([]); - } - else { - acc[acc.length - 1].push(t); - } - return acc; - }, [[]]) - .reduce((acc, values) => { - if (acc.has("all")) { - return acc; + function splitRule(buffer) { + const result = [[]]; + let str = ""; + for (let i = 0; i < buffer.length; i++) { + let chr = buffer.charAt(i); + if (isWhiteSpace(chr.charCodeAt(0))) { + if (str !== "") { + // @ts-ignore + result.at(-1).push(str); + str = ""; + } + // @ts-ignore + if (result.at(-1).length > 0) { + // @ts-ignore + result.at(-1).push(" "); + } + // i = k; + continue; } - const result = transformAtRuleMediaPrelude(values); - if (result.values.length === 0) { - return acc; + if (chr == ",") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + result.push([]); + continue; } - if (result.hasUpdates) { - hasUpdates = true; + if (chr == ".") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + str += chr; + continue; } - acc.set(values.reduce((acc, t) => acc + renderValue(t), ""), result.values); - return acc; - }, new Map()); - if (sections.has("all")) { - tokens.length = 0; - } - else if (hasUpdates) { - tokens.length = 0; - tokens.push(...[...sections.values()].reduce((acc, t) => { - if (acc.length > 0) { - acc.push({ - typ: exports.EnumToken.CommaTokenType, - }); + if (combinators.includes(chr)) { + if (str !== "") { + result.at(-1).push(str); + str = ""; } - acc.push(...t); - return acc; - }, [])); + if (chr == "|" && buffer.charAt(i + 1) == "|") { + chr += buffer.charAt(++i); + } + result.at(-1).push(chr); + continue; + } + if (chr == ":") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + if (buffer.charAt(i + 1) == ":") { + chr += buffer.charAt(++i); + } + str += chr; + continue; + } + str += chr; + if (chr == "\\") { + str += buffer.charAt(++i); + continue; + } + if (chr == "(" || chr == "[") { + const open = chr; + const close = chr == "(" ? ")" : "]"; + let inParens = 1; + let k = i; + while (++k < buffer.length) { + chr = buffer.charAt(k); + if (chr == "\\") { + str += buffer.slice(k, k + 2); + k++; + continue; + } + str += chr; + if (chr == open) { + inParens++; + } + else if (chr == close) { + inParens--; + } + if (inParens == 0) { + break; + } + } + i = k; + } } - // return ast; - return tokens; + if (str !== "") { + result.at(-1).push(str); + } + return result; } /** - * Reduce selectors + * Reduce selector * @param acc * @param curr * * @private */ - function reduce(acc, curr) { - // trim :is() - if (curr[0] == "&") { - if (curr[1] == " " && !isIdent(curr[2]) && !isFunction(curr[2])) { - curr.splice(0, 2); + function reduceSelector(acc, curr) { + let hasCompoundSelector = true; + // @ts-ignore + curr = curr.slice(this.match[0].length); + while (curr.length > 0) { + if (curr[0] == " ") { + hasCompoundSelector = false; + curr.unshift("&"); + continue; } + break; } - acc.push(curr.join("")); + if (hasCompoundSelector && curr.length > 0) { + hasCompoundSelector = !["&"].concat(combinators).includes(curr[0].charAt(0)); + } + if (curr[0] == ":is(") { + let canReduce = true; + const isCompound = curr.reduce((acc, token, index) => { + if (index == 0) { + canReduce = curr[1] == "&"; + } + else if (token == ")") ; + else if (token == ",") { + if (!canReduce) { + canReduce = curr[index + 1] == "&"; + } + acc.push([]); + } + else + acc.at(-1)?.push(token); + return acc; + }, [[]]); + if (canReduce) { + curr = isCompound.reduce((acc, curr) => { + if (acc.length > 0) { + acc.push(","); + } + for (const c of curr) { + acc.push(c); + } + return acc; + }, []); + } + } + acc.push( + // @ts-ignore + this.match.length == 0 + ? ["&"] + : hasCompoundSelector && curr[0] != "&" && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) + ? ["&"].concat(curr) + : curr); return acc; } /** - * Apply minification rules to the ast tree - * @param ast - * @param options - * @param recursive - * @param errors - * @param nestingContent - * @param context + * Match selectors + * @param selector1 + * @param selector2 * * @private */ - function doMinify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { - if (!("nodes" in context)) { - context.nodes = new Set(); - } - if (context.nodes.has(ast)) { - return ast; - } - context.nodes.add(ast); - // @ts-ignore - if ("chi" in ast && ast.chi.length > 0) { - const reducer = reduce.bind(ast); - if (!nestingContent) { - nestingContent = options.nestingRules && ast.typ == exports.EnumToken.RuleNodeType; + function matchSelectors(selector1, selector2) { + let match = [[]]; + const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0)); + let i = 0; + let k; + let l; + let token; + let matching = true; + let matchFunction = 0; + let inAttr = 0; + const regEx = /^:is\(([:.][^\s,]+)\)$/; + for (const _1 of selector1) { + if (_1[0] !== "&") { + continue; } - let i = 0; - let previous = null; - let node = null; - let nodeIndex = -1; - for (; i < ast.chi.length; i++) { - if (ast.chi[i].typ === exports.EnumToken.CommentNodeType) { - continue; - } - while (previous?.typ === exports.EnumToken.CommentNodeType) { - // @ts-ignore - previous = ast.chi[--nodeIndex]; - } - node = ast.chi[i]; - if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { - continue; - } - if (node.typ === exports.EnumToken.KeyframesAtRuleNodeType) { - if (previous?.typ === exports.EnumToken.KeyframesAtRuleNodeType && - node.nam === previous.nam && - node.val === previous.val) { - ast.chi?.splice(nodeIndex--, 1); - previous = ast?.chi?.[nodeIndex] ?? null; - i = nodeIndex; - continue; + for (let i = 1; i < _1.length; i++) { + const token = _1[i]; + if (token.startsWith(":is(")) { + const match = regEx.exec(token); + if (match != null) { + _1[i] = match[1]; } } - else if (node.typ === exports.EnumToken.KeyframesRuleNodeType) { - if (previous?.typ === exports.EnumToken.KeyframesRuleNodeType && - node.sel === previous.sel) { - // do not merge keyframes - // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates - previous.chi.push(...node.chi); - // @ts-ignore - ast.chi.splice(i, 1); - previous = ast?.chi?.[nodeIndex] ?? null; - i = nodeIndex; - continue; + } + } + for (const _1 of selector2) { + if (_1[0] !== "&") { + continue; + } + for (let i = 1; i < _1.length; i++) { + const token = _1[i]; + if (token.startsWith(":is(")) { + const match = regEx.exec(token); + if (match != null) { + _1[i] = match[1]; } - let k; - for (k = 0; k < node.chi.length; k++) { - if (node.chi[k].typ == exports.EnumToken.DeclarationNodeType) { - let l = node.chi[k].val.length; - while (l--) { - if (node.chi[k].val[l].typ == - exports.EnumToken.ImportantTokenType) { - node.chi.splice(k--, 1); - break; - } - if ([exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(node.chi[k].val[l].typ)) { - continue; - } - break; - } - } + } + } + } + for (; i < j; i++) { + k = 0; + token = selector1[0][i]; + for (; k < selector1.length; k++) { + if (selector1[k][i] != token) { + matching = false; + break; + } + } + if (matching) { + l = 0; + for (; l < selector2.length; l++) { + if (selector2[l][i] != token) { + matching = false; + break; } } - else if (node.typ == exports.EnumToken.AtRuleNodeType) { - if (node.nam == "media") { - if (Array.isArray(node[TOKENS])) { - const slice = node[TOKENS].slice(); - minifyAtRuleMedia(slice); - if (slice.length !== node[TOKENS].length) { - node[TOKENS].length = 0; - node[TOKENS].push(...slice); - node.val = slice.reduce((acc, curr, index, arr) => acc + - (curr.typ === exports.EnumToken.CommentTokenType || - (curr.typ === exports.EnumToken.WhitespaceTokenType && - arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && - (index + 3 < arr.length || - arr[index + 2]?.typ === exports.EnumToken.WhitespaceTokenType)) - ? "" - : renderValue(curr)), ""); - } - } - if (["all", "", null].includes(node.val)) { - ast.chi?.splice(i--, 1, ...node.chi); - continue; + } + if (!matching) { + break; + } + if (token.endsWith("(")) { + matchFunction++; + } + match.at(-1).push(token); + } + // invalid function + if (matchFunction != 0 || inAttr != 0) { + return null; + } + for (const part of match) { + while (part.length > 0) { + const token = part.at(-1); + if (token == " " || combinators.includes(token) || notEndingWith.includes(token.at(-1))) { + part.pop(); + continue; + } + break; + } + } + if (match.every((t) => t.length == 0)) { + return null; + } + if (eq([["&"]], match)) { + return null; + } + const reducer = reduceSelector.bind({ match }); + // @ts-ignore + selector1 = selector1.reduce(reducer, []); + // @ts-ignore + selector2 = selector2.reduce(reducer, []); + return selector1 == null || selector2 == null + ? null + : { + eq: eq(selector1, selector2), + match, + selector1, + selector2, + }; + } + /** + * Fix selector + * @param node + * + * @private + */ + function fixSelector(node) { + if (node.sel.includes("&")) { + const attributes = parseString(node.sel); + for (const attr of walkValues(attributes)) { + if (attr.value.typ == exports.EnumToken.PseudoClassFuncTokenType && + attr.value.val == ":is") { + let i = attr.value.chi.length; + while (i--) { + if (attr.value.chi[i].typ == exports.EnumToken.NestingSelectorTokenType) { + attr.value.chi.splice(i, 1); } } - else if (node.nam === "import" && Array.isArray(node[TOKENS])) { - let l = 0; - let token; - for (; l < node[TOKENS].length; l++) { - token = node[TOKENS][l]; - if (token.typ === exports.EnumToken.ParensTokenType || - token.typ === exports.EnumToken.MediaQueryConditionTokenType || - (token.typ === exports.EnumToken.IdenTokenType && "layer" !== token.val)) { - break; - } - } - if (l < node[TOKENS].length) { - const slice = node[TOKENS]?.slice(l); - node[TOKENS].splice(l, slice.length, ...minifyAtRuleMedia(slice)); - node.val = trimArray(node[TOKENS]).reduce((acc, curr, index, arr) => acc + - (curr.typ === exports.EnumToken.CommentTokenType || - (curr.typ === exports.EnumToken.WhitespaceTokenType && - arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && - (index + 3 < arr.length || arr[index + 2].typ === exports.EnumToken.WhitespaceTokenType)) - ? "" - : renderValue(curr)), ""); + } + } + node.sel = attributes.reduce((acc, curr) => acc + renderValue(curr), ""); + node[TOKENS] = null; + } + } + /** + * Wrap nodes + * @param previous + * @param node + * @param match + * @param ast + * @param reducer + * @param i + * @param nodeIndex + * + * @private + */ + function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) { + // @ts-ignore + let pSel = match.selector1.reduce(reducer, []).join(","); + // @ts-ignore + let nSel = match.selector2.reduce(reducer, []).join(","); + const wrapper = { + ...previous, + chi: [], + // @ts-ignore + sel: match.match.reduce(reducer, []).join(","), + [RAW]: match.match.map((t) => t.slice()), + }; + if (pSel == "&" || pSel === "") { + for (const child of previous.chi) { + wrapper.chi.push(child); + } + if (nSel == "&" || nSel === "") { + for (const child of node.chi) { + wrapper.chi.push(child); + } + } + else { + wrapper.chi.push(node); + } + } + else { + wrapper.chi.push(previous, node); + } + ast.chi.splice(i, 1, wrapper); + ast.chi.splice(nodeIndex, 1); + previous.sel = pSel; + previous[RAW] = match.selector1; + previous[TOKENS] = null; + node.sel = nSel; + node[RAW] = match.selector2; + node[TOKENS] = null; + reduceRuleSelector(wrapper); + wrapper[TOKENS] = null; + return wrapper; + } + /** + * Diff nodes + * @param n1 + * @param n2 + * @param options + * + * @private + */ + function diff$1(n1, n2, options = {}) { + if (!("cache" in options)) { + options.cache = new WeakMap(); + } + let node1 = n1; + let node2 = n2; + let exchanged = false; + if (node1.chi.length > node2.chi.length) { + const t = node1; + node1 = node2; + node2 = t; + exchanged = true; + } + let i = node1.chi.length; + let j = node2.chi.length; + const raw1 = node1[RAW]; + const raw2 = node2[RAW]; + if (raw1 != null && raw2 != null) { + const prefixes1 = new Set(); + const prefixes2 = new Set(); + for (const token1 of raw1) { + for (const t of token1) { + if (t.includes(":")) { + const matches = t.match(/::?-([a-z]+)-/); + if (matches == null) { + continue; } - } - else if (ast.typ === node.typ && - ast.nam === node.nam && - ast.val === node.val) { - // @ts-ignore - replaceNodeOrValue(ast, node, node.chi); - i--; - continue; - } - if (previous?.typ == exports.EnumToken.AtRuleNodeType && - node.nam != "font-face" && - previous.nam === node.nam && - previous.val === node.val) { - if ("chi" in node) { - // @ts-ignore - previous.chi.push(...node.chi); - if (!hasDeclaration(previous)) { - context.nodes.delete(previous); - doMinify(previous, options, recursive, errors, nestingContent, context); - } + prefixes1.add(matches[1]); + if (prefixes1.size > 1) { + break; } - ast?.chi?.splice(i--, 1); - continue; - } - // if (!hasDeclaration(node as AstAtRule)) { - // doMinify(node, options, recursive, errors, nestingContent, context); - // } - if ("chi" in node) { - doMinify(node, options, recursive, errors, nestingContent, context); } - previous = node; - nodeIndex = i; - continue; } - // @ts-ignore - else if (node.typ === exports.EnumToken.RuleNodeType) { - reduceRuleSelector(node); - let wrapper = null; - let match; - if (options.nestingRules) { - if (previous?.typ == exports.EnumToken.RuleNodeType) { - reduceRuleSelector(previous); - // @ts-ignore - match = matchSelectors(previous[RAW], node[RAW]); - if (match != null) { - wrapper = wrapNodes(previous, node, match, ast, reducer, i, nodeIndex); - nodeIndex = i - 1; - previous = ast.chi[nodeIndex]; - } - } - if (wrapper != null) { - while (i < ast.chi.length) { - const nextNode = ast.chi[i]; - if (nextNode.typ != exports.EnumToken.RuleNodeType) { - break; - } - reduceRuleSelector(nextNode); - match = matchSelectors(wrapper[RAW], nextNode[RAW]); - if (match == null) { - break; - } - wrapper = wrapNodes(wrapper, nextNode, match, ast, reducer, i, nodeIndex); - } - nodeIndex = --i; - previous = ast.chi[nodeIndex]; - doMinify(wrapper, options, recursive, errors, nestingContent, context); + if (prefixes1.size > 1) { + break; + } + } + for (const token2 of raw2) { + for (const t of token2) { + if (t.includes(":")) { + const matches = t.match(/::?-([a-z]+)-/); + if (matches == null) { continue; } - // @ts-ignore - else if (node[OPTIMIZED] != null && - // @ts-ignore - node[OPTIMIZED].match && - // @ts-ignore - node[OPTIMIZED].selector.length > 1) { - // @ts-ignore - wrapper = { - ...node, - chi: [], - sel: node[OPTIMIZED].optimized[0], - [RAW]: [[node[OPTIMIZED].optimized[0]]], - }; - // @ts-ignore - node.sel = node[OPTIMIZED].selector.reduce(reducer, []).join(","); - // @ts-ignore - node[RAW] = node[OPTIMIZED].selector.slice(); - node[TOKENS] = null; - // @ts-ignore - wrapper.chi.push(node); - // @ts-ignore - ast.chi.splice(i, 1, wrapper); - node = wrapper; - } - else if (node[OPTIMIZED]?.reducible) { - if (node[OPTIMIZED].optimized.length === 1) { - const sel1 = node[OPTIMIZED].optimized[0] + - ":is(" + - node[OPTIMIZED].selector.reduce(reducer, []).join(",") + - ")"; - const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => - // @ts-ignore - (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); - node.sel = sel1.length < sel2.length ? sel1 : sel2; - node[TOKENS] = null; - } - else if (node[OPTIMIZED].optimized.length === 0) { - const testIdent = /^[a-zA-Z]/; - node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + - (nestingContent && testIdent.test(curr[0]) ? "& " : "") + - curr.join(""), ""); - node[TOKENS] = null; - } - } - } - // @ts-ignore - else if (node[OPTIMIZED]?.match) { - let wrap = true; - // @ts-ignore - const selector = node[OPTIMIZED].selector.reduce((acc, curr) => { - if (curr[0] == "&" && curr.length > 1) { - if (curr[1] == " ") { - curr.splice(0, 2); - } - else { - curr.splice(0, 1); - } - } - else if (combinators.includes(curr[0])) { - curr.unshift("&"); - wrap = false; - } - acc.push(curr); - return acc; - }, []); - if (!wrap) { - wrap = selector.some((s) => s[0] != "&"); - } - let rule = null; - const optimized = node[OPTIMIZED].optimized.slice(); - if (optimized.length > 1) { - const check = optimized.at(-2); - if (!combinators.includes(check)) { - let last = optimized.pop(); - wrap = false; - rule = - optimized.join("") + - `:is(${selector - .map((s) => { - if (s[0] == "&") { - s.splice(0, 1, last); - } - else { - s.unshift(last); - } - return s.join(""); - }) - .join(",")})`; - } - } - if (rule == null) { - rule = selector - .map((s) => { - if (s[0] == "&") { - s.splice(0, 1, ...node[OPTIMIZED].optimized); - } - return s.join(""); - }) - .join(","); - } - let sel = wrap ? node[OPTIMIZED].optimized.join("") + `:is(${rule})` : rule; - if (sel.length < node.sel.length) { - node.sel = sel; - node[TOKENS] = null; - } - } - else if (node[OPTIMIZED]?.reducible) { - if (node[OPTIMIZED].optimized.length === 1) { - const sel1 = node[OPTIMIZED].optimized[0] + - ":is(" + - node[OPTIMIZED].selector.reduce(reducer, []).join(",") + - ")"; - const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => - // @ts-ignore - (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); - node.sel = sel1.length < sel2.length ? sel1 : sel2; - node[TOKENS] = null; - } - else if (node[OPTIMIZED].optimized.length === 0) { - const testIdent = /^[a-zA-Z]/; - node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + - (nestingContent && testIdent.test(curr[0]) ? "& " : "") + - curr.join(""), ""); - node[TOKENS] = null; - } - // @ts-ignore - } - else if (node[OPTIMIZED]?.optimized.length > 0) { - // @ts-ignore - const sel = node[OPTIMIZED].optimized.join(""); - if (sel.length < node.sel.length) { - node.sel = sel; - // @ts-ignore - node[RAW] = [node[OPTIMIZED].optimized.slice()]; - node[TOKENS] = null; - } - } - doMinify(node, options, recursive, errors, nestingContent, context); - } - if (previous != null) { - if ("chi" in previous && "chi" in node) { - if (previous.typ === node.typ) { - let shouldMerge = true; - let k = previous.chi.length; - while (k-- > 0) { - if (previous.chi[k].typ === exports.EnumToken.CommentNodeType || - previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType || - previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType) { - continue; - } - shouldMerge = previous.chi[k].typ === exports.EnumToken.DeclarationNodeType; - break; - } - if (shouldMerge) { - if (((node.typ === exports.EnumToken.RuleNodeType || - node.typ === exports.EnumToken.KeyframesRuleNodeType) && - node.sel === previous.sel) || - // @ts-ignore - (node.typ == exports.EnumToken.AtRuleNodeType && - node.nam !== "font-face" && - // @ts-ignore - node.nam === previous.nam)) { - // @ts-ignore - node.chi.unshift(...previous.chi); - doMinify(node, options, recursive, errors, nestingContent, context); - ast.chi.splice(nodeIndex, 1); - previous = ast.chi[--i]; - nodeIndex = i; - continue; - } - else if (node.typ == previous?.typ && - [exports.EnumToken.KeyframesRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) { - const intersect = diff$1(previous, node, options); - if (intersect != null) { - if (intersect.node1.chi.length == 0) { - ast.chi.splice(i--, 1); - } - else { - ast.chi.splice(i--, 1, intersect.node1); - } - if (intersect.node2.chi.length == 0) { - if (intersect.result != null) { - ast.chi.splice(nodeIndex, 1, intersect.result); - } - else { - ast.chi.splice(nodeIndex, 1); - } - i--; - if (nodeIndex == i) { - nodeIndex = i; - } - } - else { - if (intersect.result != null) { - ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2); - } - else { - ast.chi.splice(nodeIndex, 1, intersect.node2); - } - i = (nodeIndex ?? 0) + 1; - } - if (node != ast.chi[i]) { - node = ast.chi[i]; - } - previous = intersect.result; - nodeIndex = i; - } - } - } - } - if (recursive && previous != null && previous != node) { - if (!hasDeclaration(previous)) { - doMinify(previous, options, recursive, errors, nestingContent, context); - } + prefixes2.add(matches[1]); + if (prefixes2.size > 1) { + break; } } } - if (!nestingContent && - previous != null && - previous.typ == exports.EnumToken.RuleNodeType && - previous.sel.includes("&")) { - fixSelector(previous); + if (prefixes2.size > 1) { + break; } - previous = node; - nodeIndex = i; } - if (recursive && node != null && "chi" in node) { - 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")) { - doMinify(node, options, recursive, errors, nestingContent, context); - } - } + if (prefixes1.size != prefixes2.size) { + return null; } - if (!nestingContent && - node != null && - node.typ == exports.EnumToken.RuleNodeType && - node.sel.includes("&")) { - fixSelector(node); + for (const prefix of prefixes1) { + if (!prefixes2.has(prefix)) { + return null; + } } } - return ast; - } - /** - * Check if a rule has a declaration - * @param node - * - * @private - */ - function hasDeclaration(node) { - // @ts-ignore - for (let i = 0; i < node.chi?.length; i++) { - // @ts-ignore - if (node.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; - } - // @ts-ignore - return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; + const css1 = options.cache.get(node1); + const css2 = options.cache.get(node2); + node1 = { ...node1, chi: node1.chi.slice() }; + node2 = { ...node2, chi: node2.chi.slice() }; + if (css1 != null) { + options.cache.set(node1, css1); } - return true; - } - /** - * Optimize selector - * @param selector - * - * @private - */ - function optimizeSelector(selector) { - const map = new Set(); - selector = selector - .reduce((acc, curr) => { - // @ts-ignore - if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { - // @ts-ignore - const rules = splitRule(curr.at(-1).slice(4, -1)).map((x) => { - if (x[0] == "&" && x.length > 1) { - return x.slice(x[1] == " " ? 2 : 1); + if (css2 != null) { + options.cache.set(node2, css2); + } + if (raw1 != null) { + node1[RAW] = raw1; + } + if (raw2 != null) { + node2[RAW] = raw2; + } + const intersect = []; + while (i--) { + if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { + continue; + } + j = node2.chi.length; + while (j--) { + if (node2.chi[j].typ == exports.EnumToken.CommentNodeType) { + continue; + } + if (node1.chi[i].nam == node2.chi[j].nam) { + if (node1.chi[i].typ == node2.chi[j].typ && eq(node1.chi[i], node2.chi[j])) { + intersect.push(node1.chi[i]); + node1.chi.splice(i, 1); + node2.chi.splice(j, 1); + options.cache.delete(node1); + options.cache.delete(node2); + break; } - return x; - }); - const part = curr.slice(0, -1); - for (const rule of rules) { - acc.push(part.concat(rule)); } - return acc; - } - acc.push(curr); - return acc; - }, []) - .filter((x) => { - const str = x.join(""); - if (map.has(str)) { - return false; } - map.add(str); - return true; - }); - const optimized = []; - const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : curr.length == 0 ? acc : Math.min(acc, curr.length), 0); - let i = 0; - let j; - let match; - for (; i < k; i++) { - const item = selector[0][i]; - match = true; - for (j = 1; j < selector.length; j++) { - if (item != selector[j][i]) { - match = false; - break; + } + const result = intersect.length === 0 && (node1.chi.length > 0 || node2.chi.length > 0) + ? null + : { + ...node1, + // @ts-ignore + sel: [ + ...new Set(splitRule(node1.sel) + .concat(splitRule(node2.sel)) + .map((s) => s.join(""))), + ].join(","), + // @ts-ignore + chi: intersect.reverse(), + }; + let op = { level: 0, ...options }; + if (result == null || + [n1, n2].reduce((acc, curr) => { + let css = options.cache.get(curr); + if (css == null) { + let level = 0; + let parent = curr[PARENT]; + while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { + level++; + parent = parent[PARENT]; + } + op.level = level; + css = doRender(curr, op).code; + options.cache.set(curr, css); } + return curr.chi.length == 0 ? acc : acc + css.length; + }, 0) <= + [node1, node2, result].reduce((acc, curr) => { + let css = options.cache.get(curr); + if (css != null) { + return curr.chi.length == 0 ? acc : acc + css.length; + } + let level = 0; + let parent = curr[PARENT]; + while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { + level++; + parent = parent[PARENT]; + } + op.level = level; + css = doRender(curr, op).code; + return curr.chi.length == 0 ? acc : acc + css.length; + }, 0)) { + if (node1.chi.length != 0 && node2.chi.length != 0) { + return null; } - if (!match) { - break; - } - optimized.push(item); } - while (optimized.length > 0) { - const last = optimized.at(-1); - if (last == " " || combinators.includes(last)) { - optimized.pop(); - continue; + if (result != null) { + result[TOKENS] = null; + result[RAW] = null; + const optimized = optimizeSelector(splitRule(result.sel)); + if (optimized?.match) { + const rule = optimized.selector.reduce((acc, curr) => { + if (acc.length > 0) { + acc += ","; + } + if (curr.length > 2 && curr[0] === "&" && curr[1] === " ") { + return acc + curr.slice(2).join(""); + } + else if (curr.length > 1 && curr[0] === "&") { + return acc + curr.slice(1).join(""); + } + return acc + curr.join(""); + }, ""); + const match = optimized.optimized.join(""); + const sel = match + ":is(" + replaceCompound(rule, match) + ")"; + if (sel.length < result.sel.length) { + result.sel = sel; + result[TOKENS] = null; + } } - break; - } - for (let i1 = 0; i1 < selector.length; i1++) { - selector[i1].splice(0, optimized.length); } - let reducible = optimized.length == 1; - if (optimized[0] == "&") { - if (optimized[1] == " ") { - optimized.splice(0, 2); - } + return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; + } + /** + * Reduce rule selector + * @param node + * + * @private + */ + function reduceRuleSelector(node) { + if (node[RAW] == null) { + node[RAW] = splitRule(node.sel); } - if (optimized.length == 0 || optimized[0].charAt(0) == "&" || selector.length == 1) { - return { - match: false, - optimized, - selector: selector.map((selector) => selector[0] == "&" && selector[1] == " " ? selector.slice(2) : selector), - reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0])), - }; + let optimized = optimizeSelector(node[RAW].reduce((acc, curr) => { + acc.push(curr.slice()); + return acc; + }, [])); + if (optimized != null) { + node[OPTIMIZED] = optimized; } - return { - match: true, - optimized, - selector: selector.reduce((acc, curr) => { - let hasCompound = true; - if (hasCompound && curr.length > 0) { - hasCompound = !["&"].concat(combinators).includes(curr[0].charAt(0)); - } - // @ts-ignore - if (hasCompound && curr[0] == " ") { - hasCompound = false; - curr.unshift("&"); - } - if (curr.length == 0) { - curr.push("&"); - hasCompound = false; + if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) { + for (const selector of optimized.selector) { + if (selector.length > 1 && + selector[0] == "&" && + (combinators.includes(selector[1]) || !/^[a-zA-Z:]/.test(selector[1]))) { + selector.shift(); } - if (reducible) { - const chr = curr[0].charAt(0); - // @ts-ignore - reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); + } + const unique = new Set(); + const reduced = optimized.selector.reduce((acc, curr) => { + const sig = curr.join(""); + if (!unique.has(sig)) { + if (acc.length > 0) { + acc.push(","); + } + unique.add(sig); + for (const c of curr) { + acc.push(c); + } } - acc.push(hasCompound ? ["&"].concat(curr) : curr); return acc; - }, []), - reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), - }; + }, []); + const raw = [ + [optimized.optimized[0], reduced.length === 1 ? reduced.join("") : ":is("].concat(reduced).concat(")"), + ]; + const sel = raw[0].join(""); + if (sel.length < node.sel.length) { + node.sel = sel; + node[RAW] = raw; + node[TOKENS] = null; + } + } } + /** - * Split selector string - * @param buffer + * expand css nesting ast nodes + * @param ast * - * @internal + * @private */ - function splitRule(buffer) { - const result = [[]]; - let str = ""; - for (let i = 0; i < buffer.length; i++) { - let chr = buffer.charAt(i); - if (isWhiteSpace(chr.charCodeAt(0))) { - if (str !== "") { - // @ts-ignore - result.at(-1).push(str); - str = ""; - } - // @ts-ignore - if (result.at(-1).length > 0) { - // @ts-ignore - result.at(-1).push(" "); - } - // i = k; - continue; - } - if (chr == ",") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - result.push([]); - continue; - } - if (chr == ".") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - str += chr; - continue; - } - if (combinators.includes(chr)) { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - if (chr == "|" && buffer.charAt(i + 1) == "|") { - chr += buffer.charAt(++i); - } - result.at(-1).push(chr); - continue; - } - if (chr == ":") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - if (buffer.charAt(i + 1) == ":") { - chr += buffer.charAt(++i); + function expand(ast) { + if (ast[STATE] == exports.EnumAstNodeStatus.Invalid || + ast[STATE] == exports.EnumAstNodeStatus.Disallowed || + ast[STATE] == exports.EnumAstNodeStatus.Unknown || + ast[STATE] == exports.EnumAstNodeStatus.Unparsed || + ast[STATE] == exports.EnumAstNodeStatus.Malformed) { + return ast; + } + const result = Object.assign(cloneNode(ast), { chi: [] }); + let children; + for (let i = 0; i < ast.chi.length; i++) { + let node = ast.chi[i]; + if (node.typ === exports.EnumToken.RuleNodeType) { + children = expandRule(node); + for (const child of children) { + child[PARENT] = result; + result.chi.push(child); } - str += chr; - continue; - } - str += chr; - if (chr == "\\") { - str += buffer.charAt(++i); - continue; } - if (chr == "(" || chr == "[") { - const open = chr; - const close = chr == "(" ? ")" : "]"; - let inParens = 1; - let k = i; - while (++k < buffer.length) { - chr = buffer.charAt(k); - if (chr == "\\") { - str += buffer.slice(k, k + 2); - k++; - continue; - } - str += chr; - if (chr == open) { - inParens++; - } - else if (chr == close) { - inParens--; - } - if (inParens == 0) { + else if (node.typ == exports.EnumToken.AtRuleNodeType && "chi" in node) { + let hasRule = false; + let j = node.chi.length; + while (j--) { + // @ts-ignore + if (node.chi[j].typ == exports.EnumToken.RuleNodeType || node.chi[j].typ == exports.EnumToken.AtRuleNodeType) { + hasRule = true; break; } } - i = k; - } - } - if (str !== "") { - result.at(-1).push(str); - } - return result; - } - /** - * Reduce selector - * @param acc - * @param curr - * - * @private - */ - function reduceSelector(acc, curr) { - let hasCompoundSelector = true; - // @ts-ignore - curr = curr.slice(this.match[0].length); - while (curr.length > 0) { - if (curr[0] == " ") { - hasCompoundSelector = false; - curr.unshift("&"); - continue; - } - break; - } - if (hasCompoundSelector && curr.length > 0) { - hasCompoundSelector = !["&"].concat(combinators).includes(curr[0].charAt(0)); - } - if (curr[0] == ":is(") { - let canReduce = true; - const isCompound = curr.reduce((acc, token, index) => { - if (index == 0) { - canReduce = curr[1] == "&"; - } - else if (token == ")") ; - else if (token == ",") { - if (!canReduce) { - canReduce = curr[index + 1] == "&"; + if (hasRule) { + node = expand(node); + for (const child of node.chi) { + child[PARENT] = result; } - acc.push([]); + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } - else - acc.at(-1)?.push(token); - return acc; - }, [[]]); - if (canReduce) { - curr = isCompound.reduce((acc, curr) => { - if (acc.length > 0) { - acc.push(","); - } - acc.push(...curr); - return acc; - }, []); - } - } - acc.push( - // @ts-ignore - this.match.length == 0 - ? ["&"] - : hasCompoundSelector && curr[0] != "&" && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) - ? ["&"].concat(curr) - : curr); - return acc; - } - /** - * Match selectors - * @param selector1 - * @param selector2 - * - * @private - */ - function matchSelectors(selector1, selector2) { - let match = [[]]; - const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0)); - let i = 0; - let k; - let l; - let token; - let matching = true; - let matchFunction = 0; - let inAttr = 0; - const regEx = /^:is\(([:.][^\s,]+)\)$/; - for (const _1 of selector1) { - if (_1[0] !== "&") { - continue; - } - for (let i = 1; i < _1.length; i++) { - const token = _1[i]; - if (token.startsWith(":is(")) { - const match = regEx.exec(token); - if (match != null) { - _1[i] = match[1]; - } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - } - for (const _1 of selector2) { - if (_1[0] !== "&") { - continue; - } - for (let i = 1; i < _1.length; i++) { - const token = _1[i]; - if (token.startsWith(":is(")) { - const match = regEx.exec(token); - if (match != null) { - _1[i] = match[1]; - } - } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - for (; i < j; i++) { - k = 0; - token = selector1[0][i]; - for (; k < selector1.length; k++) { - if (selector1[k][i] != token) { - matching = false; - break; - } - } - if (matching) { - l = 0; - for (; l < selector2.length; l++) { - if (selector2[l][i] != token) { - matching = false; - break; - } - } - } - if (!matching) { - break; - } - if (token.endsWith("(")) { - matchFunction++; - } - match.at(-1).push(token); + return result; + } + function expandRule(node) { + if (node[STATE] == exports.EnumAstNodeStatus.Invalid || + node[STATE] == exports.EnumAstNodeStatus.Disallowed || + node[STATE] == exports.EnumAstNodeStatus.Unknown || + node[STATE] == exports.EnumAstNodeStatus.Unparsed || + node[STATE] == exports.EnumAstNodeStatus.Malformed) { + return [node]; } - // invalid function - if (matchFunction != 0 || inAttr != 0) { - return null; - } - for (const part of match) { - while (part.length > 0) { - const token = part.at(-1); - if (token == " " || combinators.includes(token) || notEndingWith.includes(token.at(-1))) { - part.pop(); - continue; + const ast = Object.assign(cloneNode(node), { chi: node.chi.slice() }); + const result = []; + if (ast.typ == exports.EnumToken.RuleNodeType) { + let i = 0; + for (; i < ast.chi.length; i++) { + if (ast.chi[i].typ == exports.EnumToken.RuleNodeType) { + const rule = ast.chi[i]; + if (!rule.sel.includes("&")) { + const selRule = splitRule(rule.sel); + const arSelf = splitRule(ast.sel) + .filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))) + .reduce((acc, curr) => acc.concat([curr.join("")]), []) + .join(","); + if (arSelf.length == 0) { + ast.chi.splice(i--, 1); + continue; + } + for (let i1 = 0; i1 < selRule.length; i1++) { + const arr = selRule[i1]; + combinators.includes(arr[0].charAt(0)) ? arr.unshift(arSelf) : arr.unshift(arSelf, " "); + } + rule.sel = selRule + .reduce((acc, curr) => { + acc.push(curr.join("")); + return acc; + }, []) + .join(","); + } + else { + let childSelectorCompound = []; + let withCompound = []; + let withoutCompound = []; + // pseudo elements cannot be used with '&' + // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e + const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))); + const parentSelector = !node.sel.includes("&"); + if (rules.length == 0) { + ast.chi.splice(i--, 1); + continue; + } + for (const sel of rule[RAW] ?? splitRule(rule.sel)) { + const s = sel.join(""); + if (s.includes("&") || parentSelector) { + if (s.indexOf("&", 1) == -1) { + if (s.at(0) == "&") { + if (s.at(1) == " ") { + childSelectorCompound.push(s.slice(2)); + } + else { + if (s == "&" || parentSelector) { + withCompound.push(s); + } + } + } + else { + withoutCompound.push(s); + } + } + else { + withCompound.push(s); + } + } + } + const selectors = []; + const selector = rules.length > 1 ? ":is(" + rules.map((a) => a.join("")).join(",") + ")" : rules[0].join(""); + if (childSelectorCompound.length > 0) { + if (childSelectorCompound.length == 1) { + selectors.push(replaceCompound("& " + childSelectorCompound[0].trim(), selector)); + } + else { + selectors.push(replaceCompound("& :is(" + + childSelectorCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + + ")", selector)); + } + } + if (withCompound.length > 0) { + if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { + // for (const w of withCompound) { + // for (let m = 0; m < w.length; m++) { + // // for (let n = 0; n < w[m].length; n++) { + // withoutCompound.push(w[m].slice(1)); + // // } + // } + // } + withoutCompound.push(...withCompound.map((t) => t.slice(1))); + withCompound.length = 0; + } + } + if (withoutCompound.length > 0) { + if (withoutCompound.length == 1) { + const useIs = rules.length == 1 && + selector.match(/^[a-zA-Z.:]/) != null && + selector.includes(" ") && + withoutCompound.length == 1 && + withoutCompound[0].match(/^[a-zA-Z]+$/) != null; + const compound = useIs ? ":is(&)" : "&"; + selectors.push(replaceCompound(rules.length == 1 + ? useIs + ? withoutCompound[0] + ":is(&)" + : selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) + ? withoutCompound[0] + compound + : compound + withoutCompound[0] + : withoutCompound[0].match(/^[a-zA-Z:]+$/) + ? withoutCompound[0].trim() + compound + : "&" + + (withoutCompound[0].match(/^\S+$/) + ? withoutCompound[0].trim() + : ":is(" + withoutCompound[0].trim() + ")"), selector)); + } + else { + selectors.push(replaceCompound("&:is(" + + withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + + ")", selector)); + } + } + if (withCompound.length > 0) { + if (withCompound.length == 1) { + selectors.push(replaceCompound(withCompound[0], selector)); + } + } + rule.sel = selectors.reduce((acc, curr) => (curr.length == 0 ? acc : acc + (acc.length > 0 ? "," : "") + curr), ""); + } + ast.chi.splice(i--, 1); + for (const s of expandRule(rule)) { + result.push(s); + } + } + else if (ast.chi[i].typ == exports.EnumToken.AtRuleNodeType) { + let astAtRule = ast.chi[i]; + const values = []; + if (astAtRule.nam === "scope") { + if (astAtRule.val.includes("&")) { + astAtRule.val = replaceCompound(astAtRule.val, ast.sel); + } + const slice = astAtRule.chi + .slice() + .filter((t) => t.typ == exports.EnumToken.RuleNodeType && t.sel.includes("&")); + if (slice.length > 0) { + expandRule({ ...node, chi: astAtRule.chi.slice() }); + } + } + else { + // @ts-ignore + const clone = { ...ast, chi: astAtRule.chi.slice() }; + // @ts-ignore + astAtRule.chi.length = 0; + for (const r of expandRule(clone)) { + if (r.typ == exports.EnumToken.AtRuleNodeType && "chi" in r) { + if (astAtRule.val !== "" && r.val !== "") { + if (astAtRule.nam === "media" && r.nam === "media") { + r.val = astAtRule.val + " and " + r.val; + } + else if (astAtRule.nam == "layer" && r.nam == "layer") { + r.val = astAtRule.val + "." + r.val; + } + } + // @ts-ignore + values.push(r); + } + else if (r.typ == exports.EnumToken.RuleNodeType) { + for (const rule of expandRule(r)) { + // @ts-ignore + astAtRule.chi.push(rule); + } + } + } + } + if (astAtRule.chi.length > 0) { + result.push(astAtRule); + } + for (const r of values) { + result.push(r); + } + ast.chi.splice(i--, 1); } - break; } } - if (match.every((t) => t.length == 0)) { - return null; - } - if (eq([["&"]], match)) { - return null; - } - const reducer = reduceSelector.bind({ match }); - // @ts-ignore - selector1 = selector1.reduce(reducer, []); // @ts-ignore - selector2 = selector2.reduce(reducer, []); - return selector1 == null || selector2 == null - ? null - : { - eq: eq(selector1, selector2), - match, - selector1, - selector2, - }; + return ast.chi.length > 0 ? [ast].concat(result) : result; } /** - * Fix selector - * @param node - * - * @private + * replace compound selector + * @param input + * @param replace */ - function fixSelector(node) { - if (node.sel.includes("&")) { - const attributes = [...tokenize(node.sel)].map((t) => t.token); // parseString(node.sel); - for (const attr of walkValues(attributes)) { - if (attr.value.typ == exports.EnumToken.PseudoClassFuncTokenType && - attr.value.val == ":is") { - let i = attr.value.chi.length; - while (i--) { - if (attr.value.chi[i].typ == exports.EnumToken.NestingSelectorTokenType) { - attr.value.chi.splice(i, 1); - } + function replaceCompound(input, replace) { + const tokens = parseString(input); + let replacement = null; + for (const t of walkValues(tokens)) { + if (t.value.typ == exports.EnumToken.NestingSelectorTokenType) { + if (tokens.length == 2) { + if (replacement == null) { + replacement = parseString(replace); } + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: replaceCompoundLiteral(t.value.val, replace), + }); + continue; } + const rule = splitRule(replace); + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: rule.length > 1 ? ":is(" + replace + ")" : replace, + }); + } + } + return tokens.reduce((acc, curr) => acc + renderValue(curr), ""); + } + function replaceCompoundLiteral(selector, replace) { + const tokens = [""]; + let i = 0; + for (; i < selector.length; i++) { + if (selector.charAt(i) == "&") { + tokens.push("&", ""); } - node.sel = attributes.reduce((acc, curr) => acc + renderValue(curr), ""); - node[TOKENS] = null; } + return tokens + .sort((a, b) => { + if (a == "&") { + return 1; + } + return b == "&" ? -1 : 0; + }) + .reduce((acc, curr) => acc + (curr == "&" ? replace : curr), ""); + } + + // from https://github.com/Rich-Harris/vlq/tree/master + // credit: Rich Harris + const integer_to_char = {}; + const char_to_integer = {}; + let i = 0; + for (const char of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=') { + char_to_integer[char] = i; + integer_to_char[i++] = char; } /** - * Wrap nodes - * @param previous - * @param node - * @param match - * @param ast - * @param reducer - * @param i - * @param nodeIndex - * - * @private + * @param {string} str */ - function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) { - // @ts-ignore - let pSel = match.selector1.reduce(reducer, []).join(","); - // @ts-ignore - let nSel = match.selector2.reduce(reducer, []).join(","); - const wrapper = { - ...previous, - chi: [], - // @ts-ignore - sel: match.match.reduce(reducer, []).join(","), - [RAW]: match.match.map((t) => t.slice()), - }; - if (pSel == "&" || pSel === "") { - wrapper.chi.push(...previous.chi); - if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); + function decode(str) { + /** @type {number[]} */ + let result = []; + let shift = 0; + let value = 0; + for (let i = 0; i < str.length; i += 1) { + let integer = char_to_integer[str[i]]; + // if (integer === undefined) { + // throw new Error('Invalid character (' + str[i] + ')'); + // } + const has_continuation_bit = integer & 32; + integer &= 31; + value += integer << shift; + if (has_continuation_bit) { + shift += 5; } else { - wrapper.chi.push(node); + const should_negate = value & 1; + value >>>= 1; + if (should_negate) { + result.push(value === 0 ? -2147483648 : -value); + } + else { + result.push(value); + } + // reset + value = shift = 0; } } - else { - wrapper.chi.push(previous, node); - } - ast.chi.splice(i, 1, wrapper); - ast.chi.splice(nodeIndex, 1); - previous.sel = pSel; - previous[RAW] = match.selector1; - previous[TOKENS] = null; - node.sel = nSel; - node[RAW] = match.selector2; - node[TOKENS] = null; - reduceRuleSelector(wrapper); - wrapper[TOKENS] = null; - return wrapper; + return result; } /** - * Diff nodes - * @param n1 - * @param n2 - * @param options * - * @private + * @param value + * @returns */ - function diff$1(n1, n2, options = {}) { - if (!("cache" in options)) { - options.cache = new WeakMap(); + function encode(value) { + if (typeof value === 'number') { + return encode_integer(value); } - let node1 = n1; - let node2 = n2; - let exchanged = false; - if (node1.chi.length > node2.chi.length) { - const t = node1; - node1 = node2; - node2 = t; - exchanged = true; + let result = ''; + for (let i = 0; i < value.length; i += 1) { + result += encode_integer(value[i]); } - let i = node1.chi.length; - let j = node2.chi.length; - const raw1 = node1[RAW]; - const raw2 = node2[RAW]; - if (raw1 != null && raw2 != null) { - const prefixes1 = new Set(); - const prefixes2 = new Set(); - for (const token1 of raw1) { - for (const t of token1) { - if (t.includes(":")) { - const matches = t.match(/::?-([a-z]+)-/); - if (matches == null) { - continue; - } - prefixes1.add(matches[1]); - if (prefixes1.size > 1) { - break; - } - } - } - if (prefixes1.size > 1) { - break; - } + return result; + } + function encode_integer(num) { + let result = ''; + if (num < 0) { + num = (-num << 1) | 1; + } + else { + num <<= 1; + } + do { + let clamped = num & 31; + num >>>= 5; + if (num > 0) { + clamped |= 32; } - for (const token2 of raw2) { - for (const t of token2) { - if (t.includes(":")) { - const matches = t.match(/::?-([a-z]+)-/); - if (matches == null) { - continue; - } - prefixes2.add(matches[1]); - if (prefixes2.size > 1) { - break; - } + result += integer_to_char[clamped]; + } while (num > 0); + return result; + } + + /** + * Generate and parse source map + */ + class SourceMap { + /** + * + * @private + */ + keys = new Set(); + /** + * Last location + */ + lastLocation = null; + /** + * Version + * @private + */ + version = 3; + /** + * Sources map + * @private + */ + sourcesMap = []; + /** + * Sources content + * @private + */ + sourcesContent = []; + /** + * Sources + * @private + */ + sources = []; + /** + * Map + * @private + * + */ + map = new Map(); + /** + * Map + * @private + * + */ + reverseMap = new Map(); + /** + * Line + * @private + */ + line = -1; + /** + * + * @param sourcemaps + */ + constructor(sourcemaps) { + if (typeof sourcemaps === "string") { + if (sourcemaps.startsWith("data:")) { + let encoding = ""; + let offset = sourcemaps.indexOf(",") + 1; + if (offset == 0) { + offset = sourcemaps.lastIndexOf(";") + 1; + } + else { + encoding = sourcemaps.slice(sourcemaps.lastIndexOf(";") + 1, offset - 1); + } + if (encoding == "base64") { + sourcemaps = atob(sourcemaps.slice(offset)); + } + else { + sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); } } - if (prefixes2.size > 1) { - break; - } - } - if (prefixes1.size != prefixes2.size) { - return null; + sourcemaps = JSON.parse(sourcemaps); } - for (const prefix of prefixes1) { - if (!prefixes2.has(prefix)) { - return null; + if (sourcemaps != null) { + this.sources = sourcemaps.sources?.slice() ?? []; + this.sourcesContent = sourcemaps.sourcesContent?.slice() ?? []; + const decodedMappings = sourcemaps.mappings + .split(";") + .map((mapping) => mapping.split(",").map((mapping) => decode(mapping))); + this.line = decodedMappings.length - 1; + for (let index = 0; index < decodedMappings.length; index++) { + if (decodedMappings[index].length == 0 || + (decodedMappings[index].length == 1 && decodedMappings[index][0].length == 0)) { + continue; + } + this.map.set(index, decodedMappings[index]); } + this.computePositions(); } } - const css1 = options.cache.get(node1); - const css2 = options.cache.get(node2); - node1 = { ...node1, chi: node1.chi.slice() }; - node2 = { ...node2, chi: node2.chi.slice() }; - if (css1 != null) { - options.cache.set(node1, css1); + /** + * add source + * @param id + * @param fileName + * @param content + * @returns + */ + addSourceContent(id, fileName, content) { + if (this.sourcesMap.includes(id)) { + return; + } + this.sourcesMap[this.sourcesMap.length] = id; + this.sources[this.sources.length] = fileName || null; + this.sourcesContent[this.sourcesContent.length] = content || null; } - if (css2 != null) { - options.cache.set(node2, css2); - } - if (raw1 != null) { - node1[RAW] = raw1; - } - if (raw2 != null) { - node2[RAW] = raw2; - } - const intersect = []; - while (i--) { - if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; - } - j = node2.chi.length; - while (j--) { - if (node2.chi[j].typ == exports.EnumToken.CommentNodeType) { + /** + * Add multiple sourcemaps + * @param maps + * @throws + */ + add(maps) { + let srcIndex; + for (let [newLine, newColumn, srcId, ln, col] of maps) { + const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; + if (this.keys.has(key)) { continue; } - if (node1.chi[i].nam == node2.chi[j].nam) { - if (node1.chi[i].typ == node2.chi[j].typ && eq(node1.chi[i], node2.chi[j])) { - intersect.push(node1.chi[i]); - node1.chi.splice(i, 1); - node2.chi.splice(j, 1); - options.cache.delete(node1); - options.cache.delete(node2); - break; - } + this.keys.add(key); + const line = newLine - 1; + let record; + if (line > this.line) { + this.line = line; + } + srcIndex = this.sourcesMap.indexOf(srcId); + if (srcIndex == -1) { + throw new Error(`Source file ${srcId} not added to sourcemap`); + } + if (!this.map.has(line)) { + record = [Math.max(0, newColumn - 1), srcIndex, ln - 1, col - 1]; + this.map.set(line, [record]); + } + else { + const arr = this.map.get(line); + record = [Math.max(0, newColumn - 1) - arr[0][0], srcIndex - arr[0][1], ln - 1, col - 1]; + arr.push(record); + } + if (this.lastLocation != null) { + record[2] -= this.lastLocation.ln - 1; + record[3] -= this.lastLocation.col - 1; } + this.lastLocation ??= { ln, col }; + this.lastLocation.ln = ln; + this.lastLocation.col = col; } } - const result = intersect.length === 0 && (node1.chi.length > 0 || node2.chi.length > 0) - ? null - : { - ...node1, - // @ts-ignore - sel: [ - ...new Set(splitRule(node1.sel) - .concat(splitRule(node2.sel)) - .map((s) => s.join(""))), - ].join(","), - // @ts-ignore - chi: intersect.reverse(), - }; - let op = { level: 0, ...options }; - if (result == null || - [n1, n2].reduce((acc, curr) => { - let css = options.cache.get(curr); - if (css == null) { - let level = 0; - let parent = curr[PARENT]; - while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { - level++; - parent = parent[PARENT]; - } - op.level = level; - css = doRender(curr, op).code; - options.cache.set(curr, css); + /** + * compute original positions + */ + computePositions() { + this.reverseMap.clear(); + let sourceFileIndex = 0; // second field + let sourceCodeLine = 0; // third field + let sourceCodeColumn = 0; // fourth field + // let nameIndex: number = 0; // fifth field + let generatedCodeColumn; + let result; + // mappings to original source + for (let [i, line] of this.map.entries()) { + if (line.length === 0 || (line.length === 1 && line[0].length === 0)) { + continue; } - return curr.chi.length == 0 ? acc : acc + css.length; - }, 0) <= - [node1, node2, result].reduce((acc, curr) => { - let css = options.cache.get(curr); - if (css != null) { - return curr.chi.length == 0 ? acc : acc + css.length; + generatedCodeColumn = line[0][0]; // first field - reset each time + line = line + .map((segment, index, array) => { + if (segment.length === 0) { + return []; } - let level = 0; - let parent = curr[PARENT]; - while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { - level++; - parent = parent[PARENT]; + generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; + result = [generatedCodeColumn]; + if (segment.length <= 1) { + return result; } - op.level = level; - css = doRender(curr, op).code; - return curr.chi.length == 0 ? acc : acc + css.length; - }, 0)) { - if (node1.chi.length != 0 && node2.chi.length != 0) { + sourceFileIndex = index == 0 ? segment[1] : segment[1] + array[0][1]; + sourceCodeLine += segment[2]; + sourceCodeColumn += segment[3]; + result.push(sourceFileIndex, sourceCodeLine, sourceCodeColumn); + // nameIndex not needed + // if (segment.length === 5) { + // nameIndex += segment[4]; + // result.push(nameIndex); + // } + return result; + }) + .sort((a, b) => { + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[0] - b[0]; + }); + if (line.length == 0 || (line.length == 1 && line[0].length == 0)) { + continue; + } + this.reverseMap.set(i, line); + } + } + /** + * retrieve original sources, lines and columns + * @param line generated line + * @param column generated column + */ + find(line, column) { + if (this.reverseMap.size == 0) { + this.computePositions(); + } + if (!this.reverseMap.has(--line)) { return null; } + column--; + const result = []; + for (const record of this.reverseMap.get(line)) { + if (record.length == 0 || record[0] < column) { + continue; + } + if (record[0] > column) { + break; + } + result.push([ + this.sources?.[record[1]] ?? null, + record[2] + 1, + record[3] + 1, + this.sourcesContent?.[record[1]] ?? null, + ]); + } + return result.length == 0 ? null : result; } - if (result != null) { - result[TOKENS] = null; - result[RAW] = null; - const optimized = optimizeSelector(splitRule(result.sel)); - if (optimized?.match) { - const rule = optimized.selector.reduce((acc, curr) => { - if (acc.length > 0) { - acc += ","; - } - if (curr.length > 2 && curr[0] === "&" && curr[1] === " ") { - return acc + curr.slice(2).join(""); - } - else if (curr.length > 1 && curr[0] === "&") { - return acc + curr.slice(1).join(""); - } - return acc + curr.join(""); - }, ""); - const match = optimized.optimized.join(""); - const sel = match + ":is(" + replaceCompound(rule, match) + ")"; - if (sel.length < result.sel.length) { - result.sel = sel; - result[TOKENS] = null; + /** + * Convert to URL encoded string + */ + toUrl() { + // /*# sourceMappingURL = ${url} */ + return `data:application/json;charset=utf-8;base64,${btoa(JSON.stringify(this.toJSON()))}`; + } + /** + * Convert to JSON object + */ + toJSON() { + const mappings = []; + let i = 0; + for (; i <= this.line; i++) { + if (!this.map.has(i)) { + mappings.push(""); + } + else { + mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); } } + return { + version: this.version, + sources: this.sources.slice(), + sourcesContent: this.sourcesContent?.slice(), + mappings: mappings.join(";"), + }; } - return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; } + /** - * Reduce rule selector - * @param node - * - * @private + * Compute line and column of the offset */ - function reduceRuleSelector(node) { - if (node[RAW] == null) { - node[RAW] = splitRule(node.sel); - } - let optimized = optimizeSelector(node[RAW].reduce((acc, curr) => { - acc.push(curr.slice()); - return acc; - }, [])); - if (optimized != null) { - node[OPTIMIZED] = optimized; + class LineMap { + /** + * line starts + */ + lineStarts; + /** + * Constructor + * @param lines + */ + constructor(lines = []) { + if (lines.length === 0) { + lines.push(0); + } + this.lineStarts = lines; } - if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) { - for (const selector of optimized.selector) { - if (selector.length > 1 && - selector[0] == "&" && - (combinators.includes(selector[1]) || !/^[a-zA-Z:]/.test(selector[1]))) { - selector.shift(); + /** + * Compute line and column of the offset + * @param offset + * @returns + */ + getOffsets(offset) { + const line = this.search(offset); + const column = offset - this.lineStarts[line]; + // [line, column] + return [line + 1, line == 0 ? column + 1 : column]; + } + /** + * search the greatest index of the value less than or equal to offset + * @param offset + * @returns + */ + search(offset) { + // search lineStarts using binary search + let start = 0; + let end = this.lineStarts.length - 1; + let mid = 0; + let result = -1; + while (start <= end) { + mid = start + ((end - start) >>> 1); + if (this.lineStarts[mid] <= offset) { + result = mid; + start = mid + 1; } - } - const unique = new Set(); - const reduced = optimized.selector.reduce((acc, curr) => { - const sig = curr.join(""); - if (!unique.has(sig)) { - if (acc.length > 0) { - acc.push(","); - } - unique.add(sig); - acc.push(...curr); + else if (this.lineStarts[mid] > offset) { + end = mid - 1; } - return acc; - }, []); - const raw = [ - [optimized.optimized[0], reduced.length === 1 ? reduced.join("") : ":is("].concat(reduced).concat(")"), - ]; - const sel = raw[0].join(""); - if (sel.length < node.sel.length) { - node.sel = sel; - node[RAW] = raw; - node[TOKENS] = null; } + return result; + } + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts; + } + /** + * add line start + */ + addLineStart(lineStart) { + this.lineStarts.push(lineStart); } } /** - * expand css nesting ast nodes - * @param ast + * match url + */ + const matchUrl = /^(https?:)?\/\//; + const windowsPathnameRegexp = /^\/?[a-zA-Z]:\/?/; + /** + * return the directory name of a path + * @param path * * @private */ - function expand(ast) { - if (ast[STATE] == exports.EnumAstNodeStatus.Invalid || - ast[STATE] == exports.EnumAstNodeStatus.Disallowed || - ast[STATE] == exports.EnumAstNodeStatus.Unknown || - ast[STATE] == exports.EnumAstNodeStatus.Unparsed || - ast[STATE] == exports.EnumAstNodeStatus.Malformed) { - return ast; + function dirname(path) { + if (path === "") { + return ""; } - const result = Object.assign(cloneNode(ast), { chi: [] }); - let children; - for (let i = 0; i < ast.chi.length; i++) { - let node = ast.chi[i]; - if (node.typ === exports.EnumToken.RuleNodeType) { - children = expandRule(node); - for (const child of children) { - child[PARENT] = result; - } - // @ts-ignore - result.chi.push(...children); + if (path.startsWith("data:")) { + return path; + } + let i = 0; + let parts = [""]; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + parts.push(""); } - else if (node.typ == exports.EnumToken.AtRuleNodeType && "chi" in node) { - let hasRule = false; - let j = node.chi.length; - while (j--) { - // @ts-ignore - if (node.chi[j].typ == exports.EnumToken.RuleNodeType || node.chi[j].typ == exports.EnumToken.AtRuleNodeType) { - hasRule = true; - break; - } - } - if (hasRule) { - node = expand(node); - for (const child of node.chi) { - child[PARENT] = result; - } - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + else { + parts[parts.length - 1] += chr; + } + } + parts.pop(); + return parts.join("/"); + } + /** + * split path + * @param result + * @private + */ + function splitPath(result) { + if (result.length == 0) { + return { parts: [], i: 0 }; + } + const parts = result == "/" ? [] : [""]; + let i = 0; + for (; i < result.length; i++) { + const chr = result.charAt(i); + if (chr == "/") { + parts.push(""); + } + // else if (chr == "?" || chr == "#") { + // break; + // } + else { + parts[parts.length - 1] += chr; + } + } + // let k: number = -1; + // while (++k < parts.length) { + // if (parts[k] == ".") { + // parts.splice(k--, 1); + // } else if (parts[k] == "..") { + // parts.splice(k - 1, 2); + // k -= 2; + // } + // } + return { parts, i }; + } + /** + * Nomalize path + * @param path + * @private + */ + const normalize = memoize(function (path) { + let parts = []; + let i = 0; + if (path.includes("\\")) { + path = path.replace(/(\\)/g, "/"); + } + if (windowsPathnameRegexp.test(path)) { + path = path.replace(windowsPathnameRegexp, ""); + } + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + if (parts.length == 0 || parts[parts.length - 1] !== "") { + parts.push(""); } - else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + } + else if (chr == "?" || chr == "#") { + break; + } + else { + if (parts.length == 0) { + parts.push(""); } + parts[parts.length - 1] += chr; + } + } + let k = -1; + while (++k < parts.length) { + // if (parts[k] == ".") { + // parts.splice(k--, 1); + // } else + if (k > 0 && parts[k] == "..") { + parts.splice(k - 1, 2); + k -= 2; + } + } + return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); + }); + /** + * diff path + * @param path1 + * @param path2 + * @private + */ + const diff = memoize(function (path1, path2) { + let { parts } = splitPath(path1); + const { parts: dirs } = splitPath(path2); + for (const p of dirs) { + if (parts[0] == p) { + parts.shift(); } else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + parts.unshift(".."); } } - return result; - } - function expandRule(node) { - if (node[STATE] == exports.EnumAstNodeStatus.Invalid || - node[STATE] == exports.EnumAstNodeStatus.Disallowed || - node[STATE] == exports.EnumAstNodeStatus.Unknown || - node[STATE] == exports.EnumAstNodeStatus.Unparsed || - node[STATE] == exports.EnumAstNodeStatus.Malformed) { - return [node]; + return parts.join("/"); + }); + /** + * resolve path + * @param url url or path to resolve + * @param currentDirectory directory used to resolve the path + * @param cwd current working directory + * + * @private + */ + const resolve = memoize(function (url, currentDirectory, cwd) { + if (matchUrl.test(url)) { + return { + absolute: url, + relative: url, + }; } - const ast = Object.assign(cloneNode(node), { chi: node.chi.slice() }); - const result = []; - if (ast.typ == exports.EnumToken.RuleNodeType) { - let i = 0; - for (; i < ast.chi.length; i++) { - if (ast.chi[i].typ == exports.EnumToken.RuleNodeType) { - const rule = ast.chi[i]; - if (!rule.sel.includes("&")) { - const selRule = splitRule(rule.sel); - const arSelf = splitRule(ast.sel) - .filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))) - .reduce((acc, curr) => acc.concat([curr.join("")]), []) - .join(","); - if (arSelf.length == 0) { - ast.chi.splice(i--, 1); - continue; - } - for (let i1 = 0; i1 < selRule.length; i1++) { - const arr = selRule[i1]; - combinators.includes(arr[0].charAt(0)) ? arr.unshift(arSelf) : arr.unshift(arSelf, " "); - } - rule.sel = selRule - .reduce((acc, curr) => { - acc.push(curr.join("")); - return acc; - }, []) - .join(","); - } - else { - let childSelectorCompound = []; - let withCompound = []; - let withoutCompound = []; - // pseudo elements cannot be used with '&' - // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))); - const parentSelector = !node.sel.includes("&"); - if (rules.length == 0) { - ast.chi.splice(i--, 1); - continue; - } - for (const sel of rule[RAW] ?? splitRule(rule.sel)) { - const s = sel.join(""); - if (s.includes("&") || parentSelector) { - if (s.indexOf("&", 1) == -1) { - if (s.at(0) == "&") { - if (s.at(1) == " ") { - childSelectorCompound.push(s.slice(2)); - } - else { - if (s == "&" || parentSelector) { - withCompound.push(s); - } - } - } - else { - withoutCompound.push(s); - } - } - else { - withCompound.push(s); - } - } - } - const selectors = []; - const selector = rules.length > 1 ? ":is(" + rules.map((a) => a.join("")).join(",") + ")" : rules[0].join(""); - if (childSelectorCompound.length > 0) { - if (childSelectorCompound.length == 1) { - selectors.push(replaceCompound("& " + childSelectorCompound[0].trim(), selector)); - } - else { - selectors.push(replaceCompound("& :is(" + - childSelectorCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + - ")", selector)); - } - } - if (withCompound.length > 0) { - if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { - withoutCompound.push(...withCompound.map((t) => t.slice(1))); - withCompound.length = 0; - } - } - if (withoutCompound.length > 0) { - if (withoutCompound.length == 1) { - const useIs = rules.length == 1 && - selector.match(/^[a-zA-Z.:]/) != null && - selector.includes(" ") && - withoutCompound.length == 1 && - withoutCompound[0].match(/^[a-zA-Z]+$/) != null; - const compound = useIs ? ":is(&)" : "&"; - selectors.push(replaceCompound(rules.length == 1 - ? useIs - ? withoutCompound[0] + ":is(&)" - : selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) - ? withoutCompound[0] + compound - : compound + withoutCompound[0] - : withoutCompound[0].match(/^[a-zA-Z:]+$/) - ? withoutCompound[0].trim() + compound - : "&" + - (withoutCompound[0].match(/^\S+$/) - ? withoutCompound[0].trim() - : ":is(" + withoutCompound[0].trim() + ")"), selector)); - } - else { - selectors.push(replaceCompound("&:is(" + - withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + - ")", selector)); - } - } - if (withCompound.length > 0) { - if (withCompound.length == 1) { - selectors.push(replaceCompound(withCompound[0], selector)); - } - } - rule.sel = selectors.reduce((acc, curr) => (curr.length == 0 ? acc : acc + (acc.length > 0 ? "," : "") + curr), ""); - } - ast.chi.splice(i--, 1); - result.push(...expandRule(rule)); - } - else if (ast.chi[i].typ == exports.EnumToken.AtRuleNodeType) { - let astAtRule = ast.chi[i]; - const values = []; - if (astAtRule.nam === "scope") { - if (astAtRule.val.includes("&")) { - astAtRule.val = replaceCompound(astAtRule.val, ast.sel); - } - const slice = astAtRule.chi - .slice() - .filter((t) => t.typ == exports.EnumToken.RuleNodeType && t.sel.includes("&")); - if (slice.length > 0) { - expandRule({ ...node, chi: astAtRule.chi.slice() }); - } - } - else { - // @ts-ignore - const clone = { ...ast, chi: astAtRule.chi.slice() }; - // @ts-ignore - astAtRule.chi.length = 0; - for (const r of expandRule(clone)) { - if (r.typ == exports.EnumToken.AtRuleNodeType && "chi" in r) { - if (astAtRule.val !== "" && r.val !== "") { - if (astAtRule.nam === "media" && r.nam === "media") { - r.val = astAtRule.val + " and " + r.val; - } - else if (astAtRule.nam == "layer" && r.nam == "layer") { - r.val = astAtRule.val + "." + r.val; - } - } - // @ts-ignore - values.push(r); - } - else if (r.typ == exports.EnumToken.RuleNodeType) { - // @ts-ignore - astAtRule.chi.push(...expandRule(r)); - } - } - } - // @ts-ignore - result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); - ast.chi.splice(i--, 1); - } - } + cwd ??= ""; + currentDirectory ??= ""; + url = normalize(url); + if (cwd !== "") { + cwd = normalize(cwd); } - // @ts-ignore - return ast.chi.length > 0 ? [ast].concat(result) : result; - } - /** - * replace compound selector - * @param input - * @param replace - */ - function replaceCompound(input, replace) { - const tokens = parseString(input); - let replacement = null; - for (const t of walkValues(tokens)) { - if (t.value.typ == exports.EnumToken.NestingSelectorTokenType) { - if (tokens.length == 2) { - if (replacement == null) { - replacement = parseString(replace); - } - Object.assign(t.value, { - typ: exports.EnumToken.LiteralTokenType, - val: replaceCompoundLiteral(t.value.val, replace), - }); - continue; - } - const rule = splitRule(replace); - Object.assign(t.value, { - typ: exports.EnumToken.LiteralTokenType, - val: rule.length > 1 ? ":is(" + replace + ")" : replace, - }); - } + if (currentDirectory !== "") { + currentDirectory = normalize(currentDirectory); } - return tokens.reduce((acc, curr) => acc + renderValue(curr), ""); - } - function replaceCompoundLiteral(selector, replace) { - const tokens = [""]; - let i = 0; - for (; i < selector.length; i++) { - if (selector.charAt(i) == "&") { - tokens.push("&", ""); - } + let dir = cwd || currentDirectory; + if (windowsPathnameRegexp.test(dir)) { + dir = dir.replace(windowsPathnameRegexp, ""); } - return tokens - .sort((a, b) => { - if (a == "&") { - return 1; - } - return b == "&" ? -1 : 0; - }) - .reduce((acc, curr) => acc + (curr == "&" ? replace : curr), ""); - } - - /** - * match url - */ - const matchUrl = /^(https?:)?\/\//; + const absolute = dir == "" || url.startsWith("/") || url.startsWith(dir) || windowsPathnameRegexp.test(url) + ? resolvePath(url) + : resolvePath(dir, url); + return { + absolute, + relative: dir === "" ? absolute : diff(absolute, dir), + }; + }); /** - * return the directory name of a path - * @param path * + * @param parts + * @returns * @private */ - function dirname(path) { - if (path === "") { - return ""; - } - if (path.startsWith("data:")) { - return path; - } - let i = 0; - let parts = [""]; - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - parts.push(""); + function resolvePath(...parts) { + const path = parts.filter(Boolean).join("/"); + const isAbsolute = /^[\\/]/.test(path); + const segments = path.split(/[\\/]+/); + const resolved = []; + for (const segment of segments) { + if (!segment || segment === ".") { + continue; + } + if (segment === "..") { + if (resolved.length && resolved[resolved.length - 1] !== "..") { + resolved.pop(); + } + else if (!isAbsolute) { + resolved.push(".."); + } } else { - parts[parts.length - 1] += chr; + resolved.push(segment); } } - parts.pop(); - return parts.join("/"); + let result = resolved.join("/"); + if (isAbsolute) { + result = "/" + result; + } + return result || (isAbsolute ? "/" : "."); } + /** - * split path - * @param result - * @private + * Source file ID */ - function splitPath(result) { - if (result.length == 0) { - return { parts: [], i: 0 }; - } - const parts = result == "/" ? [] : [""]; - let i = 0; - for (; i < result.length; i++) { - const chr = result.charAt(i); - if (chr == "/") { - parts.push(""); - } - // else if (chr == "?" || chr == "#") { - // break; - // } - else { - parts[parts.length - 1] += chr; - } - } - // let k: number = -1; - // while (++k < parts.length) { - // if (parts[k] == ".") { - // parts.splice(k--, 1); - // } else if (parts[k] == "..") { - // parts.splice(k - 1, 2); - // k -= 2; - // } - // } - return { parts, i }; - } + let sourceId = 0; /** - * Nomalize path - * @param path - * @private + * Source file helper class */ - const normalize = memoize(function (path) { - let parts = []; - let i = 0; - if (path.includes("\\")) { - path = path.replace(/(\\)/g, "/"); + class SourceFile { + inputSourceMap = null; + /** + * Source file ID + */ + id; + /** + * Source file path + */ + file; + /** + * Line map + */ + lineStarts; + /** + * Source file content + */ + content; + /** + * Constructor + * @param content + * @param lines + * @param file + */ + constructor(content, lines, file = null) { + this.id = sourceId++; + this.content = content; + this.file = file; + this.lineStarts = new LineMap(lines); } - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - if (parts.length == 0 || parts[parts.length - 1] !== "") { - parts.push(""); - } - } - else if (chr == "?" || chr == "#") { - break; - } - else { - if (parts.length == 0) { - parts.push(""); - } - parts[parts.length - 1] += chr; - } + /** + * Update source content + * @param content + */ + append(content) { + this.content += content; } - let k = -1; - while (++k < parts.length) { - // if (parts[k] == ".") { - // parts.splice(k--, 1); - // } else - if (k > 0 && parts[k] == "..") { - parts.splice(k - 1, 2); - k -= 2; - } + /** + * get file name + * @returns + */ + getFileName() { + return this.file; } - return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); - }); - /** - * diff path - * @param path1 - * @param path2 - * @private - */ - const diff = memoize(function (path1, path2) { - let { parts } = splitPath(path1); - const { parts: dirs } = splitPath(path2); - for (const p of dirs) { - if (parts[0] == p) { - parts.shift(); - } - else { - parts.unshift(".."); - } + /** + * get content + * @returns + */ + getContent() { + return this.content; } - return parts.join("/"); - }); - /** - * resolve path - * @param url url or path to resolve - * @param currentDirectory directory used to resolve the path - * @param cwd current working directory - * - * @private - */ - const resolve = memoize(function (url, currentDirectory, cwd) { - if (matchUrl.test(url)) { - return { - absolute: url, - relative: url, - }; + /** + * get text + * @param start + * @param length + * @returns + */ + getText(start, length) { + return this.content.slice(start, start + length); } - cwd ??= ""; - currentDirectory ??= ""; - url = normalize(url); - if (cwd !== "") { - cwd = normalize(cwd); + /** + * Compute line and column of the offset + * @param offset + * @returns + */ + getOffsets(offset) { + return this.lineStarts.getOffsets(offset); } - if (currentDirectory !== "") { - currentDirectory = normalize(currentDirectory); + /** + * get source location + * @param offset + * @returns + */ + getSourceLocation(offset) { + return [this.file, ...this.getOffsets(offset)]; } - const dir = cwd || currentDirectory; - const absolute = dir == "" || url.startsWith("/") || url.match(/^[a-zA-Z]:/) ? resolvePath(url) : resolvePath(dir, url); - return { - absolute, - relative: dir === "" ? absolute : diff(absolute, dir), - }; - }); - /** - * - * @param parts - * @returns - * @private - */ - function resolvePath(...parts) { - const path = parts.filter(Boolean).join("/"); - const isAbsolute = /^[\\/]/.test(path); - const segments = path.split(/[\\/]+/); - const resolved = []; - for (const segment of segments) { - if (!segment || segment === ".") { - continue; - } - if (segment === "..") { - if (resolved.length && resolved[resolved.length - 1] !== "..") { - resolved.pop(); - } - else if (!isAbsolute) { - resolved.push(".."); - } - } - else { - resolved.push(segment); - } + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts.getLineStarts(); } - let result = resolved.join("/"); - if (isAbsolute) { - result = "/" + result; + /** + * add line start + * @param lineStart + */ + addLineStart(lineStart) { + this.lineStarts.addLineStart(lineStart); + } + /** + * set input source map + * @param inputSourceMap + */ + setInputSourceMap(inputSourceMap) { + this.inputSourceMap = inputSourceMap == null ? null : new SourceMap(inputSourceMap); + } + /** + * return input source map + * @returns + */ + getInputSourceMap() { + return this.inputSourceMap; } - return result || (isAbsolute ? "/" : "."); } /** @@ -24829,7 +24134,7 @@ source = options.sourcesMap.get(sourceId); sourcemap.addSourceContent(source.id, source.getFileName(), source.getContent()); } - sourcemap.add(...sourcemaps.maps); + sourcemap.add(sourcemaps.maps); result.map = sourcemap; if (options.sourcemap === "inline") { result.code += `\n/*# sourceMappingURL=${result.map.toUrl()} */`; @@ -24851,43 +24156,33 @@ */ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str) { let offset = 0; - while (true) { - if (str.charAt(offset) == options.newLine) { - offset += options.newLine.length; - continue; - } - if (str.charAt(offset) == options.indent) { - offset += options.indent.length; - continue; - } - break; + // eat leanding whitespace + while (offset < str.length && isWhiteSpace(str.charCodeAt(offset))) { + offset++; } if (offset > 0) { - move(sourceLocation, linesMap, str.slice(0, offset)); + move(sourceLocation, linesMap, str, 0, offset + 1); } - if (node[LOC] != null && - [ - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.KeyframesRuleNodeType, - exports.EnumToken.KeyframesAtRuleNodeType, - ].includes(node.typ)) { - const source = options.sourcesMap.get(node[LOC].srcId); + if (node[LOCSTA] != null) { + const source = options.sourcesMap.get(node[LOCSRCID]); const inputSourceMap = source.getInputSourceMap(); - const offsets = source.getOffsets(node[LOC].sta); + const offsets = source.getOffsets(node[LOCSTA]); const [newLine, newColumn] = linesMap.getOffsets(sourceLocation.end); let records = null; - let srcId = node[LOC].srcId; + let srcId = node[LOCSRCID]; let sourceFileName = source.getFileName() || null; - source.getContent() || null; + let sourceContent; // = (source.getContent() as string) || null; if (inputSourceMap != null && (records = inputSourceMap.find(offsets[0], offsets[1])) != null) { + let newId = null; for (const record of records) { + newId = null; // @ts-ignore sourceFileName = record[0] || null; // @ts-ignore offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; + sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { const absolute = options.resolve(dirname(options.output), options.cwd) @@ -24900,30 +24195,46 @@ } sourceFileName = cache[sourceFileName]; } + for (const [id, file] of options.sourcesMap.entries()) { + if (file.getFileName() === sourceFileName) { + newId = id; + break; + } + if (sourceFileName == null && file.getContent() === sourceContent) { + newId = id; + break; + } + } + if (newId == null) { + const source = new SourceFile(sourceContent, [], sourceFileName); + options.sourcesMap.set(source.id, source); + newId = source.id; + } + srcId = newId; if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } else { - if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { - if (cache[sourceFileName] == null) { - const absolute = options.resolve(dirname(options.output), options.cwd) - .absolute; - const absoluteSourceFileName = options.resolve(sourceFileName, options.cwd) - .absolute; - cache[sourceFileName] = options.resolve(absoluteSourceFileName, absolute).relative; - } - sourceFileName = cache[sourceFileName]; - } + // if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { + // if (cache[sourceFileName] == null) { + // const absolute = options.resolve!(dirname(options.output as string), options.cwd as string) + // .absolute as string; + // const absoluteSourceFileName = options.resolve!(sourceFileName, options.cwd as string) + // .absolute as string; + // cache[sourceFileName] = options.resolve!(absoluteSourceFileName, absolute).relative as string; + // } + // sourceFileName = cache[sourceFileName] as string; + // } if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -24931,11 +24242,12 @@ * @param linesMap * @param str */ - function move(sourceLocation, linesMap, str) { - let i = 0; + function move(sourceLocation, linesMap, str, start, end) { + let i = start ?? 0; + let j = end ?? str.length; let codepoint; let char; - for (; i < str.length; i++) { + for (; i < j; i++) { char = str.charAt(i); codepoint = char.charCodeAt(0); sourceLocation.end += char.length; @@ -25059,7 +24371,6 @@ str = options.newLine + indentSub + str; children += str; if (sourcemaps != null && str !== "") { - move(sourceLocation, linesMap, str); if (node.typ == exports.EnumToken.DeclarationNodeType && recordDeclarationSourceMap) { // if declaration is child of at-rule, then record it // .rule { @@ -25067,15 +24378,11 @@ // color: red; // } // } - const source = options.sourcesMap.get(node[LOC].srcId); - if (!sourcemaps.sources.includes(node[LOC].srcId)) { - sourcemaps.sources.push(node[LOC].srcId); - } - sourcemaps.maps.push([ - ...linesMap.getOffsets(sourceLocation.end - str.length + options.newLine.length + indentSub.length), - node[LOC].srcId, - ...source.getOffsets(node[LOC].sta), - ]); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } @@ -25380,7 +24687,9 @@ // } } if (slice[i]?.typ === exports.EnumToken.ColorTokenType) { - slice.push(...reduceColorStops(slice.splice(i, slice.length - i))); + for (const token of reduceColorStops(slice.splice(i, slice.length - i))) { + slice.push(token); + } } } break; @@ -25571,32 +24880,45 @@ } const result = []; if (form.length > 0) { - result.push(...form); + for (const token of form) { + result.push(token); + } } if (size.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...size); + for (const token of size) { + result.push(token); + } } if (positions.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + result.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const token of positions) { + result.push(token); + } } if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } if (result.length > 0) { result.push({ typ: exports.EnumToken.CommaTokenType }); } - result.push(...reduceColorStops(slice.slice(i))); + for (const token of reduceColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (const token of result) { + slice.push(token); + } } break; case "conic-gradient": @@ -25701,24 +25023,36 @@ if (angles.length > 0) { angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const position of positions) { + angles.push(position); + } } } if (angles.length > 0) { - result.push(...angles, { typ: exports.EnumToken.CommaTokenType }); + for (const angle of angles) { + result.push(angle); + } + result.push({ typ: exports.EnumToken.CommaTokenType }); } if (colorSpaceDef.length > 0) { if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } result.push({ typ: exports.EnumToken.CommaTokenType }); } - result.push(...reduceConicColorStops(slice.slice(i))); + for (const token of reduceConicColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (let j = 0; j < result.length; j++) { + slice.push(result[j]); + } } break; } @@ -25852,210 +25186,1815 @@ const angle = getAngle(token); let v; let value = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { + for (const u of ["deg", "turn", "rad", "grad"]) { if (token.unit == u) { continue; } - switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + switch (u) { + case "deg": + v = minifyNumber(toPrecisionAngle(angle * 360, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "turn": + v = minifyNumber(toPrecisionAngle(angle, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 4 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "rad": + v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "grad": + v = minifyNumber(toPrecisionAngle(angle * 400, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 4 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + } + } + } + if (val === "0") { + if (token.typ == exports.EnumToken.TimeTokenType) { + return "0s"; + } + if (token.typ == exports.EnumToken.FrequencyTokenType) { + return "0Hz"; + } + // @ts-ignore + if (token.typ == exports.EnumToken.ResolutionTokenType) { + return "0x"; + } + return "0"; + } + if (token.typ == exports.EnumToken.TimeTokenType) { + if (unit == "ms") { + // @ts-ignore + const v = minifyNumber(val / 1000); + if (v.length + 1 <= val.length) { + return v + "s"; + } + return val + "ms"; + } + return val + "s"; + } + if (token.typ == exports.EnumToken.ResolutionTokenType && unit == "dppx") { + unit = "x"; + } + return val.includes("/") ? val.replace("/", unit + "/") : minifyNumber(toPrecisionValue(val)) + unit; + case exports.EnumToken.FlexTokenType: + case exports.EnumToken.PercentageTokenType: + const uni = token.typ == exports.EnumToken.PercentageTokenType ? "%" : "fr"; + 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; + case exports.EnumToken.NumberTokenType: + return token.val.typ == exports.EnumToken.FractionTokenType + ? renderValue(token.val, options, cache) + : minifyNumber(token.val); + case exports.EnumToken.AtRuleTokenType: + return "@" + token.nam; + case exports.EnumToken.CommentTokenType: + case exports.EnumToken.CDOCOMMNodeType: + if (options.removeComments && + (!options.preserveLicense || !token.val.startsWith("/*!"))) { + return ""; + } + case exports.EnumToken.PseudoClassTokenType: + case exports.EnumToken.PseudoElementTokenType: + // https://www.w3.org/TR/selectors-4/#single-colon-pseudos + if (token.typ == exports.EnumToken.PseudoElementTokenType && + pseudoElements.includes(token.val.slice(1))) { + return token.val.slice(1); + } + case exports.EnumToken.UrlTokenTokenType: + case exports.EnumToken.HashTokenType: + case exports.EnumToken.IdenTokenType: + case exports.EnumToken.StringTokenType: + case exports.EnumToken.LiteralTokenType: + case exports.EnumToken.DashedIdenTokenType: + case exports.EnumToken.PseudoPageTokenType: + case exports.EnumToken.ClassSelectorTokenType: + return token.val; + case exports.EnumToken.NestingSelectorTokenType: + return "&"; + case exports.EnumToken.InvalidAttrTokenType: + return ("[" + + token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.InvalidClassSelectorTokenType: + return token.val; + case exports.EnumToken.SupportsQueryUnaryConditionTokenType: + case exports.EnumToken.WhenElseUnaryConditionTokenType: + return (renderValue(token.l, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); + case exports.EnumToken.SupportsQueryConditionTokenType: + case exports.EnumToken.WhenElseQueryConditionTokenType: + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + " " + + renderValue(token.op, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); + case exports.EnumToken.IfConditionTokenType: + return token.l.length == 0 + ? "" + : token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + ":" + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), ""); + case exports.EnumToken.IfElseConditionTokenType: + return renderValue(token.l) + renderValue(token.r); + case exports.EnumToken.DeclarationNodeType: + return (token.nam + + ":" + + (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaQueryUnaryFeatureTokenType: + return (renderValue(token.l, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaQueryConditionTokenType: { + const indent = token.op.typ == exports.EnumToken.LtTokenType || + token.op.typ == exports.EnumToken.GtTokenType || + token.op.typ == exports.EnumToken.ColonTokenType || + token.op.typ == exports.EnumToken.DelimTokenType || + token.op.typ == exports.EnumToken.LteTokenType || + token.op.typ == exports.EnumToken.GteTokenType + ? "" + : " "; + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + indent + + renderValue(token.op, options, cache, reducer, errors) + + indent + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + } + case exports.EnumToken.MediaRangeQueryTokenType: + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache), "") + + renderValue(token.op1) + + token.val.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + renderValue(token.op2) + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaFeatureTokenType: + return token.val; + case exports.EnumToken.NotTokenType: + return "not"; + case exports.EnumToken.OnlyTokenType: + return "only"; + case exports.EnumToken.AndTokenType: + return "and"; + case exports.EnumToken.OrTokenType: + return "or"; + case exports.EnumToken.InvalidMediaQueryTokenType: + case exports.EnumToken.InvalidCommentTokenType: + case exports.EnumToken.BadCommentTokenType: + case exports.EnumToken.BadCdoTokenType: + case exports.EnumToken.BadStringTokenType: + case exports.EnumToken.BadUrlTokenType: + case exports.EnumToken.EOFTokenType: + return ""; + default: + console.debug({ token }); + throw new Error(`Unsupported token type for ${exports.EnumToken[token.typ]}`); + } + errors?.push({ action: "ignore", message: `render: unexpected token ${JSON.stringify(token, null, 1)}` }); + return ""; + } + /** + * Remove whitespace tokens that are not needed + * @param values + * + * @internal + */ + function filterValues(values) { + let i = 0; + for (; i < values.length; i++) { + if (values[i].typ == exports.EnumToken.ImportantTokenType && values[i - 1]?.typ === exports.EnumToken.WhitespaceTokenType) { + values.splice(i - 1, 1); + } + else if (tokensfuncSet.has(values[i].typ) && + "chi" in values[i] && + values[i].typ != exports.EnumToken.WildCardFunctionTokenType && + values[i + 1]?.typ == exports.EnumToken.WhitespaceTokenType) { + values.splice(i + 1, 1); + } + } + return values; + } + + const SymbolsMapTokens = Object.create(null); + // Regex for escape sequence decoding - compile once, reuse many times + const ESCAPE_SEQUENCE_REGEX = /\\([0-9a-fA-F]{1,6})(?:\s)?/g; + function decodeEscapeSequences(value) { + return value.replace(ESCAPE_SEQUENCE_REGEX, (_, sequence) => { + const codepoint = parseInt(sequence, 16); + if (codepoint == 0 || + // leading surrogate + (0xd800 <= codepoint && codepoint <= 0xdbff) || + // trailing surrogate + (0xdc00 <= codepoint && codepoint <= 0xdfff) || + codepoint > 0x10ffff) { + return "\uFFFD"; + } + return String.fromCodePoint(codepoint); + }); + } + function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { + for (const entry of entries) { + SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + } + } + SymbolsMapTokens[""] = exports.EnumToken.DelimTokenType; + SymbolsMapTokens["+"] = exports.EnumToken.Plus; + SymbolsMapTokens["="] = exports.EnumToken.DelimTokenType; + SymbolsMapTokens["|"] = exports.EnumToken.Pipe; + SymbolsMapTokens["||"] = exports.EnumToken.ColumnCombinatorTokenType; + SymbolsMapTokens["|="] = exports.EnumToken.DashMatchTokenType; + SymbolsMapTokens["&"] = exports.EnumToken.NestingSelectorTokenType; + SymbolsMapTokens["*"] = exports.EnumToken.Star; + SymbolsMapTokens["*="] = exports.EnumToken.ContainMatchTokenType; + SymbolsMapTokens["~"] = exports.EnumToken.Tilda; + SymbolsMapTokens["~="] = exports.EnumToken.IncludeMatchTokenType; + SymbolsMapTokens["^="] = exports.EnumToken.StartMatchTokenType; + SymbolsMapTokens["$="] = exports.EnumToken.EndMatchTokenType; + SymbolsMapTokens[","] = exports.EnumToken.Comma; + SymbolsMapTokens[":"] = exports.EnumToken.ColonTokenType; + SymbolsMapTokens["::"] = exports.EnumToken.DoubleColonTokenType; + SymbolsMapTokens[";"] = exports.EnumToken.SemiColonTokenType; + SymbolsMapTokens["("] = exports.EnumToken.StartParensTokenType; + SymbolsMapTokens[")"] = exports.EnumToken.EndParensTokenType; + SymbolsMapTokens["["] = exports.EnumToken.AttrStartTokenType; + SymbolsMapTokens["]"] = exports.EnumToken.AttrEndTokenType; + SymbolsMapTokens["{"] = exports.EnumToken.BlockStartTokenType; + SymbolsMapTokens["}"] = exports.EnumToken.BlockEndTokenType; + SymbolsMapTokens["<="] = exports.EnumToken.LteTokenType; + SymbolsMapTokens[">"] = exports.EnumToken.GtTokenType; + SymbolsMapTokens[">="] = exports.EnumToken.GteTokenType; + SymbolsMapTokens[" "] = exports.EnumToken.Whitespace; + SymbolsMapTokens["\t"] = exports.EnumToken.Whitespace; + SymbolsMapTokens["\r"] = exports.EnumToken.Whitespace; + SymbolsMapTokens["\n"] = exports.EnumToken.Whitespace; + SymbolsMapTokens["\f"] = exports.EnumToken.Whitespace; + assignTokenMap(flexUnits, exports.EnumToken.FlexTokenType); + assignTokenMap(dimensionUnits, exports.EnumToken.LengthTokenType); + assignTokenMap(resolutionUnits, exports.EnumToken.ResolutionTokenType); + assignTokenMap(angleUnits, exports.EnumToken.AngleTokenType); + assignTokenMap(timeUnits, exports.EnumToken.TimeTokenType); + assignTokenMap(frequencyUnits, exports.EnumToken.FrequencyTokenType); + assignTokenMap(pseudoElements, exports.EnumToken.PseudoElementTokenType); + assignTokenMap(containerFunc, exports.EnumToken.ContainerFunctionTokenDefType, "("); + assignTokenMap(urlFunc, exports.EnumToken.UrlFunctionTokenDefType, "("); + assignTokenMap(gridTemplateFunc, exports.EnumToken.GridTemplateFuncTokenDefType, "("); + assignTokenMap(imageFunc, exports.EnumToken.ImageFunctionTokenDefType, "("); + assignTokenMap(timelineFunc, exports.EnumToken.TimelineFunctionTokenDefType, "("); + assignTokenMap(supportFunc, exports.EnumToken.SupportsFunctionTokenDefType, "("); + assignTokenMap(timingFunc, exports.EnumToken.TimingFunctionTokenDefType, "("); + assignTokenMap(colorsFunc, exports.EnumToken.ColorFunctionTokenDefType, "("); + assignTokenMap(mathFuncs, exports.EnumToken.MathFunctionTokenDefType, "("); + assignTokenMap(transformFunctions, exports.EnumToken.TransformFunctionTokenDefType, "(", true); + assignTokenMap(whenElseFunc, exports.EnumToken.WhenElseFunctionTokenDefType, "("); + assignTokenMap(wildCardFuncs, exports.EnumToken.WildCardFunctionTokenDefType, "("); + const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); + // do not capture the value + const hintsEnum = new Set([ + exports.EnumToken.CommaTokenType, + exports.EnumToken.ImportantTokenType, + exports.EnumToken.SemiColonTokenType, + exports.EnumToken.BlockStartTokenType, + exports.EnumToken.BlockEndTokenType, + exports.EnumToken.StartParensTokenType, + exports.EnumToken.EndParensTokenType, + exports.EnumToken.ColonTokenType, + exports.EnumToken.EOFTokenType, + ]); + var TokenMap; + (function (TokenMap) { + TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; + TokenMap[TokenMap["SLASH"] = 47] = "SLASH"; + TokenMap[TokenMap["LOWERTHAN"] = 60] = "LOWERTHAN"; + TokenMap[TokenMap["HASH"] = 35] = "HASH"; + TokenMap[TokenMap["REVERSE_SOLIDUS"] = 92] = "REVERSE_SOLIDUS"; + TokenMap[TokenMap["DOUBLE_QUOTE"] = 34] = "DOUBLE_QUOTE"; + TokenMap[TokenMap["SINGLE_QUOTE"] = 39] = "SINGLE_QUOTE"; + TokenMap[TokenMap["DOT"] = 46] = "DOT"; + TokenMap[TokenMap["AT"] = 64] = "AT"; + TokenMap[TokenMap["PIPE"] = 124] = "PIPE"; + TokenMap[TokenMap["EQUALS"] = 61] = "EQUALS"; + TokenMap[TokenMap["AMPERSAND"] = 38] = "AMPERSAND"; + TokenMap[TokenMap["STAR"] = 42] = "STAR"; + TokenMap[TokenMap["TILDA"] = 126] = "TILDA"; + TokenMap[TokenMap["CARET"] = 94] = "CARET"; + TokenMap[TokenMap["DOLLAR"] = 36] = "DOLLAR"; + TokenMap[TokenMap["COMMA"] = 44] = "COMMA"; + TokenMap[TokenMap["COLON"] = 58] = "COLON"; + TokenMap[TokenMap["SEMICOLON"] = 59] = "SEMICOLON"; + TokenMap[TokenMap["LEFT_PARENTHESIS"] = 40] = "LEFT_PARENTHESIS"; + TokenMap[TokenMap["RIGHT_PARENTHESIS"] = 41] = "RIGHT_PARENTHESIS"; + TokenMap[TokenMap["LEFT_BRACKETS"] = 91] = "LEFT_BRACKETS"; + TokenMap[TokenMap["RIGHT_BRACKETS"] = 93] = "RIGHT_BRACKETS"; + TokenMap[TokenMap["LEFT_BRACE"] = 123] = "LEFT_BRACE"; + TokenMap[TokenMap["RIGHT_BRACE"] = 125] = "RIGHT_BRACE"; + TokenMap[TokenMap["PLUS"] = 43] = "PLUS"; + TokenMap[TokenMap["MINUS"] = 45] = "MINUS"; + TokenMap[TokenMap["GREATERTHAN"] = 62] = "GREATERTHAN"; + TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; + })(TokenMap || (TokenMap = {})); + function getSymbolHint(parseInfo, start, end) { + const len = end - start; + const keysLength = SymbolsMapTokensKeys.length; + // Early exit for impossible lengths + if (len < 0) + return null; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca !== cb) { + match = false; + break; + } + } + if (match) { + return SymbolsMapTokens[key]; + } + } + return null; + } + function searchArray(array, parseInfo, start, end) { + const len = end - start; + // Early exit for impossible lengths + 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) + continue; + // Match character by character + let match = true; + const arrayItem = array[i]; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + match = false; + break; + } + } + if (match) { + return arrayItem; + } + } + return null; + } + /** + * tokenizer class + */ + class Tokenizer { + parseInfo; + input; + /** + * token type + */ + typ = null; + /** + * token kind + */ + kin = null; + /** + * token name + */ + nam = null; + /** + * token value + */ + val = null; + /** + * token unit + */ + unit = null; + /** + * source id + */ + srcId = null; + /** + * token start + */ + sta = null; + /** + * token end + */ + end = null; + /** + * bytes in + */ + bytesIn = null; + /** + * decode string + */ + decodeString = null; + /** + * token slice + */ + slice = null; + /** + * source file + */ + source = null; + /** + * token hint + */ + hint = null; + state = null; + constructor(parseInfo, input = null) { + this.parseInfo = parseInfo; + this.input = input; + if (typeof this.parseInfo == "string") { + if (typeof parseInfo == "string") { + this.parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + } + } + /** + * + * @param parseInfo + * @returns + */ + consumeString(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.advance(parseInfo); + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + } + if (isNewLine(charCode)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + } + this.advance(parseInfo); + } + // EOF - 'Unclosed-string' fixed + return this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + // return result; + } + /** + * + * @param parseInfo + * @returns + */ + consumeURLToken(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.advance(parseInfo); + let k = 1; + let end = parseInfo.stream.length - parseInfo.offset; + let position = parseInfo.currentPosition - parseInfo.offset; + while (position + k < end) { + charCode = parseInfo.stream.charCodeAt(position); + // NaN != NaN + if (charCode != charCode) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + if (isWhiteSpace(charCode)) { + this.advance(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + break; + } + // consume until the ')' + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.advance(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.advance(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + this.advance(parseInfo); + } + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + } + this.advance(parseInfo); + } + // EOF - bad url token + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + // return result; + } + /** + * consume number, dimension, or percentage + * @param parseInfo + * @returns + */ + consumeNumericToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let hasDigits = false; + let hasLetter = false; + let hasPercent = false; + let codepoint = parseInfo.stream.charCodeAt(position); + this.slice = null; + this.hint = null; + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + // consume digits + while (position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + hasDigits = true; + position++; + continue; + } + // '.' 'E' 'e' + if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + return 0; + } + if (!hasLetter && !hasPercent) { + // '.' + if (codepoint == 0x2e) { + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint) { + return !hasDigits ? 0 : position - offset; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; + } + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + } + else if (isLetter(codepoint)) { + hasLetter = true; + } + else { + return 0; + } + } + else { + position++; + hasDigits = true; + } + } + if (!hasLetter && !hasPercent) { + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; + } + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + return 0; + } + // 'E' 'e' - 'em' + if ((codepoint == 0x45 || codepoint == 0x65) && hasDigits && !hasLetter && !hasPercent) { + if (isLetter(parseInfo.stream.charCodeAt(position))) { + hasLetter = true; + } + } + if (!hasLetter && !hasPercent) { + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + codepoint = parseInfo.stream.charCodeAt(position + 1); + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + codepoint = position = parseInfo.stream.charCodeAt(position + 1); + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; } - break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + if (isLetter(codepoint)) { + hasLetter = true; } - break; - case "rad": - v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; } - break; - case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + else { + return 0; } - break; + } + } + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + // eof + if (codepoint != codepoint) { + break; + } + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + else if (isLetter(codepoint)) { + hasLetter = true; + break; + } + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + else { + return 0; + } + } + if (!hasLetter && !hasPercent) { + return position - offset; + } + } + } + } + } + if (!hasDigits) { + return 0; + } + if (hasPercent) { + const slice = position; + codepoint = parseInfo.stream.charCodeAt(++position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = exports.EnumToken.PercentageTokenType; + return position - offset; + } + return 0; + } + if (hasLetter) { + codepoint = parseInfo.stream.charCodeAt(position - 1); + // 'E' 'e' + const slice = codepoint == 0x45 || codepoint == 0x65 ? position - 1 : position; + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(++position); + if (!isLetter(codepoint)) { + break; + } + } + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 43 /* TokenMap.PLUS */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = getSymbolHint(parseInfo, slice, position) ?? exports.EnumToken.DimensionTokenType; + return position - offset; + } + return 0; + } + return 0; + } + /** + * + * @param parseInfo + * @returns + */ + consumeIdentToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + if (codepoint == 45 /* TokenMap.MINUS */) { + position++; + codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + } + while ((codepoint = parseInfo.stream.charCodeAt(position)) == codepoint) { + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + // eof + if ((codepoint = parseInfo.stream.charCodeAt(position + 1)) != codepoint) { + // this.next(parseInfo, position); + return 0; + } + // \n \r \f \v + if (codepoint == 0xa || + codepoint == 0xb || + codepoint == 0xc || + codepoint == 0xd || + codepoint == 0x2028 || + codepoint == 0x2029) { + return 0; + } + position += 2; + continue; + } + if (codepoint == 0x2d || isIdentCodepoint(codepoint)) { + position++; + } + else { + switch (codepoint) { + case 58 /* TokenMap.COLON */: + case 123 /* TokenMap.LEFT_BRACE */: + case 125 /* TokenMap.RIGHT_BRACE */: + case 40 /* TokenMap.LEFT_PARENTHESIS */: + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + case 91 /* TokenMap.LEFT_BRACKETS */: + case 93 /* TokenMap.RIGHT_BRACKETS */: + case 59 /* TokenMap.SEMICOLON */: + case 33 /* TokenMap.EXCLAMATION */: + case 47 /* TokenMap.SLASH */: + case 35 /* TokenMap.HASH */: + case 42 /* TokenMap.STAR */: + case 61 /* TokenMap.EQUALS */: + case 126 /* TokenMap.TILDA */: + case 124 /* TokenMap.PIPE */: + case 94 /* TokenMap.CARET */: + case 36 /* TokenMap.DOLLAR */: + case 44 /* TokenMap.COMMA */: + case 62 /* TokenMap.GREATERTHAN */: + case 46 /* TokenMap.DOT */: + case 43 /* TokenMap.PLUS */: + return position - offset; + } + if (codepoint != codepoint || isWhiteSpace(codepoint)) { + return position - offset; + } + return 0; + } + } + return position - offset; + } + /** + * + * @param parseInfo + * @returns + */ + consumeColor(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != 35 /* TokenMap.HASH */) { + return 0; + } + position++; + let count = 0; + while (true) { + codepoint = parseInfo.stream.charCodeAt(position); + // 'a-f0-9' 'A-F0-9' + if ((codepoint >= 0x30 && codepoint <= 0x39) || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46)) { + position++; + count++; + continue; + } + break; + } + if (count != 3 && count != 4 && count != 6 && count != 8) { + return 0; + } + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + return 0; + } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peekCharCode(parseInfo))) { + this.advance(parseInfo); + } + charCode = this.peekCharCode(parseInfo); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + // if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + // } + } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ + makeToken(parseInfo, hint, options) { + let val = null; + this.typ = null; + this.nam = null; + this.val = null; + this.unit = null; + this.kin = null; + this.decodeString = null; + this.slice = null; + this.hint = null; + if (options?.slice) { + this.slice = options.slice; + } + if (options?.decodeSegments) { + this.decodeString = true; + } + if (hint != null) { + let array = null; + let hasUnit = false; + switch (hint) { + case exports.EnumToken.TransformFunctionTokenDefType: + array = transformFunctions; + break; + case exports.EnumToken.ColorFunctionTokenDefType: + array = colorsFunc; + break; + case exports.EnumToken.ContainerFunctionTokenDefType: + array = containerFunc; + break; + case exports.EnumToken.UrlFunctionTokenDefType: + array = urlFunc; + break; + case exports.EnumToken.GridTemplateFuncTokenDefType: + array = gridTemplateFunc; + break; + case exports.EnumToken.ImageFunctionTokenDefType: + array = imageFunc; + break; + case exports.EnumToken.TimelineFunctionTokenDefType: + array = timelineFunc; + break; + // case EnumToken.GeneralEnclosedFunctionTokenDefType: + // searchArray = generalEnclosedFunc; + // break; + case exports.EnumToken.SupportsFunctionTokenDefType: + array = supportFunc; + break; + case exports.EnumToken.TimingFunctionTokenDefType: + array = timingFunc; + break; + case exports.EnumToken.MathFunctionTokenDefType: + array = mathFuncs; + break; + case exports.EnumToken.WhenElseFunctionTokenDefType: + array = whenElseFunc; + break; + case exports.EnumToken.WildCardFunctionTokenDefType: + array = wildCardFuncs; + break; + case exports.EnumToken.FrequencyTokenType: + array = frequencyUnits; + hasUnit = true; + break; + case exports.EnumToken.ResolutionTokenType: + array = resolutionUnits; + hasUnit = true; + break; + case exports.EnumToken.LengthTokenType: + array = dimensionUnits; + hasUnit = true; + break; + case exports.EnumToken.FlexTokenType: + array = flexUnits; + hasUnit = true; + break; + case exports.EnumToken.AngleTokenType: + array = angleUnits; + hasUnit = true; + break; + case exports.EnumToken.TimeTokenType: + array = timeUnits; + hasUnit = true; + break; + case exports.EnumToken.DimensionTokenType: + hasUnit = true; + break; + } + if (array != null) { + val = searchArray(array, parseInfo, hasUnit ? options?.slice : parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + else if (!hintsEnum.has(hint)) { + val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + if (this.decodeString) { + val = decodeEscapeSequences(val); + } + if (hintsEnum.has(hint)) { + this.typ = hint; + } + else { + this.typ = hint; + if (hasUnit || hint == exports.EnumToken.PercentageTokenType || hint == exports.EnumToken.DimensionTokenType) { + this.val = parseFloat(parseInfo.stream.slice(parseInfo.position - parseInfo.offset, options?.slice)); + if (hint != exports.EnumToken.PercentageTokenType) { + this.unit = val; + } + } + else if (hint == exports.EnumToken.NumberTokenType) { + this.val = parseFloat(val); + } + else if (hint == exports.EnumToken.AtRuleTokenType) { + this.nam = val; + } + else { + this.val = val; + if (hint == exports.EnumToken.ColorTokenType) { + this.kin = exports.ColorType.HEX; } } } - if (val === "0") { - if (token.typ == exports.EnumToken.TimeTokenType) { - return "0s"; + } + else { + if (this.equalsIgnoreCase(parseInfo, "!important")) { + this.typ = exports.EnumToken.ImportantTokenType; + } + } + if (this.typ == null) { + val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + if (options?.decodeSegments) { + val = decodeEscapeSequences(val); + this.decodeString = true; + } + this.typ = exports.EnumToken.LiteralTokenType; + this.val = val; + } + this.srcId = parseInfo.source.id; + this.sta = parseInfo.position; + this.end = parseInfo.currentPosition; + this.bytesIn = parseInfo.currentPosition; + parseInfo.position = parseInfo.currentPosition; + return this; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + equalsIgnoreCase(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + let ca; + let cb; + for (let i = 0; i < input.length; i++) { + ca = parseInfo.stream.charCodeAt(position + i); + cb = input.charCodeAt(i); + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + match(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + for (let i = 0; i < input.length; i++) { + if (parseInfo.stream[position + i] != input.charAt(i)) { + return false; + } + } + return true; + } + /** + * Get the current character code without creating a string + * @param parseInfo + * @returns charCode at current position + */ + peekCharCode(parseInfo) { + return parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + peek(parseInfo, count = 1) { + if (count == 1) { + return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); + } + const position = parseInfo.currentPosition - parseInfo.offset; + return parseInfo.stream.slice(position, position + count); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + advance(parseInfo, count = 1) { + let position = parseInfo.currentPosition - parseInfo.offset; + let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); + let i = 0; + let codepoint; + const lineStarts = parseInfo.source.lineStarts.lineStarts; + for (; i < char.length; i++) { + codepoint = char.charCodeAt(i); + if (codepoint == 0xa || // \n + codepoint == 0xb || // \v + codepoint == 0xc || // \f + codepoint == 0xd || // \r + codepoint == 0x2028 || // \u2028 + codepoint == 0x2029 // \u2029 + ) { + // \r\n + if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; + else { + lineStarts.push(position + parseInfo.offset + i); + } + } + } + parseInfo.currentPosition += char.length; + return char; + } + /** + * + * @param parseInfo + * @param start + * @param end + * @returns + */ + isIdentToken(parseInfo, start, end) { + let j = parseInfo.currentPosition - parseInfo.offset; + let i = parseInfo.position - parseInfo.offset; + if (start != null) { + if (end == null) { + if (start < 0) { + j += start; + } + else { + i += start; + } + } + else { + if (end < 0) { + j += end; + } + else { + j = parseInfo.position + end; + } + } + } + j--; + let codepoint = parseInfo.stream.charCodeAt(i); + // - + if (codepoint == 0x2d) { + let nextCodepoint; + // NaN != NaN + if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { + return false; + } + if (!isIdentStart(nextCodepoint) && nextCodepoint != 0x2d) { + return false; + } + codepoint = nextCodepoint; + i++; + } + if (codepoint !== 0x2d && !isIdentStart(codepoint)) { + return false; + } + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + codepoint = parseInfo.stream.charCodeAt(i + 1); + i += String.fromCodePoint(codepoint).length; + } + while (i < j) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + continue; + } + if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isPseudo(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let endPosition = 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 + * @param input + * @returns + */ + startsWith(parseInfo, input) { + let i = 0; + let j = input.length; + while (i < j) { + if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { + return false; + } + i++; + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isURLToken(parseInfo) { + let i = parseInfo.position - parseInfo.offset; + let c; + while (++i < parseInfo.currentPosition) { + c = parseInfo.stream.charCodeAt(i); + // single quote or double quote or start parenthesis or close parenthesis + if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { + return false; + } + // valid escape + if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i++; + if (i >= parseInfo.currentPosition) { + return false; + } + c = parseInfo.stream.charCodeAt(i); + // c is not '\n' or '\r' or '\f' + if (c == 0x6e || c == 0x72 || c == 0x66) { + return false; + } + continue; + } + // is white space + if (c == 0x20 || c == 0x09) { + break; + } + } + return i == parseInfo.currentPosition; + } + done() { + return this.typ === exports.EnumToken.EOF; + } + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; + this.source = parseInfo.source; + let charCode; + let nextCharCode; + // const result: TokenizeResult[] = []; + // allow 10 characters buffer for the streaming parser to avoid incomplete tokens + const endPosition = parseInfo.stream.length - 1; // yieldEOFToken ? parseInfo.stream.length - 1 : parseInfo.stream.length - 10; + let tokensCount; + // NaN is not equal to NaN + while ((charCode = this.peekCharCode(parseInfo)) == charCode) { + if (this.state === exports.EnumToken.UrlFunctionTokenDefType) { + this.state = null; + return this.parseURLToken(parseInfo, endPosition); + } + if (parseInfo.position == parseInfo.currentPosition) { + if (charCode == 45 /* TokenMap.MINUS */ || + charCode == 43 /* TokenMap.PLUS */ || + charCode == 46 /* TokenMap.DOT */ || + 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: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + } } - if (token.typ == exports.EnumToken.FrequencyTokenType) { - return "0Hz"; + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + charCode = this.peekCharCode(parseInfo); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? exports.EnumToken.DashedIdenTokenType + : exports.EnumToken.IdenTokenType); + } + } } - // @ts-ignore - if (token.typ == exports.EnumToken.ResolutionTokenType) { - return "0x"; + if (charCode == 64 /* TokenMap.AT */) { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); + } + } } - return "0"; - } - if (token.typ == exports.EnumToken.TimeTokenType) { - if (unit == "ms") { - // @ts-ignore - const v = minifyNumber(val / 1000); - if (v.length + 1 <= val.length) { - return v + "s"; + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); + } + this.advance(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.HashTokenType); } - return val + "ms"; } - return val + "s"; - } - if (token.typ == exports.EnumToken.ResolutionTokenType && unit == "dppx") { - unit = "x"; - } - return val.includes("/") ? val.replace("/", unit + "/") : minifyNumber(toPrecisionValue(val)) + unit; - case exports.EnumToken.FlexTokenType: - case exports.EnumToken.PercentageTokenType: - const uni = token.typ == exports.EnumToken.PercentageTokenType ? "%" : "fr"; - 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; - case exports.EnumToken.NumberTokenType: - return token.val.typ == exports.EnumToken.FractionTokenType - ? renderValue(token.val, options, cache) - : minifyNumber(token.val); - case exports.EnumToken.AtRuleTokenType: - return "@" + token.nam; - case exports.EnumToken.CommentTokenType: - case exports.EnumToken.CDOCOMMNodeType: - if (options.removeComments && - (!options.preserveLicense || !token.val.startsWith("/*!"))) { - return ""; - } - case exports.EnumToken.PseudoClassTokenType: - case exports.EnumToken.PseudoElementTokenType: - // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == exports.EnumToken.PseudoElementTokenType && - pseudoElements.includes(token.val.slice(1))) { - return token.val.slice(1); } - case exports.EnumToken.UrlTokenTokenType: - case exports.EnumToken.HashTokenType: - case exports.EnumToken.IdenTokenType: - case exports.EnumToken.StringTokenType: - case exports.EnumToken.LiteralTokenType: - case exports.EnumToken.DashedIdenTokenType: - case exports.EnumToken.PseudoPageTokenType: - case exports.EnumToken.ClassSelectorTokenType: - return token.val; - case exports.EnumToken.NestingSelectorTokenType: - return "&"; - case exports.EnumToken.InvalidAttrTokenType: - return ("[" + - token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.InvalidClassSelectorTokenType: - return token.val; - case exports.EnumToken.SupportsQueryUnaryConditionTokenType: - case exports.EnumToken.WhenElseUnaryConditionTokenType: - return (renderValue(token.l, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); - case exports.EnumToken.SupportsQueryConditionTokenType: - case exports.EnumToken.WhenElseQueryConditionTokenType: - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - " " + - renderValue(token.op, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); - case exports.EnumToken.IfConditionTokenType: - return token.l.length == 0 - ? "" - : token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - ":" + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), ""); - case exports.EnumToken.IfElseConditionTokenType: - return renderValue(token.l) + renderValue(token.r); - case exports.EnumToken.DeclarationNodeType: - return (token.nam + - ":" + - (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaQueryUnaryFeatureTokenType: - return (renderValue(token.l, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaQueryConditionTokenType: { - const indent = token.op.typ == exports.EnumToken.LtTokenType || - token.op.typ == exports.EnumToken.GtTokenType || - token.op.typ == exports.EnumToken.ColonTokenType || - token.op.typ == exports.EnumToken.DelimTokenType || - token.op.typ == exports.EnumToken.LteTokenType || - token.op.typ == exports.EnumToken.GteTokenType - ? "" - : " "; - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - indent + - renderValue(token.op, options, cache, reducer, errors) + - indent + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - } - case exports.EnumToken.MediaRangeQueryTokenType: - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache), "") + - renderValue(token.op1) + - token.val.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - renderValue(token.op2) + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaFeatureTokenType: - return token.val; - case exports.EnumToken.NotTokenType: - return "not"; - case exports.EnumToken.OnlyTokenType: - return "only"; - case exports.EnumToken.AndTokenType: - return "and"; - case exports.EnumToken.OrTokenType: - return "or"; - case exports.EnumToken.InvalidMediaQueryTokenType: - case exports.EnumToken.InvalidCommentTokenType: - case exports.EnumToken.BadCommentTokenType: - case exports.EnumToken.BadCdoTokenType: - case exports.EnumToken.BadStringTokenType: - case exports.EnumToken.BadUrlTokenType: - case exports.EnumToken.EOFTokenType: - return ""; - default: - console.debug({ token }); - throw new Error(`Unsupported token type for ${exports.EnumToken[token.typ]}`); - } - errors?.push({ action: "ignore", message: `render: unexpected token ${JSON.stringify(token, null, 1)}` }); - return ""; - } - /** - * Remove whitespace tokens that are not needed - * @param values - * - * @internal - */ - function filterValues(values) { - let i = 0; - for (; i < values.length; i++) { - if (values[i].typ == exports.EnumToken.ImportantTokenType && values[i - 1]?.typ === exports.EnumToken.WhitespaceTokenType) { - values.splice(i - 1, 1); + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + 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); + } + 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: "+", + }); + } + } + return this.makeToken(parseInfo, exports.EnumToken.Plus); + case 45 /* TokenMap.MINUS */: + if (parseInfo.position == parseInfo.currentPosition) { + nextCharCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + // not a number + if (isWhiteSpace(nextCharCode)) { + 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); + } + } + } + this.advance(parseInfo); + break; + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); + } + else if (this.isIdentToken(parseInfo)) { + const hint = this.startsWith(parseInfo, "--") + ? exports.EnumToken.CustomFunctionTokenDefType + : (getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset + 1) ?? exports.EnumToken.FunctionTokenDefType); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === exports.EnumToken.UrlFunctionTokenDefType) { + this.state = hint; + } + return this; + } + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + 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); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); + case 59 /* TokenMap.SEMICOLON */: + 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); + } + this.advance(parseInfo); + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); + } + return this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); + // \n \r \f \v \t space + case 0x9: + case 0x20: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x2028: + case 0x2029: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.advance(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); + case 44 /* TokenMap.COMMA */: + 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 (this.match(parseInfo, "$=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); + } + this.advance(parseInfo); + break; + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Tilda); + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); + } + this.advance(parseInfo); + break; + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Star); + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); + } + else if (this.match(parseInfo, "|=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Pipe); + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); + } + this.advance(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + 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)); + } + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); + } + } + } + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); + } + break; + case 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.GtTokenType); + case 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "<=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.LteTokenType); + } + this.advance(parseInfo); + if (this.match(parseInfo, "!--")) { + this.advance(parseInfo, 3); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + return this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + } + else { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + } + } + break; + case 35 /* TokenMap.HASH */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + 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; + } + this.advance(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + return this.consumeString(parseInfo); + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.advance(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); + } + } + 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; + // } } - else if (tokensfuncSet.has(values[i].typ) && - "chi" in values[i] && - values[i].typ != exports.EnumToken.WildCardFunctionTokenType && - values[i + 1]?.typ == exports.EnumToken.WhitespaceTokenType) { - values.splice(i + 1, 1); + // if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } + return this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); + // } + } + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async tokenizeStream() { + const decoder = new TextDecoder("utf-8"); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; + parseInfo.stream = ""; + while (true) { + const { done, value } = await reader.read(); + const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; + if (!done) { + parseInfo.source.append(stream); + } + else { + break; + } + } + parseInfo.stream = parseInfo.source.getContent(); + return this; // .next(); } - return values; } /** @@ -26075,7 +27014,9 @@ filtered[0] = { typ: exports.EnumToken.PercentageTokenType, val: 0, - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } else if (filtered[0].typ === exports.EnumToken.PercentageTokenType && @@ -26083,7 +27024,9 @@ filtered[0] = { typ: exports.EnumToken.IdenTokenType, val: "to", - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } part.splice(0, part.length, ...filtered); @@ -26094,7 +27037,9 @@ if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, [])); return { @@ -26106,10 +27051,9 @@ }, new Set()), ].join(), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? tokens[0]?.[LOC]?.end, - }, + [LOCSRCID]: tokens[0]?.[LOCSRCID], + [LOCSTA]: tokens[0]?.[LOCSTA], + [LOCEND]: tokens[tokens.length - 1]?.[LOCEND], [TOKENS]: tokens.length === 0 ? null : tokens, [STATE]: result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -26159,7 +27103,7 @@ typ: exports.EnumToken.PseudoElementTokenType, val: ":" + tokens[i + 1].val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26171,7 +27115,7 @@ : tokens[i + 1].typ, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26183,7 +27127,7 @@ typ: exports.EnumToken.PseudoClassTokenType, val: (pseudoElements.includes(val) ? "" : ":") + val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26195,7 +27139,7 @@ : exports.EnumToken.FunctionTokenDefType, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26250,10 +27194,9 @@ .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: exports.EnumAstNodeStatus.Invalid, [ERRORS]: [ @@ -26281,10 +27224,9 @@ index = tokens.indexOf(stack.at(-1)); // @ts-expect-error const { val, ...attr } = stack.at(-1); - attr[LOC] = { - ...stack.at(-1)[LOC], - end: token[LOC].end, - }; + attr[LOCSRCID] = stack.at(-1)[LOCSRCID]; + attr[LOCSTA] = stack.at(-1)[LOCSTA]; + attr[LOCEND] = token[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: exports.EnumToken.AttrTokenType, @@ -26302,7 +27244,7 @@ if (stack.at(-1)?.typ == exports.EnumToken.PseudoClassFunctionTokenDefType) { const func = stack.at(-1); index = tokens.indexOf(func); - stack.at(-1)[LOC].end = token[LOC].end; + stack.at(-1)[LOCEND] = token[LOCEND]; tokens.splice(i, 1); if (tokensfuncDefMap.has(func.typ)) { // @ts-expect-error @@ -26319,20 +27261,77 @@ const list = []; let index; for (index = 0; index < func.chi.length; index++) { - if (func.chi[index].typ == exports.EnumToken.CommentTokenType || func.chi[index].typ == exports.EnumToken.WhitespaceTokenType) { + if (func.chi[index].typ == exports.EnumToken.CommentTokenType || + func.chi[index].typ == exports.EnumToken.WhitespaceTokenType) { continue; } - if (func.chi[index].typ == exports.EnumToken.IdenTokenType && equalsIgnoreCase('of', func.chi[index].val)) { + if (func.chi[index].typ == exports.EnumToken.IdenTokenType && + equalsIgnoreCase("of", func.chi[index].val)) { index--; break; } list.push(func.chi[index]); } + if (list.length == 2) { + if (list[1].typ == exports.EnumToken.NumberTokenType) { + if (list[1].val == 0) { + list.length = 1; + if (list[0].typ == exports.EnumToken.DimensionTokenType && + list[0].val == -2) { + list[0].val = 2; + } + } + else { + const sign = Math.sign(list[1].val); + // @ts-ignore + list[1].val *= sign; + list.splice(1, 0, { + typ: exports.EnumToken.LiteralTokenType, + val: sign > 0 ? "+" : "-", + }); + } + } + if (list.length == 3 && + list[2].typ == exports.EnumToken.NumberTokenType && + list[0].typ == exports.EnumToken.DimensionTokenType && + (list[0].val == 2 || + list[0].val == -2)) { + if (1 == list[2].val) { + list.splice(0, 3, { + typ: exports.EnumToken.IdenTokenType, + val: "odd", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + else if (0 == list[2].val) { + list.splice(0, 3, { + typ: exports.EnumToken.IdenTokenType, + val: "even", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + } + func.chi.splice(0, index, ...list); + } + if (list.length == 1) { + if (list[0].typ == exports.EnumToken.IdenTokenType && + equalsIgnoreCase("-n", list[0].val)) { + list[0].val = "n"; + } + } if (list.length == 3) { - if (list[0].typ == exports.EnumToken.IdenTokenType && ('n' == list[0].val || '-n' == list[0].val || '+n' == list[0].val)) { + if (list[0].typ == exports.EnumToken.IdenTokenType && + ("n" == list[0].val || + "-n" == list[0].val || + "+n" == list[0].val)) { if (list[1].typ == exports.EnumToken.NextSiblingCombinatorTokenType) { - if (list[2].typ == exports.EnumToken.NumberTokenType && (0 == list[2].val)) { - list[0].val = 'n'; + if (list[2].typ == exports.EnumToken.NumberTokenType && + 0 == list[2].val) { + list[0].val = "n"; func.chi.splice(0, index, list[0]); break; } @@ -26352,83 +27351,10 @@ } } else { - // if (!/\d+$/.test((token as IdentToken | LiteralToken).val)) { - // let index = func.chi.indexOf(token); - // let i: number = index + 1; - // let sign: Token | null = null; - // let num: NumberToken | null = null; - // for (; i < func.chi.length; i++) { - // if ( - // func.chi[i].typ == EnumToken.WhitespaceTokenType || - // func.chi[i].typ == EnumToken.CommentTokenType - // ) { - // continue; - // } - // if (func.chi[i].typ == EnumToken.NumberTokenType) { - // num = func.chi[i] as NumberToken; - // break; - // } else { - // sign = func.chi[i] as Token; - // } - // } - // if (num != null) { - // if (num.val === 0) { - // func.chi.splice(index + 1, i - index); - // if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } - // if (sign == null) { - // func.chi.splice(index + 1, i - index - 1); - // if (Math.sign(num.val as number) === 1) { - // func.chi.splice(index + 1, 0, { - // typ: EnumToken.LiteralTokenType, - // val: "+", - // }); - // } - // } - // } else if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } const matches = /^(([+-]?[0-9]*)?n)?([+-]?[0-9]+)?$/.exec(token.val); if (matches != null) { const a1 = matches[2] === "" ? 1 : matches[2] === "-" ? -1 : +matches[2]; const b1 = +matches[3]; - // if (a1 === 0) { - // if (b1 === 1) { - // let hasSelector: boolean = false; - // let i: number = func.chi.indexOf(token); - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // Object.assign(token, { - // typ: EnumToken.NumberTokenType, - // val: b1, - // }); - // } else { - // // :first-child - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // Object.assign(token, { typ: EnumToken.NumberTokenType, val: b1 }); - // } - // } else if (b1 === 0) { Object.assign(token, Math.abs(a1) === 1 ? { @@ -26441,17 +27367,6 @@ unit: "n", }); } - // else if (Math.abs(a1) === 2) { - // if (b1 === 0) { - // Object.assign(token, { - // typ: EnumToken.DimensionTokenType, - // val: a1, - // unit: "n", - // }); - // } else if (Math.abs(b1) === 1) { - // Object.assign(token, { typ: EnumToken.IdenTokenType, val: "odd" }); - // } - // } } } } @@ -26470,36 +27385,6 @@ } } if (num != null) { - // if ((token as DimensionToken).val === 0) { - // if (num.val === 0) { - // func.chi.splice(0, i); - // } else if (num.val === 1) { - // let hasSelector: boolean = false; - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // func.chi.splice(0, i); - // } else { - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // func.chi.splice(0, i); - // } - // break; - // } else if (num.val === 0) { func.chi.splice(index + 1, i - index); if (token.val < 0) { @@ -26588,10 +27473,9 @@ .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: result.success && allowed ? exports.EnumAstNodeStatus.Validated @@ -26643,6 +27527,7 @@ * @param errors */ function parseDeclaration(tokens, parent, options, errors) { + // console.error(tokens); const name = tokens.shift(); let i; let rules = null; @@ -26663,16 +27548,15 @@ } if ((name.typ !== exports.EnumToken.IdenTokenType && name.typ !== exports.EnumToken.DashedIdenTokenType) || tokens[i]?.typ !== exports.EnumToken.ColonTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Unparsed; name[ERRORS] = [ { action: "drop", node: name, - location: name[LOC], + location: options.source.getSourceLocation(name[LOCSTA]), message: "invalid declaration", }, ]; @@ -26702,39 +27586,6 @@ rules.acceptAnyDeclaration && rules.acceptAnyRule ? getParsedSyntax(ValidationSyntaxGroupEnum.Declarations, name.val.toLowerCase()) : rules.getBlockRules(); - // if (syntaxRules == null) { - // // check rule in nested context - // let pr = parent[PARENT] as AstNode | null; - // while (pr != null && pr.typ !== EnumToken.RuleNodeType) { - // pr = pr[PARENT]; - // } - // if (pr != null) { - // syntaxRules = getParsedSyntax( - // ValidationSyntaxGroupEnum.Declarations, - // name.val.toLowerCase(), - // ); - // } - // if (syntaxRules == null) { - // errors.push({ - // action: "drop", - // message: "declaration not allowed in context", - // node: name, - // location: name[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1][LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Disallowed; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } - // } } } } @@ -26772,12 +27623,11 @@ action: "drop", message: "declaration value missing", node: name, - location: options.source.getSourceLocation(name[LOC].sta), + location: options.source.getSourceLocation(name[LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC].end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Invalid; name[ERRORS] = [errors[errors.length - 1]]; // @ts-expect-error @@ -26809,7 +27659,9 @@ } } if (!doNotValidate && !result?.success && result.errors.length > 0) { - errors.push(...result.errors); + for (index = 0; index < result.errors.length; index++) { + errors.push(result.errors[index]); + } } } } @@ -26827,7 +27679,7 @@ // Object.assign(token, { // typ: EnumToken.FunctionTokenDefType, // }); - // token[LOC]!.end = tokens[i + 1][LOC]!.end; + // token[LOCEND] = tokens[i + 1][LOCEND]; // tokens.splice(i + 1, 1); // stack.push(token); // } @@ -26865,26 +27717,6 @@ } break; case exports.EnumToken.EndParensTokenType: - // if (stack.length == 0) { - // errors.push({ - // action: "drop", - // message: "unbalanced parentheses", - // node: token, - // location: token[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1]?.[LOC]!.end ?? name[LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Invalid; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } if (stack.at(-1)?.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(stack.at(-1)?.typ)) { index = tokens.indexOf(stack.at(-1)); tokens.splice(i, 1); @@ -26957,9 +27789,9 @@ // ((tokens[index] as FunctionToken).chi[l] as IdentToken | UrlToken).val + // ((tokens[index] as FunctionToken).chi[m] as ClassSelectorToken).val, // }); - // (tokens[index] as FunctionToken).chi[l][LOC]!.end = ( + // (tokens[index] as FunctionToken).chi[l][LOCEND] = ( // tokens[index] as FunctionToken - // ).chi[m][LOC]!.end; + // ).chi[m][LOCEND]; // (tokens[index] as FunctionToken).chi.splice(m, 1); // } // break; @@ -26989,7 +27821,7 @@ action: "drop", message: `invalid color`, node: tokens[index], - location: options.source.getSourceLocation(tokens[index][LOC].sta), + location: options.source.getSourceLocation(tokens[index][LOCSTA]), }); } } @@ -27041,12 +27873,11 @@ action: "drop", message: "unbalanced token", node: stack[stack.length - 1], - location: options.source.getSourceLocation(stack[stack.length - 1][LOC].sta), + location: options.source.getSourceLocation(stack[stack.length - 1][LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1][LOC].end, - }; + if (tokens[tokens.length - 1][LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Invalid; name[ERRORS] = result?.errors ?? []; //@ts-expect-error @@ -27079,10 +27910,9 @@ } } if (validate && syntaxRules == null && name.typ === exports.EnumToken.IdenTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Unknown; name[ERRORS] = result?.errors ?? []; // @ts-expect-error @@ -27091,14 +27921,6 @@ nam: name.val, val: tokens, }); - // if ((options.validation as ValidationLevel) & ValidationLevel.Declaration) { - // errors.push({ - // action: "drop", - // message: "unknown declaration", - // node: node, - // location: node[LOC], - // }); - // } return node; } if (equalsIgnoreCase("composes", name.val)) { @@ -27116,18 +27938,15 @@ typ: exports.EnumToken.ComposesSelectorNodeType, l: left, r: right?.[0] ?? null, - [LOC]: { - ...tokens[0][LOC], - sta: left[0]?.[LOC]?.sta, - end: index != -1 ? right[right.length - 1]?.[LOC]?.end : left[left.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: index != -1 ? right[right.length - 1]?.[LOCEND] : left[left.length - 1][LOCEND], }, ]; } - name[LOC] = { - ...name[LOC], - end: (tokens[tokens.length - 1] ?? name)[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = success ? result == null ? exports.EnumAstNodeStatus.Unvalidated @@ -27197,7 +28016,7 @@ action: "drop", message: `expecting ''`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27207,7 +28026,7 @@ action: "drop", message: `expecting '('`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27249,7 +28068,7 @@ action: "drop", node: stream[i], message: ` is not allowed outside of parentheses`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); break; } @@ -27259,7 +28078,7 @@ action: "drop", node: stream[i], message: `cannot mix and at the same level`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } currentScope.add(stream[i].typ); @@ -27270,7 +28089,7 @@ case exports.EnumToken.EndParensTokenType: if (tokensfuncDefMap.has(stack.at(-1)?.typ)) { const index = tokens.indexOf(stack.at(-1)); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCEND] = stream[i][LOCEND]; Object.assign(tokens[index], { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), @@ -27281,7 +28100,9 @@ scopes.pop(); currentScope = scopes.at(-1); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } success = false; } break; @@ -27313,7 +28134,9 @@ val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -27348,7 +28171,9 @@ op1: prevToken, op2: stack.at(-1), r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }); stack.pop(); stack.pop(); @@ -27376,7 +28201,9 @@ val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -27392,7 +28219,7 @@ errors.push({ action: "drop", node: arr[0], - location: options.source.getSourceLocation(arr[0]?.[LOC].sta), + location: options.source.getSourceLocation(arr[0]?.[LOCSTA]), message: `${mfValue.isValueAllowed === false ? "invalid " : "expected "}`, }); break; @@ -27413,13 +28240,15 @@ val.splice(0, val.length, ...filteredValues); } } + // @ts-expect-error tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: exports.EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - // @ts-expect-error - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); } if (stack.length === 0) { @@ -27427,7 +28256,7 @@ errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `unmatched ')'`, }); break; @@ -27437,8 +28266,9 @@ tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - // @ts-expect-error - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; tokens.length = index + 1; scopes.pop(); @@ -27460,7 +28290,9 @@ op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOrComma = true; @@ -27477,7 +28309,9 @@ parts.splice(parts.indexOf(stream), 1); } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const t of trimArray(tokens)) { + stream.push(t); + } } } stream.length = 0; @@ -27487,7 +28321,9 @@ if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...b); + for (const t of b) { + acc.push(t); + } return acc; }, [])); return { @@ -27529,7 +28365,7 @@ : exports.EnumToken.PseudoClassTokenType, val: ":" + val, }); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -27542,7 +28378,7 @@ val, }); stack.push(stream[i]); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -27592,7 +28428,9 @@ tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: slice, - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); tokens.pop(); @@ -27606,7 +28444,9 @@ typ: tokensfuncDefMap.get(stack.at(-1)?.typ), val: stack.at(-1).val, chi: trimArray(tokens.splice(index + 1, tokens.length - index - 2)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; if (tokens[index].typ === exports.EnumToken.PseudoClassFuncTokenType) { // not a declaration @@ -27637,7 +28477,9 @@ typ: exports.EnumToken.SupportsQueryUnaryConditionTokenType, l: stack.at(-1), r: trimArray(tokens.splice(index + 1, i - index - 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); } @@ -27652,7 +28494,9 @@ op: stack.at(-1), l: left, r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -27673,7 +28517,7 @@ if ("and" === val || "or" === val) { if ("or" === val && scopes.length === 1) { const fileName = options.source.getFileName() ?? ""; - const [line, column] = options.source.getOffsets(stream[i]?.[LOC]?.sta); + const [line, column] = options.source.getOffsets(stream[i]?.[LOCSTA]); return { success: false, errors: [ @@ -27697,7 +28541,9 @@ } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -27733,11 +28579,7 @@ } } const slice = stream.slice(index + 1, k); - // @ts-expect-error - stream[0][LOC] = { - ...stream[0][LOC], - end: stream[1][LOC].end, - }; + stream[0][LOCEND] = stream[1][LOCEND]; tokens.push(Object.assign({ typ: tokensfuncDefMap.get(stream[0].typ), chi: trimArray(slice), @@ -27753,7 +28595,7 @@ message: "Expected string or url()", syntax: "@import", node: stream[0], - location: stream[0]?.[LOC], + location: options.source.getSourceLocation(stream[0]?.[LOCSTA]), }, ], }; @@ -27783,7 +28625,7 @@ message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27810,7 +28652,7 @@ message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27852,7 +28694,9 @@ { const result = parseAtRuleSupportSyntax(tokens[tokens.length - 1].chi, context, options); if (!result.success && result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -27862,15 +28706,21 @@ } const splice = stream.splice(index, stream.length - index); const sliced = parseMediaqueryList(splice, options); - tokens.push(...splice); + for (const sp of splice) { + tokens.push(sp); + } if (sliced.errors.length > 0) { - errors.push(...sliced.errors); + for (const error of sliced.errors) { + errors.push(error); + } } if (!sliced.success) { success = false; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors, @@ -27933,7 +28783,9 @@ const tokenList = [ { typ: exports.EnumToken.StartParensTokenType, - [LOC]: { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }, + [LOCSRCID]: stream[i][LOCSRCID], + [LOCSTA]: stream[i][LOCSTA], + [LOCEND]: stream[j]?.[LOCEND], }, // @ts-expect-error ].concat(slice.slice(1)); @@ -27956,32 +28808,13 @@ return result; } } - // else { - // errors.push({ - // action: "ignore", - // message: `unknown function '${funcName}' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // node: stream[i], - // location: stream[i][LOC], - // }); - // } - stream[i][LOC] = { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }; + stream[i][LOCEND] = stream[j]?.[LOCEND]; Object.assign(stream[i], { typ: tokensfuncDefMap.get(stream[i].typ), chi: stream[i].typ === exports.EnumToken.SupportsFunctionTokenDefType ? trimArray(slice.slice(1, -1)) : tokenList[0].chi, }); - // if (stack.at(-1)?.typ === EnumToken.NotTokenType || stack.at(-1)?.typ === EnumToken.OnlyTokenType) { - // const index: number = tokens.indexOf(stack.at(-1)!); - // tokens[index] = { - // typ: EnumToken.WhenElseUnaryConditionTokenType, - // l: stack.at(-1)!, - // r: trimArray(tokens.slice(index + 1)), - // [LOC]: { ...stack.at(-1)![LOC], end: { ...stream[i]?.[LOC]?.end } }, - // } as WhenElseUnaryConditionToken; - // tokens.length = index + 1; - // stack.pop(); - // } if (stack.at(-1)?.typ === exports.EnumToken.AndTokenType || stack.at(-1)?.typ === exports.EnumToken.OrTokenType) { const index = tokens.indexOf(stack.at(-1)); const index2 = stack.length > 1 ? tokens.indexOf(stack.at(-2)) + 1 : 0; @@ -27990,7 +28823,9 @@ op: stack.at(-1), l: trimArray(tokens.slice(index2, index)), r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -28001,22 +28836,10 @@ break; } } - // if (stack.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${renderValue(stack.at(-1) as Token)}' at ${stack.at(-1)![LOC]!.src}:${ - // stack.at(-1)![LOC]!.sta.lin - // }:${stack.at(-1)![LOC]!.sta.col}`, - // }, - // ], - // }; - // } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -28044,7 +28867,9 @@ }, [[]]); const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -28064,19 +28889,6 @@ (stream[i]?.typ === exports.EnumToken.WhitespaceTokenType || stream[i]?.typ === exports.EnumToken.CommentTokenType)) { tokens.push(stream[i++]); } - // if (i >= stream.length) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: context, - // location: context[LOC], - // message: `expecting at ${context[LOC]?.src}:${context?.[LOC]?.sta.lin}:${context[LOC]?.sta.col}`, - // }, - // ], - // }; - // } if (stream[i].typ === exports.EnumToken.IdenTokenType) { tokens.push(stream[i++]); } @@ -28092,7 +28904,7 @@ { action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), // ?? context[LOC], + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting `, }, ], @@ -28117,11 +28929,10 @@ action: "drop", node: stream[i], message: `expecting , or comma`, - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), }); break; } - // expectAndOr = false; } if (stream[i].typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(stream[i].typ)) { scopes.push((currentScope = new Set())); @@ -28155,174 +28966,34 @@ errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: ` is not allowed outside of parentheses`, }); break; } - // if (currentScope.has(val === "or" ? EnumToken.AndTokenType : EnumToken.OrTokenType)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `cannot mix and at the same level at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } currentScope.add(stream[i].typ); stack.push(stream[i]); } - // else if (scopes.length === 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unexpected at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // return { - // success, - // errors, - // }; - // } } break; case exports.EnumToken.EndParensTokenType: - // feature - // if (mFLT.has(stack.at(-1)?.typ) || mFGT.has(stack.at(-1)?.typ)) { - // // | - // const index: number = tokens.indexOf(stack.at(-1)!); - // const prevToken: Token = stack[stack.length - 2]; - // if (mFLT.has(prevToken?.typ) || mFGT.has(prevToken?.typ)) { - // if (stack[stack.length - 3]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `unmatched '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!mFLT.has(stack.at(-1)?.typ) && mFLT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } else if (!mFGT.has(stack.at(-1)?.typ) && mFGT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } - // // - // // const index: number = tokens.indexOf(stack.at(-1)!); - // // | - // const index2: number = tokens.indexOf(prevToken); - // // '(' - // const index3: number = tokens.indexOf(stack.at(-3)!); - // const left: Token[] = trimArray(tokens.slice(index3 + 1, index2)); - // const right: Token[] = trimArray(tokens.slice(index + 1, tokens.length - 1)); - // const names: Token[] = trimArray(tokens.slice(index2 + 1, index)); - // if (!isStyleFeatureValue(left)) { - // success = false; - // errors.push({ - // action: "drop", - // node: left[0], - // message: `expected at ${left[0]?.[LOC]?.src}:${left[0]?.[LOC]?.sta.lin}:${left[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(right)) { - // success = false; - // errors.push({ - // action: "drop", - // node: right[0], - // message: `expected at ${right[0]?.[LOC]?.src}:${right[0]?.[LOC]?.sta.lin}:${right[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(names)) { - // success = false; - // errors.push({ - // action: "drop", - // node: names[0], - // message: `expected at ${names[0]?.[LOC]?.src}:${names[0]?.[LOC]?.sta.lin}:${names[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // tokens.splice(index3 + 1, tokens.length - index3 - 2, { - // typ: EnumToken.ContainerStyleRangeTokenType, - // l: left, - // op: names, - // r: right, - // [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, - // } as ContainerStyleRangeToken); - // // check or - // stack.pop(); - // stack.pop(); - // } else if (stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `expected '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // } if (mFGT.has(stack.at(-1)?.typ) || mFLT.has(stack.at(-1)?.typ) || stack.at(-1)?.typ === exports.EnumToken.DelimTokenType || stack.at(-1)?.typ === exports.EnumToken.ColonTokenType) { stack[stack.length - 2].val?.toLowerCase?.(); - // if ( - // stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType && - // !( - // stack[stack.length - 2]?.typ === EnumToken.ContainerFunctionTokenDefType && - // ("style" === funcName || "scroll-state" === funcName) - // ) - // ) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unmatched2 ')' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } const index2 = tokens.indexOf(stack.at(-1)); const index3 = tokens.indexOf(stack.at(-2)); let names = trimArray(tokens.slice(index3 + 1, index2)); let values = trimArray(tokens.slice(index2 + 1, tokens.length - 1)); - // if ( - // stack.at(-1)?.typ !== EnumToken.ColonTokenType && - // stack.at(-1)?.typ !== EnumToken.DelimTokenType - // ) { - // const filteredNames = names.filter( - // (n) => - // n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, - // ); - // if ( - // filteredNames.length !== 1 || - // (filteredNames[0].typ !== EnumToken.IdenTokenType && - // filteredNames[0].typ !== EnumToken.DashedIdenTokenType) - // ) { - // } - // } tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: exports.EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); // check or } @@ -28332,13 +29003,15 @@ typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), }); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCSRCID] = tokens[index][LOCSRCID]; + tokens[index][LOCSTA] = tokens[index][LOCSTA]; + tokens[index][LOCEND] = stream[i][LOCEND]; if (tokens[index].chi.every((t) => t.typ === exports.EnumToken.WhitespaceTokenType || t.typ === exports.EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting '<${tokens[index].val}-query>'`, }); break; @@ -28353,14 +29026,16 @@ tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; if (tokens[index].chi.every((t) => t.typ === exports.EnumToken.WhitespaceTokenType || t.typ === exports.EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting ''`, }); break; @@ -28382,21 +29057,12 @@ errors.push({ action: "drop", node: tokens[k], - location: options.source.getSourceLocation(tokens[k]?.[LOC].sta), + location: options.source.getSourceLocation(tokens[k]?.[LOCSTA]), message: `unexpected token 'not'`, }); break; } } - // const index = tokens.indexOf(stack.at(-1)!); - // const slice = trimArray(tokens.slice(index + 1)); - // tokens[index] = { - // typ: EnumToken.MediaQueryUnaryFeatureTokenType, - // l: stack.pop()!, - // r: slice, - // [LOC]: { ...tokens[index][LOC]!, end: slice.at(-1)![LOC]!.end }, - // }; - // tokens.length = index + 1; } if (stack.at(-1)?.typ === exports.EnumToken.AndTokenType || stack.at(-1)?.typ === exports.EnumToken.OrTokenType) { @@ -28414,31 +29080,19 @@ op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOr = true; } break; - // default: - // if (tokensfuncDefMap.has(stream[i]?.typ)) { - // stack.push(stream[i]); - // scopes.push((currentScope = new Set())); - // } - // break; } if (!success) { break; } } - // if (success && stack.length > 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${EnumToken[stack.at(-1)?.typ]}' at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // } if (!success) { return { success, @@ -28446,17 +29100,18 @@ }; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } } } stream.length = 0; stream.push(...parts .filter((p) => p.length > 0 && p[0].typ !== exports.EnumToken.InvalidMediaQueryTokenType) .reduce((acc, b) => { - // if (acc.length > 0) { - // acc.push({ typ: EnumToken.CommaTokenType }); - // } - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { @@ -28470,24 +29125,6 @@ const syntax = syntaxRules?.getPreludeRules()?.slice?.(1); trimArray(stream); if (syntax.length === 0) { - // const filtered = stream.filter( - // (token) => token.typ !== EnumToken.WhitespaceTokenType && token.typ !== EnumToken.CommentTokenType, - // ); - // if (filtered.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // message: `unexpected token ${EnumToken[filtered[0].typ]} at ${filtered[0][LOC]!.src}:${ - // filtered[0][LOC]!.sta.lin - // }:${filtered[0][LOC]!.sta.col}`, - // node: filtered[0], - // location: filtered[0][LOC]!, - // }, - // ], - // }; - // } return { success: true, errors: [] }; } const { success, errors } = matchAllSyntaxes(syntax, createValidationContext(stream), options); @@ -28528,7 +29165,7 @@ action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28543,7 +29180,7 @@ action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28559,7 +29196,7 @@ action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28575,7 +29212,7 @@ action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28595,8 +29232,7 @@ action: "drop", message: `unexpected token ${exports.EnumToken[stack.at(-1)?.typ]}`, node: stack.at(-1), - // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)?.[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)?.[LOCSTA]), }); success = false; } @@ -28931,7 +29567,9 @@ } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { @@ -28948,7 +29586,6 @@ .push(value); } else if (typeof value == "object") { - // visitors.push(...Object.entries(value)); if ("type" in value && "handler" in value && value.type in exports.WalkerEvent) { if (value.type == exports.WalkerEvent.Enter) { if (!preVisitorsHandlersMap.has(key)) { @@ -29016,7 +29653,7 @@ * @throws Error * @private */ - function doParseSync(iter, options = {}) { + function doParseSync(tokenizer, options = {}) { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -29078,46 +29715,78 @@ // @ts-ignore ignore error let parensMatch = 0; let curlyBracketMatch = 0; - let currentItemIndex; - // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - for (currentItemIndex = 0; currentItemIndex < iter.length; currentItemIndex++) { - item = iter[currentItemIndex]; - stats.bytesIn = item.bytesIn; + // let currentItemIndex: number; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); + // item = (iter as Array)[currentItemIndex]; + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + if (item.typ === exports.EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === exports.EnumToken.SemiColonTokenType || - item.token.typ === exports.EnumToken.BlockStartTokenType || - item.token.typ === exports.EnumToken.EOFTokenType)) { + (item.typ === exports.EnumToken.SemiColonTokenType || + item.typ === exports.EnumToken.BlockStartTokenType || + item.typ === exports.EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -29125,37 +29794,67 @@ context = node; } } - else if (item.token.typ == exports.EnumToken.BlockStartTokenType) { + else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = iter[++currentItemIndex]; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === exports.EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -29164,7 +29863,7 @@ context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -29207,17 +29906,23 @@ case exports.EnumToken.AtRuleNodeType: case exports.EnumToken.KeyframesRuleNodeType: case exports.EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case exports.EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (const child of nodes[i].chi) { + subNodes.push(child); + } } if (subNodes.length > 0) { if (freeBlock <= i) { @@ -29379,7 +30084,7 @@ ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -29408,7 +30113,7 @@ : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & exports.ModuleCaseTransformEnum.CamelCase) { @@ -29453,7 +30158,7 @@ for (const { node, parent } of walk(ast)) { if (node.typ == exports.EnumToken.CssVariableImportTokenType) { throw new Error("css variable import not supported by parseSync() or transformSync(). use parse() or transform() instead.\nat " + - options.source.getSourceLocation(node[LOC].sta).join(":")); + options.source.getSourceLocation(node[LOCSTA]).join(":")); } // @ts-ignore if (node.typ == exports.EnumToken.CssVariableDeclarationMapTokenType) { @@ -29572,7 +30277,7 @@ } // composes: a b c from 'file.css'; else if (token.r.typ == exports.EnumToken.String) { - throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOC].sta).join(":")}`); + throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOCSTA]).join(":")}`); } // composes: a b c from global; else if (token.r.typ == exports.EnumToken.IdenTokenType) { @@ -29806,7 +30511,7 @@ } if (moduleSettings.scoped & exports.ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOC]?.sta).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOCSTA]).join(":")}'`); } } node.sel = ""; @@ -29939,56 +30644,84 @@ const imports = []; let item; let node; - // @ts-ignore ignore error - let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - if (Array.isArray(iter)) { - // @ts-expect-error - iter = iter[Symbol.iterator](); - } - while ((item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value)) { - stats.bytesIn = item.bytesIn; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + ast[LOCEND] = 0; + // if (Array.isArray(iter)) { + // // @ts-expect-error + // iter = iter[Symbol.iterator]() as Iterator; + // } + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + if (item.typ === exports.EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === exports.EnumToken.SemiColonTokenType || - item.token.typ === exports.EnumToken.BlockStartTokenType || - item.token.typ === exports.EnumToken.EOFTokenType)) { + (item.typ === exports.EnumToken.SemiColonTokenType || + item.typ === exports.EnumToken.BlockStartTokenType || + item.typ === exports.EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -29999,41 +30732,67 @@ imports.push(node); } } - else if (item.token.typ == exports.EnumToken.BlockStartTokenType) { + else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === exports.EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -30042,7 +30801,7 @@ context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -30081,8 +30840,11 @@ source, position: 0, currentPosition: 0, + time: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { minify: false, setParent: false, src: options.resolve(url, options.src || options.cwd).relative, @@ -30094,7 +30856,9 @@ // @ts-ignore node[PARENT].chi.splice(node[PARENT].chi.indexOf(node), 1, ...root.ast.chi); if (root.errors.length > 0) { - errors.push(...root.errors); + for (const error of root.errors) { + errors.push(error); + } } } catch (error) { @@ -30131,17 +30895,24 @@ case exports.EnumToken.AtRuleNodeType: case exports.EnumToken.KeyframesRuleNodeType: case exports.EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case exports.EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (k = 0; k < nodes[i].chi.length; k++) { + // @ts-ignore + subNodes.push(nodes[i].chi[k]); + } } if (subNodes.length > 0) { if (freeblock <= i) { @@ -30306,7 +31077,7 @@ ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -30335,7 +31106,7 @@ : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & exports.ModuleCaseTransformEnum.CamelCase) { @@ -30396,13 +31167,15 @@ position: 0, currentPosition: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { source, minify: false, setParent: false, src: src.relative, })); - options.parseInfo.time += parseInfo.time; + // options.parseInfo!.time += parseInfo.time; cssVariablesMap[node.nam] = root.cssModuleVariables; parent.chi.splice(parent.chi.indexOf(node), 1); continue; @@ -30537,13 +31310,13 @@ ? await result : result; const root = await doParse(stream instanceof ReadableStream - ? tokenizeStream(stream, { + ? new Tokenizer({ offset: 0, source: new SourceFile("", [], src.relative), position: 0, currentPosition: 0, - }) - : tokenize({ + }, stream).tokenizeStream() + : new Tokenizer({ stream, offset: 0, position: 0, @@ -30842,7 +31615,7 @@ } if (moduleSettings.scoped & exports.ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOC]?.sta) ?? []).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOCSTA]) ?? []).join(":")}'`); } } node.sel = ""; @@ -30879,31 +31652,6 @@ } node.val = renderTokens(node[TOKENS]); } - // else { - // let isReplaced: boolean = false; - // for (const { value, parent } of walkValues(node[TOKENS], node)) { - // if ( - // EnumToken.MediaQueryConditionTokenType == parent.typ && - // // @ts-expect-error - // value != (parent as MediaQueryConditionToken).l - // ) { - // if ( - // (value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && - // (value as IdentToken).val in importedCssVariables - // ) { - // isReplaced = true; - // (parent as MediaQueryConditionToken).r.splice( - // (parent as MediaQueryConditionToken).r.indexOf(value), - // 1, - // ...importedCssVariables[(value as IdentToken).val].val, - // ); - // } - // } - // } - // if (isReplaced) { - // node.val = renderTokens(node[TOKENS]!); - // } - // } } } if (moduleSettings.naming != exports.ModuleCaseTransformEnum.IgnoreCase) { @@ -30935,7 +31683,6 @@ tokens.pop(); // check parenthesis are balanced let matchCount = 0; - let position = tokens.at(-1)?.[LOC]; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(token.typ)) { @@ -30956,7 +31703,9 @@ while (matchCount > 0) { tokens.push({ typ: exports.EnumToken.EndParensTokenType, - [LOC]: { ...position }, + [LOCSRCID]: tokens[k]?.[LOCSRCID], + [LOCSTA]: tokens[k]?.[LOCSTA], + [LOCEND]: tokens[k]?.[LOCEND], }); matchCount--; } @@ -30968,7 +31717,7 @@ action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = exports.EnumToken.InvalidCommentTokenType; continue; @@ -30991,7 +31740,7 @@ action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = exports.EnumToken.InvalidCommentTokenType; continue; @@ -31072,7 +31821,7 @@ message: " not allowed in ", action: "drop", node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); } else if (options.lenient || node.typ === exports.EnumToken.DeclarationNodeType) { @@ -31111,7 +31860,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "unknown at-rule", }); const result = matchGenericSyntax(stream, options); @@ -31132,7 +31881,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -31150,8 +31899,8 @@ errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${exports.EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); atRule[TOKENS] = parseTokens(stream); atRule[STATE] = exports.EnumAstNodeStatus.Invalid; @@ -31171,7 +31920,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -31194,7 +31943,7 @@ errors.push({ action: "drop", node: stream[0] ?? atRule, - location: options.source.getSourceLocation((stream[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[0] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -31203,7 +31952,7 @@ errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -31212,7 +31961,7 @@ errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting double-quoted string", }); } @@ -31220,7 +31969,7 @@ atRule[TOKENS] = stream; atRule[STATE] = exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? exports.EnumToken.AtRuleNodeType : exports.EnumToken.InvalidRuleNodeType, @@ -31233,7 +31982,7 @@ atRule[TOKENS] = stream; atRule[STATE] = exports.EnumAstNodeStatus.Validated; atRule[ERRORS] = []; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? exports.EnumToken.AtRuleNodeType : exports.EnumToken.InvalidRuleNodeType, @@ -31243,12 +31992,14 @@ case "font-feature-values": { const result = parseAtRuleFontFeatureValues(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } atRule[TOKENS] = stream; atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: exports.EnumToken.AtRuleNodeType, @@ -31267,7 +32018,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: `unexpected at-rule ${atRule.nam}`, }); } @@ -31278,13 +32029,13 @@ errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${exports.EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); } } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; @@ -31298,9 +32049,11 @@ case "container": { const result = parseAtRuleContainerQueryList(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31315,11 +32068,13 @@ const tokens = trimArray(stream.slice(1)); const result = matchAllSyntaxes(syntax, createValidationContext(tokens), options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.ValidationFailed; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31339,14 +32094,14 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), - message: `expected at ${atRule[LOC].srcId}:${atRule[LOC].sta}:${atRule[LOC].sta}`, + location: options.source.getSourceLocation(atRule[LOCSTA]), + message: `expected `, }); success = false; } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31360,7 +32115,9 @@ case "namespace": { const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // else { // parseUrlToken(stream); @@ -31389,7 +32146,7 @@ stream.splice(start - 1, end - start + 2, ...stream.slice(start, end)); } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = valid ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = valid ? [] : result.errors; @@ -31409,7 +32166,9 @@ case "import": { const result = matchAtRuleImportSyntax(atRule, stream, context, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } else { if (stream[0]?.typ == exports.EnumToken.UrlFunctionTokenType && @@ -31417,8 +32176,7 @@ stream.splice(0, 1, ...stream[0].chi); } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31442,7 +32200,9 @@ ? parseAtRuleSupportSyntax(stream, atRule, options) : matchAtRuleWhenElseSyntax(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } let success = result.success; if (atRule.nam === "else") { @@ -31479,7 +32239,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @when is required before @else block", }); } @@ -31488,14 +32248,14 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @else block is defined after last @else block", }); } } // @ts-expect-error options = { ...options, minify: false, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : [errors[errors.length - 1]].concat(result.errors); @@ -31510,9 +32270,11 @@ options = { ...options, parseColor: false }; const result = parseMediaqueryList(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31532,7 +32294,7 @@ errors.push({ action: "drop", node: range[0] ?? atRule, - location: options.source.getSourceLocation((range[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range[0] ?? atRule)[LOCSTA]), message: "expected '(' at start of @scope block", }); success = false; @@ -31541,7 +32303,7 @@ errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -31567,7 +32329,7 @@ errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -31580,7 +32342,7 @@ errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -31593,7 +32355,7 @@ errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -31612,8 +32374,7 @@ } } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31626,7 +32387,7 @@ } case "page": { trimArray(stream); - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31657,7 +32418,7 @@ errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "node is allowed only in @page rule", }); } @@ -31670,14 +32431,14 @@ errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: "expected whitespace or comment", }); break; } } } - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31699,7 +32460,9 @@ }); stream.splice(index, 0, { typ: exports.EnumToken.ColonTokenType, - [LOC]: { ...stream[index][LOC], end: stream[index]?.[LOC]?.end }, + [LOCSRCID]: stream[index][LOCSRCID], + [LOCSTA]: stream[index][LOCSTA], + [LOCEND]: stream[index][LOCEND], }); isVarDeclaration = true; break; @@ -31721,14 +32484,15 @@ atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { typ: exports.EnumToken.AtRuleNodeType, val: renderTokens(stream, options), - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -31743,10 +32507,9 @@ typ: exports.EnumToken.CssVariableImportTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Validated, [ERRORS]: [], @@ -31757,19 +32520,15 @@ typ: exports.EnumToken.CssVariableTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Validated, [ERRORS]: [], }; } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[STATE] = exports.EnumAstNodeStatus.Validated; atRule[ERRORS] = []; // @ts-expect-error @@ -31789,13 +32548,17 @@ // check or and and result = matchGenericSyntax(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } else { result = matchAtRuleSyntax(atRule, stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } if (result.success) { let i = 0; @@ -31807,7 +32570,7 @@ } if (stream[i].typ === exports.EnumToken.EndParensTokenType && stack.length > 0) { const index = stream.indexOf(stack[stack.length - 1]); - stream[index][LOC].end = stream[i][LOC].end; + stream[index][LOCEND] = stream[i][LOCEND]; Object.assign(stream[index], { typ: tokensfuncDefMap.get(stream[index].typ), chi: stream.splice(index + 1, i - index - 1), @@ -31815,15 +32578,11 @@ i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.errors; @@ -31849,7 +32608,7 @@ */ async function parseDeclarations(declaration) { const stream = `.x{${declaration}}`; - return doParse(tokenize({ + return doParse(new Tokenizer({ stream, offset: 0, position: 0, @@ -31882,18 +32641,57 @@ * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const tokenizer = new Tokenizer({ stream: src, + buffer: "", + src: options?.src ?? "", offset: 0, time: 0, - source: new SourceFile(src, [], ""), + source: new SourceFile(src, [], options?.src ?? ""), position: 0, currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + }); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.val === null) { + token = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + token[LOCSRCID] = tokenizer.source.id; + token[LOCEND] = tokenizer.end; + token[LOCSTA] = tokenizer.sta; + mapped.push(token); } const result = parseTokens(mapped, options, errors); // remove EOF token @@ -31939,7 +32737,7 @@ val: (tokens[i - 1].typ === exports.EnumToken.ColonTokenType ? ":" : "::") + tokens[i].val, }); - t[LOC].end = tokens[i][LOC].end; + t[LOCEND] = tokens[i][LOCEND]; tokens.splice(i--, 1); } } @@ -31958,7 +32756,7 @@ action: "drop", message: `Unbalanced token ')'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); // return []; continue; @@ -31986,13 +32784,13 @@ action: "drop", message: `Unbalanced token ']'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); continue; } index = tokens.indexOf(stack.at(-1)); const attr = stack.at(-1); - attr[LOC].end = t[LOC].end; + attr[LOCEND] = t[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: exports.EnumToken.AttrTokenType, @@ -32108,9 +32906,8 @@ action: "drop", message: `Unbalanced token. Expecting ${node.typ === exports.EnumToken.AttrStartTokenType ? "']'" : ")"}'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } @@ -32132,6 +32929,10 @@ * return an arraybuffer */ ResponseType[ResponseType["ArrayBuffer"] = 2] = "ArrayBuffer"; + /** + * return a json object + */ + ResponseType[ResponseType["JSON"] = 3] = "JSON"; })(exports.ResponseType || (exports.ResponseType = {})); /** @@ -32151,7 +32952,26 @@ const token = result.ast.chi.at(-1); if (token?.typ == exports.EnumToken.CommentTokenType && token.val.startsWith("/*# sourceMappingURL=")) { - options.source.setInputSourceMap(token.val.slice(21, -2).trim()); + let data = token.val.slice(21, -2).trim(); + if (data.endsWith(".map")) { + if (options.load == null) { + data = ""; + } + else { + options + .load(options.resolve(data, dirname(options.src)).absolute, ".", exports.ResponseType.JSON) + .catch((error) => console.error({ error })) + .then((res) => { + if (res != null) { + // @ts-expect-error + options.source.setInputSourceMap(res); + } + }); + } + } + else { + options.source.setInputSourceMap(data); + } } } } @@ -32194,7 +33014,7 @@ case "parent": return node[PARENT]; case "location": - return node[LOC]; + return node[LOCSRCID] == null && node[LOCSTA] == null && node[LOCEND] == null ? null : { srcId: node[LOCSRCID], sta: node[LOCSTA], end: node[LOCEND] }; case "state": return node[STATE]; case "errors": @@ -32216,7 +33036,9 @@ node[PARENT] = value; break; case "location": - node[LOC] = value; + node[LOCSRCID] = value.srcId; + node[LOCSTA] = value.sta; + node[LOCEND] = value.end; break; case "state": node[STATE] = value; @@ -32267,6 +33089,9 @@ if (responseType == exports.ResponseType.ArrayBuffer) { return response.arrayBuffer(); } + if (responseType == exports.ResponseType.JSON) { + return response.json(); + } return responseType == exports.ResponseType.ReadableStream ? response.body : response.text(); }); } @@ -32393,8 +33218,10 @@ position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -32527,7 +33354,11 @@ position: 0, currentPosition: 0, }; - return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS file diff --git a/dist/index.cjs b/dist/index.cjs index fceaa1b3..a651d369 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -2802,6 +2802,9 @@ var declarations = { "text-emphasis-style": { syntax: "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | " }, + "text-fit": { + syntax: "[ none | grow | shrink ] [consistent | per-line | per-line-all]? ?" + }, "text-indent": { syntax: " && hanging? && each-line?" }, @@ -6342,6 +6345,15 @@ var config$4 = { mediaFeatures: mediaFeatures }; +/** + * Location source id + */ +const LOCSRCID = Symbol.for("locSrcId"); +const LOCSTA = Symbol.for("locSta"); +const LOCEND = Symbol.for("locEnd"); +/** + * Used by the validation parser + */ const LOC = Symbol.for("loc"); const RAW = Symbol.for("raw"); const STATE = Symbol.for("state"); @@ -6394,7 +6406,7 @@ const colorPrecision = 6; /** * Angle precision */ -const anglePrecision = 0.001; +const anglePrecision = 3; /** * Color range definitions */ @@ -6450,6 +6462,7 @@ const mathFuncs = [ "acos", "atan", "atan2", + "tan", "pow", "sqrt", "hypot", @@ -6834,9 +6847,11 @@ function camelize(value) { function equalsIgnoreCase(a, b) { if (a.length !== b.length) return false; + let ca; + let cb; for (let i = 0; i < a.length; i++) { - let ca = a.charCodeAt(i); - let cb = b.charCodeAt(i); + ca = a.charCodeAt(i); + cb = b.charCodeAt(i); // Normalize A-Z to a-z if (ca >= 65 && ca <= 90) ca += 32; @@ -7028,41 +7043,41 @@ function lchToken(values) { function hex2lchvalues(token) { const values = hex2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2lchvalues(token) { const values = rgb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2lchvalues(token) { const values = hsl2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2lchvalues(token) { const values = hwb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lab2lchvalues(token) { const values = getLABComponents(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2lch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2labvalues(r, g, blue, alpha)); + let values = srgb2labvalues(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2lchvalues(token) { const values = oklab2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2lchvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2lch(...values); + return values == null ? null : srgb2lch(values[0], values[1], values[2], values[3]); } function oklch2lchvalues(token) { const values = oklch2labvalues(token); @@ -7070,7 +7085,7 @@ function oklch2lchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function color2lchvalues(token) { const values = color2srgbvalues(token); @@ -7078,7 +7093,7 @@ function color2lchvalues(token) { return null; } // @ts-ignore - return srgb2lch(...values); + return srgb2lch(values[0], values[1], values[2], values[3]); } function labvalues2lchvalues(l, a, b, alpha = null) { let c = Math.sqrt(a * a + b * b); @@ -7092,8 +7107,8 @@ function labvalues2lchvalues(l, a, b, alpha = null) { return alpha == null ? [l, c, h] : [l, c, h, alpha]; } function xyz2lchvalues(x, y, z, alpha) { - // @ts-ignore( - const lch = labvalues2lchvalues(...xyz2lab(x, y, z)); + const values = xyz2lab(x, y, z); + const lch = labvalues2lchvalues(values[0], values[1], values[2]); return alpha == null || alpha == 1 ? lch : lch.concat(alpha); } function getLCHComponents(token) { @@ -7133,8 +7148,8 @@ function getLCHComponents(token) { /* */ function xyzd502lch(x, y, z, alpha) { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + const values = XYZ_D50_to_D65(x, y, z); + const [l, a, b] = xyz2lab(values[0], values[1], values[2]); // L in range [0,100]. For use in CSS, add a percent return labvalues2lchvalues(l, a, b, alpha); } @@ -7202,8 +7217,8 @@ function srgb2xyz(r, g, b, alpha) { // xyz d50 function srgb2xyz_d65(r, g, b, alpha) { // xyx d65 - // @ts-ignore - let rgb = XYZ_D65_to_D50(...srgb2xyz(r, g, b)); + let values = srgb2xyz(r, g, b); + let rgb = XYZ_D65_to_D50(values[0], values[1], values[2]); if (alpha != null && alpha != 1) { rgb.push(alpha); } @@ -7212,7 +7227,7 @@ function srgb2xyz_d65(r, g, b, alpha) { function hex2oklchToken(token) { const values = hex2oklchvalues(token); - return oklchToken(values); + return values == null ? null : oklchToken(values); } function rgb2oklchToken(token) { const values = rgb2oklchvalues(token); @@ -7268,8 +7283,7 @@ function color2oklchToken(token) { if (values == null) { return null; } - // @ts-ignore - return oklchToken(srgb2oklch(...values)); + return oklchToken(srgb2oklch(values[0], values[1], values[2], values[3])); } function oklchToken(values) { values[2] = values[2]; @@ -7292,29 +7306,27 @@ function oklchToken(values) { }; } function hex2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hex2oklabvalues(token)); + const values = hex2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2oklchvalues(token) { const values = rgb2oklabvalues(token); if (values == null) { return null; } - // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hsl2oklabvalues(token)); + const values = hsl2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hwb2oklabvalues(token)); + const values = hwb2oklabvalues(token); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2oklchvalues(token) { const values = cmyk2srgbvalues(token); - // @ts-ignore - return values == null ? null : srgb2oklch(...values); + return values == null ? null : srgb2oklch(values[0], values[1], values[2], values[3]); } function lab2oklchvalues(token) { const values = lab2oklabvalues(token); @@ -7322,7 +7334,7 @@ function lab2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lch2oklchvalues(token) { const values = lch2oklabvalues(token); @@ -7330,7 +7342,7 @@ function lch2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2oklchvalues(token) { const values = getOKLABComponents(token); @@ -7338,11 +7350,11 @@ function oklab2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2oklch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2oklab(r, g, blue, alpha)); + const values = srgb2oklab(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function getOKLCHComponents(token) { const components = getColorComponents(token); @@ -7466,15 +7478,14 @@ function hex2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function rgb2oklabvalues(token) { const values = rgb2srgb(token); if (values == null) { return null; } - // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hsl2oklabvalues(token) { const values = hsl2srgb(token); @@ -7482,16 +7493,16 @@ function hsl2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hwb2oklabvalues(token) { - // @ts-ignore - return srgb2oklab(...hwb2srgbvalues(token)); + const values = hwb2srgbvalues(token); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function cmyk2oklabvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function lab2oklabvalues(token) { const values = lab2srgbvalues(token); @@ -7499,22 +7510,22 @@ function lab2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function lch2oklabvalues(token) { const values = lch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function oklch2oklabvalues(token) { const values = getOKLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function color2oklabvalues(token) { const values = color2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function srgb2oklab(r, g, blue, alpha) { [r, g, blue] = srgb2lsrgbvalues(r, g, blue); @@ -7669,19 +7680,19 @@ function labToken(values) { // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 function hex2labvalues(token) { - const values = hex2srgbvalues(token); + let values = hex2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function rgb2labvalues(token) { const values = rgb2srgb(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function cmyk2labvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function hsl2labvalues(token) { const values = hsl2srgb(token); @@ -7689,7 +7700,7 @@ function hsl2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function hwb2labvalues(token) { const values = hwb2srgbvalues(token); @@ -7697,20 +7708,21 @@ function hwb2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function lch2labvalues(token) { const values = getLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function oklab2labvalues(token) { - const values = getOKLABComponents(token); + let values = getOKLABComponents(token); if (values == null) { return null; } - // @ts-ignore - return xyz2lab(...XYZ_D65_to_D50(...OKLab_to_XYZ(...values))); + values = OKLab_to_XYZ(values[0], values[1], values[2], values[3]); + values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); + return xyz2lab(values[0], values[1], values[2], values[3]); } function oklch2labvalues(token) { const values = oklch2srgbvalues(token); @@ -7718,19 +7730,18 @@ function oklch2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function color2labvalues(token) { const val = color2srgbvalues(token); if (val == null) { return null; } - // @ts-ignore - return srgb2labvalues(...val); + return srgb2labvalues(val[0], val[1], val[2], val[3]); } function srgb2labvalues(r, g, b, a) { - // @ts-ignore */ - const result = xyz2lab(...srgb2xyz_d65(r, g, b)); + let result = srgb2xyz_d65(r, g, b); + result = xyz2lab(result[0], result[1], result[2]); // Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors // and approximated computations in sRGB <-> CIELab. // See: https://github.com/d3/d3-color/pull/46 @@ -7812,9 +7823,9 @@ function getLABComponents(token) { function Lab_to_sRGB(l, a, b) { const xyz_d50 = Lab_to_XYZ(l, a, b); // @ts-ignore - const xyz_d65 = XYZ_D50_to_D65(...xyz_d50); + const xyz_d65 = XYZ_D50_to_D65(xyz_d50[0], xyz_d50[1], xyz_d50[2]); // @ts-ignore - return xyz2srgb(...xyz_d65); + return xyz2srgb(xyz_d65[0], xyz_d65[1], xyz_d65[2]); } // from https://www.w3.org/TR/css-color-4/#color-conversion-code function Lab_to_XYZ(l, a, b) { @@ -7896,8 +7907,9 @@ function hex2srgbvalues(token) { } // xyz d65 input function xyz2srgb(x, y, z, alpha = null) { + let values = XYZ_to_lin_sRGB(x, y, z); // @ts-ignore - return lsrgb2srgbvalues(...XYZ_to_lin_sRGB(x, y, z, alpha)); + return lsrgb2srgbvalues(values[0], values[1], values[2], alpha); } function hwb2srgbvalues(token) { const { h: hue, s: white, l: black, a: alpha } = hslvalues(token) ?? {}; @@ -7968,8 +7980,8 @@ function oklch2srgbvalues(token) { if (l == null || c == null || h == null) { return null; } - // @ts-ignore - const rgb = OKLab_to_sRGB(...lchvalues2labvalues(l, c, h)); + const values = lchvalues2labvalues(l, c, h); + const rgb = OKLab_to_sRGB(values[0], values[1], values[2]); if (alpha != 1) { rgb.push(alpha); } @@ -8070,7 +8082,7 @@ function lch2srgbvalues(token) { return null; } // @ts-ignore - const [l, a, b, alpha] = lchvalues2labvalues(...components); + const [l, a, b, alpha] = lchvalues2labvalues(components[0], components[1], components[2], components[3]); if (l == null || a == null || b == null) { return null; } @@ -8440,8 +8452,11 @@ function hsl2hsv(h, s, l, a = null) { } function hex2HslToken(token) { - // @ts-ignore - return hslToken(srgb2hslvalues(...hex2srgbvalues(token))); + let values = hex2srgbvalues(token); + if (values == null) { + return null; + } + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function rgb2HslToken(token) { const values = rgb2hslvalues(token); @@ -8497,8 +8512,7 @@ function color2HslToken(token) { if (values == null) { return null; } - // @ts-ignore - return hslToken(srgb2hslvalues(...values)); + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function hslToken(values) { values[0] = values[0] * 360; @@ -8546,8 +8560,7 @@ function rgb2hslvalues(token) { if (a != null && a != 1) { values.push(a); } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } // https://gist.github.com/defims/0ca2ef8832833186ed396a2f8a204117#file-annotated-js function hsv2hsl(h, s, v, a) { @@ -8569,20 +8582,19 @@ function hsv2hsl(h, s, v, a) { } function cmyk2hslvalues(token) { const values = cmyk2rgbvalues(token); - // @ts-ignore - return values == null ? null : rgbvalues2hslvalues(...values); + return values == null ? null : rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function hwb2hslvalues(token) { - // @ts-ignore - return hsv2hsl(...hwb2hsv(...Object.values(hslvalues(token)))); + const hsla = hslvalues(token); + const hwba = hwb2hsv(hsla.h, hsla.s, hsla.l, hsla.a); + return hsv2hsl(hwba[0], hwba[1], hwba[2], hwba[3]); } function lab2hslvalues(token) { const values = lab2rgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function lch2hslvalues(token) { const values = lch2rgbvalues(token); @@ -8590,17 +8602,17 @@ function lch2hslvalues(token) { return null; } // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function oklab2hslvalues(token) { const t = oklab2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function oklch2hslvalues(token) { const t = oklch2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function rgbvalues2hslvalues(r, g, b, a = null) { return srgb2hslvalues(r / 255, g / 255, b / 255, a); @@ -8702,7 +8714,7 @@ function hwbToken(values) { if (values.length == 4) { chi.push({ typ: exports.EnumToken.LiteralTokenType, val: "/" }, { typ: exports.EnumToken.PercentageTokenType, - val: values[3] * 100 + val: values[3] * 100, }); } return { @@ -8713,21 +8725,21 @@ function hwbToken(values) { }; } function rgb2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3) { return getNumber(t); } return getNumber(t) / 255; - })); + }); + // @ts-ignore + return srgb2hwb(values[0], values[1], values[2], values[3]); } function cmyk2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...cmyk2srgbvalues(token)); + const values = cmyk2srgbvalues(token); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function hsl2hwbvalues(token) { - // @ts-ignore - return hslvalues2hwbvalues(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3 && t.typ == exports.EnumToken.IdenTokenType && t.val == "none") { return 1; } @@ -8735,23 +8747,23 @@ function hsl2hwbvalues(token) { return getAngle(t); } return getNumber(t); - })); + }); + // @ts-ignore + return hslvalues2hwbvalues(values[0], values[1], values[2], values[3]); } function lab2hwbvalues(token) { const values = lab2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function lch2hwbvalues(token) { const values = lch2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklab2hwbvalues(token) { const values = oklab2srgbvalues(token); @@ -8759,12 +8771,12 @@ function oklab2hwbvalues(token) { return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklch2hwbvalues(token) { const values = oklch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2hwb(...values); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function rgb2hue(r, g, b, fallback = 0) { let value = rgb2value(r, g, b); @@ -8792,7 +8804,7 @@ function color2hwbvalues(token) { return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function srgb2hwb(r, g, b, a = null, fallback = 0) { r *= 100; @@ -8816,69 +8828,72 @@ function hsv2hwb(h, s, v, a = null) { return result; } function hslvalues2hwbvalues(h, s, l, a = null) { + let values = hsl2hsv(h, s, l); // @ts-ignore - return hsv2hwb(...hsl2hsv(h, s, l, a)); + return hsv2hwb(values[0], values[1], values[2], a); } function prophotorgb2srgbvalues(r, g, b, a = null) { + let values = prophotorgb2xyz50(r, g, b); // @ts-ignore - return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); + return xyzd502srgb(values[0], values[1], values[2], a); } function srgb2prophotorgbvalues(r, g, b, a) { - // @ts-ignore - return xyz50_to_prophotorgb(...XYZ_D65_to_D50(...srgb2xyz(r, g, b, a))); + let values = srgb2xyz(r, g, b); + values = XYZ_D65_to_D50(values[0], values[1], values[2]); + values = xyz50_to_prophotorgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; } function prophotorgb2lin_ProPhoto(r, g, b, a = null) { - return [r, g, b].map(v => { + return [r, g, b] + .map((v) => { let abs = Math.abs(v); if (abs >= 16 / 512) { return Math.sign(v) * Math.pow(abs, 1.8); } return v / 16; - }).concat(a == null || a == 1 ? [] : [a]); + }) + .concat(a == null || a == 1 ? [] : [a]); } function prophotorgb2xyz50(r, g, b, a = null) { [r, g, b, a] = prophotorgb2lin_ProPhoto(r, g, b, a); const xyz = [ - 0.7977666449006423 * r + - 0.1351812974005331 * g + - 0.0313477341283922 * b, - 0.2880748288194013 * r + - 0.7118352342418731 * g + - 0.0000899369387256 * b, - 0.8251046025104602 * b + 0.7977666449006423 * r + 0.1351812974005331 * g + 0.0313477341283922 * b, + 0.2880748288194013 * r + 0.7118352342418731 * g + 0.0000899369387256 * b, + 0.8251046025104602 * b, ]; return xyz.concat(a == null || a == 1 ? [] : [a]); } function xyz50_to_prophotorgb(x, y, z, a) { // @ts-ignore - return gam_prophotorgb(...[ - x * 1.3457868816471585 - - y * 0.2555720873797946 - - 0.0511018649755453 * z, - x * -0.5446307051249019 + - y * 1.5082477428451466 + - 0.0205274474364214 * z, - 1.2119675456389452 * z - ].concat(a == null || a == 1 ? [] : [a])); + return gam_prophotorgb(x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z, x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z, 1.2119675456389452 * z); +} +function gam_prophotorgbvalue(v) { + let abs = Math.abs(v); + if (abs >= 1 / 512) { + return Math.sign(v) * Math.pow(abs, 1 / 1.8); + } + return 16 * v; } function gam_prophotorgb(r, g, b, a) { - return [r, g, b].map(v => { - let abs = Math.abs(v); - if (abs >= 1 / 512) { - return Math.sign(v) * Math.pow(abs, 1 / 1.8); - } - return 16 * v; - }).concat(a == null || a == 1 ? [] : [a]); + const values = [gam_prophotorgbvalue(r), gam_prophotorgbvalue(g), gam_prophotorgbvalue(b)]; + return values; } function rec20202srgb(r, g, b, a) { + let values = rec20202lrec2020(r, g, b); + values = lrec20202xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lrec20202xyz(...rec20202lrec2020(r, g, b)), a); + return xyz2srgb(values[0], values[1], values[2], a); } function srgb2rec2020values(r, g, b, a) { + let values = srgb2xyz(r, g, b); + values = xyz2lrec2020(values[0], values[1], values[2]); // @ts-ignore - return lrec20202rec2020(...xyz2lrec2020(...srgb2xyz(r, g, b)), a); + return lrec20202rec2020(values[0], values[1], values[2], a); } function rec20202lrec2020(r, g, b, a) { // convert an array of rec2020 RGB values in the range 0.0 - 1.0 @@ -8924,7 +8939,7 @@ function lrec20202xyz(r, g, b, a) { [0, 19567812 / 697040785, 295819943 / 278816314], ]; // 0 is actually calculated as 4.994106574466076e-17 - return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [r, g, b]).concat([] ); } function xyz2lrec2020(x, y, z, a) { // convert XYZ to linear-light rec2020 @@ -8933,24 +8948,36 @@ function xyz2lrec2020(x, y, z, a) { [-19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200], [792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125], ]; - return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [x, y, z]).concat([] ); } function p32srgbvalues(r, g, b, alpha) { + let values = p32lp3(r, g, b); + values = lp32xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lp32xyz(...p32lp3(r, g, b, alpha))); + return xyz2srgb(values[0], values[1], values[2], alpha); } function srgb2p3values(r, g, b, alpha) { - // @ts-ignore - return lp32p3(...xyz2lp3(...srgb2xyz(r, g, b, alpha))); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + values = lp32p3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function srgb2lp3values(r, g, b, alpha) { - // @ts-ignore - return xyz2lp3(...srgb2xyz(r, g, b, alpha)); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function lp32srgbvalues(r, g, b, alpha) { + let values = lp32xyz(r, g, b); // @ts-ignore - return xyz2srgb(...lp32xyz(r, g, b, alpha)); + return xyz2srgb(values[0], values[1], values[2], alpha); } function p32lp3(r, g, b, alpha) { // convert an array of display-p3 RGB values in the range 0.0 - 1.0 @@ -8972,9 +8999,6 @@ function lp32xyz(r, g, b, alpha) { [0, 32229 / 714400, 5220557 / 5000800], ]; const result = multiplyMatrices(M, [r, g, b]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } function xyz2lp3(x, y, z, alpha) { @@ -8985,12 +9009,77 @@ function xyz2lp3(x, y, z, alpha) { [11844 / 330415, -50337 / 660830, 316169 / 330415], ]; const result = multiplyMatrices(M, [x, y, z]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } +function a98rgb2srgbvalues(r, g, b, a = null) { + let values = a98rgb2la98(r, g, b); + values = la98rgb2xyz(values[0], values[1], values[2]); + values = xyz2srgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; +} +function srgb2a98values(r, g, b, a = null) { + let values = srgb2xyz(r, g, b); + values = xyz2la98rgb(values[0], values[1], values[2]); + values = la98rgb2a98rgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; +} +// a98-rgb functions +function a98rgb2la98(r, g, b, a = null) { + // convert an array of a98-rgb values in the range 0.0 - 1.0 + // to linear light (un-companded) form. + // negative values are also now accepted + return [r, g, b] + .map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = Math.abs(val); + return sign * Math.pow(abs, 563 / 256); + }) + .concat(a == null || a == 1 ? [] : [a]); +} +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] + .map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = Math.abs(val); + return sign * Math.pow(abs, 256 / 563); + }) + .concat(a == null || a == 1 ? [] : [a]); +} +function la98rgb2xyz(r, g, b, a = null) { + // convert an array of linear-light a98-rgb values to CIE XYZ + // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + // has greater numerical precision than section 4.3.5.3 of + // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf + // but the values below were calculated from first principles + // from the chromaticity coordinates of R G B W + // see matrixmaker.html + var M = [ + [573536 / 994567, 263643 / 1420810, 187206 / 994567], + [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835], + [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835], + ]; + return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); +} +function xyz2la98rgb(x, y, z, a = null) { + // convert XYZ to linear-light a98-rgb + var M = [ + [1829569 / 896150, -506331 / 896150, -308931 / 896150], + [-851781 / 878810, 1648619 / 878810, 36519 / 878810], + [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040], + ]; + return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); +} + function interpolateHue(interpolationMethod, h1, h2) { switch (interpolationMethod) { case "longer": @@ -9098,65 +9187,53 @@ function colorMix(...args) { case "srgb": break; case "display-p3": - // @ts-ignore - values = srgb2p3values(...values); + values = srgb2p3values(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = srgb2lp3values(...values); + values = srgb2lp3values(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = srgb2a98values(...values); + values = srgb2a98values(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = srgb2prophotorgbvalues(...values); + values = srgb2prophotorgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = srgb2lsrgbvalues(...values); + values = srgb2lsrgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = srgb2rec2020values(...values); + values = srgb2rec2020values(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = srgb2xyz_d65(...values); + values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = XYZ_D65_to_D50(...srgb2xyz_d65(...values)); + 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": - // @ts-ignore - values = srgb2rgb(...values); + for (let j = 0; j < values.length; j++) { + values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + } break; case "hsl": - // @ts-ignore - values = srgb2hslvalues(...values); + values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; case "hwb": - // @ts-ignore - values = srgb2hwb(...values); + values = srgb2hwb(values[0], values[1], values[2], values[3]); break; case "lab": - // @ts-ignore - values = srgb2labvalues(...values); + values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; case "lch": - // @ts-ignore - values = srgb2lch(...values); + values = srgb2lch(values[0], values[1], values[2], values[3]); break; case "oklab": - // @ts-ignore - values = srgb2oklab(...values); + values = srgb2oklab(values[0], values[1], values[2], values[3]); break; case "oklch": - // @ts-ignore - values = srgb2oklch(...values); + values = srgb2oklch(values[0], values[1], values[2], values[3]); break; default: return null; @@ -9305,12 +9382,10 @@ function colorMix(...args) { case "xyz-d65": case "xyz-d50": if (colorSpace == "xyz-d50") { - // @ts-ignore - values = xyzd502lch(...values); + values = xyzd502lch(values[0], values[1], values[2], values[3]); } else { - // @ts-ignore - values = xyz2lchvalues(...values); + values = xyz2lchvalues(values[0], values[1], values[2], values[3]); } // @ts-ignore return { @@ -9655,6 +9730,7 @@ function* walkValues(values, root = null, filter, reverse) { (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value) ?? root, exports.WalkerEvent.Enter, // @ts-expect-error function* () { @@ -9677,8 +9753,13 @@ function* walkValues(values, root = null, filter, reverse) { const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } @@ -9709,8 +9790,13 @@ function* walkValues(values, root = null, filter, reverse) { const sliced = value.chi.slice(); for (const child of sliced) { map.set(child, value); + if (reverse) { + stack.unshift(child); + } + else { + stack.push(child); + } } - stack[reverse ? "push" : "unshift"](...sliced); } else { const values = []; @@ -9743,7 +9829,14 @@ function* walkValues(values, root = null, filter, reverse) { } } if (values.length > 0) { - stack[reverse ? "push" : "unshift"](...values); + for (const v of values) { + if (reverse) { + stack.unshift(v); + } + else { + stack.push(v); + } + } } } } @@ -9753,14 +9846,20 @@ function* walkValues(values, root = null, filter, reverse) { (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value), exports.WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } @@ -9901,7 +10000,9 @@ function evaluate(tokens) { if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }); const result = evaluateFunc(tokens[0]); @@ -9931,7 +10032,9 @@ function evaluate(tokens) { // @ts-ignore val: Math[nodes[0].val.toUpperCase()], typ: exports.EnumToken.NumberTokenType, - [LOC]: nodes[0][LOC], + [LOCSRCID]: nodes[0][LOCSRCID], + [LOCSTA]: nodes[0][LOCSTA], + [LOCEND]: nodes[0][LOCEND], }, ]; } @@ -9951,11 +10054,19 @@ function evaluate(tokens) { token = { typ: exports.EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]], - [LOC]: { ...nodes[i][LOC], end: nodes[i + 1][LOC].end }, + [LOCSRCID]: nodes[i][LOCSRCID], + [LOCSTA]: nodes[i][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], }; } else { - token = doEvaluate(nodes[i + 1], { typ: exports.EnumToken.NumberTokenType, val: -1, [LOC]: nodes[i + 1][LOC] }, exports.EnumToken.Mul); + token = doEvaluate(nodes[i + 1], { + typ: exports.EnumToken.NumberTokenType, + val: -1, + [LOCSRCID]: nodes[i + 1][LOCSRCID], + [LOCSTA]: nodes[i + 1][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], + }, exports.EnumToken.Mul); } i++; } @@ -9970,16 +10081,28 @@ function evaluate(tokens) { const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, exports.EnumToken.Add)); if (token.typ != exports.EnumToken.BinaryExpressionTokenType) { if ("val" in token && +token.val < 0) { - acc.push({ typ: exports.EnumToken.Sub, [LOC]: token[LOC] }, { + acc.push({ + typ: exports.EnumToken.Sub, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, { ...token, val: -token.val, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }); return acc; } } if (acc.length > 0 && curr[0] != exports.EnumToken.ListToken) { - acc.push({ typ: exports.EnumToken.Add, [LOC]: token[LOC] }); + acc.push({ + typ: exports.EnumToken.Add, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); } acc.push(token); return acc; @@ -9997,7 +10120,9 @@ function doEvaluate(l, r, op) { op, l, r, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -10035,15 +10160,39 @@ function doEvaluate(l, r, op) { if (typeof v1 == "number" && l.typ == exports.EnumToken.PercentageTokenType) { v1 = { typ: exports.EnumToken.FractionTokenType, - l: { typ: exports.EnumToken.NumberTokenType, val: v1, [LOC]: l[LOC] }, - r: { typ: exports.EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: exports.EnumToken.NumberTokenType, + val: v1, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: exports.EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } else if (typeof v2 == "number" && r.typ == exports.EnumToken.PercentageTokenType) { v2 = { typ: exports.EnumToken.FractionTokenType, - l: { typ: exports.EnumToken.NumberTokenType, val: v2, [LOC]: l[LOC] }, - r: { typ: exports.EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: exports.EnumToken.NumberTokenType, + val: v2, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: exports.EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } } @@ -10054,7 +10203,9 @@ function doEvaluate(l, r, op) { ...(l.typ === exports.EnumToken.NumberTokenType || l.typ === exports.EnumToken.IdenTokenType ? r : l), typ, val /* : typeof val == 'number' ? minifyNumber(val) : val */, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l?.[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (token.typ == exports.EnumToken.IdenTokenType) { // @ts-ignore @@ -10083,25 +10234,64 @@ function evaluateFunc(token) { case "sign": case "sqrt": case "exp": { + if (token.val == "tan" || token.val == "atan") { + for (let i = 0; i < values.length; i++) { + if (values[i].typ == exports.EnumToken.NumberTokenType) { + values[i] = Object.assign(values[i], { typ: exports.EnumToken.AngleTokenType, unit: "rad" }); + } + else if (values[i].typ == exports.EnumToken.AngleTokenType && values[i].unit != "rad") { + switch (values[i].unit) { + case "deg": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (2 * Math.PI), + }); + break; + } + } + } + } const value = evaluate(values); // @ts-ignore - let val = value[0].typ == exports.EnumToken.NumberTokenType + let val = value[0].typ == exports.EnumToken.NumberTokenType || value[0].typ == exports.EnumToken.AngleTokenType ? +value[0].val : // @ts-expect-error value[0].l.val / value[0].r.val; return [ - { - typ: exports.EnumToken.NumberTokenType, - val: Math[token.val](val), - [LOC]: value[0][LOC], - }, + token.val == "tan" || token.val == "atan" + ? { + typ: exports.EnumToken.AngleTokenType, + val: Math[token.val](val), + unit: "rad", + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + } + : { + typ: exports.EnumToken.NumberTokenType, + val: Math[token.val](val), + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + }, ]; } case "hypot": { const chi = values.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType, exports.EnumToken.CommaTokenType].includes(t.typ)); let all = []; let ref = chi[0]; - let value = 0; for (let i = 0; i < chi.length; i++) { // @ts-ignore const val = getValue$1(chi[i]); @@ -10109,13 +10299,14 @@ function evaluateFunc(token) { return null; } all.push(val); - value += val * val; } return [ { ...ref, - val: +Math.sqrt(value).toFixed(rem(...all)), - [LOC]: token[LOC], + val: Math.hypot(...all), + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10124,6 +10315,35 @@ function evaluateFunc(token) { case "rem": case "mod": { const chi = values.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(t.typ)); + if (token.val == "atan2") { + for (let i = 0; i < chi.length; i++) { + if (chi[i].typ == exports.EnumToken.NumberTokenType) { + chi[i] = Object.assign(chi[i], { typ: exports.EnumToken.AngleTokenType, unit: "rad" }); + } + else if (chi[i].typ == exports.EnumToken.AngleTokenType && chi[i].unit != "rad") { + switch (chi[i].unit) { + case "deg": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (2 * Math.PI), + }); + break; + } + } + } + } // https://developer.mozilla.org/en-US/docs/Web/CSS/mod const v1 = evaluate([chi[0]]); const v2 = evaluate([chi[2]]); @@ -10144,7 +10364,9 @@ function evaluateFunc(token) { { ...v1[0], val: Math.pow(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10153,8 +10375,12 @@ function evaluateFunc(token) { { ...{}, ...v1[0], + typ: exports.EnumToken.AngleTokenType, + unit: "rad", val: Math.atan2(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10162,7 +10388,9 @@ function evaluateFunc(token) { { ...v1[0], val: val2 == 0 ? val1 : val1 - Math.floor(val1 / val2) * val2, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10199,7 +10427,9 @@ function evaluateFunc(token) { { ...values[0], val: Math.log(val1) / Math.log(val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10235,7 +10465,15 @@ function evaluateFunc(token) { : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOC]: token[LOC] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -10253,7 +10491,18 @@ function inlineExpression$1(token) { result.push(token); } else { - result.push(...inlineExpression$1(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression$1(token.r)); + for (const child of inlineExpression$1(token.l)) { + result.push(child); + } + result.push({ + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); + for (const child of inlineExpression$1(token.r)) { + result.push(child); + } } } else { @@ -10316,7 +10565,13 @@ function factorToken(token) { token.val == "calc")) { if ((token.typ == exports.EnumToken.MathFunctionTokenType || token.typ == exports.EnumToken.FunctionTokenType) && token.val == "calc") { - token = { ...token, typ: exports.EnumToken.ParensTokenType, [LOC]: token[LOC] }; + token = { + ...token, + typ: exports.EnumToken.ParensTokenType, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }; // @ts-ignore delete token.val; } @@ -10354,7 +10609,9 @@ function factor(tokens, ops) { : getArithmeticOperation(tokens[i].val), l: factorToken(tokens[i - 1]), r: factorToken(tokens[i + 1]), - [LOC]: { ...tokens[i - 1][LOC], end: tokens[i + 1][LOC]?.end }, + [LOCSRCID]: tokens[i - 1][LOCSRCID], + [LOCSTA]: tokens[i - 1][LOCSTA], + [LOCEND]: tokens[i + 1][LOCEND], }); i--; } @@ -10390,7 +10647,9 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, const validKeys = names.split(""); let val = ""; if (components != null) { - allComponents.push(...components); + for (const component of components) { + allComponents.push(component); + } } // ensure all components are valid for the color space for (const component of allComponents) { @@ -10459,19 +10718,25 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, ? { typ: exports.EnumToken.NumberTokenType, val: 1, - [LOC]: b[LOC], + [LOCSRCID]: b[LOCSRCID], + [LOCSTA]: b[LOCSTA], + [LOCEND]: b[LOCEND], } : alpha.typ == exports.EnumToken.IdenTokenType && alpha.val == "none" ? { typ: exports.EnumToken.NumberTokenType, val: 0, - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha.typ == exports.EnumToken.PercentageTokenType ? { typ: exports.EnumToken.NumberTokenType, val: getNumber(alpha), - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha, }; @@ -10484,13 +10749,17 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, ? { typ: exports.EnumToken.NumberTokenType, val: 1, - [LOC]: bExp[LOC], + [LOCSRCID]: bExp[LOCSRCID], + [LOCSTA]: bExp[LOCSTA], + [LOCEND]: bExp[LOCEND], } : aExp.typ == exports.EnumToken.IdenTokenType && aExp.val == "none" ? { typ: exports.EnumToken.NumberTokenType, val: 0, - [LOC]: aExp[LOC], + [LOCSRCID]: aExp[LOCSRCID], + [LOCSTA]: aExp[LOCSTA], + [LOCEND]: aExp[LOCEND], } : aExp), }; @@ -10521,7 +10790,9 @@ function getValue(t, converted, component) { return { typ: exports.EnumToken.NumberTokenType, val: value, - [LOC]: t[LOC], + [LOCSRCID]: t[LOCSRCID], + [LOCSTA]: t[LOCSTA], + [LOCEND]: t[LOCEND], }; } return t; @@ -10564,8 +10835,10 @@ function computeComponentValue(expr, values) { { typ: exports.EnumToken.NumberTokenType, // @ts-ignore - val: "" + Math[value.val.toUpperCase()], - [LOC]: value[LOC], + val: Math[value.val.toUpperCase()], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], // @ts-ignore }); } @@ -10604,68 +10877,60 @@ function replaceValue(parent, value, newValue) { } function rgb2cmykToken(token) { - const components = rgb2srgbvalues(token); + let components = rgb2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function hsl2cmykToken(token) { - const values = hsl2srgbvalues(token); + let values = hsl2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function hwb2cmykToken(token) { const values = hwb2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function lab2cmykToken(token) { const components = lab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function lch2cmykToken(token) { const components = lch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklab2cmyk(token) { const components = oklab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklch2cmykToken(token) { const components = oklch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function color2cmykToken(token) { const values = color2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function srgb2cmykvalues(r, g, b, a = null) { const k = 1 - Math.max(r, g, b); @@ -10706,64 +10971,6 @@ function cmyktoken(values) { }; } -function a98rgb2srgbvalues(r, g, b, a = null) { - // @ts-ignore - return xyz2srgb(...la98rgb2xyz(...a98rgb2la98(r, g, b, a))); -} -function srgb2a98values$1(r, g, b, a = null) { - // @ts-ignore - return la98rgb2a98rgb(...xyz2la98rgb(...srgb2xyz(r, g, b, a))); -} -// a98-rgb functions -function a98rgb2la98(r, g, b, a = null) { - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - return [r, g, b] - .map(function (val) { - let sign = val < 0 ? -1 : 1; - let abs = Math.abs(val); - return sign * Math.pow(abs, 563 / 256); - }) - .concat(a == null || a == 1 ? [] : [a]); -} -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] - .map(function (val) { - let sign = val < 0 ? -1 : 1; - let abs = Math.abs(val); - return sign * Math.pow(abs, 256 / 563); - }) - .concat(a == null || a == 1 ? [] : [a]); -} -function la98rgb2xyz(r, g, b, a = null) { - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - var M = [ - [573536 / 994567, 263643 / 1420810, 187206 / 994567], - [591459 / 1989134, 6239551 / 9945670, 374412 / 4972835], - [53769 / 1989134, 351524 / 4972835, 4929758 / 4972835], - ]; - return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); -} -function xyz2la98rgb(x, y, z, a = null) { - // convert XYZ to linear-light a98-rgb - var M = [ - [1829569 / 896150, -506331 / 896150, -308931 / 896150], - [-851781 / 878810, 1648619 / 878810, 36519 / 878810], - [16779 / 1248040, -147721 / 1248040, 1266979 / 1248040], - ]; - return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); -} - var ValidationTokenEnum; (function (ValidationTokenEnum) { ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root"; @@ -10944,7 +11151,7 @@ function getTokenType(token, position, currentPosition) { [LOC]: pos, }; } - if (isPseudo$1(token)) { + if (isPseudo(token)) { return { typ: ValidationTokenEnum.PseudoClassToken, val: token, @@ -11734,11 +11941,8 @@ const allValues = config$3.declarations.all.syntax.split(/[\s|]+/g); /** * @type {Array.} */ -const funcTypes = [ - ...tokensfuncDefMap.values(), - exports.EnumToken.FunctionTokenType, - exports.EnumToken.PseudoClassFuncTokenType, -]; +const funcTypes = Array.from(tokensfuncDefMap.values()); +funcTypes.push(exports.EnumToken.FunctionTokenType, exports.EnumToken.PseudoClassFuncTokenType); /** * trim leading and trailing whitespace * @param tokens @@ -12061,7 +12265,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${exports.EnumToken[stream[i].typ]}`, node: stream[i], // @ts-expect-error - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }, ], }; @@ -12096,7 +12300,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } } @@ -12115,7 +12321,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Nesting selector is not allowed`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12149,7 +12355,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected combinator ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12193,7 +12399,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12244,7 +12450,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${exports.EnumToken[slice[0].typ]}`, node: slice[0], // @ts-expect-error - location: options.source.getSourceLocation(slice[0][LOC].sta), + location: options.source.getSourceLocation(slice[0][LOCSTA]), }, ], }; @@ -12256,8 +12462,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOC]!.sta.lin}:${ - // slice[0][LOC]!.sta.col + // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOCSTA].lin}:${ + // slice[0][LOCSTA].col // }`, // node: slice[0], // location: slice[0][LOC], @@ -12295,8 +12501,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -12328,8 +12534,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -12358,7 +12564,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12387,7 +12593,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } stack.pop(); @@ -12401,7 +12609,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12423,7 +12631,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unsupported selector token ${exports.EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -12449,13 +12657,15 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unmatched token ${exports.EnumToken[stack.at(-1).typ]}`, node: stack.at(-1), // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)[LOCSTA]), }, ], }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** @@ -12496,7 +12706,7 @@ function matchAllSyntaxes(syntaxes, context, options) { message: result.errors[0]?.message || "could not match syntax", node: result.token, syntax: result.syntaxToken, - location: options.source.getSourceLocation((result.token?.[LOC] ?? context.tokens.at(-1)?.[LOC]).sta), + location: options.source.getSourceLocation((result.token?.[LOCSTA] ?? context.tokens.at(-1)?.[LOCSTA])), }, ] : result.errors, @@ -12591,7 +12801,7 @@ function matchOccurenceSyntax(syntax, context, options) { action: "drop", message: "could not match syntax", node: context.peek(), - // location: options.source!.getSourceLocation(context.peek()?.[LOC]!.sta), + // location: options.source!.getSourceLocation(context.peek()?.[LOCSTA]), }, ], syntaxToken: null, @@ -14338,8 +14548,8 @@ function convertColor(token, to) { if (args.at(-2)?.typ === exports.EnumToken.LiteralTokenType && "/" === args.at(-2)?.val) { args.splice(args.length - 2, 1); } - // @ts-expect-error - token = alpha(...trimArray(args.slice(1))); + let values = trimArray(args.slice(1)); + token = alpha(values[0], values[1]); if (token == null) { return null; } @@ -14374,10 +14584,15 @@ function convertColor(token, to) { } let { cal, ...tk } = { ...token, - chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], + chi: token.val == "color" ? [chi[offset]] : [], kin: exports.ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + for (const t of Object.values(components)) { + tk.chi.push(t); + } + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } @@ -14728,46 +14943,28 @@ function color2colorToken(token, to) { return values2colortoken(values, to); } function srgb2srgbcolorspace(val, to) { - const values = []; switch (to) { case exports.ColorType.SRGB: - values.push(...val); - break; + return val; case exports.ColorType.SRGB_LINEAR: - // @ts-ignore - values.push(...srgb2lsrgbvalues(...val)); - break; + return srgb2lsrgbvalues(val[0], val[1], val[2], val[3]); case exports.ColorType.DISPLAY_P3: - // @ts-ignore - values.push(...srgb2p3values(...val)); - break; + return srgb2p3values(val[0], val[1], val[2], val[3]); case exports.ColorType.DISPLAY_P3_LINEAR: - // @ts-ignore - values.push(...srgb2lp3values(...val)); - break; + return srgb2lp3values(val[0], val[1], val[2], val[3]); case exports.ColorType.PROPHOTO_RGB: - // @ts-ignore - values.push(...srgb2prophotorgbvalues(...val)); - break; + return srgb2prophotorgbvalues(val[0], val[1], val[2], val[3]); case exports.ColorType.A98_RGB: - // @ts-ignore - values.push(...srgb2a98values$1(...val)); - break; + return srgb2a98values(val[0], val[1], val[2], val[3]); case exports.ColorType.REC2020: - // @ts-ignore - values.push(...srgb2rec2020values(...val)); - break; + return srgb2rec2020values(val[0], val[1], val[2], val[3]); case exports.ColorType.XYZ: case exports.ColorType.XYZ_D65: - // @ts-ignore - values.push(...srgb2xyz(...val)); - break; + return srgb2xyz(val[0], val[1], val[2], val[3]); case exports.ColorType.XYZ_D50: - // @ts-ignore - values.push(...srgb2xyz_d65(...val)); - break; + return srgb2xyz_d65(val[0], val[1], val[2], val[3]); } - return values; + return null; } function minmax(value, min, max) { return value < min ? min : value > max ? max : value; @@ -14781,37 +14978,29 @@ function color2srgbvalues(token) { let values = components.map((val) => getNumber(val)); switch (colorSpace.val) { case "display-p3": - // @ts-ignore - values = p32srgbvalues(...values); + values = p32srgbvalues(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = lp32srgbvalues(...values); + values = lp32srgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = lsrgb2srgbvalues(...values); + values = lsrgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = prophotorgb2srgbvalues(...values); + values = prophotorgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = a98rgb2srgbvalues(...values); + values = a98rgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = rec20202srgb(...values); + values = rec20202srgb(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = xyz2srgb(...values); + values = xyz2srgb(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = xyzd502srgb(...values); + values = xyzd502srgb(values[0], values[1], values[2], values[3]); break; } if (values.length == 4) { @@ -14820,7 +15009,11 @@ function color2srgbvalues(token) { return values; } function values2colortoken(values, to) { + // @ts-expect-error values = srgb2srgbcolorspace(values, to); + if (values == null) { + return null; + } const chi = [ { typ: exports.EnumToken.NumberTokenType, val: values[0] }, { typ: exports.EnumToken.NumberTokenType, val: values[1] }, @@ -14918,7 +15111,7 @@ function okLabDistance(color1, color2) { if (okLab1[3] != null || okLab2[3] != null) { diff.push((okLab1[3] ?? 1) - (okLab2[3] ?? 1)); } - return toPrecisionValue(Math.hypot(...diff)); + return toPrecisionValue(Math.hypot(diff[0], diff[1], diff[2], diff[3] ?? 0)); } /** * Check if two colors are close in okLab space. @@ -15046,7 +15239,12 @@ function getColorSpace(color) { // https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token // '\\' const REVERSE_SOLIDUS = 0x5c; -const dimensionUnits = new Set([ +const flexUnits = ["fr"]; +const frequencyUnits = ["hz", "khz"]; +const timeUnits = ["ms", "s"]; +const angleUnits = ["rad", "turn", "deg", "grad"]; +const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; +const dimensionUnits = [ "q", "cap", "ch", @@ -15090,7 +15288,7 @@ const dimensionUnits = new Set([ "vmax", "vmin", "vw", -]); +]; // https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions // https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions const pseudoAliasMap = { @@ -15227,19 +15425,19 @@ const pseudoAliasMap = { // renamed standard properties const renamedStandardProperties = new Map([["color-adjust", "print-color-adjust"]]); function isLength(dimension) { - return "unit" in dimension && dimensionUnits.has(dimension.unit.toLowerCase()); + return "unit" in dimension && dimensionUnits.includes(dimension.unit.toLowerCase()); } function isResolution(dimension) { - return "unit" in dimension && ["dpi", "dpcm", "dppx", "x"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && resolutionUnits.includes(dimension.unit.toLowerCase()); } function isAngle(dimension) { - return "unit" in dimension && ["rad", "turn", "deg", "grad"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && angleUnits.includes(dimension.unit.toLowerCase()); } function isTime(dimension) { - return "unit" in dimension && ["ms", "s"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && timeUnits.includes(dimension.unit.toLowerCase()); } function isFrequency(dimension) { - return "unit" in dimension && ["hz", "khz"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && frequencyUnits.includes(dimension.unit.toLowerCase()); } /** * Reduce color stops @@ -15262,7 +15460,9 @@ function reduceColorStops(stops) { if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.PercentageTokenType, val: ((k - 1) * 100) / n }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -15286,7 +15486,9 @@ function reduceColorStops(stops) { if (stops.length > 0) { stops.push({ typ: exports.EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (let m = 0; m < parts[j].length; m++) { + stops.push(parts[j][m]); + } } } return stops; @@ -15384,7 +15586,9 @@ function reduceConicColorStops(stops) { if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.AngleTokenType, val: ((k - 1) * 100) / n, unit: "deg" }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -15407,7 +15611,9 @@ function reduceConicColorStops(stops) { if (stops.length > 0) { stops.push({ typ: exports.EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (const token of parts[j]) { + stops.push(token); + } } } return stops; @@ -15703,11 +15909,10 @@ function isColor(token, errors) { return true; } else { - const keywords = ["from", "none"]; // @ts-ignore if (["rgb", "hsl", "hwb", "lab", "lch", "oklab", "oklch"].some((t) => equalsIgnoreCase(t, token.val))) { - // @ts-ignore - keywords.push("alpha", ...token.val.slice(-3).split("")); + for (const keyword of token.val.slice(-3).split("")) { + } } // @ts-ignore for (const v of token.chi) { @@ -15864,7 +16069,7 @@ function isNonPrintable(codepoint) { codepoint == 0x7f || (codepoint >= 0xe && codepoint <= 0x1f)); } -function isPseudo$1(name) { +function isPseudo(name) { return (name.charAt(0) == ":" && ((name.endsWith("(") && isIdent(name.charAt(1) == ":" ? name.slice(2, -1) : name.slice(1, -1))) || isIdent(name.charAt(1) == ":" ? name.slice(2) : name.slice(1)))); @@ -15872,75 +16077,6 @@ function isPseudo$1(name) { function isHash(name) { return name.charAt(0) == "#" && isIdentStart(name.charCodeAt(1)); } -const isNumber = memoize(function (name) { - let codepoint = name.charCodeAt(0); - let i = 0; - const j = name.length; - if (j == 1 && !isDigit(codepoint)) { - return false; - } - // '+' '-' - if ([0x2b, 0x2d].includes(codepoint)) { - i++; - } - // consume digits - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // '.' 'E' 'e' - if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { - break; - } - return false; - } - // '.' - if (codepoint == 0x2e) { - if (!isDigit(name.charCodeAt(++i))) { - return false; - } - } - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - i++; - break; - } - return false; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - // if (i == j) { - // return false; - // } - codepoint = name.charCodeAt(i + 1); - // '+' '-' - // if ([0x2b, 0x2d].includes(codepoint)) { - // i++; - // } - codepoint = name.charCodeAt(i + 1); - if (!isDigit(codepoint)) { - return false; - } - } - // while (++i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isDigit(codepoint)) { - // return false; - // } - // } - return true; -}); -function isPercentage(name) { - return name.endsWith("%") && isNumber(name.slice(0, -1)); -} function isFlex(dimension) { return "unit" in dimension && "fr" == dimension.unit.toLowerCase(); } @@ -15981,9 +16117,9 @@ function parseDimension(name) { else if (isResolution(dimension)) { // @ts-ignore dimension.typ = exports.EnumToken.ResolutionTokenType; - if (dimension.unit == "dppx") { - dimension.unit = "x"; - } + // if (dimension.unit == "dppx") { + // dimension.unit = "x"; + // } } else if (isFrequency(dimension)) { // @ts-ignore @@ -15995,22 +16131,6 @@ function parseDimension(name) { } return dimension; } -function isHexColor(name) { - if (name.charAt(0) != "#" || ![4, 5, 7, 9].includes(name.length)) { - return false; - } - for (let chr of name.slice(1)) { - let codepoint = chr.charCodeAt(0); - if (!isDigit(codepoint) && - // A-F - !(codepoint >= 0x41 && codepoint <= 0x46) && - // a-f - !(codepoint >= 0x61 && codepoint <= 0x66)) { - return false; - } - } - return true; -} function isFunction(name) { return name.endsWith("(") && isIdent(name.slice(0, -1)); } @@ -16105,14 +16225,11 @@ function toPrecisionValue(value, precision = colorPrecision) { value = Math.round(value * div) / div; return Math.abs(value) < epsilon ? 0 : value; } -function toPrecisionAngle(angle, precision = colorPrecision, correctValue = true) { +function toPrecisionAngle(angle, precision = anglePrecision, correctValue = true) { angle = toPrecisionValue(angle, precision); if (correctValue && Math.abs(angle) >= 360) { angle %= 360; } - if (Math.abs(angle) < anglePrecision) { - angle = 0; - } if (correctValue && angle < 0) { angle += 360; } @@ -16228,8 +16345,8 @@ function replaceAstNodes(tokens, root) { // typ: EnumToken.ResolutionTokenType, // unit: "x", // }); - // } - // else + // } + // else if (isPseudClass && value.typ == exports.EnumToken.PseudoElementTokenType) { // @ts-ignore value.typ = exports.EnumToken.PseudoClassTokenType; @@ -16242,7 +16359,7 @@ function replaceAstNodes(tokens, root) { const set = new Set(); const split = splitTokenList(tokens, [exports.EnumToken.CommaTokenType]); tokens.length = 0; - tokens.push(...split.reduce((acc, curr) => { + for (const token of split.reduce((acc, curr) => { const str = curr.reduce((acc, curr) => acc + renderValue(curr), ""); if (set.has(str)) { return acc; @@ -16254,7 +16371,9 @@ function replaceAstNodes(tokens, root) { }); } return acc.concat(curr); - }, [])); + }, [])) { + tokens.push(token); + } } return result; } @@ -16472,52 +16591,28 @@ class ComputePrefixFeature { // right bottom → left top to top left const replacements = []; if (key === "left top left bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }); } else if (key === "left bottom left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }); } else if (key === "left top right top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } else if (key === "left top right bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left bottom") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "bottom" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } else if (key === "left bottom right top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "right" }); } else if (key === "right bottom left top") { - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: exports.EnumToken.WhitespaceTokenType }); - replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: exports.EnumToken.IdenTokenType, val: "to" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "top" }, { typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "left" }); } tokens.splice(0, i, ...replacements); let checkStop = true; @@ -16530,7 +16625,10 @@ class ComputePrefixFeature { } if (tokens[i].typ === exports.EnumToken.FunctionTokenType) { if (equalsIgnoreCase(tokens[i].val, "to")) { - colorStop.push(tokens[checkStopIndex], ...tokens[i].chi); + colorStop.push(tokens[checkStopIndex]); + for (const token of tokens[i].chi) { + colorStop.push(token); + } tokens.splice(checkStopIndex, i - checkStopIndex + 1); i = checkStopIndex; checkStop = false; @@ -16558,12 +16656,16 @@ class ComputePrefixFeature { } } if (colorStop.length > 0) { - tokens.push(...colorStop); + for (const t of colorStop) { + tokens.push(t); + } } if (type !== "") { token.val = type; token.chi.length = 0; - token.chi.push(...tokens); + for (const t of tokens) { + token.chi.push(t); + } } } /** @@ -16634,7 +16736,9 @@ class ComputePrefixFeature { i++; } } - colorStops.push(...tokens.slice(i)); + for (let m = i; m < tokens.length; m++) { + colorStops.push(tokens[m]); + } tokens.length = 0; if (form.length > 0 || size.length > 0) { if (form.length === 0) { @@ -16642,17 +16746,27 @@ class ComputePrefixFeature { } if (size.length > 0) { form.push({ typ: exports.EnumToken.WhitespaceTokenType }); - form.push(...size); + for (const token of size) { + form.push(token); + } } if (positions.length > 0) { - form.push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + form.push({ typ: exports.EnumToken.WhitespaceTokenType }, { typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const position of positions) { + form.push(position); + } + } + for (const token of form) { + tokens.push(token); } - tokens.push(...form, { typ: exports.EnumToken.CommaTokenType }); + tokens.push({ typ: exports.EnumToken.CommaTokenType }); } token.val = equalsIgnoreCase(token.val, "-webkit-repeating-radial-gradient") ? "repeating-radial-gradient" : "radial-gradient"; - tokens.push(...colorStops); + for (const colorStop of colorStops) { + tokens.push(colorStop); + } return tokens; } } @@ -16660,13 +16774,14 @@ class ComputePrefixFeature { function inlineExpression(token) { const result = []; if (token.typ == exports.EnumToken.BinaryExpressionTokenType) { + const chi = inlineExpression(token.l); + chi.push({ typ: token.op }); + for (const child of inlineExpression(token.r)) { + chi.push(child); + } result.push({ typ: exports.EnumToken.ParensTokenType, - chi: [ - ...inlineExpression(token.l), - { typ: token.op }, - ...inlineExpression(token.r), - ], + chi, }); } else { @@ -16978,7 +17093,9 @@ class PropertySet { // @ts-ignore acc.push({ ...this.config.separator, typ: exports.EnumToken.LiteralTokenType }); } - acc.push(...curr); + for (const token of curr) { + acc.push(token); + } return acc; }, []), }, @@ -18700,10 +18817,17 @@ class PropertyMap { else { if (current == tokens[property].length) { tokens[property].push([]); - tokens[property][current].push(...defaults); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } else { - tokens[property][current].push({ typ: exports.EnumToken.WhitespaceTokenType }, ...defaults); + tokens[property][current].push({ + typ: exports.EnumToken.WhitespaceTokenType, + }); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } } } @@ -18720,7 +18844,9 @@ class PropertyMap { if (acc.length > 0) { acc.push({ ...separator }); } - acc.push(...curr); + for (let i = 0; i < curr.length; i++) { + acc.push(curr[i]); + } return acc; }, []), }); @@ -18855,7 +18981,9 @@ class PropertyMap { }; const values = [...this.declarations.values()].reduce((acc, curr) => { if (curr instanceof PropertySet) { - acc.push(...curr); + for (const declaration of curr) { + acc.push(declaration); + } } else { acc.push(curr); @@ -19077,7 +19205,7 @@ class PropertyMap { else if (acc[i].length > 0) { acc[i].push({ typ: exports.EnumToken.WhitespaceTokenType }); } - acc[i].push(...values.reduce((acc, curr) => { + for (const v of values.reduce((acc, curr) => { if (acc.length > 0) { // @ts-ignore acc.push({ @@ -19091,7 +19219,9 @@ class PropertyMap { // @ts-ignore acc.push(curr); return acc; - }, [])); + }, [])) { + acc[i].push(v); + } } } return acc; @@ -19109,7 +19239,9 @@ class PropertyMap { return acc; }, [])); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); if (this.config.mapping != null) { @@ -19177,10 +19309,13 @@ class PropertyMap { } matchTypes(declaration) { const patterns = this.pattern.slice(); - const values = [...declaration.val]; + const values = []; let i; let j; const map = new Map(); + for (i = 0; i < declaration.val.length; i++) { + values.push(declaration.val[i]); + } for (i = 0; i < patterns.length; i++) { for (j = 0; j < values.length; j++) { if (!map.has(patterns[i])) { @@ -19283,7 +19418,7 @@ function hashId(input, length = 6) { chars.push(FIRST_ALPHABET[n % FIRST_ALPHABET.length]); // Remaining characters for (let i = 1; i < length; i++) { - n = (n + chars.length + i) % FULL_ALPHABET.length; + n = (n + chars.length * i) % FULL_ALPHABET.length; chars.push(FULL_ALPHABET[n]); } return chars.join(""); @@ -19314,13 +19449,13 @@ function toSortedString(input) { * @returns */ function objectHash(object) { - return hashId(toSortedString(object)); + return hashCode(toSortedString(object)).toString(16); } /** * convert input to hex * @param input */ -function toHex(input) { +function toHex(input, length) { let result = ""; if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) { for (const byte of Array.from(new Uint8Array(input))) { @@ -19394,6 +19529,7 @@ const config = getConfig(); class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; + // ketsey = new Map; constructor(options = {}) { this.options = options; this.declarations = new Map(); @@ -19410,15 +19546,12 @@ class PropertyList { let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != exports.EnumToken.DeclarationNodeType - ? null - : declaration.nam.toLowerCase(); + name = declaration.typ != exports.EnumToken.DeclarationNodeType ? null : declaration.nam; if (declaration[STATE] == exports.EnumAstNodeStatus.Invalid || declaration[STATE] == exports.EnumAstNodeStatus.Unknown || declaration[STATE] == exports.EnumAstNodeStatus.ValidationFailed || declaration.typ != exports.EnumToken.DeclarationNodeType || - "composes" === name || + equalsIgnoreCase("composes", name) || (typeof this.options.removeDuplicateDeclarations === "string" && this.options.removeDuplicateDeclarations === name) || (Array.isArray(this.options.removeDuplicateDeclarations) @@ -19446,7 +19579,21 @@ class PropertyList { } // do not compute shorthand for invalid declarations if (declaration[STATE] !== exports.EnumAstNodeStatus.Validated) { - this.declarations.set(declaration.nam, declaration); + // const key = objectHash(declaration); + // if (!this.ketsey.has(key)) { + // this.ketsey.set(key, [declaration.nam]); + // console.error( + // `Adding declaration : ${(declaration).nam} with key : ${key}` + // ) + // } + // else { + // console.error( + // `Duplicate declaration found: ${(declaration).nam} with key : [ ${key} => ${this.ketsey.get(key)} ]` + // ) + // console.error(JSON.stringify(toSortedString(declaration))) + // this.ketsey.get(key).push(declaration.nam); + // } + this.declarations.set(objectHash(declaration), declaration); return this; } let propertyName = declaration.nam; @@ -19562,7 +19709,9 @@ class PropertyList { } if (values != declaration.val) { declaration.val.length = 0; - declaration.val.push(...values); + for (const v of values) { + declaration.val.push(v); + } } } [Symbol.iterator]() { @@ -19609,7 +19758,7 @@ class ComputeShorthandFeature { options.features.push(new ComputeShorthandFeature(options)); } } - run(ast, options = {}, parent, context) { + run(ast, options) { if (!("chi" in ast)) { return null; } @@ -19635,15 +19784,20 @@ class ComputeShorthandFeature { // @ts-ignore const node = ast.chi[l]; if (node.typ == exports.EnumToken.DeclarationNodeType) { - properties.add(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + properties.add(ast.chi[m]); + } } else { - rules.push(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + rules.push(ast.chi[m]); + } } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi.length = 0; + // @ts-expect-error + ast.chi.push(...properties, ...rules); return ast; } } @@ -19671,57 +19825,15 @@ class ComputeCalcExpressionFeature { continue; } const set = new Set(); - for (const { value, parent } of walkValues(node.val, node, { - event: exports.WalkerEvent.Enter, - // @ts-ignore - fn(node, parent) { - if (parent != null && - // @ts-ignore - parent.typ == exports.EnumToken.DeclarationNodeType && - // @ts-ignore - parent.val.length == 1 && - (node.typ === exports.EnumToken.MathFunctionTokenType || node.typ === exports.EnumToken.FunctionTokenType) && - mathFuncs.includes(node.val) && - node.chi.length == 1 && - node.chi[0].typ == exports.EnumToken.IdenTokenType) { - return exports.WalkerOptionEnum.Ignore; - } - if ((node.typ === exports.EnumToken.WildCardFunctionTokenType && node.val == "var") || - (!mathFuncs.includes(parent.val) && - [ - exports.EnumToken.MathFunctionTokenType, - exports.EnumToken.ColorTokenType, - exports.EnumToken.DeclarationNodeType, - exports.EnumToken.ImageFunc, - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.StyleSheetNodeType, - ].includes(parent?.typ))) { - return null; - } + for (const { value, parent } of walkValues(node.val, node)) { + if (parent?.typ == exports.EnumToken.BinaryExpressionTokenType) { + continue; + } + if (value.typ == exports.EnumToken.BinaryExpressionTokenType) { // @ts-ignore - const slice = (node.typ == exports.EnumToken.FunctionTokenType || node.typ == exports.EnumToken.MathFunctionTokenType - ? node.chi - : node.typ == exports.EnumToken.DeclarationNodeType - ? node.val - : node.chi)?.slice(); - if (slice != null && - (node.typ === exports.EnumToken.MathFunctionTokenType || - (node.typ == exports.EnumToken.FunctionTokenType && - mathFuncs.includes(node.val)))) { - // @ts-ignore - const key = "chi" in node ? "chi" : "val"; - const str1 = renderValue({ ...node, [key]: slice }); - const str2 = renderValue(node); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); - if (str1.length < str2.length) { - // @ts-ignore - node[key] = slice; - } - return exports.WalkerOptionEnum.Ignore; - } - return null; - }, - })) { + replaceNodeOrValue(parent, value, evaluate([value])); + continue; + } if (value != null && tokensfuncSet.has(value.typ)) { if (!set.has(value)) { set.add(value); @@ -19768,7 +19880,9 @@ class ComputeCalcExpressionFeature { typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], } : values[0]); break; @@ -19782,7 +19896,9 @@ class ComputeCalcExpressionFeature { typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; } @@ -19798,8 +19914,9 @@ class ComputeCalcExpressionFeature { } } +const identityMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); function identity() { - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + return identityMatrix.slice(); } function normalize$1(point) { const [x, y, z] = point; @@ -19813,37 +19930,64 @@ function dot(point1, point2) { return point1[0] * point2[0] + point1[1] * point2[1] + point1[2] * point2[2]; } function multiply(matrixA, matrixB) { - let result = new Array(16).fill(0); - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - for (let k = 0; k < 4; k++) { - // Utiliser l'indexation linéaire pour accéder aux éléments - // Pour une matrice 4x4, l'index est (row * 4 + col) - result[j * 4 + i] += matrixA[k * 4 + i] * matrixB[j * 4 + k]; - } - } - } + const result = new Float32Array(16); + result[0] = matrixA[0] * matrixB[0] + matrixA[4] * matrixB[1] + matrixA[8] * matrixB[2] + matrixA[12] * matrixB[3]; + result[1] = matrixA[1] * matrixB[0] + matrixA[5] * matrixB[1] + matrixA[9] * matrixB[2] + matrixA[13] * matrixB[3]; + result[2] = matrixA[2] * matrixB[0] + matrixA[6] * matrixB[1] + matrixA[10] * matrixB[2] + matrixA[14] * matrixB[3]; + result[3] = matrixA[3] * matrixB[0] + matrixA[7] * matrixB[1] + matrixA[11] * matrixB[2] + matrixA[15] * matrixB[3]; + result[4] = matrixA[0] * matrixB[4] + matrixA[4] * matrixB[5] + matrixA[8] * matrixB[6] + matrixA[12] * matrixB[7]; + result[5] = matrixA[1] * matrixB[4] + matrixA[5] * matrixB[5] + matrixA[9] * matrixB[6] + matrixA[13] * matrixB[7]; + result[6] = matrixA[2] * matrixB[4] + matrixA[6] * matrixB[5] + matrixA[10] * matrixB[6] + matrixA[14] * matrixB[7]; + result[7] = matrixA[3] * matrixB[4] + matrixA[7] * matrixB[5] + matrixA[11] * matrixB[6] + matrixA[15] * matrixB[7]; + result[8] = + matrixA[0] * matrixB[8] + matrixA[4] * matrixB[9] + matrixA[8] * matrixB[10] + matrixA[12] * matrixB[11]; + result[9] = + matrixA[1] * matrixB[8] + matrixA[5] * matrixB[9] + matrixA[9] * matrixB[10] + matrixA[13] * matrixB[11]; + result[10] = + matrixA[2] * matrixB[8] + matrixA[6] * matrixB[9] + matrixA[10] * matrixB[10] + matrixA[14] * matrixB[11]; + result[11] = + matrixA[3] * matrixB[8] + matrixA[7] * matrixB[9] + matrixA[11] * matrixB[10] + matrixA[15] * matrixB[11]; + result[12] = + matrixA[0] * matrixB[12] + matrixA[4] * matrixB[13] + matrixA[8] * matrixB[14] + matrixA[12] * matrixB[15]; + result[13] = + matrixA[1] * matrixB[12] + matrixA[5] * matrixB[13] + matrixA[9] * matrixB[14] + matrixA[13] * matrixB[15]; + result[14] = + matrixA[2] * matrixB[12] + matrixA[6] * matrixB[13] + matrixA[10] * matrixB[14] + matrixA[14] * matrixB[15]; + result[15] = + matrixA[3] * matrixB[12] + matrixA[7] * matrixB[13] + matrixA[11] * matrixB[14] + matrixA[15] * matrixB[15]; return result; } function inverse(matrix) { // Create augmented matrix [matrix | identity] let augmented = [ - ...matrix.slice(0, 4), + matrix[0], + matrix[1], + matrix[2], + matrix[3], 1, 0, 0, 0, - ...matrix.slice(4, 8), + matrix[4], + matrix[5], + matrix[6], + matrix[7], 0, 1, 0, 0, - ...matrix.slice(8, 12), + matrix[8], + matrix[9], + matrix[10], + matrix[11], 0, 0, 1, 0, - ...matrix.slice(12, 16), + matrix[12], + matrix[13], + matrix[14], + matrix[15], 0, 0, 0, @@ -19939,11 +20083,11 @@ function decompose(original) { row1[0] * row2[1] - row1[1] * row2[0], ]; // Compute scale - const scaleX = Math.hypot(...row0); + const scaleX = Math.hypot(row0[0], row0[1], row0[2]); const row0Norm = normalize$1(row0); const skewXY = dot(row0Norm, row1); const row1Proj = [row1[0] - skewXY * row0Norm[0], row1[1] - skewXY * row0Norm[1], row1[2] - skewXY * row0Norm[2]]; - const scaleY = Math.hypot(...row1Proj); + const scaleY = Math.hypot(row1Proj[0], row1Proj[1], row1Proj[2]); const row1Norm = normalize$1(row1Proj); const skewXZ = dot(row0Norm, row2); const skewYZ = dot(row1Norm, row2); @@ -19954,7 +20098,7 @@ function decompose(original) { ]; const row2Norm = normalize$1(row2Proj); const determinant = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2]; - const scaleZ = Math.hypot(...row2Proj) * (determinant < 0 ? -1 : 1); + const scaleZ = Math.hypot(row2Proj[0], row2Proj[1], row2Proj[2]) * (determinant < 0 ? -1 : 1); // Build rotation matrix from orthonormalized vectors const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0]; const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1]; @@ -20475,7 +20619,7 @@ function minify$1(matrix) { function eqMatrix(a, b) { let mat = identity(); let tmp = identity(); - const data = (Array.isArray(a) ? a : parseMatrix(a)); + const data = (Array.isArray(a) || ArrayBuffer.isView(a) ? a : parseMatrix(a)); for (const transform of b) { tmp = computeMatrix([transform], identity()); if (tmp == null) { @@ -20497,7 +20641,7 @@ function eqMatrix(a, b) { } function minifyTransformFunctions(transform) { const name = transform.val.toLowerCase(); - if ("skewx" == name) { + if ("skewX" == name) { transform.val = "skew"; return transform; } @@ -20537,10 +20681,10 @@ function minifyTransformFunctions(transform) { } const ignoredValue = name.startsWith("scale") ? 1 : 0; const t = new Set(["x", "y", "z"]); - let i = 3; - while (i--) { + for (let i = 0; i < 3; i++) { + const axis = i == 0 ? "x" : i == 1 ? "y" : "z"; if (values.length <= i || values[i].val == ignoredValue) { - t.delete(i == 0 ? "x" : i == 1 ? "y" : "z"); + t.delete(axis); } } if (name == "translate3d" || name == "translate") { @@ -20630,6 +20774,7 @@ function compute(transformLists) { stripCommaToken(transformLists); let matrix = identity(); let mat; + let transforms; const cumulative = []; for (const transformList of splitTransformList(transformLists)) { mat = computeMatrix(transformList, identity()); @@ -20637,7 +20782,10 @@ function compute(transformLists) { return null; } matrix = multiply(matrix, mat); - cumulative.push(...(minify$1(mat) ?? transformList)); + transforms = minify$1(mat) ?? transformList; + for (let i = 0; i < transforms.length; i++) { + cumulative.push(transforms[i]); + } } const serialized = serialize(matrix); if (cumulative.length > 0) { @@ -20653,11 +20801,66 @@ function compute(transformLists) { }); } } - return { + const result = { matrix: serialize(toZero(matrix)), cumulative, minified: minify$1(matrix) ?? [serialized], }; + // valid identity matrix + if ((result.minified.length == 1 && + result.minified[0].typ == exports.EnumToken.IdenTokenType && + result.minified[0].val == "none") || + (result.cumulative.length == 1 && + result.cumulative[0].typ == exports.EnumToken.IdenTokenType && + result.cumulative[0].val == "none") || + (result.matrix?.typ == exports.EnumToken.IdenTokenType && result.matrix.val == "none")) { + // all transform function arguments must be 0 or scale(1) + for (const transform of transformLists) { + switch (transform.val) { + case "translate": + case "translateX": + case "translateY": + case "translateZ": + case "translate3d": + case "rotate": + case "rotateX": + case "rotateY": + case "rotateZ": + case "rotate3d": + case "skew": + case "skewX": + case "skewY": + for (const child of transform.chi) { + if (child.typ == exports.EnumToken.WhitespaceTokenType || child.typ == exports.EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != exports.EnumToken.AngleTokenType && + child.typ != exports.EnumToken.NumberTokenType && + child.typ != exports.EnumToken.PercentageTokenType) || + getNumber(child) != 0) { + return null; + } + } + break; + case "scale": + case "scaleX": + case "scaleY": + case "scaleZ": + case "scale3d": + for (const child of transform.chi) { + if (child.typ == exports.EnumToken.WhitespaceTokenType || child.typ == exports.EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != exports.EnumToken.NumberTokenType && child.typ != exports.EnumToken.PercentageTokenType) || + getNumber(child) != 1) { + return null; + } + } + break; + } + } + } + return result; } function computeMatrix(transformList, matrixVar) { let values = []; @@ -20779,7 +20982,7 @@ function computeMatrix(transformList, matrixVar) { if (values.length != 3) { return null; } - matrixVar = scale3d(...values, matrixVar); + matrixVar = scale3d(values[0], values[1], values[2], matrixVar); break; } if (transformList[i].val == "scale") { @@ -20956,7 +21159,7 @@ class TransformCssFeature { } } run(ast) { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } let i = 0; @@ -21259,7 +21462,9 @@ function substituteIfElseNode(declaration, node, wrapper, parentWrapper, cache) chi: [], }); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } atRule[TOKENS] = [{ typ: exports.EnumToken.ParensTokenType, chi: left.chi.slice() }]; const minify = atRule.nam !== "supports"; @@ -21284,7 +21489,9 @@ function substituteIfElseNode(declaration, node, wrapper, parentWrapper, cache) atRule[TOKENS] = [left]; atRule.val = atRule[TOKENS].reduce((acc, curr) => acc + renderValue(curr), ""); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } clonedDeclaration = cloneNode(declaration, true, nodeMap); replaceNodeOrValue(nodeMap.get(targetWrapper.typ === exports.EnumToken.WildCardFunctionTokenType ? targetParentWrapper : targetWrapper), nodeMap.get(targetWrapper.typ === exports.EnumToken.WildCardFunctionTokenType ? targetWrapper : node), node.r.at(-1)?.typ === exports.EnumToken.SemiColonTokenType @@ -21368,3364 +21575,2462 @@ var allFeatures = /*#__PURE__*/Object.freeze({ TransformCssFeature: TransformCssFeature }); -// from https://github.com/Rich-Harris/vlq/tree/master -// credit: Rich Harris -const integer_to_char = {}; -const char_to_integer = {}; -let i = 0; -for (const char of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=') { - char_to_integer[char] = i; - integer_to_char[i++] = char; -} +const notEndingWith = ["(", "["].concat(combinators); +const rules = [ + exports.EnumToken.AtRuleNodeType, + exports.EnumToken.RuleNodeType, + exports.EnumToken.AtRuleTokenType, + exports.EnumToken.KeyframesRuleNodeType, +]; +// @ts-ignore +const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering); /** - * @param {string} str + * Apply minification rules to the ast tree + * @param ast + * @param options + * @param recursive + * @param errors + * @param nestingContent + * + * @param context + * @private */ -function decode(str) { - /** @type {number[]} */ - let result = []; - let shift = 0; - let value = 0; - for (let i = 0; i < str.length; i += 1) { - let integer = char_to_integer[str[i]]; - // if (integer === undefined) { - // throw new Error('Invalid character (' + str[i] + ')'); - // } - const has_continuation_bit = integer & 32; - integer &= 31; - value += integer << shift; - if (has_continuation_bit) { - shift += 5; - } - else { - const should_negate = value & 1; - value >>>= 1; - if (should_negate) { - result.push(value === 0 ? -2147483648 : -value); - } - else { - result.push(value); - } - // reset - value = shift = 0; +function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { + let preprocess = false; + let postprocess = false; + let parents; + let replacement; + let { sourcemap, module, ...options2 } = options; + if (!(options2.features != null)) { + options2 = { + removeDuplicateDeclarations: true, + computeShorthand: true, + computeCalcExpression: true, + removePrefix: false, + features: [], + ...options2, + }; + for (const feature of features) { + feature.register(options2); } + options2.features.sort((a, b) => a.ordering - b.ordering); } - return result; -} -/** - * - * @param value - * @returns - */ -function encode(value) { - if (typeof value === 'number') { - return encode_integer(value); - } - let result = ''; - for (let i = 0; i < value.length; i += 1) { - result += encode_integer(value[i]); - } - return result; -} -function encode_integer(num) { - let result = ''; - if (num < 0) { - num = (-num << 1) | 1; - } - else { - num <<= 1; - } - do { - let clamped = num & 31; - num >>>= 5; - if (num > 0) { - clamped |= 32; + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Pre) { + preprocess = true; } - result += integer_to_char[clamped]; - } while (num > 0); - return result; -} - -/** - * Generate and parse source map - */ -class SourceMap { - /** - * - * @private - */ - keys = new Set(); - /** - * Last location - */ - lastLocation = null; - /** - * Version - * @private - */ - version = 3; - /** - * Sources map - * @private - */ - sourcesMap = []; - /** - * Sources content - * @private - */ - sourcesContent = []; - /** - * Sources - * @private - */ - sources = []; - /** - * Map - * @private - * - */ - map = new Map(); - /** - * Map - * @private - * - */ - reverseMap = new Map(); - /** - * Line - * @private - */ - line = -1; - /** - * - * @param sourcemaps - */ - constructor(sourcemaps) { - if (typeof sourcemaps === "string") { - if (sourcemaps.startsWith("data:")) { - let encoding = ""; - let offset = sourcemaps.indexOf(",") + 1; - if (offset == 0) { - offset = sourcemaps.lastIndexOf(";") + 1; + if (feature.processMode & exports.FeatureWalkMode.Post) { + postprocess = true; + } + } + if (preprocess) { + parents = new Set([ast]); + for (const parent of parents) { + if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { + continue; + } + replacement = parent; + for (const feature of options2.features) { + if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || + (feature.accept != null && !feature.accept.has(parent.typ))) { + continue; } - else { - encoding = sourcemaps.slice(sourcemaps.lastIndexOf(";") + 1, offset - 1); + if (rules.includes(replacement.typ) && !Array.isArray(replacement[TOKENS])) { + replacement[TOKENS] = parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ === exports.EnumToken.KeyframesRuleNodeType + ? replacement.sel + : // @ts-ignore + replacement.nam); } - if (encoding == "base64") { - sourcemaps = atob(sourcemaps.slice(offset)); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Pre); + if (result != null) { + replacement = result; } - else { - sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); + } + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); + } + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); } } - sourcemaps = JSON.parse(sourcemaps); } - if (sourcemaps != null) { - this.sources = sourcemaps.sources?.slice() ?? []; - this.sourcesContent = sourcemaps.sourcesContent?.slice() ?? []; - const decodedMappings = sourcemaps.mappings - .split(";") - .map((mapping) => mapping.split(",").map((mapping) => decode(mapping))); - this.line = decodedMappings.length - 1; - for (let index = 0; index < decodedMappings.length; index++) { - if (decodedMappings[index].length == 0 || - (decodedMappings[index].length == 1 && decodedMappings[index][0].length == 0)) { + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Pre && "cleanup" in feature) { + // @ts-ignore + feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Pre); + } + } + } + doMinify(ast, options2, recursive, errors, nestingContent, context); + parents = new Set([ast]); + for (const parent of parents) { + if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { + continue; + } + replacement = parent; + if (postprocess) { + for (const feature of options2.features) { + if ((feature.processMode & exports.FeatureWalkMode.Post) === 0 || + (feature.accept != null && !feature.accept.has(parent.typ))) { continue; } - this.map.set(index, decodedMappings[index]); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); + if (result != null) { + replacement = result; + } } - this.computePositions(); } - } - /** - * add source - * @param id - * @param fileName - * @param content - * @returns - */ - addSourceContent(id, fileName, content) { - if (this.sourcesMap.includes(id)) { - return; + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); } - this.sourcesMap[this.sourcesMap.length] = id; - this.sources[this.sources.length] = fileName || null; - this.sourcesContent[this.sourcesContent.length] = content || null; - } - /** - * Add all location - * @param maps - * @throws - */ - add(...maps) { - let srcIndex; - if (typeof maps[0] === "number") { - maps = [maps]; + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } } - for (let [newLine, newColumn, srcId, ln, col] of maps) { - const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; - if (this.keys.has(key)) { - continue; + } + if (postprocess) { + for (const feature of options2.features) { + if (feature.processMode & exports.FeatureWalkMode.Post && "cleanup" in feature) { + // @ts-ignore + feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Post); } - this.keys.add(key); - const line = newLine - 1; - let record; - if (line > this.line) { - this.line = line; - } - srcIndex = this.sourcesMap.indexOf(srcId); - if (srcIndex == -1) { - throw new Error(`Source file ${srcId} not added to sourcemap`); - } - if (!this.map.has(line)) { - record = [Math.max(0, newColumn - 1), srcIndex, ln - 1, col - 1]; - this.map.set(line, [record]); - } - else { - const arr = this.map.get(line); - record = [Math.max(0, newColumn - 1) - arr[0][0], srcIndex - arr[0][1], ln - 1, col - 1]; - arr.push(record); - } - if (this.lastLocation != null) { - record[2] -= this.lastLocation.ln - 1; - record[3] -= this.lastLocation.col - 1; - } - this.lastLocation ??= { ln, col }; - this.lastLocation.ln = ln; - this.lastLocation.col = col; } } - /** - * compute original positions - */ - computePositions() { - this.reverseMap.clear(); - let sourceFileIndex = 0; // second field - let sourceCodeLine = 0; // third field - let sourceCodeColumn = 0; // fourth field - // let nameIndex: number = 0; // fifth field - let generatedCodeColumn; - let result; - // mappings to original source - for (let [i, line] of this.map.entries()) { - if (line.length === 0 || (line.length === 1 && line[0].length === 0)) { - continue; - } - generatedCodeColumn = line[0][0]; // first field - reset each time - line = line - .map((segment, index, array) => { - if (segment.length === 0) { - return []; + return ast; +} +function transformAtRuleMediaPrelude(values) { + let hasUpdates = false; + for (let { value, parent, parents } of walkValues(values)) { + if (value.typ === exports.EnumToken.MediaQueryConditionTokenType) { + if (value.op.typ == exports.EnumToken.AndTokenType && + // @ts-ignore + value.l.typ === exports.EnumToken.IdenTokenType && + // @ts-ignore + value.l.val.toLowerCase() === "all") { + if (parent === null) { + // @ts-ignore + values[values.indexOf(value)] = value.l; } - generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; - result = [generatedCodeColumn]; - if (segment.length <= 1) { - return result; + else { + // @ts-ignore + replaceNodeOrValue(parent, value, value.l); + // @ts-ignore + value = value.l; } - sourceFileIndex = index == 0 ? segment[1] : segment[1] + array[0][1]; - sourceCodeLine += segment[2]; - sourceCodeColumn += segment[3]; - result.push(sourceFileIndex, sourceCodeLine, sourceCodeColumn); - // nameIndex not needed - // if (segment.length === 5) { - // nameIndex += segment[4]; - // result.push(nameIndex); - // } - return result; - }) - .sort((a, b) => { - if (a[1] !== b[1]) { - return a[1] - b[1]; + hasUpdates = true; + } + } + // range operator + if (parent != null && + parent.typ === exports.EnumToken.MediaQueryConditionTokenType && + parent.op.typ == exports.EnumToken.AndTokenType && + // @ts-ignore + parent.l.typ == exports.EnumToken.ParensTokenType) { + let token = parent.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + if (token?.typ === exports.EnumToken.ParensTokenType) { + // @ts-ignore + const node1 = parent.l.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const node2 = token.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + if (node1?.typ === exports.EnumToken.MediaQueryConditionTokenType && + node2?.typ === exports.EnumToken.MediaQueryConditionTokenType && + node1.op.typ == exports.EnumToken.ColonTokenType && + node2.op.typ == exports.EnumToken.ColonTokenType && + // @ts-ignore + node1.l.typ == exports.EnumToken.IdenTokenType && + // @ts-ignore + node2.l.typ == exports.EnumToken.IdenTokenType && + // @ts-ignore + node1.l.val.startsWith("min-") && + // @ts-ignore + node2.l.val.startsWith("max-") && + // @ts-ignore + node1.l.val.slice(4) == + // @ts-ignore + node2.l.val.slice(4)) { + const val1 = node1.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const val2 = node2.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); + const replacement = { + typ: exports.EnumToken.ParensTokenType, + chi: [ + // @ts-ignore + { + typ: exports.EnumToken.MediaRangeQueryTokenType, + op: { + typ: exports.EnumToken.IdenTokenType, + // @ts-ignore + val: node1.l.val.slice(4), + }, + l: val1, + r: val2, + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], + }, + ], + }; + // @ts-expect-error + const p = parents?.[parents?.indexOf?.(parent) + 1]; + if (p != null) { + // @ts-ignore + replaceNodeOrValue(p, parent, replacement); + } + else { + // @ts-ignore + values.splice(values.indexOf(parent), 1, replacement); + } + hasUpdates = true; + value = replacement; } - return a[0] - b[0]; - }); - if (line.length == 0 || (line.length == 1 && line[0].length == 0)) { - continue; } - this.reverseMap.set(i, line); } } - /** - * retrieve original sources, lines and columns - * @param line generated line - * @param column generated column - */ - find(line, column) { - if (this.reverseMap.size == 0) { - this.computePositions(); + return { hasUpdates, values: trimArray(values) }; +} +/** + * Minify at-rule media + * - remove redundant tokens + * - generate range queries + * + * @private + * @param tokens + */ +function minifyAtRuleMedia(tokens) { + let hasUpdates = false; + const sections = tokens + .reduce((acc, t) => { + if (t.typ === exports.EnumToken.CommaTokenType) { + acc.push([]); } - if (!this.reverseMap.has(--line)) { - return null; + else { + acc[acc.length - 1].push(t); } - column--; - const result = []; - for (const record of this.reverseMap.get(line)) { - if (record.length == 0 || record[0] < column) { - continue; - } - if (record[0] > column) { - break; - } - result.push([ - this.sources?.[record[1]] ?? null, - record[2] + 1, - record[3] + 1, - this.sourcesContent?.[record[1]] ?? null, - ]); + return acc; + }, [[]]) + .reduce((acc, values) => { + if (acc.has("all")) { + return acc; } - return result.length == 0 ? null : result; - } - /** - * Convert to URL encoded string - */ - toUrl() { - // /*# sourceMappingURL = ${url} */ - return `data:application/json;charset=utf-8;base64,${btoa(JSON.stringify(this.toJSON()))}`; + const result = transformAtRuleMediaPrelude(values); + if (result.values.length === 0) { + return acc; + } + if (result.hasUpdates) { + hasUpdates = true; + } + acc.set(values.reduce((acc, t) => acc + renderValue(t), ""), result.values); + return acc; + }, new Map()); + if (sections.has("all")) { + tokens.length = 0; } - /** - * Convert to JSON object - */ - toJSON() { - const mappings = []; - let i = 0; - for (; i <= this.line; i++) { - if (!this.map.has(i)) { - mappings.push(""); + else if (hasUpdates) { + tokens.length = 0; + tokens.push(...[...sections.values()].reduce((acc, t) => { + if (acc.length > 0) { + acc.push({ + typ: exports.EnumToken.CommaTokenType, + }); } - else { - mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); + for (const token of t) { + acc.push(token); } - } - return { - version: this.version, - sources: this.sources.slice(), - sourcesContent: this.sourcesContent?.slice(), - mappings: mappings.join(";"), - }; + return acc; + }, [])); } + // return ast; + return tokens; } - /** - * Compute line and column of the offset + * Reduce selectors + * @param acc + * @param curr + * + * @private */ -class LineMap { - /** - * line starts - */ - lineStarts; - /** - * Constructor - * @param lines - */ - constructor(lines = []) { - if (lines.length === 0) { - lines.push(0); - } - this.lineStarts = lines; - } - /** - * Compute line and column of the offset - * @param offset - * @returns - */ - getOffsets(offset) { - const line = this.search(offset); - // if (offset < 0 || line < 0) { - // return [1, 1]; - // } - // [line, column] - return [line + 1, offset - this.lineStarts[line] + 1]; - } - /** - * search the greatest index of the value less than or equal to offset - * @param offset - * @returns - */ - search(offset) { - // search lineStarts using binary search - let start = 0; - let end = this.lineStarts.length - 1; - let mid = 0; - let result = -1; - while (start <= end) { - mid = start + ((end - start) >>> 1); - if (this.lineStarts[mid] <= offset) { - result = mid; - start = mid + 1; - } - else if (this.lineStarts[mid] > offset) { - end = mid - 1; - } +function reduce(acc, curr) { + // trim :is() + if (curr[0] == "&") { + if (curr[1] == " " && !isIdent(curr[2]) && !isFunction(curr[2])) { + curr.splice(0, 2); } - return result; - } - /** - * get line starts - * @returns - */ - getLineStarts() { - return this.lineStarts; - } - /** - * add line start - */ - addLineStart(lineStart) { - this.lineStarts.push(lineStart); } + acc.push(curr.join("")); + return acc; } - /** - * Source file ID - */ -let sourceId = 0; -/** - * Source file helper class + * Apply minification rules to the ast tree + * @param ast + * @param options + * @param recursive + * @param errors + * @param nestingContent + * @param context + * + * @private */ -class SourceFile { - inputSourceMap = null; - /** - * Source file ID - */ - id; - /** - * Source file path - */ - file; - /** - * Line map - */ - lineStarts; - /** - * Source file content - */ - content; - /** - * Constructor - * @param content - * @param lines - * @param file - */ - constructor(content, lines, file = null) { - this.id = sourceId++; - this.content = content; - this.file = file; - this.lineStarts = new LineMap(lines); - } - /** - * Update source content - * @param content - */ - append(content) { - this.content += content; - } - /** - * get file name - * @returns - */ - getFileName() { - return this.file; - } - /** - * get content - * @returns - */ - getContent() { - return this.content; - } - /** - * get text - * @param start - * @param length - * @returns - */ - getText(start, length) { - return this.content.slice(start, start + length); - } - /** - * Compute line and column of the offset - * @param offset - * @returns - */ - getOffsets(offset) { - return this.lineStarts.getOffsets(offset); - } - /** - * get source location - * @param offset - * @returns - */ - getSourceLocation(offset) { - return [this.file, ...this.getOffsets(offset)]; - } - /** - * get line starts - * @returns - */ - getLineStarts() { - return this.lineStarts.getLineStarts(); - } - /** - * add line start - * @param lineStart - */ - addLineStart(lineStart) { - this.lineStarts.addLineStart(lineStart); - } - /** - * set input source map - * @param inputSourceMap - */ - setInputSourceMap(inputSourceMap) { - this.inputSourceMap = inputSourceMap == null ? null : new SourceMap(inputSourceMap); +function doMinify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { + if (!("nodes" in context)) { + context.nodes = new Set(); } - /** - * return input source map - * @returns - */ - getInputSourceMap() { - return this.inputSourceMap; + if (context.nodes.has(ast)) { + return ast; } -} - -const SymbolsMapTokens = { - "+": exports.EnumToken.Plus, - "=": exports.EnumToken.DelimTokenType, - "|": exports.EnumToken.Pipe, - "||": exports.EnumToken.ColumnCombinatorTokenType, - "|=": exports.EnumToken.DashMatchTokenType, - "&": exports.EnumToken.NestingSelectorTokenType, - "*": exports.EnumToken.Star, - "*=": exports.EnumToken.ContainMatchTokenType, - "~": exports.EnumToken.Tilda, - "~=": exports.EnumToken.IncludeMatchTokenType, - "^=": exports.EnumToken.StartMatchTokenType, - "$=": exports.EnumToken.EndMatchTokenType, - ",": exports.EnumToken.Comma, - ":": exports.EnumToken.ColonTokenType, - "::": exports.EnumToken.DoubleColonTokenType, - ";": exports.EnumToken.SemiColonTokenType, - "(": exports.EnumToken.StartParensTokenType, - ")": exports.EnumToken.EndParensTokenType, - "[": exports.EnumToken.AttrStartTokenType, - "]": exports.EnumToken.AttrEndTokenType, - "{": exports.EnumToken.BlockStartTokenType, - "}": exports.EnumToken.BlockEndTokenType, - "<=": exports.EnumToken.LteTokenType, - ">": exports.EnumToken.GtTokenType, - ">=": exports.EnumToken.GteTokenType, - " ": exports.EnumToken.Whitespace, - "\t": exports.EnumToken.Whitespace, - "\r": exports.EnumToken.Whitespace, - "\n": exports.EnumToken.Whitespace, - "\f": exports.EnumToken.Whitespace, - ...pseudoElements.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.PseudoElementTokenType; - return acc; - }, Object.create(null)), - ...containerFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ContainerFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...urlFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.UrlFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...gridTemplateFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.GridTemplateFuncTokenDefType; - return acc; - }, Object.create(null)), - ...imageFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ImageFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timelineFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.TimelineFunctionTokenDefType; - return acc; - }, Object.create(null)), - // ...generalEnclosedFunc.reduce((acc, curr: string) => { - // acc[curr + "("] = EnumToken.GeneralEnclosedFunctionTokenDefType; - // return acc; - // }, Object.create(null)), - ...supportFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.SupportsFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timingFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.TimingFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...colorsFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.ColorFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...mathFuncs.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.MathFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...transformFunctions.reduce((acc, curr) => { - acc[curr.toLowerCase() + "("] = exports.EnumToken.TransformFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...whenElseFunc.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.WhenElseFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...wildCardFuncs.reduce((acc, curr) => { - acc[curr + "("] = exports.EnumToken.WildCardFunctionTokenDefType; - return acc; - }, Object.create(null)), -}; -// do not capture the value -const hintsEnum = new Set([ - exports.EnumToken.CommaTokenType, - exports.EnumToken.ImportantTokenType, - exports.EnumToken.SemiColonTokenType, - exports.EnumToken.BlockStartTokenType, - exports.EnumToken.BlockEndTokenType, - exports.EnumToken.StartParensTokenType, - exports.EnumToken.EndParensTokenType, - exports.EnumToken.ColonTokenType, - exports.EnumToken.EOFTokenType, -]); -var TokenMap; -(function (TokenMap) { - TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; - TokenMap[TokenMap["SLASH"] = 47] = "SLASH"; - TokenMap[TokenMap["LOWERTHAN"] = 60] = "LOWERTHAN"; - TokenMap[TokenMap["HASH"] = 35] = "HASH"; - TokenMap[TokenMap["REVERSE_SOLIDUS"] = 92] = "REVERSE_SOLIDUS"; - TokenMap[TokenMap["DOUBLE_QUOTE"] = 34] = "DOUBLE_QUOTE"; - TokenMap[TokenMap["SINGLE_QUOTE"] = 39] = "SINGLE_QUOTE"; - TokenMap[TokenMap["DOT"] = 46] = "DOT"; - TokenMap[TokenMap["AT"] = 64] = "AT"; - TokenMap[TokenMap["PIPE"] = 124] = "PIPE"; - TokenMap[TokenMap["EQUALS"] = 61] = "EQUALS"; - TokenMap[TokenMap["AMPERSAND"] = 38] = "AMPERSAND"; - TokenMap[TokenMap["STAR"] = 42] = "STAR"; - TokenMap[TokenMap["TILDA"] = 126] = "TILDA"; - TokenMap[TokenMap["CARET"] = 94] = "CARET"; - TokenMap[TokenMap["DOLLAR"] = 36] = "DOLLAR"; - TokenMap[TokenMap["COMMA"] = 44] = "COMMA"; - TokenMap[TokenMap["COLON"] = 58] = "COLON"; - TokenMap[TokenMap["SEMICOLON"] = 59] = "SEMICOLON"; - TokenMap[TokenMap["LEFT_PARENTHESIS"] = 40] = "LEFT_PARENTHESIS"; - TokenMap[TokenMap["RIGHT_PARENTHESIS"] = 41] = "RIGHT_PARENTHESIS"; - TokenMap[TokenMap["LEFT_BRACKETS"] = 91] = "LEFT_BRACKETS"; - TokenMap[TokenMap["RIGHT_BRACKETS"] = 93] = "RIGHT_BRACKETS"; - TokenMap[TokenMap["LEFT_BRACE"] = 123] = "LEFT_BRACE"; - TokenMap[TokenMap["RIGHT_BRACE"] = 125] = "RIGHT_BRACE"; - TokenMap[TokenMap["PLUS"] = 43] = "PLUS"; - TokenMap[TokenMap["MINUS"] = 45] = "MINUS"; - TokenMap[TokenMap["GREATERTHAN"] = 62] = "GREATERTHAN"; -})(TokenMap || (TokenMap = {})); -function consumeString(parseInfo) { - const quote = next(parseInfo).charCodeAt(0); - let charCode; - let decodeSegments = false; - const result = []; - while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { - if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { - next(parseInfo, 2); - continue; - } - const sequence = peek(parseInfo, 7); - let escapeSequence = ""; - let codepoint; - let i; - for (i = 1; i < sequence.length; i++) { - codepoint = sequence.charCodeAt(i); - if (codepoint == 0x20 || - (codepoint >= 0x61 && codepoint <= 0x66) || - (codepoint >= 0x41 && codepoint <= 0x46) || - (codepoint >= 0x30 && codepoint <= 0x39)) { - escapeSequence += sequence[i]; - if (codepoint == 0x20) { - break; - } - continue; - } - break; - } - if (escapeSequence.trimEnd().length > 0) { - // const codepoint = parseInt(escapeSequence, 16); - // TODO set decode flag ON - // if ( - // codepoint == 0 || - // // leading surrogate - // (0xd800 <= codepoint && codepoint <= 0xdbff) || - // // trailing surrogate - // (0xdc00 <= codepoint && codepoint <= 0xdfff) - // ) { - // buffer += String.fromCodePoint(0xfffd); - // } else { - // buffer += String.fromCodePoint(codepoint); - // } - const length = escapeSequence.length + - 1 + - (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) - ? 1 - : 0); - decodeSegments = true; - next(parseInfo, length); - continue; - } - next(parseInfo, 2); - continue; - } - if (charCode == quote) { - next(parseInfo); - result.push(yieldResult(parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null)); - return result; - } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BadStringTokenType)); - return result; - } - next(parseInfo); - } - // EOF - 'Unclosed-string' fixed - result.push(yieldResult(parseInfo, exports.EnumToken.StringTokenType)); - return result; -} -function yieldResult(parseInfo, hint, options) { - let val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); - let token = null; - let dimension; - if (options?.decodeSegments) { - val = val.replace(/\\([0-9a-fA-F]{1,6})(?:\s)?/g, (_, sequence) => { - const codepoint = parseInt(sequence, 16); - if (codepoint == 0 || - // leading surrogate - (0xd800 <= codepoint && codepoint <= 0xdbff) || - // trailing surrogate - (0xdc00 <= codepoint && codepoint <= 0xdfff) || - codepoint > 0x10ffff) { - return "\uFFFD"; - } - return String.fromCodePoint(codepoint); - }); - } - if (hint != null) { - let searchArray = null; - switch (hint) { - case exports.EnumToken.TransformFunctionTokenDefType: - searchArray = transformFunctions; - break; - case exports.EnumToken.ColorFunctionTokenDefType: - searchArray = colorsFunc; - break; - case exports.EnumToken.ContainerFunctionTokenDefType: - searchArray = containerFunc; - break; - case exports.EnumToken.UrlFunctionTokenDefType: - searchArray = urlFunc; - break; - case exports.EnumToken.GridTemplateFuncTokenDefType: - searchArray = gridTemplateFunc; - break; - case exports.EnumToken.ImageFunctionTokenDefType: - searchArray = imageFunc; - break; - case exports.EnumToken.TimelineFunctionTokenDefType: - searchArray = timelineFunc; - break; - // case EnumToken.GeneralEnclosedFunctionTokenDefType: - // searchArray = generalEnclosedFunc; - // break; - case exports.EnumToken.SupportsFunctionTokenDefType: - searchArray = supportFunc; - break; - case exports.EnumToken.TimingFunctionTokenDefType: - searchArray = timingFunc; - break; - case exports.EnumToken.MathFunctionTokenDefType: - searchArray = mathFuncs; - break; - case exports.EnumToken.WhenElseFunctionTokenDefType: - searchArray = whenElseFunc; - break; - case exports.EnumToken.WildCardFunctionTokenDefType: - searchArray = wildCardFuncs; - break; - } - if (searchArray != null) { - val = searchArray.find((v) => equalsIgnoreCase(v, val)); - } - token = hintsEnum.has(hint) ? { typ: hint } : { typ: hint, val }; - } - else { - let slice = val.slice(1); - const chr = val.charAt(0); - if (chr == "!" && equalsIgnoreCase("!important", val)) { - token = { - typ: exports.EnumToken.ImportantTokenType, - }; - } - else if (chr == "@" && isIdent(slice)) { - token = { - typ: exports.EnumToken.AtRuleTokenType, - nam: slice, - }; - } - else if (chr == "." && isIdent(slice)) { - token = { - typ: exports.EnumToken.ClassSelectorTokenType, - val, - }; - } - else if (chr == "#") { - if (isHexColor(val)) { - token = { - typ: exports.EnumToken.ColorTokenType, - val: val, - kin: exports.ColorType.HEX, - }; - } - else if (isHash(val)) { - token = { - typ: exports.EnumToken.HashTokenType, - val: val, - }; - } - } - else if ("\"'".includes(chr)) { - token = { - typ: exports.EnumToken.UnclosedStringTokenType, - val: val, - }; - } - else if (isNumber(val)) { - token = - val[0] === "-" || val[0] === "+" - ? { - typ: exports.EnumToken.NumberTokenType, - sign: val[0], - val: +val, - } - : { - typ: exports.EnumToken.NumberTokenType, - val: +val, - }; - } - else if (isPercentage(val)) { - token = { - typ: exports.EnumToken.PercentageTokenType, - val: +val.slice(0, -1), - }; - } - else if ((dimension = parseDimension(val))) { - token = dimension; - } - else if (isIdent(val)) { - token = { - typ: val.startsWith("--") ? exports.EnumToken.DashedIdenTokenType : exports.EnumToken.IdenTokenType, - val, - }; - } - } - if (token == null) { - token = { - typ: exports.EnumToken.LiteralTokenType, - val, - }; - } - // return token; - token[LOC] = { - srcId: parseInfo.source.id, - sta: parseInfo.position, - end: parseInfo.currentPosition, - }; - parseInfo.position = parseInfo.currentPosition; - return { token, bytesIn: parseInfo.currentPosition }; -} -function match(parseInfo, input) { - let position = parseInfo.currentPosition - parseInfo.offset; - for (let i = 0; i < input.length; i++) { - if (parseInfo.stream[position + i] != input.charAt(i)) { - return false; - } - } - return true; -} -function peek(parseInfo, count = 1) { - if (count == 1) { - return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); - } - const position = parseInfo.currentPosition - parseInfo.offset; - return parseInfo.stream.slice(position, position + count); -} -function next(parseInfo, count = 1) { - let position = parseInfo.currentPosition - parseInfo.offset; - let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); - let i = 0; - let codepoint; - for (; i < char.length; i++) { - codepoint = char[i].charCodeAt(0); - if (codepoint == 0xa || // \n - codepoint == 0xb || // \v - codepoint == 0xc || // \f - codepoint == 0xd || // \r - codepoint == 0x2028 || // \u2028 - codepoint == 0x2029 // \u2029 - ) { - // \r\n - if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; - else { - parseInfo.source.lineStarts.lineStarts.push(position + i); - } - } - } - parseInfo.currentPosition += char.length; - return char; -} -function isIdentToken(parseInfo, start, end) { - let j = parseInfo.currentPosition - parseInfo.offset; - let i = parseInfo.position - parseInfo.offset; - if (start != null) { - if (end == null) { - if (start < 0) { - j += start; - } - else { - i += start; - } + context.nodes.add(ast); + // @ts-ignore + if ("chi" in ast && ast.chi.length > 0) { + const reducer = reduce.bind(ast); + if (!nestingContent) { + nestingContent = options.nestingRules && ast.typ == exports.EnumToken.RuleNodeType; } - else { - if (end < 0) { - j += end; + let i = 0; + let previous = null; + let node = null; + let nodeIndex = -1; + for (; i < ast.chi.length; i++) { + if (ast.chi[i].typ === exports.EnumToken.CommentNodeType) { + continue; } - else { - j = parseInfo.position + end; + while (previous?.typ === exports.EnumToken.CommentNodeType) { + // @ts-ignore + previous = ast.chi[--nodeIndex]; } - } - } - j--; - let codepoint = parseInfo.stream.charCodeAt(i); - // - - if (codepoint == 0x2d) { - let nextCodepoint; - if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { - return false; - } - if (isDigit(nextCodepoint)) { - return false; - } - codepoint = nextCodepoint; - i++; - } - if (codepoint !== 0x2d && !isIdentStart(codepoint)) { - return false; - } - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - codepoint = parseInfo.stream.charCodeAt(i + 1); - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - i += String.fromCodePoint(codepoint).length; - // if (i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - // } - } - while (i < j) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - continue; - } - if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { - return false; - } - } - return true; -} -function isPseudo(parseInfo) { - let position = parseInfo.currentPosition - parseInfo.offset; - let endPosition = parseInfo.currentPosition - parseInfo.offset; - return (parseInfo.stream.charAt(position) == ":" && - parseInfo.stream.charAt(endPosition - 1) == "(" && - (parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2, -1) - : isIdentToken(parseInfo, 1, -1))) || - parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2) - : isIdentToken(parseInfo, 1); -} -function startsWith(parseInfo, input) { - let i = 0; - let j = input.length; - while (i < j) { - if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { - return false; - } - i++; - } - return true; -} -function isURLToken(parseInfo) { - let i = parseInfo.position - parseInfo.offset; - let c; - while (++i < parseInfo.currentPosition) { - c = parseInfo.stream.charCodeAt(i); - // single quote or double quote or start parenthesis or close parenthesis - if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { - return false; - } - // valid escape - if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i++; - if (i >= parseInfo.currentPosition) { - return false; + node = ast.chi[i]; + if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { + continue; } - c = parseInfo.stream.charCodeAt(i); - // c is not '\n' or '\r' or '\f' - if (c == 0x6e || c == 0x72 || c == 0x66) { - return false; + if (node.typ === exports.EnumToken.KeyframesAtRuleNodeType) { + if (previous?.typ === exports.EnumToken.KeyframesAtRuleNodeType && + node.nam === previous.nam && + node.val === previous.val) { + ast.chi?.splice(nodeIndex--, 1); + previous = ast?.chi?.[nodeIndex] ?? null; + i = nodeIndex; + continue; + } } - continue; - } - // is white space - if (c == 0x20 || c == 0x09) { - break; - } - } - return i == parseInfo.currentPosition; -} -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -function tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } - let charCode; - let nextCharCode; - const startTime = performance.now(); - const result = []; - // allow 10 characters buffer for the streaming parser to avoid incomplete tokens - const endPosition = parseInfo.stream.length - 1; - // NaN is not equal to NaN - while ((charCode = peek(parseInfo).charCodeAt(0)) == charCode) { - switch (charCode) { - case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.DelimTokenType)); - break; - // '+' or '-' - case 43 /* TokenMap.PLUS */: - case 45 /* TokenMap.MINUS */: - nextCharCode = peek(parseInfo).charCodeAt(0); - // not a number - if (charCode === 43 /* TokenMap.PLUS */ && !(nextCharCode >= 0x30 && nextCharCode <= 0x39)) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + else if (node.typ === exports.EnumToken.KeyframesRuleNodeType) { + if (previous?.typ === exports.EnumToken.KeyframesRuleNodeType && + node.sel === previous.sel) { + // do not merge keyframes + // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates + for (const child of node.chi) { + previous.chi.push(child); } - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase()])); - break; - } - next(parseInfo); - break; - // '{' - case 123 /* TokenMap.LEFT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // @ts-ignore + ast.chi.splice(i, 1); + previous = ast?.chi?.[nodeIndex] ?? null; + i = nodeIndex; + continue; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockEndTokenType)); - break; - // '(' - case 40 /* TokenMap.LEFT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && isPseudo(parseInfo)) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType)); - break; - } - else if (isIdentToken(parseInfo)) { - const hint = startsWith(parseInfo, "--") - ? exports.EnumToken.CustomFunctionTokenDefType - : (SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase() + "("] ?? exports.EnumToken.FunctionTokenDefType); - result.push(yieldResult(parseInfo, hint)); - next(parseInfo); - // consume '(' - parseInfo.position = parseInfo.currentPosition; - if (hint === exports.EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(peek(parseInfo).charCodeAt(0))) { - next(parseInfo); - } - charCode = peek(parseInfo).charCodeAt(0); - let values = null; - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - values = consumeString(parseInfo); - } - else { - do { - next(parseInfo); - // value = peek(parseInfo); - charCode = peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); - } - if (values != null) { - // NaN is not equal to NaN - if ((charCode = peek(parseInfo).charCodeAt(0)) != charCode) { - for (let i = 0; i < values.length; i++) { - values[i].token.typ = exports.EnumToken.BadUrlTokenType; - } - } - result.push(...values); + let k; + for (k = 0; k < node.chi.length; k++) { + if (node.chi[k].typ == exports.EnumToken.DeclarationNodeType) { + let l = node.chi[k].val.length; + while (l--) { + if (node.chi[k].val[l].typ == + exports.EnumToken.ImportantTokenType) { + node.chi.splice(k--, 1); + break; } - else if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = peek(parseInfo).charCodeAt(0)) != charCode || !isURLToken(parseInfo) - ? exports.EnumToken.BadUrlTokenType - : exports.EnumToken.UrlTokenTokenType)); + if ([exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(node.chi[k].val[l].typ)) { + continue; } + break; } - break; } } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.StartParensTokenType)); - break; - // ')' - case 41 /* TokenMap.RIGHT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.EndParensTokenType)); - break; - // '[' - case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.AttrStartTokenType)); - break; - // ']' - case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.AttrEndTokenType)); - break; - case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.SemiColonTokenType)); - break; - case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - if (peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.DoubleColonTokenType)); - break; - } - result.push(yieldResult(parseInfo, exports.EnumToken.ColonTokenType)); - break; - // \n \r \f \v \t space - case 0x9: - case 0x20: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0x2028: - case 0x2029: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - while (nextCharCode == 0x20 || - (nextCharCode >= 0x9 && nextCharCode <= 0xd) || - nextCharCode == 0x2028 || - nextCharCode == 0x2029) { - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - } - result.push(yieldResult(parseInfo, exports.EnumToken.WhitespaceTokenType)); - break; - case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.CommaTokenType)); - break; - case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "$=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.EndMatchTokenType)); - break; - } - next(parseInfo); - break; - case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "~=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.IncludeMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Tilda)); - break; - // case '^': - case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "^=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.StartMatchTokenType)); - break; - } - next(parseInfo); - break; - case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "*=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.ContainMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Star)); - break; - case 38 /* TokenMap.AMPERSAND */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.NestingSelectorTokenType)); - break; - case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - // '||' - if (match(parseInfo, "||")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.ColumnCombinatorTokenType)); - break; - } - else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.DashMatchTokenType)); - break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.Pipe)); - break; - case 33 /* TokenMap.EXCLAMATION */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "!important")) { - next(parseInfo, 10); - result.push(yieldResult(parseInfo, exports.EnumToken.ImportantTokenType)); - break; - } - next(parseInfo); - break; - case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (!match(parseInfo, "/*")) { - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream.slice(parseInfo.position, parseInfo.currentPosition)])); - break; + } + else if (node.typ == exports.EnumToken.AtRuleNodeType) { + if (node.nam == "media") { + if (Array.isArray(node[TOKENS])) { + const slice = node[TOKENS].slice(); + minifyAtRuleMedia(slice); + if (slice.length !== node[TOKENS].length) { + node[TOKENS].length = 0; + for (const token of slice) { + node[TOKENS].push(token); + } + node.val = slice.reduce((acc, curr, index, arr) => acc + + (curr.typ === exports.EnumToken.CommentTokenType || + (curr.typ === exports.EnumToken.WhitespaceTokenType && + arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && + (index + 3 < arr.length || + arr[index + 2]?.typ === exports.EnumToken.WhitespaceTokenType)) + ? "" + : renderValue(curr)), ""); + } + } + if (["all", "", null].includes(node.val)) { + ast.chi?.splice(i--, 1, ...node.chi); + continue; + } } - next(parseInfo, 2); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 42 /* TokenMap.STAR */) { - if (match(parseInfo, "/")) { - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.CommentTokenType)); + else if (node.nam === "import" && Array.isArray(node[TOKENS])) { + let l = 0; + let token; + for (; l < node[TOKENS].length; l++) { + token = node[TOKENS][l]; + if (token.typ === exports.EnumToken.ParensTokenType || + token.typ === exports.EnumToken.MediaQueryConditionTokenType || + (token.typ === exports.EnumToken.IdenTokenType && "layer" !== token.val)) { break; } } - // else { - // buffer += value; - // } - } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, exports.EnumToken.BadCommentTokenType)); - } - break; - case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (l < node[TOKENS].length) { + const slice = node[TOKENS]?.slice(l); + node[TOKENS].splice(l, slice.length, ...minifyAtRuleMedia(slice)); + node.val = trimArray(node[TOKENS]).reduce((acc, curr, index, arr) => acc + + (curr.typ === exports.EnumToken.CommentTokenType || + (curr.typ === exports.EnumToken.WhitespaceTokenType && + arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && + (index + 3 < arr.length || arr[index + 2].typ === exports.EnumToken.WhitespaceTokenType)) + ? "" + : renderValue(curr)), ""); + } } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.GteTokenType)); - break; + else if (ast.typ === node.typ && + ast.nam === node.nam && + ast.val === node.val) { + // @ts-ignore + replaceNodeOrValue(ast, node, node.chi); + i--; + continue; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.GtTokenType)); - break; - case 60 /* TokenMap.LOWERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (previous?.typ == exports.EnumToken.AtRuleNodeType && + node.nam != "font-face" && + previous.nam === node.nam && + previous.val === node.val) { + if ("chi" in node) { + for (const child of node.chi) { + previous.chi.push(child); + } + if (!hasDeclaration(previous)) { + context.nodes.delete(previous); + doMinify(previous, options, recursive, errors, nestingContent, context); + } + } + ast?.chi?.splice(i--, 1); + continue; } - if (match(parseInfo, "<=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.LteTokenType)); - break; + // if (!hasDeclaration(node as AstAtRule)) { + // doMinify(node, options, recursive, errors, nestingContent, context); + // } + if ("chi" in node) { + doMinify(node, options, recursive, errors, nestingContent, context); } - next(parseInfo); - if (match(parseInfo, "!--")) { - next(parseInfo, 3); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 45 /* TokenMap.MINUS */ && match(parseInfo, "->")) { - break; + previous = node; + nodeIndex = i; + continue; + } + // @ts-ignore + else if (node.typ === exports.EnumToken.RuleNodeType) { + reduceRuleSelector(node); + let wrapper = null; + let match; + if (options.nestingRules) { + if (previous?.typ == exports.EnumToken.RuleNodeType) { + reduceRuleSelector(previous); + // @ts-ignore + match = matchSelectors(previous[RAW], node[RAW]); + if (match != null) { + wrapper = wrapNodes(previous, node, match, ast, reducer, i, nodeIndex); + nodeIndex = i - 1; + previous = ast.chi[nodeIndex]; + } + } + if (wrapper != null) { + while (i < ast.chi.length) { + const nextNode = ast.chi[i]; + if (nextNode.typ != exports.EnumToken.RuleNodeType) { + break; + } + reduceRuleSelector(nextNode); + match = matchSelectors(wrapper[RAW], nextNode[RAW]); + if (match == null) { + break; + } + wrapper = wrapNodes(wrapper, nextNode, match, ast, reducer, i, nodeIndex); } + nodeIndex = --i; + previous = ast.chi[nodeIndex]; + doMinify(wrapper, options, recursive, errors, nestingContent, context); + continue; } - if (parseInfo.currentPosition >= endPosition) { - result.push(yieldResult(parseInfo, exports.EnumToken.BadCdoTokenType)); + // @ts-ignore + else if (node[OPTIMIZED] != null && + // @ts-ignore + node[OPTIMIZED].match && + // @ts-ignore + node[OPTIMIZED].selector.length > 1) { + // @ts-ignore + wrapper = { + ...node, + chi: [], + sel: node[OPTIMIZED].optimized[0], + [RAW]: [[node[OPTIMIZED].optimized[0]]], + }; + // @ts-ignore + node.sel = node[OPTIMIZED].selector.reduce(reducer, []).join(","); + // @ts-ignore + node[RAW] = node[OPTIMIZED].selector.slice(); + node[TOKENS] = null; + // @ts-ignore + wrapper.chi.push(node); + // @ts-ignore + ast.chi.splice(i, 1, wrapper); + node = wrapper; } - else { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, exports.EnumToken.CDOCOMMTokenType)); + else if (node[OPTIMIZED]?.reducible) { + if (node[OPTIMIZED].optimized.length === 1) { + const sel1 = node[OPTIMIZED].optimized[0] + + ":is(" + + node[OPTIMIZED].selector.reduce(reducer, []).join(",") + + ")"; + const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => + // @ts-ignore + (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); + node.sel = sel1.length < sel2.length ? sel1 : sel2; + node[TOKENS] = null; + } + else if (node[OPTIMIZED].optimized.length === 0) { + const testIdent = /^[a-zA-Z]/; + node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + + (nestingContent && testIdent.test(curr[0]) ? "& " : "") + + curr.join(""), ""); + node[TOKENS] = null; + } } } - break; - case 35 /* TokenMap.HASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - break; - case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } - next(parseInfo); - // EOF - if (!peek(parseInfo)) { - if (!yieldEOFToken) { - break; + // @ts-ignore + else if (node[OPTIMIZED]?.match) { + let wrap = true; + // @ts-ignore + const selector = node[OPTIMIZED].selector.reduce((acc, curr) => { + if (curr[0] == "&" && curr.length > 1) { + if (curr[1] == " ") { + curr.splice(0, 2); + } + else { + curr.splice(0, 1); + } + } + else if (combinators.includes(curr[0])) { + curr.unshift("&"); + wrap = false; + } + acc.push(curr); + return acc; + }, []); + if (!wrap) { + wrap = selector.some((s) => s[0] != "&"); } - // end of stream ignore \\ - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + let rule = null; + const optimized = node[OPTIMIZED].optimized.slice(); + if (optimized.length > 1) { + const check = optimized.at(-2); + if (!combinators.includes(check)) { + let last = optimized.pop(); + wrap = false; + rule = + optimized.join("") + + `:is(${selector + .map((s) => { + if (s[0] == "&") { + s.splice(0, 1, last); + } + else { + s.unshift(last); + } + return s.join(""); + }) + .join(",")})`; + } + } + if (rule == null) { + rule = selector + .map((s) => { + if (s[0] == "&") { + s.splice(0, 1, ...node[OPTIMIZED].optimized); + } + return s.join(""); + }) + .join(","); + } + let sel = wrap ? node[OPTIMIZED].optimized.join("") + `:is(${rule})` : rule; + if (sel.length < node.sel.length) { + node.sel = sel; + node[TOKENS] = null; } - break; - } - next(parseInfo); - break; - case 39 /* TokenMap.SINGLE_QUOTE */: - case 34 /* TokenMap.DOUBLE_QUOTE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - result.push(...consumeString(parseInfo)); - break; - case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - next(parseInfo, 2); - break; } - next(parseInfo); - break; - default: - next(parseInfo); - break; + else if (node[OPTIMIZED]?.reducible) { + if (node[OPTIMIZED].optimized.length === 1) { + const sel1 = node[OPTIMIZED].optimized[0] + + ":is(" + + node[OPTIMIZED].selector.reduce(reducer, []).join(",") + + ")"; + const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => + // @ts-ignore + (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); + node.sel = sel1.length < sel2.length ? sel1 : sel2; + node[TOKENS] = null; + } + else if (node[OPTIMIZED].optimized.length === 0) { + const testIdent = /^[a-zA-Z]/; + node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + + (nestingContent && testIdent.test(curr[0]) ? "& " : "") + + curr.join(""), ""); + node[TOKENS] = null; + } + // @ts-ignore + } + else if (node[OPTIMIZED]?.optimized.length > 0) { + // @ts-ignore + const sel = node[OPTIMIZED].optimized.join(""); + if (sel.length < node.sel.length) { + node.sel = sel; + // @ts-ignore + node[RAW] = [node[OPTIMIZED].optimized.slice()]; + node[TOKENS] = null; + } + } + doMinify(node, options, recursive, errors, nestingContent, context); + } + if (previous != null) { + if ("chi" in previous && "chi" in node) { + if (previous.typ === node.typ) { + let shouldMerge = true; + let k = previous.chi.length; + while (k-- > 0) { + if (previous.chi[k].typ === exports.EnumToken.CommentNodeType || + previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType || + previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType) { + continue; + } + shouldMerge = previous.chi[k].typ === exports.EnumToken.DeclarationNodeType; + break; + } + if (shouldMerge) { + if (((node.typ === exports.EnumToken.RuleNodeType || + node.typ === exports.EnumToken.KeyframesRuleNodeType) && + node.sel === previous.sel) || + // @ts-ignore + (node.typ == exports.EnumToken.AtRuleNodeType && + node.nam !== "font-face" && + // @ts-ignore + node.nam === previous.nam)) { + const array = []; + for (let i = 0; i < previous.chi.length; i++) { + array.push(previous.chi[i]); + } + for (let i = 0; i < node.chi.length; i++) { + array.push(node.chi[i]); + } + // @ts-ignore + node.chi = array; + doMinify(node, options, recursive, errors, nestingContent, context); + ast.chi.splice(nodeIndex, 1); + previous = ast.chi[--i]; + nodeIndex = i; + continue; + } + else if (node.typ == previous?.typ && + [exports.EnumToken.KeyframesRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) { + const intersect = diff$1(previous, node, options); + if (intersect != null) { + if (intersect.node1.chi.length == 0) { + ast.chi.splice(i--, 1); + } + else { + ast.chi.splice(i--, 1, intersect.node1); + } + if (intersect.node2.chi.length == 0) { + if (intersect.result != null) { + ast.chi.splice(nodeIndex, 1, intersect.result); + } + else { + ast.chi.splice(nodeIndex, 1); + } + i--; + if (nodeIndex == i) { + nodeIndex = i; + } + } + else { + if (intersect.result != null) { + ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2); + } + else { + ast.chi.splice(nodeIndex, 1, intersect.node2); + } + i = (nodeIndex ?? 0) + 1; + } + if (node != ast.chi[i]) { + node = ast.chi[i]; + } + previous = intersect.result; + nodeIndex = i; + } + } + } + } + if (recursive && previous != null && previous != node) { + if (!hasDeclaration(previous)) { + doMinify(previous, options, recursive, errors, nestingContent, context); + } + } + } + } + if (!nestingContent && + previous != null && + previous.typ == exports.EnumToken.RuleNodeType && + previous.sel.includes("&")) { + fixSelector(previous); + } + previous = node; + nodeIndex = i; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + if (recursive && node != null && "chi" in node) { + 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")) { + doMinify(node, options, recursive, errors, nestingContent, context); + } + } } - } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (!nestingContent && + node != null && + node.typ == exports.EnumToken.RuleNodeType && + node.sel.includes("&")) { + fixSelector(node); } - result.push(yieldResult(parseInfo, exports.EnumToken.EOFTokenType)); } - parseInfo.time += performance.now() - startTime; - return result; + return ast; } /** - * tokenize readable stream - * @param input - * @param parseInfo + * Check if a rule has a declaration + * @param node + * + * @private */ -async function* tokenizeStream(input, parseInfo) { - const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); - parseInfo.stream = ""; - while (true) { - const { done, value } = await reader.read(); - const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; - if (!done) { - parseInfo.source.append(stream); - parseInfo.stream = (parseInfo.stream.slice(parseInfo.position - parseInfo.offset) + stream); - parseInfo.offset = parseInfo.offset = parseInfo.position; - } - else { - parseInfo.stream = ""; - } - yield* tokenize(parseInfo, done); - if (done) { - break; +function hasDeclaration(node) { + // @ts-ignore + for (let i = 0; i < node.chi?.length; i++) { + // @ts-ignore + if (node.chi[i].typ == exports.EnumToken.CommentNodeType) { + continue; } + // @ts-ignore + return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; } + return true; } - -const notEndingWith = ["(", "["].concat(combinators); -const rules = [ - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleTokenType, - exports.EnumToken.KeyframesRuleNodeType, -]; -// @ts-ignore -const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering); /** - * Apply minification rules to the ast tree - * @param ast - * @param options - * @param recursive - * @param errors - * @param nestingContent + * Optimize selector + * @param selector * - * @param context * @private */ -function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { - let preprocess = false; - let postprocess = false; - let parents; - let replacement; - let { sourcemap, module, ...options2 } = options; - if (!(options2.features != null)) { - options2 = { - removeDuplicateDeclarations: true, - computeShorthand: true, - computeCalcExpression: true, - removePrefix: false, - features: [], - ...options2, - }; - for (const feature of features) { - feature.register(options2); - } - options2.features.sort((a, b) => a.ordering - b.ordering); - } - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Pre) { - preprocess = true; - } - if (feature.processMode & exports.FeatureWalkMode.Post) { - postprocess = true; - } - } - if (preprocess) { - parents = new Set([ast]); - for (const parent of parents) { - if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { - continue; - } - replacement = parent; - for (const feature of options2.features) { - if ((feature.processMode & exports.FeatureWalkMode.Pre) === 0 || - (feature.accept != null && !feature.accept.has(parent.typ))) { - continue; - } - if (rules.includes(replacement.typ) && !Array.isArray(replacement[TOKENS])) { - replacement[TOKENS] = parseString(replacement.typ == exports.EnumToken.RuleNodeType || replacement.typ === exports.EnumToken.KeyframesRuleNodeType - ? replacement.sel - : // @ts-ignore - replacement.nam); - } - const result = feature.run(replacement, options2, - // @ts-ignore - parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Pre); - if (result != null) { - replacement = result; - } - } - if (replacement != null && - (!Array.isArray(replacement) || replacement.length > 0) && - replacement != parent && - parent[PARENT] != null) { - // @ts-ignore - replaceNodeOrValue(parent[PARENT], parent, replacement); - } +function optimizeSelector(selector) { + const map = new Set(); + selector = selector + .reduce((acc, curr) => { + // @ts-ignore + if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { // @ts-ignore - if (replacement.chi != null) { - // @ts-ignore - for (const node of replacement.chi) { - node[PARENT] = replacement; - parents.add(node); + const rules = splitRule(curr.at(-1).slice(4, -1)).map((x) => { + if (x[0] == "&" && x.length > 1) { + return x.slice(x[1] == " " ? 2 : 1); } + return x; + }); + const part = curr.slice(0, -1); + for (const rule of rules) { + acc.push(part.concat(rule)); } + return acc; } - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Pre && "cleanup" in feature) { - // @ts-ignore - feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Pre); - } - } - } - doMinify(ast, options2, recursive, errors, nestingContent, context); - parents = new Set([ast]); - for (const parent of parents) { - if (parent.typ == exports.EnumToken.CommentTokenType || parent.typ == exports.EnumToken.CDOCOMMTokenType) { - continue; + acc.push(curr); + return acc; + }, []) + .filter((x) => { + const str = x.join(""); + if (map.has(str)) { + return false; } - replacement = parent; - if (postprocess) { - for (const feature of options2.features) { - if ((feature.processMode & exports.FeatureWalkMode.Post) === 0 || - (feature.accept != null && !feature.accept.has(parent.typ))) { - continue; - } - const result = feature.run(replacement, options2, - // @ts-ignore - parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); - if (result != null) { - replacement = result; - } + map.add(str); + return true; + }); + const optimized = []; + const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : curr.length == 0 ? acc : Math.min(acc, curr.length), 0); + let i = 0; + let j; + let match; + for (; i < k; i++) { + const item = selector[0][i]; + match = true; + for (j = 1; j < selector.length; j++) { + if (item != selector[j][i]) { + match = false; + break; } } - if (replacement != null && - (!Array.isArray(replacement) || replacement.length > 0) && - replacement != parent && - parent[PARENT] != null) { - // @ts-ignore - replaceNodeOrValue(parent[PARENT], parent, replacement); + if (!match) { + break; } - // @ts-ignore - if (replacement.chi != null) { - // @ts-ignore - for (const node of replacement.chi) { - node[PARENT] = replacement; - parents.add(node); - } + optimized.push(item); + } + while (optimized.length > 0) { + const last = optimized.at(-1); + if (last == " " || combinators.includes(last)) { + optimized.pop(); + continue; } + break; } - if (postprocess) { - for (const feature of options2.features) { - if (feature.processMode & exports.FeatureWalkMode.Post && "cleanup" in feature) { - // @ts-ignore - feature.cleanup(ast, options2, context, exports.FeatureWalkMode.Post); - } + for (let i1 = 0; i1 < selector.length; i1++) { + selector[i1].splice(0, optimized.length); + } + let reducible = optimized.length == 1; + if (optimized[0] == "&") { + if (optimized[1] == " ") { + optimized.splice(0, 2); } } - return ast; -} -function transformAtRuleMediaPrelude(values) { - let hasUpdates = false; - for (let { value, parent, parents } of walkValues(values)) { - if (value.typ === exports.EnumToken.MediaQueryConditionTokenType) { - if (value.op.typ == exports.EnumToken.AndTokenType && - // @ts-ignore - value.l.typ === exports.EnumToken.IdenTokenType && - // @ts-ignore - value.l.val.toLowerCase() === "all") { - if (parent === null) { - // @ts-ignore - values[values.indexOf(value)] = value.l; - } - else { - // @ts-ignore - replaceNodeOrValue(parent, value, value.l); - // @ts-ignore - value = value.l; - } - hasUpdates = true; + if (optimized.length == 0 || optimized[0].charAt(0) == "&" || selector.length == 1) { + return { + match: false, + optimized, + selector: selector.map((selector) => selector[0] == "&" && selector[1] == " " ? selector.slice(2) : selector), + reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0])), + }; + } + return { + match: true, + optimized, + selector: selector.reduce((acc, curr) => { + let hasCompound = true; + if (hasCompound && curr.length > 0) { + hasCompound = !["&"].concat(combinators).includes(curr[0].charAt(0)); } - } - // range operator - if (parent != null && - parent.typ === exports.EnumToken.MediaQueryConditionTokenType && - parent.op.typ == exports.EnumToken.AndTokenType && // @ts-ignore - parent.l.typ == exports.EnumToken.ParensTokenType) { - let token = parent.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - if (token?.typ === exports.EnumToken.ParensTokenType) { + if (hasCompound && curr[0] == " ") { + hasCompound = false; + curr.unshift("&"); + } + if (curr.length == 0) { + curr.push("&"); + hasCompound = false; + } + if (reducible) { + const chr = curr[0].charAt(0); // @ts-ignore - const node1 = parent.l.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const node2 = token.chi.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - if (node1?.typ === exports.EnumToken.MediaQueryConditionTokenType && - node2?.typ === exports.EnumToken.MediaQueryConditionTokenType && - node1.op.typ == exports.EnumToken.ColonTokenType && - node2.op.typ == exports.EnumToken.ColonTokenType && - // @ts-ignore - node1.l.typ == exports.EnumToken.IdenTokenType && - // @ts-ignore - node2.l.typ == exports.EnumToken.IdenTokenType && - // @ts-ignore - node1.l.val.startsWith("min-") && - // @ts-ignore - node2.l.val.startsWith("max-") && - // @ts-ignore - node1.l.val.slice(4) == - // @ts-ignore - node2.l.val.slice(4)) { - const val1 = node1.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const val2 = node2.r.find((t) => t.typ !== exports.EnumToken.WhitespaceTokenType && t.typ !== exports.EnumToken.CommentTokenType); - const replacement = { - typ: exports.EnumToken.ParensTokenType, - chi: [ - // @ts-ignore - { - typ: exports.EnumToken.MediaRangeQueryTokenType, - op: { - typ: exports.EnumToken.IdenTokenType, - // @ts-ignore - val: node1.l.val.slice(4), - }, - l: val1, - r: val2, - [LOC]: value[LOC], - }, - ], - }; - // @ts-expect-error - const p = parents?.[parents?.indexOf?.(parent) + 1]; - if (p != null) { - // @ts-ignore - replaceNodeOrValue(p, parent, replacement); - } - else { - // @ts-ignore - values.splice(values.indexOf(parent), 1, replacement); - } - hasUpdates = true; - value = replacement; - } + reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); } - } - } - return { hasUpdates, values: trimArray(values) }; + acc.push(hasCompound ? ["&"].concat(curr) : curr); + return acc; + }, []), + reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), + }; } /** - * Minify at-rule media - * - remove redundant tokens - * - generate range queries + * Split selector string + * @param buffer * - * @private - * @param tokens + * @internal */ -function minifyAtRuleMedia(tokens) { - let hasUpdates = false; - const sections = tokens - .reduce((acc, t) => { - if (t.typ === exports.EnumToken.CommaTokenType) { - acc.push([]); - } - else { - acc[acc.length - 1].push(t); - } - return acc; - }, [[]]) - .reduce((acc, values) => { - if (acc.has("all")) { - return acc; +function splitRule(buffer) { + const result = [[]]; + let str = ""; + for (let i = 0; i < buffer.length; i++) { + let chr = buffer.charAt(i); + if (isWhiteSpace(chr.charCodeAt(0))) { + if (str !== "") { + // @ts-ignore + result.at(-1).push(str); + str = ""; + } + // @ts-ignore + if (result.at(-1).length > 0) { + // @ts-ignore + result.at(-1).push(" "); + } + // i = k; + continue; } - const result = transformAtRuleMediaPrelude(values); - if (result.values.length === 0) { - return acc; + if (chr == ",") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + result.push([]); + continue; } - if (result.hasUpdates) { - hasUpdates = true; + if (chr == ".") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + str += chr; + continue; } - acc.set(values.reduce((acc, t) => acc + renderValue(t), ""), result.values); - return acc; - }, new Map()); - if (sections.has("all")) { - tokens.length = 0; - } - else if (hasUpdates) { - tokens.length = 0; - tokens.push(...[...sections.values()].reduce((acc, t) => { - if (acc.length > 0) { - acc.push({ - typ: exports.EnumToken.CommaTokenType, - }); + if (combinators.includes(chr)) { + if (str !== "") { + result.at(-1).push(str); + str = ""; } - acc.push(...t); - return acc; - }, [])); + if (chr == "|" && buffer.charAt(i + 1) == "|") { + chr += buffer.charAt(++i); + } + result.at(-1).push(chr); + continue; + } + if (chr == ":") { + if (str !== "") { + result.at(-1).push(str); + str = ""; + } + if (buffer.charAt(i + 1) == ":") { + chr += buffer.charAt(++i); + } + str += chr; + continue; + } + str += chr; + if (chr == "\\") { + str += buffer.charAt(++i); + continue; + } + if (chr == "(" || chr == "[") { + const open = chr; + const close = chr == "(" ? ")" : "]"; + let inParens = 1; + let k = i; + while (++k < buffer.length) { + chr = buffer.charAt(k); + if (chr == "\\") { + str += buffer.slice(k, k + 2); + k++; + continue; + } + str += chr; + if (chr == open) { + inParens++; + } + else if (chr == close) { + inParens--; + } + if (inParens == 0) { + break; + } + } + i = k; + } } - // return ast; - return tokens; + if (str !== "") { + result.at(-1).push(str); + } + return result; } /** - * Reduce selectors + * Reduce selector * @param acc * @param curr * * @private */ -function reduce(acc, curr) { - // trim :is() - if (curr[0] == "&") { - if (curr[1] == " " && !isIdent(curr[2]) && !isFunction(curr[2])) { - curr.splice(0, 2); +function reduceSelector(acc, curr) { + let hasCompoundSelector = true; + // @ts-ignore + curr = curr.slice(this.match[0].length); + while (curr.length > 0) { + if (curr[0] == " ") { + hasCompoundSelector = false; + curr.unshift("&"); + continue; } + break; } - acc.push(curr.join("")); + if (hasCompoundSelector && curr.length > 0) { + hasCompoundSelector = !["&"].concat(combinators).includes(curr[0].charAt(0)); + } + if (curr[0] == ":is(") { + let canReduce = true; + const isCompound = curr.reduce((acc, token, index) => { + if (index == 0) { + canReduce = curr[1] == "&"; + } + else if (token == ")") ; + else if (token == ",") { + if (!canReduce) { + canReduce = curr[index + 1] == "&"; + } + acc.push([]); + } + else + acc.at(-1)?.push(token); + return acc; + }, [[]]); + if (canReduce) { + curr = isCompound.reduce((acc, curr) => { + if (acc.length > 0) { + acc.push(","); + } + for (const c of curr) { + acc.push(c); + } + return acc; + }, []); + } + } + acc.push( + // @ts-ignore + this.match.length == 0 + ? ["&"] + : hasCompoundSelector && curr[0] != "&" && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) + ? ["&"].concat(curr) + : curr); return acc; } /** - * Apply minification rules to the ast tree - * @param ast - * @param options - * @param recursive - * @param errors - * @param nestingContent - * @param context + * Match selectors + * @param selector1 + * @param selector2 * * @private */ -function doMinify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) { - if (!("nodes" in context)) { - context.nodes = new Set(); - } - if (context.nodes.has(ast)) { - return ast; - } - context.nodes.add(ast); - // @ts-ignore - if ("chi" in ast && ast.chi.length > 0) { - const reducer = reduce.bind(ast); - if (!nestingContent) { - nestingContent = options.nestingRules && ast.typ == exports.EnumToken.RuleNodeType; +function matchSelectors(selector1, selector2) { + let match = [[]]; + const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0)); + let i = 0; + let k; + let l; + let token; + let matching = true; + let matchFunction = 0; + let inAttr = 0; + const regEx = /^:is\(([:.][^\s,]+)\)$/; + for (const _1 of selector1) { + if (_1[0] !== "&") { + continue; } - let i = 0; - let previous = null; - let node = null; - let nodeIndex = -1; - for (; i < ast.chi.length; i++) { - if (ast.chi[i].typ === exports.EnumToken.CommentNodeType) { - continue; - } - while (previous?.typ === exports.EnumToken.CommentNodeType) { - // @ts-ignore - previous = ast.chi[--nodeIndex]; - } - node = ast.chi[i]; - if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { - continue; - } - if (node.typ === exports.EnumToken.KeyframesAtRuleNodeType) { - if (previous?.typ === exports.EnumToken.KeyframesAtRuleNodeType && - node.nam === previous.nam && - node.val === previous.val) { - ast.chi?.splice(nodeIndex--, 1); - previous = ast?.chi?.[nodeIndex] ?? null; - i = nodeIndex; - continue; + for (let i = 1; i < _1.length; i++) { + const token = _1[i]; + if (token.startsWith(":is(")) { + const match = regEx.exec(token); + if (match != null) { + _1[i] = match[1]; } } - else if (node.typ === exports.EnumToken.KeyframesRuleNodeType) { - if (previous?.typ === exports.EnumToken.KeyframesRuleNodeType && - node.sel === previous.sel) { - // do not merge keyframes - // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates - previous.chi.push(...node.chi); - // @ts-ignore - ast.chi.splice(i, 1); - previous = ast?.chi?.[nodeIndex] ?? null; - i = nodeIndex; - continue; + } + } + for (const _1 of selector2) { + if (_1[0] !== "&") { + continue; + } + for (let i = 1; i < _1.length; i++) { + const token = _1[i]; + if (token.startsWith(":is(")) { + const match = regEx.exec(token); + if (match != null) { + _1[i] = match[1]; } - let k; - for (k = 0; k < node.chi.length; k++) { - if (node.chi[k].typ == exports.EnumToken.DeclarationNodeType) { - let l = node.chi[k].val.length; - while (l--) { - if (node.chi[k].val[l].typ == - exports.EnumToken.ImportantTokenType) { - node.chi.splice(k--, 1); - break; - } - if ([exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(node.chi[k].val[l].typ)) { - continue; - } - break; - } - } + } + } + } + for (; i < j; i++) { + k = 0; + token = selector1[0][i]; + for (; k < selector1.length; k++) { + if (selector1[k][i] != token) { + matching = false; + break; + } + } + if (matching) { + l = 0; + for (; l < selector2.length; l++) { + if (selector2[l][i] != token) { + matching = false; + break; } } - else if (node.typ == exports.EnumToken.AtRuleNodeType) { - if (node.nam == "media") { - if (Array.isArray(node[TOKENS])) { - const slice = node[TOKENS].slice(); - minifyAtRuleMedia(slice); - if (slice.length !== node[TOKENS].length) { - node[TOKENS].length = 0; - node[TOKENS].push(...slice); - node.val = slice.reduce((acc, curr, index, arr) => acc + - (curr.typ === exports.EnumToken.CommentTokenType || - (curr.typ === exports.EnumToken.WhitespaceTokenType && - arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && - (index + 3 < arr.length || - arr[index + 2]?.typ === exports.EnumToken.WhitespaceTokenType)) - ? "" - : renderValue(curr)), ""); - } - } - if (["all", "", null].includes(node.val)) { - ast.chi?.splice(i--, 1, ...node.chi); - continue; + } + if (!matching) { + break; + } + if (token.endsWith("(")) { + matchFunction++; + } + match.at(-1).push(token); + } + // invalid function + if (matchFunction != 0 || inAttr != 0) { + return null; + } + for (const part of match) { + while (part.length > 0) { + const token = part.at(-1); + if (token == " " || combinators.includes(token) || notEndingWith.includes(token.at(-1))) { + part.pop(); + continue; + } + break; + } + } + if (match.every((t) => t.length == 0)) { + return null; + } + if (eq([["&"]], match)) { + return null; + } + const reducer = reduceSelector.bind({ match }); + // @ts-ignore + selector1 = selector1.reduce(reducer, []); + // @ts-ignore + selector2 = selector2.reduce(reducer, []); + return selector1 == null || selector2 == null + ? null + : { + eq: eq(selector1, selector2), + match, + selector1, + selector2, + }; +} +/** + * Fix selector + * @param node + * + * @private + */ +function fixSelector(node) { + if (node.sel.includes("&")) { + const attributes = parseString(node.sel); + for (const attr of walkValues(attributes)) { + if (attr.value.typ == exports.EnumToken.PseudoClassFuncTokenType && + attr.value.val == ":is") { + let i = attr.value.chi.length; + while (i--) { + if (attr.value.chi[i].typ == exports.EnumToken.NestingSelectorTokenType) { + attr.value.chi.splice(i, 1); } } - else if (node.nam === "import" && Array.isArray(node[TOKENS])) { - let l = 0; - let token; - for (; l < node[TOKENS].length; l++) { - token = node[TOKENS][l]; - if (token.typ === exports.EnumToken.ParensTokenType || - token.typ === exports.EnumToken.MediaQueryConditionTokenType || - (token.typ === exports.EnumToken.IdenTokenType && "layer" !== token.val)) { - break; - } - } - if (l < node[TOKENS].length) { - const slice = node[TOKENS]?.slice(l); - node[TOKENS].splice(l, slice.length, ...minifyAtRuleMedia(slice)); - node.val = trimArray(node[TOKENS]).reduce((acc, curr, index, arr) => acc + - (curr.typ === exports.EnumToken.CommentTokenType || - (curr.typ === exports.EnumToken.WhitespaceTokenType && - arr[index + 1]?.typ === exports.EnumToken.CommentTokenType && - (index + 3 < arr.length || arr[index + 2].typ === exports.EnumToken.WhitespaceTokenType)) - ? "" - : renderValue(curr)), ""); + } + } + node.sel = attributes.reduce((acc, curr) => acc + renderValue(curr), ""); + node[TOKENS] = null; + } +} +/** + * Wrap nodes + * @param previous + * @param node + * @param match + * @param ast + * @param reducer + * @param i + * @param nodeIndex + * + * @private + */ +function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) { + // @ts-ignore + let pSel = match.selector1.reduce(reducer, []).join(","); + // @ts-ignore + let nSel = match.selector2.reduce(reducer, []).join(","); + const wrapper = { + ...previous, + chi: [], + // @ts-ignore + sel: match.match.reduce(reducer, []).join(","), + [RAW]: match.match.map((t) => t.slice()), + }; + if (pSel == "&" || pSel === "") { + for (const child of previous.chi) { + wrapper.chi.push(child); + } + if (nSel == "&" || nSel === "") { + for (const child of node.chi) { + wrapper.chi.push(child); + } + } + else { + wrapper.chi.push(node); + } + } + else { + wrapper.chi.push(previous, node); + } + ast.chi.splice(i, 1, wrapper); + ast.chi.splice(nodeIndex, 1); + previous.sel = pSel; + previous[RAW] = match.selector1; + previous[TOKENS] = null; + node.sel = nSel; + node[RAW] = match.selector2; + node[TOKENS] = null; + reduceRuleSelector(wrapper); + wrapper[TOKENS] = null; + return wrapper; +} +/** + * Diff nodes + * @param n1 + * @param n2 + * @param options + * + * @private + */ +function diff$1(n1, n2, options = {}) { + if (!("cache" in options)) { + options.cache = new WeakMap(); + } + let node1 = n1; + let node2 = n2; + let exchanged = false; + if (node1.chi.length > node2.chi.length) { + const t = node1; + node1 = node2; + node2 = t; + exchanged = true; + } + let i = node1.chi.length; + let j = node2.chi.length; + const raw1 = node1[RAW]; + const raw2 = node2[RAW]; + if (raw1 != null && raw2 != null) { + const prefixes1 = new Set(); + const prefixes2 = new Set(); + for (const token1 of raw1) { + for (const t of token1) { + if (t.includes(":")) { + const matches = t.match(/::?-([a-z]+)-/); + if (matches == null) { + continue; } - } - else if (ast.typ === node.typ && - ast.nam === node.nam && - ast.val === node.val) { - // @ts-ignore - replaceNodeOrValue(ast, node, node.chi); - i--; - continue; - } - if (previous?.typ == exports.EnumToken.AtRuleNodeType && - node.nam != "font-face" && - previous.nam === node.nam && - previous.val === node.val) { - if ("chi" in node) { - // @ts-ignore - previous.chi.push(...node.chi); - if (!hasDeclaration(previous)) { - context.nodes.delete(previous); - doMinify(previous, options, recursive, errors, nestingContent, context); - } + prefixes1.add(matches[1]); + if (prefixes1.size > 1) { + break; } - ast?.chi?.splice(i--, 1); - continue; - } - // if (!hasDeclaration(node as AstAtRule)) { - // doMinify(node, options, recursive, errors, nestingContent, context); - // } - if ("chi" in node) { - doMinify(node, options, recursive, errors, nestingContent, context); } - previous = node; - nodeIndex = i; - continue; } - // @ts-ignore - else if (node.typ === exports.EnumToken.RuleNodeType) { - reduceRuleSelector(node); - let wrapper = null; - let match; - if (options.nestingRules) { - if (previous?.typ == exports.EnumToken.RuleNodeType) { - reduceRuleSelector(previous); - // @ts-ignore - match = matchSelectors(previous[RAW], node[RAW]); - if (match != null) { - wrapper = wrapNodes(previous, node, match, ast, reducer, i, nodeIndex); - nodeIndex = i - 1; - previous = ast.chi[nodeIndex]; - } - } - if (wrapper != null) { - while (i < ast.chi.length) { - const nextNode = ast.chi[i]; - if (nextNode.typ != exports.EnumToken.RuleNodeType) { - break; - } - reduceRuleSelector(nextNode); - match = matchSelectors(wrapper[RAW], nextNode[RAW]); - if (match == null) { - break; - } - wrapper = wrapNodes(wrapper, nextNode, match, ast, reducer, i, nodeIndex); - } - nodeIndex = --i; - previous = ast.chi[nodeIndex]; - doMinify(wrapper, options, recursive, errors, nestingContent, context); + if (prefixes1.size > 1) { + break; + } + } + for (const token2 of raw2) { + for (const t of token2) { + if (t.includes(":")) { + const matches = t.match(/::?-([a-z]+)-/); + if (matches == null) { continue; } - // @ts-ignore - else if (node[OPTIMIZED] != null && - // @ts-ignore - node[OPTIMIZED].match && - // @ts-ignore - node[OPTIMIZED].selector.length > 1) { - // @ts-ignore - wrapper = { - ...node, - chi: [], - sel: node[OPTIMIZED].optimized[0], - [RAW]: [[node[OPTIMIZED].optimized[0]]], - }; - // @ts-ignore - node.sel = node[OPTIMIZED].selector.reduce(reducer, []).join(","); - // @ts-ignore - node[RAW] = node[OPTIMIZED].selector.slice(); - node[TOKENS] = null; - // @ts-ignore - wrapper.chi.push(node); - // @ts-ignore - ast.chi.splice(i, 1, wrapper); - node = wrapper; - } - else if (node[OPTIMIZED]?.reducible) { - if (node[OPTIMIZED].optimized.length === 1) { - const sel1 = node[OPTIMIZED].optimized[0] + - ":is(" + - node[OPTIMIZED].selector.reduce(reducer, []).join(",") + - ")"; - const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => - // @ts-ignore - (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); - node.sel = sel1.length < sel2.length ? sel1 : sel2; - node[TOKENS] = null; - } - else if (node[OPTIMIZED].optimized.length === 0) { - const testIdent = /^[a-zA-Z]/; - node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + - (nestingContent && testIdent.test(curr[0]) ? "& " : "") + - curr.join(""), ""); - node[TOKENS] = null; - } - } - } - // @ts-ignore - else if (node[OPTIMIZED]?.match) { - let wrap = true; - // @ts-ignore - const selector = node[OPTIMIZED].selector.reduce((acc, curr) => { - if (curr[0] == "&" && curr.length > 1) { - if (curr[1] == " ") { - curr.splice(0, 2); - } - else { - curr.splice(0, 1); - } - } - else if (combinators.includes(curr[0])) { - curr.unshift("&"); - wrap = false; - } - acc.push(curr); - return acc; - }, []); - if (!wrap) { - wrap = selector.some((s) => s[0] != "&"); - } - let rule = null; - const optimized = node[OPTIMIZED].optimized.slice(); - if (optimized.length > 1) { - const check = optimized.at(-2); - if (!combinators.includes(check)) { - let last = optimized.pop(); - wrap = false; - rule = - optimized.join("") + - `:is(${selector - .map((s) => { - if (s[0] == "&") { - s.splice(0, 1, last); - } - else { - s.unshift(last); - } - return s.join(""); - }) - .join(",")})`; - } - } - if (rule == null) { - rule = selector - .map((s) => { - if (s[0] == "&") { - s.splice(0, 1, ...node[OPTIMIZED].optimized); - } - return s.join(""); - }) - .join(","); - } - let sel = wrap ? node[OPTIMIZED].optimized.join("") + `:is(${rule})` : rule; - if (sel.length < node.sel.length) { - node.sel = sel; - node[TOKENS] = null; - } - } - else if (node[OPTIMIZED]?.reducible) { - if (node[OPTIMIZED].optimized.length === 1) { - const sel1 = node[OPTIMIZED].optimized[0] + - ":is(" + - node[OPTIMIZED].selector.reduce(reducer, []).join(",") + - ")"; - const sel2 = node[OPTIMIZED].selector.reduce((acc, curr) => - // @ts-ignore - (acc.length > 0 ? acc + "," : "") + node[OPTIMIZED].optimized[0] + curr.join(""), ""); - node.sel = sel1.length < sel2.length ? sel1 : sel2; - node[TOKENS] = null; - } - else if (node[OPTIMIZED].optimized.length === 0) { - const testIdent = /^[a-zA-Z]/; - node.sel = node[OPTIMIZED].selector.reduce((acc, curr) => (acc.length > 0 ? acc + "," : "") + - (nestingContent && testIdent.test(curr[0]) ? "& " : "") + - curr.join(""), ""); - node[TOKENS] = null; - } - // @ts-ignore - } - else if (node[OPTIMIZED]?.optimized.length > 0) { - // @ts-ignore - const sel = node[OPTIMIZED].optimized.join(""); - if (sel.length < node.sel.length) { - node.sel = sel; - // @ts-ignore - node[RAW] = [node[OPTIMIZED].optimized.slice()]; - node[TOKENS] = null; - } - } - doMinify(node, options, recursive, errors, nestingContent, context); - } - if (previous != null) { - if ("chi" in previous && "chi" in node) { - if (previous.typ === node.typ) { - let shouldMerge = true; - let k = previous.chi.length; - while (k-- > 0) { - if (previous.chi[k].typ === exports.EnumToken.CommentNodeType || - previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType || - previous.chi[k].typ === exports.EnumToken.InvalidRuleNodeType) { - continue; - } - shouldMerge = previous.chi[k].typ === exports.EnumToken.DeclarationNodeType; - break; - } - if (shouldMerge) { - if (((node.typ === exports.EnumToken.RuleNodeType || - node.typ === exports.EnumToken.KeyframesRuleNodeType) && - node.sel === previous.sel) || - // @ts-ignore - (node.typ == exports.EnumToken.AtRuleNodeType && - node.nam !== "font-face" && - // @ts-ignore - node.nam === previous.nam)) { - // @ts-ignore - node.chi.unshift(...previous.chi); - doMinify(node, options, recursive, errors, nestingContent, context); - ast.chi.splice(nodeIndex, 1); - previous = ast.chi[--i]; - nodeIndex = i; - continue; - } - else if (node.typ == previous?.typ && - [exports.EnumToken.KeyframesRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) { - const intersect = diff$1(previous, node, options); - if (intersect != null) { - if (intersect.node1.chi.length == 0) { - ast.chi.splice(i--, 1); - } - else { - ast.chi.splice(i--, 1, intersect.node1); - } - if (intersect.node2.chi.length == 0) { - if (intersect.result != null) { - ast.chi.splice(nodeIndex, 1, intersect.result); - } - else { - ast.chi.splice(nodeIndex, 1); - } - i--; - if (nodeIndex == i) { - nodeIndex = i; - } - } - else { - if (intersect.result != null) { - ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2); - } - else { - ast.chi.splice(nodeIndex, 1, intersect.node2); - } - i = (nodeIndex ?? 0) + 1; - } - if (node != ast.chi[i]) { - node = ast.chi[i]; - } - previous = intersect.result; - nodeIndex = i; - } - } - } - } - if (recursive && previous != null && previous != node) { - if (!hasDeclaration(previous)) { - doMinify(previous, options, recursive, errors, nestingContent, context); - } + prefixes2.add(matches[1]); + if (prefixes2.size > 1) { + break; } } } - if (!nestingContent && - previous != null && - previous.typ == exports.EnumToken.RuleNodeType && - previous.sel.includes("&")) { - fixSelector(previous); + if (prefixes2.size > 1) { + break; } - previous = node; - nodeIndex = i; } - if (recursive && node != null && "chi" in node) { - 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")) { - doMinify(node, options, recursive, errors, nestingContent, context); - } - } + if (prefixes1.size != prefixes2.size) { + return null; } - if (!nestingContent && - node != null && - node.typ == exports.EnumToken.RuleNodeType && - node.sel.includes("&")) { - fixSelector(node); + for (const prefix of prefixes1) { + if (!prefixes2.has(prefix)) { + return null; + } } } - return ast; -} -/** - * Check if a rule has a declaration - * @param node - * - * @private - */ -function hasDeclaration(node) { - // @ts-ignore - for (let i = 0; i < node.chi?.length; i++) { - // @ts-ignore - if (node.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; - } - // @ts-ignore - return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; + const css1 = options.cache.get(node1); + const css2 = options.cache.get(node2); + node1 = { ...node1, chi: node1.chi.slice() }; + node2 = { ...node2, chi: node2.chi.slice() }; + if (css1 != null) { + options.cache.set(node1, css1); } - return true; -} -/** - * Optimize selector - * @param selector - * - * @private - */ -function optimizeSelector(selector) { - const map = new Set(); - selector = selector - .reduce((acc, curr) => { - // @ts-ignore - if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { - // @ts-ignore - const rules = splitRule(curr.at(-1).slice(4, -1)).map((x) => { - if (x[0] == "&" && x.length > 1) { - return x.slice(x[1] == " " ? 2 : 1); + if (css2 != null) { + options.cache.set(node2, css2); + } + if (raw1 != null) { + node1[RAW] = raw1; + } + if (raw2 != null) { + node2[RAW] = raw2; + } + const intersect = []; + while (i--) { + if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { + continue; + } + j = node2.chi.length; + while (j--) { + if (node2.chi[j].typ == exports.EnumToken.CommentNodeType) { + continue; + } + if (node1.chi[i].nam == node2.chi[j].nam) { + if (node1.chi[i].typ == node2.chi[j].typ && eq(node1.chi[i], node2.chi[j])) { + intersect.push(node1.chi[i]); + node1.chi.splice(i, 1); + node2.chi.splice(j, 1); + options.cache.delete(node1); + options.cache.delete(node2); + break; } - return x; - }); - const part = curr.slice(0, -1); - for (const rule of rules) { - acc.push(part.concat(rule)); } - return acc; - } - acc.push(curr); - return acc; - }, []) - .filter((x) => { - const str = x.join(""); - if (map.has(str)) { - return false; } - map.add(str); - return true; - }); - const optimized = []; - const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : curr.length == 0 ? acc : Math.min(acc, curr.length), 0); - let i = 0; - let j; - let match; - for (; i < k; i++) { - const item = selector[0][i]; - match = true; - for (j = 1; j < selector.length; j++) { - if (item != selector[j][i]) { - match = false; - break; + } + const result = intersect.length === 0 && (node1.chi.length > 0 || node2.chi.length > 0) + ? null + : { + ...node1, + // @ts-ignore + sel: [ + ...new Set(splitRule(node1.sel) + .concat(splitRule(node2.sel)) + .map((s) => s.join(""))), + ].join(","), + // @ts-ignore + chi: intersect.reverse(), + }; + let op = { level: 0, ...options }; + if (result == null || + [n1, n2].reduce((acc, curr) => { + let css = options.cache.get(curr); + if (css == null) { + let level = 0; + let parent = curr[PARENT]; + while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { + level++; + parent = parent[PARENT]; + } + op.level = level; + css = doRender(curr, op).code; + options.cache.set(curr, css); } + return curr.chi.length == 0 ? acc : acc + css.length; + }, 0) <= + [node1, node2, result].reduce((acc, curr) => { + let css = options.cache.get(curr); + if (css != null) { + return curr.chi.length == 0 ? acc : acc + css.length; + } + let level = 0; + let parent = curr[PARENT]; + while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { + level++; + parent = parent[PARENT]; + } + op.level = level; + css = doRender(curr, op).code; + return curr.chi.length == 0 ? acc : acc + css.length; + }, 0)) { + if (node1.chi.length != 0 && node2.chi.length != 0) { + return null; } - if (!match) { - break; - } - optimized.push(item); } - while (optimized.length > 0) { - const last = optimized.at(-1); - if (last == " " || combinators.includes(last)) { - optimized.pop(); - continue; + if (result != null) { + result[TOKENS] = null; + result[RAW] = null; + const optimized = optimizeSelector(splitRule(result.sel)); + if (optimized?.match) { + const rule = optimized.selector.reduce((acc, curr) => { + if (acc.length > 0) { + acc += ","; + } + if (curr.length > 2 && curr[0] === "&" && curr[1] === " ") { + return acc + curr.slice(2).join(""); + } + else if (curr.length > 1 && curr[0] === "&") { + return acc + curr.slice(1).join(""); + } + return acc + curr.join(""); + }, ""); + const match = optimized.optimized.join(""); + const sel = match + ":is(" + replaceCompound(rule, match) + ")"; + if (sel.length < result.sel.length) { + result.sel = sel; + result[TOKENS] = null; + } } - break; - } - for (let i1 = 0; i1 < selector.length; i1++) { - selector[i1].splice(0, optimized.length); } - let reducible = optimized.length == 1; - if (optimized[0] == "&") { - if (optimized[1] == " ") { - optimized.splice(0, 2); - } + return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; +} +/** + * Reduce rule selector + * @param node + * + * @private + */ +function reduceRuleSelector(node) { + if (node[RAW] == null) { + node[RAW] = splitRule(node.sel); } - if (optimized.length == 0 || optimized[0].charAt(0) == "&" || selector.length == 1) { - return { - match: false, - optimized, - selector: selector.map((selector) => selector[0] == "&" && selector[1] == " " ? selector.slice(2) : selector), - reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0])), - }; + let optimized = optimizeSelector(node[RAW].reduce((acc, curr) => { + acc.push(curr.slice()); + return acc; + }, [])); + if (optimized != null) { + node[OPTIMIZED] = optimized; } - return { - match: true, - optimized, - selector: selector.reduce((acc, curr) => { - let hasCompound = true; - if (hasCompound && curr.length > 0) { - hasCompound = !["&"].concat(combinators).includes(curr[0].charAt(0)); - } - // @ts-ignore - if (hasCompound && curr[0] == " ") { - hasCompound = false; - curr.unshift("&"); - } - if (curr.length == 0) { - curr.push("&"); - hasCompound = false; + if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) { + for (const selector of optimized.selector) { + if (selector.length > 1 && + selector[0] == "&" && + (combinators.includes(selector[1]) || !/^[a-zA-Z:]/.test(selector[1]))) { + selector.shift(); } - if (reducible) { - const chr = curr[0].charAt(0); - // @ts-ignore - reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); + } + const unique = new Set(); + const reduced = optimized.selector.reduce((acc, curr) => { + const sig = curr.join(""); + if (!unique.has(sig)) { + if (acc.length > 0) { + acc.push(","); + } + unique.add(sig); + for (const c of curr) { + acc.push(c); + } } - acc.push(hasCompound ? ["&"].concat(curr) : curr); return acc; - }, []), - reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), - }; + }, []); + const raw = [ + [optimized.optimized[0], reduced.length === 1 ? reduced.join("") : ":is("].concat(reduced).concat(")"), + ]; + const sel = raw[0].join(""); + if (sel.length < node.sel.length) { + node.sel = sel; + node[RAW] = raw; + node[TOKENS] = null; + } + } } + /** - * Split selector string - * @param buffer + * expand css nesting ast nodes + * @param ast * - * @internal + * @private */ -function splitRule(buffer) { - const result = [[]]; - let str = ""; - for (let i = 0; i < buffer.length; i++) { - let chr = buffer.charAt(i); - if (isWhiteSpace(chr.charCodeAt(0))) { - if (str !== "") { - // @ts-ignore - result.at(-1).push(str); - str = ""; - } - // @ts-ignore - if (result.at(-1).length > 0) { - // @ts-ignore - result.at(-1).push(" "); - } - // i = k; - continue; - } - if (chr == ",") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - result.push([]); - continue; - } - if (chr == ".") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - str += chr; - continue; - } - if (combinators.includes(chr)) { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - if (chr == "|" && buffer.charAt(i + 1) == "|") { - chr += buffer.charAt(++i); - } - result.at(-1).push(chr); - continue; - } - if (chr == ":") { - if (str !== "") { - result.at(-1).push(str); - str = ""; - } - if (buffer.charAt(i + 1) == ":") { - chr += buffer.charAt(++i); +function expand(ast) { + if (ast[STATE] == exports.EnumAstNodeStatus.Invalid || + ast[STATE] == exports.EnumAstNodeStatus.Disallowed || + ast[STATE] == exports.EnumAstNodeStatus.Unknown || + ast[STATE] == exports.EnumAstNodeStatus.Unparsed || + ast[STATE] == exports.EnumAstNodeStatus.Malformed) { + return ast; + } + const result = Object.assign(cloneNode(ast), { chi: [] }); + let children; + for (let i = 0; i < ast.chi.length; i++) { + let node = ast.chi[i]; + if (node.typ === exports.EnumToken.RuleNodeType) { + children = expandRule(node); + for (const child of children) { + child[PARENT] = result; + result.chi.push(child); } - str += chr; - continue; - } - str += chr; - if (chr == "\\") { - str += buffer.charAt(++i); - continue; } - if (chr == "(" || chr == "[") { - const open = chr; - const close = chr == "(" ? ")" : "]"; - let inParens = 1; - let k = i; - while (++k < buffer.length) { - chr = buffer.charAt(k); - if (chr == "\\") { - str += buffer.slice(k, k + 2); - k++; - continue; - } - str += chr; - if (chr == open) { - inParens++; - } - else if (chr == close) { - inParens--; - } - if (inParens == 0) { + else if (node.typ == exports.EnumToken.AtRuleNodeType && "chi" in node) { + let hasRule = false; + let j = node.chi.length; + while (j--) { + // @ts-ignore + if (node.chi[j].typ == exports.EnumToken.RuleNodeType || node.chi[j].typ == exports.EnumToken.AtRuleNodeType) { + hasRule = true; break; } } - i = k; - } - } - if (str !== "") { - result.at(-1).push(str); - } - return result; -} -/** - * Reduce selector - * @param acc - * @param curr - * - * @private - */ -function reduceSelector(acc, curr) { - let hasCompoundSelector = true; - // @ts-ignore - curr = curr.slice(this.match[0].length); - while (curr.length > 0) { - if (curr[0] == " ") { - hasCompoundSelector = false; - curr.unshift("&"); - continue; - } - break; - } - if (hasCompoundSelector && curr.length > 0) { - hasCompoundSelector = !["&"].concat(combinators).includes(curr[0].charAt(0)); - } - if (curr[0] == ":is(") { - let canReduce = true; - const isCompound = curr.reduce((acc, token, index) => { - if (index == 0) { - canReduce = curr[1] == "&"; - } - else if (token == ")") ; - else if (token == ",") { - if (!canReduce) { - canReduce = curr[index + 1] == "&"; + if (hasRule) { + node = expand(node); + for (const child of node.chi) { + child[PARENT] = result; } - acc.push([]); + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } - else - acc.at(-1)?.push(token); - return acc; - }, [[]]); - if (canReduce) { - curr = isCompound.reduce((acc, curr) => { - if (acc.length > 0) { - acc.push(","); - } - acc.push(...curr); - return acc; - }, []); - } - } - acc.push( - // @ts-ignore - this.match.length == 0 - ? ["&"] - : hasCompoundSelector && curr[0] != "&" && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) - ? ["&"].concat(curr) - : curr); - return acc; -} -/** - * Match selectors - * @param selector1 - * @param selector2 - * - * @private - */ -function matchSelectors(selector1, selector2) { - let match = [[]]; - const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0)); - let i = 0; - let k; - let l; - let token; - let matching = true; - let matchFunction = 0; - let inAttr = 0; - const regEx = /^:is\(([:.][^\s,]+)\)$/; - for (const _1 of selector1) { - if (_1[0] !== "&") { - continue; - } - for (let i = 1; i < _1.length; i++) { - const token = _1[i]; - if (token.startsWith(":is(")) { - const match = regEx.exec(token); - if (match != null) { - _1[i] = match[1]; - } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - } - for (const _1 of selector2) { - if (_1[0] !== "&") { - continue; - } - for (let i = 1; i < _1.length; i++) { - const token = _1[i]; - if (token.startsWith(":is(")) { - const match = regEx.exec(token); - if (match != null) { - _1[i] = match[1]; - } - } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - for (; i < j; i++) { - k = 0; - token = selector1[0][i]; - for (; k < selector1.length; k++) { - if (selector1[k][i] != token) { - matching = false; - break; - } - } - if (matching) { - l = 0; - for (; l < selector2.length; l++) { - if (selector2[l][i] != token) { - matching = false; - break; - } - } - } - if (!matching) { - break; - } - if (token.endsWith("(")) { - matchFunction++; - } - match.at(-1).push(token); + return result; +} +function expandRule(node) { + if (node[STATE] == exports.EnumAstNodeStatus.Invalid || + node[STATE] == exports.EnumAstNodeStatus.Disallowed || + node[STATE] == exports.EnumAstNodeStatus.Unknown || + node[STATE] == exports.EnumAstNodeStatus.Unparsed || + node[STATE] == exports.EnumAstNodeStatus.Malformed) { + return [node]; } - // invalid function - if (matchFunction != 0 || inAttr != 0) { - return null; - } - for (const part of match) { - while (part.length > 0) { - const token = part.at(-1); - if (token == " " || combinators.includes(token) || notEndingWith.includes(token.at(-1))) { - part.pop(); - continue; + const ast = Object.assign(cloneNode(node), { chi: node.chi.slice() }); + const result = []; + if (ast.typ == exports.EnumToken.RuleNodeType) { + let i = 0; + for (; i < ast.chi.length; i++) { + if (ast.chi[i].typ == exports.EnumToken.RuleNodeType) { + const rule = ast.chi[i]; + if (!rule.sel.includes("&")) { + const selRule = splitRule(rule.sel); + const arSelf = splitRule(ast.sel) + .filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))) + .reduce((acc, curr) => acc.concat([curr.join("")]), []) + .join(","); + if (arSelf.length == 0) { + ast.chi.splice(i--, 1); + continue; + } + for (let i1 = 0; i1 < selRule.length; i1++) { + const arr = selRule[i1]; + combinators.includes(arr[0].charAt(0)) ? arr.unshift(arSelf) : arr.unshift(arSelf, " "); + } + rule.sel = selRule + .reduce((acc, curr) => { + acc.push(curr.join("")); + return acc; + }, []) + .join(","); + } + else { + let childSelectorCompound = []; + let withCompound = []; + let withoutCompound = []; + // pseudo elements cannot be used with '&' + // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e + const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))); + const parentSelector = !node.sel.includes("&"); + if (rules.length == 0) { + ast.chi.splice(i--, 1); + continue; + } + for (const sel of rule[RAW] ?? splitRule(rule.sel)) { + const s = sel.join(""); + if (s.includes("&") || parentSelector) { + if (s.indexOf("&", 1) == -1) { + if (s.at(0) == "&") { + if (s.at(1) == " ") { + childSelectorCompound.push(s.slice(2)); + } + else { + if (s == "&" || parentSelector) { + withCompound.push(s); + } + } + } + else { + withoutCompound.push(s); + } + } + else { + withCompound.push(s); + } + } + } + const selectors = []; + const selector = rules.length > 1 ? ":is(" + rules.map((a) => a.join("")).join(",") + ")" : rules[0].join(""); + if (childSelectorCompound.length > 0) { + if (childSelectorCompound.length == 1) { + selectors.push(replaceCompound("& " + childSelectorCompound[0].trim(), selector)); + } + else { + selectors.push(replaceCompound("& :is(" + + childSelectorCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + + ")", selector)); + } + } + if (withCompound.length > 0) { + if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { + // for (const w of withCompound) { + // for (let m = 0; m < w.length; m++) { + // // for (let n = 0; n < w[m].length; n++) { + // withoutCompound.push(w[m].slice(1)); + // // } + // } + // } + withoutCompound.push(...withCompound.map((t) => t.slice(1))); + withCompound.length = 0; + } + } + if (withoutCompound.length > 0) { + if (withoutCompound.length == 1) { + const useIs = rules.length == 1 && + selector.match(/^[a-zA-Z.:]/) != null && + selector.includes(" ") && + withoutCompound.length == 1 && + withoutCompound[0].match(/^[a-zA-Z]+$/) != null; + const compound = useIs ? ":is(&)" : "&"; + selectors.push(replaceCompound(rules.length == 1 + ? useIs + ? withoutCompound[0] + ":is(&)" + : selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) + ? withoutCompound[0] + compound + : compound + withoutCompound[0] + : withoutCompound[0].match(/^[a-zA-Z:]+$/) + ? withoutCompound[0].trim() + compound + : "&" + + (withoutCompound[0].match(/^\S+$/) + ? withoutCompound[0].trim() + : ":is(" + withoutCompound[0].trim() + ")"), selector)); + } + else { + selectors.push(replaceCompound("&:is(" + + withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + + ")", selector)); + } + } + if (withCompound.length > 0) { + if (withCompound.length == 1) { + selectors.push(replaceCompound(withCompound[0], selector)); + } + } + rule.sel = selectors.reduce((acc, curr) => (curr.length == 0 ? acc : acc + (acc.length > 0 ? "," : "") + curr), ""); + } + ast.chi.splice(i--, 1); + for (const s of expandRule(rule)) { + result.push(s); + } + } + else if (ast.chi[i].typ == exports.EnumToken.AtRuleNodeType) { + let astAtRule = ast.chi[i]; + const values = []; + if (astAtRule.nam === "scope") { + if (astAtRule.val.includes("&")) { + astAtRule.val = replaceCompound(astAtRule.val, ast.sel); + } + const slice = astAtRule.chi + .slice() + .filter((t) => t.typ == exports.EnumToken.RuleNodeType && t.sel.includes("&")); + if (slice.length > 0) { + expandRule({ ...node, chi: astAtRule.chi.slice() }); + } + } + else { + // @ts-ignore + const clone = { ...ast, chi: astAtRule.chi.slice() }; + // @ts-ignore + astAtRule.chi.length = 0; + for (const r of expandRule(clone)) { + if (r.typ == exports.EnumToken.AtRuleNodeType && "chi" in r) { + if (astAtRule.val !== "" && r.val !== "") { + if (astAtRule.nam === "media" && r.nam === "media") { + r.val = astAtRule.val + " and " + r.val; + } + else if (astAtRule.nam == "layer" && r.nam == "layer") { + r.val = astAtRule.val + "." + r.val; + } + } + // @ts-ignore + values.push(r); + } + else if (r.typ == exports.EnumToken.RuleNodeType) { + for (const rule of expandRule(r)) { + // @ts-ignore + astAtRule.chi.push(rule); + } + } + } + } + if (astAtRule.chi.length > 0) { + result.push(astAtRule); + } + for (const r of values) { + result.push(r); + } + ast.chi.splice(i--, 1); } - break; } } - if (match.every((t) => t.length == 0)) { - return null; - } - if (eq([["&"]], match)) { - return null; - } - const reducer = reduceSelector.bind({ match }); - // @ts-ignore - selector1 = selector1.reduce(reducer, []); // @ts-ignore - selector2 = selector2.reduce(reducer, []); - return selector1 == null || selector2 == null - ? null - : { - eq: eq(selector1, selector2), - match, - selector1, - selector2, - }; + return ast.chi.length > 0 ? [ast].concat(result) : result; } /** - * Fix selector - * @param node - * - * @private + * replace compound selector + * @param input + * @param replace */ -function fixSelector(node) { - if (node.sel.includes("&")) { - const attributes = [...tokenize(node.sel)].map((t) => t.token); // parseString(node.sel); - for (const attr of walkValues(attributes)) { - if (attr.value.typ == exports.EnumToken.PseudoClassFuncTokenType && - attr.value.val == ":is") { - let i = attr.value.chi.length; - while (i--) { - if (attr.value.chi[i].typ == exports.EnumToken.NestingSelectorTokenType) { - attr.value.chi.splice(i, 1); - } +function replaceCompound(input, replace) { + const tokens = parseString(input); + let replacement = null; + for (const t of walkValues(tokens)) { + if (t.value.typ == exports.EnumToken.NestingSelectorTokenType) { + if (tokens.length == 2) { + if (replacement == null) { + replacement = parseString(replace); } + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: replaceCompoundLiteral(t.value.val, replace), + }); + continue; } + const rule = splitRule(replace); + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: rule.length > 1 ? ":is(" + replace + ")" : replace, + }); + } + } + return tokens.reduce((acc, curr) => acc + renderValue(curr), ""); +} +function replaceCompoundLiteral(selector, replace) { + const tokens = [""]; + let i = 0; + for (; i < selector.length; i++) { + if (selector.charAt(i) == "&") { + tokens.push("&", ""); } - node.sel = attributes.reduce((acc, curr) => acc + renderValue(curr), ""); - node[TOKENS] = null; } + return tokens + .sort((a, b) => { + if (a == "&") { + return 1; + } + return b == "&" ? -1 : 0; + }) + .reduce((acc, curr) => acc + (curr == "&" ? replace : curr), ""); +} + +// from https://github.com/Rich-Harris/vlq/tree/master +// credit: Rich Harris +const integer_to_char = {}; +const char_to_integer = {}; +let i = 0; +for (const char of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=') { + char_to_integer[char] = i; + integer_to_char[i++] = char; } /** - * Wrap nodes - * @param previous - * @param node - * @param match - * @param ast - * @param reducer - * @param i - * @param nodeIndex - * - * @private + * @param {string} str */ -function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) { - // @ts-ignore - let pSel = match.selector1.reduce(reducer, []).join(","); - // @ts-ignore - let nSel = match.selector2.reduce(reducer, []).join(","); - const wrapper = { - ...previous, - chi: [], - // @ts-ignore - sel: match.match.reduce(reducer, []).join(","), - [RAW]: match.match.map((t) => t.slice()), - }; - if (pSel == "&" || pSel === "") { - wrapper.chi.push(...previous.chi); - if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); +function decode(str) { + /** @type {number[]} */ + let result = []; + let shift = 0; + let value = 0; + for (let i = 0; i < str.length; i += 1) { + let integer = char_to_integer[str[i]]; + // if (integer === undefined) { + // throw new Error('Invalid character (' + str[i] + ')'); + // } + const has_continuation_bit = integer & 32; + integer &= 31; + value += integer << shift; + if (has_continuation_bit) { + shift += 5; } else { - wrapper.chi.push(node); + const should_negate = value & 1; + value >>>= 1; + if (should_negate) { + result.push(value === 0 ? -2147483648 : -value); + } + else { + result.push(value); + } + // reset + value = shift = 0; } } - else { - wrapper.chi.push(previous, node); - } - ast.chi.splice(i, 1, wrapper); - ast.chi.splice(nodeIndex, 1); - previous.sel = pSel; - previous[RAW] = match.selector1; - previous[TOKENS] = null; - node.sel = nSel; - node[RAW] = match.selector2; - node[TOKENS] = null; - reduceRuleSelector(wrapper); - wrapper[TOKENS] = null; - return wrapper; + return result; } /** - * Diff nodes - * @param n1 - * @param n2 - * @param options * - * @private + * @param value + * @returns */ -function diff$1(n1, n2, options = {}) { - if (!("cache" in options)) { - options.cache = new WeakMap(); +function encode(value) { + if (typeof value === 'number') { + return encode_integer(value); } - let node1 = n1; - let node2 = n2; - let exchanged = false; - if (node1.chi.length > node2.chi.length) { - const t = node1; - node1 = node2; - node2 = t; - exchanged = true; + let result = ''; + for (let i = 0; i < value.length; i += 1) { + result += encode_integer(value[i]); } - let i = node1.chi.length; - let j = node2.chi.length; - const raw1 = node1[RAW]; - const raw2 = node2[RAW]; - if (raw1 != null && raw2 != null) { - const prefixes1 = new Set(); - const prefixes2 = new Set(); - for (const token1 of raw1) { - for (const t of token1) { - if (t.includes(":")) { - const matches = t.match(/::?-([a-z]+)-/); - if (matches == null) { - continue; - } - prefixes1.add(matches[1]); - if (prefixes1.size > 1) { - break; - } - } - } - if (prefixes1.size > 1) { - break; - } + return result; +} +function encode_integer(num) { + let result = ''; + if (num < 0) { + num = (-num << 1) | 1; + } + else { + num <<= 1; + } + do { + let clamped = num & 31; + num >>>= 5; + if (num > 0) { + clamped |= 32; } - for (const token2 of raw2) { - for (const t of token2) { - if (t.includes(":")) { - const matches = t.match(/::?-([a-z]+)-/); - if (matches == null) { - continue; - } - prefixes2.add(matches[1]); - if (prefixes2.size > 1) { - break; - } + result += integer_to_char[clamped]; + } while (num > 0); + return result; +} + +/** + * Generate and parse source map + */ +class SourceMap { + /** + * + * @private + */ + keys = new Set(); + /** + * Last location + */ + lastLocation = null; + /** + * Version + * @private + */ + version = 3; + /** + * Sources map + * @private + */ + sourcesMap = []; + /** + * Sources content + * @private + */ + sourcesContent = []; + /** + * Sources + * @private + */ + sources = []; + /** + * Map + * @private + * + */ + map = new Map(); + /** + * Map + * @private + * + */ + reverseMap = new Map(); + /** + * Line + * @private + */ + line = -1; + /** + * + * @param sourcemaps + */ + constructor(sourcemaps) { + if (typeof sourcemaps === "string") { + if (sourcemaps.startsWith("data:")) { + let encoding = ""; + let offset = sourcemaps.indexOf(",") + 1; + if (offset == 0) { + offset = sourcemaps.lastIndexOf(";") + 1; + } + else { + encoding = sourcemaps.slice(sourcemaps.lastIndexOf(";") + 1, offset - 1); + } + if (encoding == "base64") { + sourcemaps = atob(sourcemaps.slice(offset)); + } + else { + sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); } } - if (prefixes2.size > 1) { - break; - } - } - if (prefixes1.size != prefixes2.size) { - return null; + sourcemaps = JSON.parse(sourcemaps); } - for (const prefix of prefixes1) { - if (!prefixes2.has(prefix)) { - return null; + if (sourcemaps != null) { + this.sources = sourcemaps.sources?.slice() ?? []; + this.sourcesContent = sourcemaps.sourcesContent?.slice() ?? []; + const decodedMappings = sourcemaps.mappings + .split(";") + .map((mapping) => mapping.split(",").map((mapping) => decode(mapping))); + this.line = decodedMappings.length - 1; + for (let index = 0; index < decodedMappings.length; index++) { + if (decodedMappings[index].length == 0 || + (decodedMappings[index].length == 1 && decodedMappings[index][0].length == 0)) { + continue; + } + this.map.set(index, decodedMappings[index]); } + this.computePositions(); } } - const css1 = options.cache.get(node1); - const css2 = options.cache.get(node2); - node1 = { ...node1, chi: node1.chi.slice() }; - node2 = { ...node2, chi: node2.chi.slice() }; - if (css1 != null) { - options.cache.set(node1, css1); + /** + * add source + * @param id + * @param fileName + * @param content + * @returns + */ + addSourceContent(id, fileName, content) { + if (this.sourcesMap.includes(id)) { + return; + } + this.sourcesMap[this.sourcesMap.length] = id; + this.sources[this.sources.length] = fileName || null; + this.sourcesContent[this.sourcesContent.length] = content || null; } - if (css2 != null) { - options.cache.set(node2, css2); - } - if (raw1 != null) { - node1[RAW] = raw1; - } - if (raw2 != null) { - node2[RAW] = raw2; - } - const intersect = []; - while (i--) { - if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; - } - j = node2.chi.length; - while (j--) { - if (node2.chi[j].typ == exports.EnumToken.CommentNodeType) { + /** + * Add multiple sourcemaps + * @param maps + * @throws + */ + add(maps) { + let srcIndex; + for (let [newLine, newColumn, srcId, ln, col] of maps) { + const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; + if (this.keys.has(key)) { continue; } - if (node1.chi[i].nam == node2.chi[j].nam) { - if (node1.chi[i].typ == node2.chi[j].typ && eq(node1.chi[i], node2.chi[j])) { - intersect.push(node1.chi[i]); - node1.chi.splice(i, 1); - node2.chi.splice(j, 1); - options.cache.delete(node1); - options.cache.delete(node2); - break; - } + this.keys.add(key); + const line = newLine - 1; + let record; + if (line > this.line) { + this.line = line; + } + srcIndex = this.sourcesMap.indexOf(srcId); + if (srcIndex == -1) { + throw new Error(`Source file ${srcId} not added to sourcemap`); + } + if (!this.map.has(line)) { + record = [Math.max(0, newColumn - 1), srcIndex, ln - 1, col - 1]; + this.map.set(line, [record]); + } + else { + const arr = this.map.get(line); + record = [Math.max(0, newColumn - 1) - arr[0][0], srcIndex - arr[0][1], ln - 1, col - 1]; + arr.push(record); + } + if (this.lastLocation != null) { + record[2] -= this.lastLocation.ln - 1; + record[3] -= this.lastLocation.col - 1; } + this.lastLocation ??= { ln, col }; + this.lastLocation.ln = ln; + this.lastLocation.col = col; } } - const result = intersect.length === 0 && (node1.chi.length > 0 || node2.chi.length > 0) - ? null - : { - ...node1, - // @ts-ignore - sel: [ - ...new Set(splitRule(node1.sel) - .concat(splitRule(node2.sel)) - .map((s) => s.join(""))), - ].join(","), - // @ts-ignore - chi: intersect.reverse(), - }; - let op = { level: 0, ...options }; - if (result == null || - [n1, n2].reduce((acc, curr) => { - let css = options.cache.get(curr); - if (css == null) { - let level = 0; - let parent = curr[PARENT]; - while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { - level++; - parent = parent[PARENT]; - } - op.level = level; - css = doRender(curr, op).code; - options.cache.set(curr, css); + /** + * compute original positions + */ + computePositions() { + this.reverseMap.clear(); + let sourceFileIndex = 0; // second field + let sourceCodeLine = 0; // third field + let sourceCodeColumn = 0; // fourth field + // let nameIndex: number = 0; // fifth field + let generatedCodeColumn; + let result; + // mappings to original source + for (let [i, line] of this.map.entries()) { + if (line.length === 0 || (line.length === 1 && line[0].length === 0)) { + continue; } - return curr.chi.length == 0 ? acc : acc + css.length; - }, 0) <= - [node1, node2, result].reduce((acc, curr) => { - let css = options.cache.get(curr); - if (css != null) { - return curr.chi.length == 0 ? acc : acc + css.length; + generatedCodeColumn = line[0][0]; // first field - reset each time + line = line + .map((segment, index, array) => { + if (segment.length === 0) { + return []; } - let level = 0; - let parent = curr[PARENT]; - while (parent != null && parent.typ != exports.EnumToken.StyleSheetNodeType) { - level++; - parent = parent[PARENT]; + generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; + result = [generatedCodeColumn]; + if (segment.length <= 1) { + return result; } - op.level = level; - css = doRender(curr, op).code; - return curr.chi.length == 0 ? acc : acc + css.length; - }, 0)) { - if (node1.chi.length != 0 && node2.chi.length != 0) { + sourceFileIndex = index == 0 ? segment[1] : segment[1] + array[0][1]; + sourceCodeLine += segment[2]; + sourceCodeColumn += segment[3]; + result.push(sourceFileIndex, sourceCodeLine, sourceCodeColumn); + // nameIndex not needed + // if (segment.length === 5) { + // nameIndex += segment[4]; + // result.push(nameIndex); + // } + return result; + }) + .sort((a, b) => { + if (a[1] !== b[1]) { + return a[1] - b[1]; + } + return a[0] - b[0]; + }); + if (line.length == 0 || (line.length == 1 && line[0].length == 0)) { + continue; + } + this.reverseMap.set(i, line); + } + } + /** + * retrieve original sources, lines and columns + * @param line generated line + * @param column generated column + */ + find(line, column) { + if (this.reverseMap.size == 0) { + this.computePositions(); + } + if (!this.reverseMap.has(--line)) { return null; } + column--; + const result = []; + for (const record of this.reverseMap.get(line)) { + if (record.length == 0 || record[0] < column) { + continue; + } + if (record[0] > column) { + break; + } + result.push([ + this.sources?.[record[1]] ?? null, + record[2] + 1, + record[3] + 1, + this.sourcesContent?.[record[1]] ?? null, + ]); + } + return result.length == 0 ? null : result; } - if (result != null) { - result[TOKENS] = null; - result[RAW] = null; - const optimized = optimizeSelector(splitRule(result.sel)); - if (optimized?.match) { - const rule = optimized.selector.reduce((acc, curr) => { - if (acc.length > 0) { - acc += ","; - } - if (curr.length > 2 && curr[0] === "&" && curr[1] === " ") { - return acc + curr.slice(2).join(""); - } - else if (curr.length > 1 && curr[0] === "&") { - return acc + curr.slice(1).join(""); - } - return acc + curr.join(""); - }, ""); - const match = optimized.optimized.join(""); - const sel = match + ":is(" + replaceCompound(rule, match) + ")"; - if (sel.length < result.sel.length) { - result.sel = sel; - result[TOKENS] = null; + /** + * Convert to URL encoded string + */ + toUrl() { + // /*# sourceMappingURL = ${url} */ + return `data:application/json;charset=utf-8;base64,${btoa(JSON.stringify(this.toJSON()))}`; + } + /** + * Convert to JSON object + */ + toJSON() { + const mappings = []; + let i = 0; + for (; i <= this.line; i++) { + if (!this.map.has(i)) { + mappings.push(""); + } + else { + mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); } } + return { + version: this.version, + sources: this.sources.slice(), + sourcesContent: this.sourcesContent?.slice(), + mappings: mappings.join(";"), + }; } - return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; } + /** - * Reduce rule selector - * @param node - * - * @private + * Compute line and column of the offset */ -function reduceRuleSelector(node) { - if (node[RAW] == null) { - node[RAW] = splitRule(node.sel); - } - let optimized = optimizeSelector(node[RAW].reduce((acc, curr) => { - acc.push(curr.slice()); - return acc; - }, [])); - if (optimized != null) { - node[OPTIMIZED] = optimized; +class LineMap { + /** + * line starts + */ + lineStarts; + /** + * Constructor + * @param lines + */ + constructor(lines = []) { + if (lines.length === 0) { + lines.push(0); + } + this.lineStarts = lines; } - if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) { - for (const selector of optimized.selector) { - if (selector.length > 1 && - selector[0] == "&" && - (combinators.includes(selector[1]) || !/^[a-zA-Z:]/.test(selector[1]))) { - selector.shift(); + /** + * Compute line and column of the offset + * @param offset + * @returns + */ + getOffsets(offset) { + const line = this.search(offset); + const column = offset - this.lineStarts[line]; + // [line, column] + return [line + 1, line == 0 ? column + 1 : column]; + } + /** + * search the greatest index of the value less than or equal to offset + * @param offset + * @returns + */ + search(offset) { + // search lineStarts using binary search + let start = 0; + let end = this.lineStarts.length - 1; + let mid = 0; + let result = -1; + while (start <= end) { + mid = start + ((end - start) >>> 1); + if (this.lineStarts[mid] <= offset) { + result = mid; + start = mid + 1; } - } - const unique = new Set(); - const reduced = optimized.selector.reduce((acc, curr) => { - const sig = curr.join(""); - if (!unique.has(sig)) { - if (acc.length > 0) { - acc.push(","); - } - unique.add(sig); - acc.push(...curr); + else if (this.lineStarts[mid] > offset) { + end = mid - 1; } - return acc; - }, []); - const raw = [ - [optimized.optimized[0], reduced.length === 1 ? reduced.join("") : ":is("].concat(reduced).concat(")"), - ]; - const sel = raw[0].join(""); - if (sel.length < node.sel.length) { - node.sel = sel; - node[RAW] = raw; - node[TOKENS] = null; } + return result; + } + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts; + } + /** + * add line start + */ + addLineStart(lineStart) { + this.lineStarts.push(lineStart); } } /** - * expand css nesting ast nodes - * @param ast + * match url + */ +const matchUrl = /^(https?:)?\/\//; +const windowsPathnameRegexp = /^\/?[a-zA-Z]:\/?/; +/** + * return the directory name of a path + * @param path * * @private */ -function expand(ast) { - if (ast[STATE] == exports.EnumAstNodeStatus.Invalid || - ast[STATE] == exports.EnumAstNodeStatus.Disallowed || - ast[STATE] == exports.EnumAstNodeStatus.Unknown || - ast[STATE] == exports.EnumAstNodeStatus.Unparsed || - ast[STATE] == exports.EnumAstNodeStatus.Malformed) { - return ast; +function dirname(path) { + if (path === "") { + return ""; } - const result = Object.assign(cloneNode(ast), { chi: [] }); - let children; - for (let i = 0; i < ast.chi.length; i++) { - let node = ast.chi[i]; - if (node.typ === exports.EnumToken.RuleNodeType) { - children = expandRule(node); - for (const child of children) { - child[PARENT] = result; - } - // @ts-ignore - result.chi.push(...children); + if (path.startsWith("data:")) { + return path; + } + let i = 0; + let parts = [""]; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + parts.push(""); } - else if (node.typ == exports.EnumToken.AtRuleNodeType && "chi" in node) { - let hasRule = false; - let j = node.chi.length; - while (j--) { - // @ts-ignore - if (node.chi[j].typ == exports.EnumToken.RuleNodeType || node.chi[j].typ == exports.EnumToken.AtRuleNodeType) { - hasRule = true; - break; - } - } - if (hasRule) { - node = expand(node); - for (const child of node.chi) { - child[PARENT] = result; - } - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + else { + parts[parts.length - 1] += chr; + } + } + parts.pop(); + return parts.join("/"); +} +/** + * split path + * @param result + * @private + */ +function splitPath(result) { + if (result.length == 0) { + return { parts: [], i: 0 }; + } + const parts = result == "/" ? [] : [""]; + let i = 0; + for (; i < result.length; i++) { + const chr = result.charAt(i); + if (chr == "/") { + parts.push(""); + } + // else if (chr == "?" || chr == "#") { + // break; + // } + else { + parts[parts.length - 1] += chr; + } + } + // let k: number = -1; + // while (++k < parts.length) { + // if (parts[k] == ".") { + // parts.splice(k--, 1); + // } else if (parts[k] == "..") { + // parts.splice(k - 1, 2); + // k -= 2; + // } + // } + return { parts, i }; +} +/** + * Nomalize path + * @param path + * @private + */ +const normalize = memoize(function (path) { + let parts = []; + let i = 0; + if (path.includes("\\")) { + path = path.replace(/(\\)/g, "/"); + } + if (windowsPathnameRegexp.test(path)) { + path = path.replace(windowsPathnameRegexp, ""); + } + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + if (parts.length == 0 || parts[parts.length - 1] !== "") { + parts.push(""); } - else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + } + else if (chr == "?" || chr == "#") { + break; + } + else { + if (parts.length == 0) { + parts.push(""); } + parts[parts.length - 1] += chr; + } + } + let k = -1; + while (++k < parts.length) { + // if (parts[k] == ".") { + // parts.splice(k--, 1); + // } else + if (k > 0 && parts[k] == "..") { + parts.splice(k - 1, 2); + k -= 2; + } + } + return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); +}); +/** + * diff path + * @param path1 + * @param path2 + * @private + */ +const diff = memoize(function (path1, path2) { + let { parts } = splitPath(path1); + const { parts: dirs } = splitPath(path2); + for (const p of dirs) { + if (parts[0] == p) { + parts.shift(); } else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + parts.unshift(".."); } } - return result; -} -function expandRule(node) { - if (node[STATE] == exports.EnumAstNodeStatus.Invalid || - node[STATE] == exports.EnumAstNodeStatus.Disallowed || - node[STATE] == exports.EnumAstNodeStatus.Unknown || - node[STATE] == exports.EnumAstNodeStatus.Unparsed || - node[STATE] == exports.EnumAstNodeStatus.Malformed) { - return [node]; + return parts.join("/"); +}); +/** + * resolve path + * @param url url or path to resolve + * @param currentDirectory directory used to resolve the path + * @param cwd current working directory + * + * @private + */ +const resolve = memoize(function (url, currentDirectory, cwd) { + if (matchUrl.test(url)) { + return { + absolute: url, + relative: url, + }; } - const ast = Object.assign(cloneNode(node), { chi: node.chi.slice() }); - const result = []; - if (ast.typ == exports.EnumToken.RuleNodeType) { - let i = 0; - for (; i < ast.chi.length; i++) { - if (ast.chi[i].typ == exports.EnumToken.RuleNodeType) { - const rule = ast.chi[i]; - if (!rule.sel.includes("&")) { - const selRule = splitRule(rule.sel); - const arSelf = splitRule(ast.sel) - .filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))) - .reduce((acc, curr) => acc.concat([curr.join("")]), []) - .join(","); - if (arSelf.length == 0) { - ast.chi.splice(i--, 1); - continue; - } - for (let i1 = 0; i1 < selRule.length; i1++) { - const arr = selRule[i1]; - combinators.includes(arr[0].charAt(0)) ? arr.unshift(arSelf) : arr.unshift(arSelf, " "); - } - rule.sel = selRule - .reduce((acc, curr) => { - acc.push(curr.join("")); - return acc; - }, []) - .join(","); - } - else { - let childSelectorCompound = []; - let withCompound = []; - let withoutCompound = []; - // pseudo elements cannot be used with '&' - // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ":before" && t != ":after" && !t.startsWith("::"))); - const parentSelector = !node.sel.includes("&"); - if (rules.length == 0) { - ast.chi.splice(i--, 1); - continue; - } - for (const sel of rule[RAW] ?? splitRule(rule.sel)) { - const s = sel.join(""); - if (s.includes("&") || parentSelector) { - if (s.indexOf("&", 1) == -1) { - if (s.at(0) == "&") { - if (s.at(1) == " ") { - childSelectorCompound.push(s.slice(2)); - } - else { - if (s == "&" || parentSelector) { - withCompound.push(s); - } - } - } - else { - withoutCompound.push(s); - } - } - else { - withCompound.push(s); - } - } - } - const selectors = []; - const selector = rules.length > 1 ? ":is(" + rules.map((a) => a.join("")).join(",") + ")" : rules[0].join(""); - if (childSelectorCompound.length > 0) { - if (childSelectorCompound.length == 1) { - selectors.push(replaceCompound("& " + childSelectorCompound[0].trim(), selector)); - } - else { - selectors.push(replaceCompound("& :is(" + - childSelectorCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + - ")", selector)); - } - } - if (withCompound.length > 0) { - if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { - withoutCompound.push(...withCompound.map((t) => t.slice(1))); - withCompound.length = 0; - } - } - if (withoutCompound.length > 0) { - if (withoutCompound.length == 1) { - const useIs = rules.length == 1 && - selector.match(/^[a-zA-Z.:]/) != null && - selector.includes(" ") && - withoutCompound.length == 1 && - withoutCompound[0].match(/^[a-zA-Z]+$/) != null; - const compound = useIs ? ":is(&)" : "&"; - selectors.push(replaceCompound(rules.length == 1 - ? useIs - ? withoutCompound[0] + ":is(&)" - : selector.match(/^[.:]/) && withoutCompound[0].match(/^[a-zA-Z]+$/) - ? withoutCompound[0] + compound - : compound + withoutCompound[0] - : withoutCompound[0].match(/^[a-zA-Z:]+$/) - ? withoutCompound[0].trim() + compound - : "&" + - (withoutCompound[0].match(/^\S+$/) - ? withoutCompound[0].trim() - : ":is(" + withoutCompound[0].trim() + ")"), selector)); - } - else { - selectors.push(replaceCompound("&:is(" + - withoutCompound.reduce((acc, curr) => acc + (acc.length > 0 ? "," : "") + curr.trim(), "") + - ")", selector)); - } - } - if (withCompound.length > 0) { - if (withCompound.length == 1) { - selectors.push(replaceCompound(withCompound[0], selector)); - } - } - rule.sel = selectors.reduce((acc, curr) => (curr.length == 0 ? acc : acc + (acc.length > 0 ? "," : "") + curr), ""); - } - ast.chi.splice(i--, 1); - result.push(...expandRule(rule)); - } - else if (ast.chi[i].typ == exports.EnumToken.AtRuleNodeType) { - let astAtRule = ast.chi[i]; - const values = []; - if (astAtRule.nam === "scope") { - if (astAtRule.val.includes("&")) { - astAtRule.val = replaceCompound(astAtRule.val, ast.sel); - } - const slice = astAtRule.chi - .slice() - .filter((t) => t.typ == exports.EnumToken.RuleNodeType && t.sel.includes("&")); - if (slice.length > 0) { - expandRule({ ...node, chi: astAtRule.chi.slice() }); - } - } - else { - // @ts-ignore - const clone = { ...ast, chi: astAtRule.chi.slice() }; - // @ts-ignore - astAtRule.chi.length = 0; - for (const r of expandRule(clone)) { - if (r.typ == exports.EnumToken.AtRuleNodeType && "chi" in r) { - if (astAtRule.val !== "" && r.val !== "") { - if (astAtRule.nam === "media" && r.nam === "media") { - r.val = astAtRule.val + " and " + r.val; - } - else if (astAtRule.nam == "layer" && r.nam == "layer") { - r.val = astAtRule.val + "." + r.val; - } - } - // @ts-ignore - values.push(r); - } - else if (r.typ == exports.EnumToken.RuleNodeType) { - // @ts-ignore - astAtRule.chi.push(...expandRule(r)); - } - } - } - // @ts-ignore - result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); - ast.chi.splice(i--, 1); - } - } + cwd ??= ""; + currentDirectory ??= ""; + url = normalize(url); + if (cwd !== "") { + cwd = normalize(cwd); } - // @ts-ignore - return ast.chi.length > 0 ? [ast].concat(result) : result; -} -/** - * replace compound selector - * @param input - * @param replace - */ -function replaceCompound(input, replace) { - const tokens = parseString(input); - let replacement = null; - for (const t of walkValues(tokens)) { - if (t.value.typ == exports.EnumToken.NestingSelectorTokenType) { - if (tokens.length == 2) { - if (replacement == null) { - replacement = parseString(replace); - } - Object.assign(t.value, { - typ: exports.EnumToken.LiteralTokenType, - val: replaceCompoundLiteral(t.value.val, replace), - }); - continue; - } - const rule = splitRule(replace); - Object.assign(t.value, { - typ: exports.EnumToken.LiteralTokenType, - val: rule.length > 1 ? ":is(" + replace + ")" : replace, - }); - } + if (currentDirectory !== "") { + currentDirectory = normalize(currentDirectory); } - return tokens.reduce((acc, curr) => acc + renderValue(curr), ""); -} -function replaceCompoundLiteral(selector, replace) { - const tokens = [""]; - let i = 0; - for (; i < selector.length; i++) { - if (selector.charAt(i) == "&") { - tokens.push("&", ""); - } + let dir = cwd || currentDirectory; + if (windowsPathnameRegexp.test(dir)) { + dir = dir.replace(windowsPathnameRegexp, ""); } - return tokens - .sort((a, b) => { - if (a == "&") { - return 1; - } - return b == "&" ? -1 : 0; - }) - .reduce((acc, curr) => acc + (curr == "&" ? replace : curr), ""); -} - -/** - * match url - */ -const matchUrl = /^(https?:)?\/\//; + const absolute = dir == "" || url.startsWith("/") || url.startsWith(dir) || windowsPathnameRegexp.test(url) + ? resolvePath(url) + : resolvePath(dir, url); + return { + absolute, + relative: dir === "" ? absolute : diff(absolute, dir), + }; +}); /** - * return the directory name of a path - * @param path * + * @param parts + * @returns * @private */ -function dirname(path) { - if (path === "") { - return ""; - } - if (path.startsWith("data:")) { - return path; - } - let i = 0; - let parts = [""]; - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - parts.push(""); +function resolvePath(...parts) { + const path = parts.filter(Boolean).join("/"); + const isAbsolute = /^[\\/]/.test(path); + const segments = path.split(/[\\/]+/); + const resolved = []; + for (const segment of segments) { + if (!segment || segment === ".") { + continue; + } + if (segment === "..") { + if (resolved.length && resolved[resolved.length - 1] !== "..") { + resolved.pop(); + } + else if (!isAbsolute) { + resolved.push(".."); + } } else { - parts[parts.length - 1] += chr; + resolved.push(segment); } } - parts.pop(); - return parts.join("/"); + let result = resolved.join("/"); + if (isAbsolute) { + result = "/" + result; + } + return result || (isAbsolute ? "/" : "."); } + /** - * split path - * @param result - * @private + * Source file ID */ -function splitPath(result) { - if (result.length == 0) { - return { parts: [], i: 0 }; - } - const parts = result == "/" ? [] : [""]; - let i = 0; - for (; i < result.length; i++) { - const chr = result.charAt(i); - if (chr == "/") { - parts.push(""); - } - // else if (chr == "?" || chr == "#") { - // break; - // } - else { - parts[parts.length - 1] += chr; - } - } - // let k: number = -1; - // while (++k < parts.length) { - // if (parts[k] == ".") { - // parts.splice(k--, 1); - // } else if (parts[k] == "..") { - // parts.splice(k - 1, 2); - // k -= 2; - // } - // } - return { parts, i }; -} +let sourceId = 0; /** - * Nomalize path - * @param path - * @private + * Source file helper class */ -const normalize = memoize(function (path) { - let parts = []; - let i = 0; - if (path.includes("\\")) { - path = path.replace(/(\\)/g, "/"); +class SourceFile { + inputSourceMap = null; + /** + * Source file ID + */ + id; + /** + * Source file path + */ + file; + /** + * Line map + */ + lineStarts; + /** + * Source file content + */ + content; + /** + * Constructor + * @param content + * @param lines + * @param file + */ + constructor(content, lines, file = null) { + this.id = sourceId++; + this.content = content; + this.file = file; + this.lineStarts = new LineMap(lines); } - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - if (parts.length == 0 || parts[parts.length - 1] !== "") { - parts.push(""); - } - } - else if (chr == "?" || chr == "#") { - break; - } - else { - if (parts.length == 0) { - parts.push(""); - } - parts[parts.length - 1] += chr; - } + /** + * Update source content + * @param content + */ + append(content) { + this.content += content; } - let k = -1; - while (++k < parts.length) { - // if (parts[k] == ".") { - // parts.splice(k--, 1); - // } else - if (k > 0 && parts[k] == "..") { - parts.splice(k - 1, 2); - k -= 2; - } + /** + * get file name + * @returns + */ + getFileName() { + return this.file; } - return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); -}); -/** - * diff path - * @param path1 - * @param path2 - * @private - */ -const diff = memoize(function (path1, path2) { - let { parts } = splitPath(path1); - const { parts: dirs } = splitPath(path2); - for (const p of dirs) { - if (parts[0] == p) { - parts.shift(); - } - else { - parts.unshift(".."); - } + /** + * get content + * @returns + */ + getContent() { + return this.content; } - return parts.join("/"); -}); -/** - * resolve path - * @param url url or path to resolve - * @param currentDirectory directory used to resolve the path - * @param cwd current working directory - * - * @private - */ -const resolve = memoize(function (url, currentDirectory, cwd) { - if (matchUrl.test(url)) { - return { - absolute: url, - relative: url, - }; + /** + * get text + * @param start + * @param length + * @returns + */ + getText(start, length) { + return this.content.slice(start, start + length); } - cwd ??= ""; - currentDirectory ??= ""; - url = normalize(url); - if (cwd !== "") { - cwd = normalize(cwd); + /** + * Compute line and column of the offset + * @param offset + * @returns + */ + getOffsets(offset) { + return this.lineStarts.getOffsets(offset); } - if (currentDirectory !== "") { - currentDirectory = normalize(currentDirectory); + /** + * get source location + * @param offset + * @returns + */ + getSourceLocation(offset) { + return [this.file, ...this.getOffsets(offset)]; } - const dir = cwd || currentDirectory; - const absolute = dir == "" || url.startsWith("/") || url.match(/^[a-zA-Z]:/) ? resolvePath(url) : resolvePath(dir, url); - return { - absolute, - relative: dir === "" ? absolute : diff(absolute, dir), - }; -}); -/** - * - * @param parts - * @returns - * @private - */ -function resolvePath(...parts) { - const path = parts.filter(Boolean).join("/"); - const isAbsolute = /^[\\/]/.test(path); - const segments = path.split(/[\\/]+/); - const resolved = []; - for (const segment of segments) { - if (!segment || segment === ".") { - continue; - } - if (segment === "..") { - if (resolved.length && resolved[resolved.length - 1] !== "..") { - resolved.pop(); - } - else if (!isAbsolute) { - resolved.push(".."); - } - } - else { - resolved.push(segment); - } + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts.getLineStarts(); } - let result = resolved.join("/"); - if (isAbsolute) { - result = "/" + result; + /** + * add line start + * @param lineStart + */ + addLineStart(lineStart) { + this.lineStarts.addLineStart(lineStart); + } + /** + * set input source map + * @param inputSourceMap + */ + setInputSourceMap(inputSourceMap) { + this.inputSourceMap = inputSourceMap == null ? null : new SourceMap(inputSourceMap); + } + /** + * return input source map + * @returns + */ + getInputSourceMap() { + return this.inputSourceMap; } - return result || (isAbsolute ? "/" : "."); } /** @@ -24832,7 +24137,7 @@ function doRender(data, options = {}, mapping) { source = options.sourcesMap.get(sourceId); sourcemap.addSourceContent(source.id, source.getFileName(), source.getContent()); } - sourcemap.add(...sourcemaps.maps); + sourcemap.add(sourcemaps.maps); result.map = sourcemap; if (options.sourcemap === "inline") { result.code += `\n/*# sourceMappingURL=${result.map.toUrl()} */`; @@ -24854,43 +24159,33 @@ function doRender(data, options = {}, mapping) { */ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str) { let offset = 0; - while (true) { - if (str.charAt(offset) == options.newLine) { - offset += options.newLine.length; - continue; - } - if (str.charAt(offset) == options.indent) { - offset += options.indent.length; - continue; - } - break; + // eat leanding whitespace + while (offset < str.length && isWhiteSpace(str.charCodeAt(offset))) { + offset++; } if (offset > 0) { - move(sourceLocation, linesMap, str.slice(0, offset)); + move(sourceLocation, linesMap, str, 0, offset + 1); } - if (node[LOC] != null && - [ - exports.EnumToken.RuleNodeType, - exports.EnumToken.AtRuleNodeType, - exports.EnumToken.KeyframesRuleNodeType, - exports.EnumToken.KeyframesAtRuleNodeType, - ].includes(node.typ)) { - const source = options.sourcesMap.get(node[LOC].srcId); + if (node[LOCSTA] != null) { + const source = options.sourcesMap.get(node[LOCSRCID]); const inputSourceMap = source.getInputSourceMap(); - const offsets = source.getOffsets(node[LOC].sta); + const offsets = source.getOffsets(node[LOCSTA]); const [newLine, newColumn] = linesMap.getOffsets(sourceLocation.end); let records = null; - let srcId = node[LOC].srcId; + let srcId = node[LOCSRCID]; let sourceFileName = source.getFileName() || null; - source.getContent() || null; + let sourceContent; // = (source.getContent() as string) || null; if (inputSourceMap != null && (records = inputSourceMap.find(offsets[0], offsets[1])) != null) { + let newId = null; for (const record of records) { + newId = null; // @ts-ignore sourceFileName = record[0] || null; // @ts-ignore offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; + sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { const absolute = options.resolve(dirname(options.output), options.cwd) @@ -24903,30 +24198,46 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } sourceFileName = cache[sourceFileName]; } + for (const [id, file] of options.sourcesMap.entries()) { + if (file.getFileName() === sourceFileName) { + newId = id; + break; + } + if (sourceFileName == null && file.getContent() === sourceContent) { + newId = id; + break; + } + } + if (newId == null) { + const source = new SourceFile(sourceContent, [], sourceFileName); + options.sourcesMap.set(source.id, source); + newId = source.id; + } + srcId = newId; if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } else { - if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { - if (cache[sourceFileName] == null) { - const absolute = options.resolve(dirname(options.output), options.cwd) - .absolute; - const absoluteSourceFileName = options.resolve(sourceFileName, options.cwd) - .absolute; - cache[sourceFileName] = options.resolve(absoluteSourceFileName, absolute).relative; - } - sourceFileName = cache[sourceFileName]; - } + // if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { + // if (cache[sourceFileName] == null) { + // const absolute = options.resolve!(dirname(options.output as string), options.cwd as string) + // .absolute as string; + // const absoluteSourceFileName = options.resolve!(sourceFileName, options.cwd as string) + // .absolute as string; + // cache[sourceFileName] = options.resolve!(absoluteSourceFileName, absolute).relative as string; + // } + // sourceFileName = cache[sourceFileName] as string; + // } if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -24934,11 +24245,12 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines * @param linesMap * @param str */ -function move(sourceLocation, linesMap, str) { - let i = 0; +function move(sourceLocation, linesMap, str, start, end) { + let i = start ?? 0; + let j = end ?? str.length; let codepoint; let char; - for (; i < str.length; i++) { + for (; i < j; i++) { char = str.charAt(i); codepoint = char.charCodeAt(0); sourceLocation.end += char.length; @@ -25062,7 +24374,6 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro str = options.newLine + indentSub + str; children += str; if (sourcemaps != null && str !== "") { - move(sourceLocation, linesMap, str); if (node.typ == exports.EnumToken.DeclarationNodeType && recordDeclarationSourceMap) { // if declaration is child of at-rule, then record it // .rule { @@ -25070,15 +24381,11 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro // color: red; // } // } - const source = options.sourcesMap.get(node[LOC].srcId); - if (!sourcemaps.sources.includes(node[LOC].srcId)) { - sourcemaps.sources.push(node[LOC].srcId); - } - sourcemaps.maps.push([ - ...linesMap.getOffsets(sourceLocation.end - str.length + options.newLine.length + indentSub.length), - node[LOC].srcId, - ...source.getOffsets(node[LOC].sta), - ]); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } @@ -25383,7 +24690,9 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, // } } if (slice[i]?.typ === exports.EnumToken.ColorTokenType) { - slice.push(...reduceColorStops(slice.splice(i, slice.length - i))); + for (const token of reduceColorStops(slice.splice(i, slice.length - i))) { + slice.push(token); + } } } break; @@ -25574,32 +24883,45 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, } const result = []; if (form.length > 0) { - result.push(...form); + for (const token of form) { + result.push(token); + } } if (size.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...size); + for (const token of size) { + result.push(token); + } } if (positions.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + result.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const token of positions) { + result.push(token); + } } if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } if (result.length > 0) { result.push({ typ: exports.EnumToken.CommaTokenType }); } - result.push(...reduceColorStops(slice.slice(i))); + for (const token of reduceColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (const token of result) { + slice.push(token); + } } break; case "conic-gradient": @@ -25704,24 +25026,36 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, if (angles.length > 0) { angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }); + for (const position of positions) { + angles.push(position); + } } } if (angles.length > 0) { - result.push(...angles, { typ: exports.EnumToken.CommaTokenType }); + for (const angle of angles) { + result.push(angle); + } + result.push({ typ: exports.EnumToken.CommaTokenType }); } if (colorSpaceDef.length > 0) { if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: exports.EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } result.push({ typ: exports.EnumToken.CommaTokenType }); } - result.push(...reduceConicColorStops(slice.slice(i))); + for (const token of reduceConicColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (let j = 0; j < result.length; j++) { + slice.push(result[j]); + } } break; } @@ -25855,210 +25189,1815 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, const angle = getAngle(token); let v; let value = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { + for (const u of ["deg", "turn", "rad", "grad"]) { if (token.unit == u) { continue; } - switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + switch (u) { + case "deg": + v = minifyNumber(toPrecisionAngle(angle * 360, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "turn": + v = minifyNumber(toPrecisionAngle(angle, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 4 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "rad": + v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + case "grad": + v = minifyNumber(toPrecisionAngle(angle * 400, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 4 < value.length) { + val = v; + unit = u; + value = v + u; + } + break; + } + } + } + if (val === "0") { + if (token.typ == exports.EnumToken.TimeTokenType) { + return "0s"; + } + if (token.typ == exports.EnumToken.FrequencyTokenType) { + return "0Hz"; + } + // @ts-ignore + if (token.typ == exports.EnumToken.ResolutionTokenType) { + return "0x"; + } + return "0"; + } + if (token.typ == exports.EnumToken.TimeTokenType) { + if (unit == "ms") { + // @ts-ignore + const v = minifyNumber(val / 1000); + if (v.length + 1 <= val.length) { + return v + "s"; + } + return val + "ms"; + } + return val + "s"; + } + if (token.typ == exports.EnumToken.ResolutionTokenType && unit == "dppx") { + unit = "x"; + } + return val.includes("/") ? val.replace("/", unit + "/") : minifyNumber(toPrecisionValue(val)) + unit; + case exports.EnumToken.FlexTokenType: + case exports.EnumToken.PercentageTokenType: + const uni = token.typ == exports.EnumToken.PercentageTokenType ? "%" : "fr"; + 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; + case exports.EnumToken.NumberTokenType: + return token.val.typ == exports.EnumToken.FractionTokenType + ? renderValue(token.val, options, cache) + : minifyNumber(token.val); + case exports.EnumToken.AtRuleTokenType: + return "@" + token.nam; + case exports.EnumToken.CommentTokenType: + case exports.EnumToken.CDOCOMMNodeType: + if (options.removeComments && + (!options.preserveLicense || !token.val.startsWith("/*!"))) { + return ""; + } + case exports.EnumToken.PseudoClassTokenType: + case exports.EnumToken.PseudoElementTokenType: + // https://www.w3.org/TR/selectors-4/#single-colon-pseudos + if (token.typ == exports.EnumToken.PseudoElementTokenType && + pseudoElements.includes(token.val.slice(1))) { + return token.val.slice(1); + } + case exports.EnumToken.UrlTokenTokenType: + case exports.EnumToken.HashTokenType: + case exports.EnumToken.IdenTokenType: + case exports.EnumToken.StringTokenType: + case exports.EnumToken.LiteralTokenType: + case exports.EnumToken.DashedIdenTokenType: + case exports.EnumToken.PseudoPageTokenType: + case exports.EnumToken.ClassSelectorTokenType: + return token.val; + case exports.EnumToken.NestingSelectorTokenType: + return "&"; + case exports.EnumToken.InvalidAttrTokenType: + return ("[" + + token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.InvalidClassSelectorTokenType: + return token.val; + case exports.EnumToken.SupportsQueryUnaryConditionTokenType: + case exports.EnumToken.WhenElseUnaryConditionTokenType: + return (renderValue(token.l, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); + case exports.EnumToken.SupportsQueryConditionTokenType: + case exports.EnumToken.WhenElseQueryConditionTokenType: + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + " " + + renderValue(token.op, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); + case exports.EnumToken.IfConditionTokenType: + return token.l.length == 0 + ? "" + : token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + ":" + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), ""); + case exports.EnumToken.IfElseConditionTokenType: + return renderValue(token.l) + renderValue(token.r); + case exports.EnumToken.DeclarationNodeType: + return (token.nam + + ":" + + (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaQueryUnaryFeatureTokenType: + return (renderValue(token.l, options, cache, reducer, errors) + + " " + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaQueryConditionTokenType: { + const indent = token.op.typ == exports.EnumToken.LtTokenType || + token.op.typ == exports.EnumToken.GtTokenType || + token.op.typ == exports.EnumToken.ColonTokenType || + token.op.typ == exports.EnumToken.DelimTokenType || + token.op.typ == exports.EnumToken.LteTokenType || + token.op.typ == exports.EnumToken.GteTokenType + ? "" + : " "; + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + indent + + renderValue(token.op, options, cache, reducer, errors) + + indent + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + } + case exports.EnumToken.MediaRangeQueryTokenType: + return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache), "") + + renderValue(token.op1) + + token.val.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + + renderValue(token.op2) + + token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); + case exports.EnumToken.MediaFeatureTokenType: + return token.val; + case exports.EnumToken.NotTokenType: + return "not"; + case exports.EnumToken.OnlyTokenType: + return "only"; + case exports.EnumToken.AndTokenType: + return "and"; + case exports.EnumToken.OrTokenType: + return "or"; + case exports.EnumToken.InvalidMediaQueryTokenType: + case exports.EnumToken.InvalidCommentTokenType: + case exports.EnumToken.BadCommentTokenType: + case exports.EnumToken.BadCdoTokenType: + case exports.EnumToken.BadStringTokenType: + case exports.EnumToken.BadUrlTokenType: + case exports.EnumToken.EOFTokenType: + return ""; + default: + console.debug({ token }); + throw new Error(`Unsupported token type for ${exports.EnumToken[token.typ]}`); + } + errors?.push({ action: "ignore", message: `render: unexpected token ${JSON.stringify(token, null, 1)}` }); + return ""; +} +/** + * Remove whitespace tokens that are not needed + * @param values + * + * @internal + */ +function filterValues(values) { + let i = 0; + for (; i < values.length; i++) { + if (values[i].typ == exports.EnumToken.ImportantTokenType && values[i - 1]?.typ === exports.EnumToken.WhitespaceTokenType) { + values.splice(i - 1, 1); + } + else if (tokensfuncSet.has(values[i].typ) && + "chi" in values[i] && + values[i].typ != exports.EnumToken.WildCardFunctionTokenType && + values[i + 1]?.typ == exports.EnumToken.WhitespaceTokenType) { + values.splice(i + 1, 1); + } + } + return values; +} + +const SymbolsMapTokens = Object.create(null); +// Regex for escape sequence decoding - compile once, reuse many times +const ESCAPE_SEQUENCE_REGEX = /\\([0-9a-fA-F]{1,6})(?:\s)?/g; +function decodeEscapeSequences(value) { + return value.replace(ESCAPE_SEQUENCE_REGEX, (_, sequence) => { + const codepoint = parseInt(sequence, 16); + if (codepoint == 0 || + // leading surrogate + (0xd800 <= codepoint && codepoint <= 0xdbff) || + // trailing surrogate + (0xdc00 <= codepoint && codepoint <= 0xdfff) || + codepoint > 0x10ffff) { + return "\uFFFD"; + } + return String.fromCodePoint(codepoint); + }); +} +function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { + for (const entry of entries) { + SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + } +} +SymbolsMapTokens[""] = exports.EnumToken.DelimTokenType; +SymbolsMapTokens["+"] = exports.EnumToken.Plus; +SymbolsMapTokens["="] = exports.EnumToken.DelimTokenType; +SymbolsMapTokens["|"] = exports.EnumToken.Pipe; +SymbolsMapTokens["||"] = exports.EnumToken.ColumnCombinatorTokenType; +SymbolsMapTokens["|="] = exports.EnumToken.DashMatchTokenType; +SymbolsMapTokens["&"] = exports.EnumToken.NestingSelectorTokenType; +SymbolsMapTokens["*"] = exports.EnumToken.Star; +SymbolsMapTokens["*="] = exports.EnumToken.ContainMatchTokenType; +SymbolsMapTokens["~"] = exports.EnumToken.Tilda; +SymbolsMapTokens["~="] = exports.EnumToken.IncludeMatchTokenType; +SymbolsMapTokens["^="] = exports.EnumToken.StartMatchTokenType; +SymbolsMapTokens["$="] = exports.EnumToken.EndMatchTokenType; +SymbolsMapTokens[","] = exports.EnumToken.Comma; +SymbolsMapTokens[":"] = exports.EnumToken.ColonTokenType; +SymbolsMapTokens["::"] = exports.EnumToken.DoubleColonTokenType; +SymbolsMapTokens[";"] = exports.EnumToken.SemiColonTokenType; +SymbolsMapTokens["("] = exports.EnumToken.StartParensTokenType; +SymbolsMapTokens[")"] = exports.EnumToken.EndParensTokenType; +SymbolsMapTokens["["] = exports.EnumToken.AttrStartTokenType; +SymbolsMapTokens["]"] = exports.EnumToken.AttrEndTokenType; +SymbolsMapTokens["{"] = exports.EnumToken.BlockStartTokenType; +SymbolsMapTokens["}"] = exports.EnumToken.BlockEndTokenType; +SymbolsMapTokens["<="] = exports.EnumToken.LteTokenType; +SymbolsMapTokens[">"] = exports.EnumToken.GtTokenType; +SymbolsMapTokens[">="] = exports.EnumToken.GteTokenType; +SymbolsMapTokens[" "] = exports.EnumToken.Whitespace; +SymbolsMapTokens["\t"] = exports.EnumToken.Whitespace; +SymbolsMapTokens["\r"] = exports.EnumToken.Whitespace; +SymbolsMapTokens["\n"] = exports.EnumToken.Whitespace; +SymbolsMapTokens["\f"] = exports.EnumToken.Whitespace; +assignTokenMap(flexUnits, exports.EnumToken.FlexTokenType); +assignTokenMap(dimensionUnits, exports.EnumToken.LengthTokenType); +assignTokenMap(resolutionUnits, exports.EnumToken.ResolutionTokenType); +assignTokenMap(angleUnits, exports.EnumToken.AngleTokenType); +assignTokenMap(timeUnits, exports.EnumToken.TimeTokenType); +assignTokenMap(frequencyUnits, exports.EnumToken.FrequencyTokenType); +assignTokenMap(pseudoElements, exports.EnumToken.PseudoElementTokenType); +assignTokenMap(containerFunc, exports.EnumToken.ContainerFunctionTokenDefType, "("); +assignTokenMap(urlFunc, exports.EnumToken.UrlFunctionTokenDefType, "("); +assignTokenMap(gridTemplateFunc, exports.EnumToken.GridTemplateFuncTokenDefType, "("); +assignTokenMap(imageFunc, exports.EnumToken.ImageFunctionTokenDefType, "("); +assignTokenMap(timelineFunc, exports.EnumToken.TimelineFunctionTokenDefType, "("); +assignTokenMap(supportFunc, exports.EnumToken.SupportsFunctionTokenDefType, "("); +assignTokenMap(timingFunc, exports.EnumToken.TimingFunctionTokenDefType, "("); +assignTokenMap(colorsFunc, exports.EnumToken.ColorFunctionTokenDefType, "("); +assignTokenMap(mathFuncs, exports.EnumToken.MathFunctionTokenDefType, "("); +assignTokenMap(transformFunctions, exports.EnumToken.TransformFunctionTokenDefType, "(", true); +assignTokenMap(whenElseFunc, exports.EnumToken.WhenElseFunctionTokenDefType, "("); +assignTokenMap(wildCardFuncs, exports.EnumToken.WildCardFunctionTokenDefType, "("); +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); +// do not capture the value +const hintsEnum = new Set([ + exports.EnumToken.CommaTokenType, + exports.EnumToken.ImportantTokenType, + exports.EnumToken.SemiColonTokenType, + exports.EnumToken.BlockStartTokenType, + exports.EnumToken.BlockEndTokenType, + exports.EnumToken.StartParensTokenType, + exports.EnumToken.EndParensTokenType, + exports.EnumToken.ColonTokenType, + exports.EnumToken.EOFTokenType, +]); +var TokenMap; +(function (TokenMap) { + TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; + TokenMap[TokenMap["SLASH"] = 47] = "SLASH"; + TokenMap[TokenMap["LOWERTHAN"] = 60] = "LOWERTHAN"; + TokenMap[TokenMap["HASH"] = 35] = "HASH"; + TokenMap[TokenMap["REVERSE_SOLIDUS"] = 92] = "REVERSE_SOLIDUS"; + TokenMap[TokenMap["DOUBLE_QUOTE"] = 34] = "DOUBLE_QUOTE"; + TokenMap[TokenMap["SINGLE_QUOTE"] = 39] = "SINGLE_QUOTE"; + TokenMap[TokenMap["DOT"] = 46] = "DOT"; + TokenMap[TokenMap["AT"] = 64] = "AT"; + TokenMap[TokenMap["PIPE"] = 124] = "PIPE"; + TokenMap[TokenMap["EQUALS"] = 61] = "EQUALS"; + TokenMap[TokenMap["AMPERSAND"] = 38] = "AMPERSAND"; + TokenMap[TokenMap["STAR"] = 42] = "STAR"; + TokenMap[TokenMap["TILDA"] = 126] = "TILDA"; + TokenMap[TokenMap["CARET"] = 94] = "CARET"; + TokenMap[TokenMap["DOLLAR"] = 36] = "DOLLAR"; + TokenMap[TokenMap["COMMA"] = 44] = "COMMA"; + TokenMap[TokenMap["COLON"] = 58] = "COLON"; + TokenMap[TokenMap["SEMICOLON"] = 59] = "SEMICOLON"; + TokenMap[TokenMap["LEFT_PARENTHESIS"] = 40] = "LEFT_PARENTHESIS"; + TokenMap[TokenMap["RIGHT_PARENTHESIS"] = 41] = "RIGHT_PARENTHESIS"; + TokenMap[TokenMap["LEFT_BRACKETS"] = 91] = "LEFT_BRACKETS"; + TokenMap[TokenMap["RIGHT_BRACKETS"] = 93] = "RIGHT_BRACKETS"; + TokenMap[TokenMap["LEFT_BRACE"] = 123] = "LEFT_BRACE"; + TokenMap[TokenMap["RIGHT_BRACE"] = 125] = "RIGHT_BRACE"; + TokenMap[TokenMap["PLUS"] = 43] = "PLUS"; + TokenMap[TokenMap["MINUS"] = 45] = "MINUS"; + TokenMap[TokenMap["GREATERTHAN"] = 62] = "GREATERTHAN"; + TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; +})(TokenMap || (TokenMap = {})); +function getSymbolHint(parseInfo, start, end) { + const len = end - start; + const keysLength = SymbolsMapTokensKeys.length; + // Early exit for impossible lengths + if (len < 0) + return null; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca !== cb) { + match = false; + break; + } + } + if (match) { + return SymbolsMapTokens[key]; + } + } + return null; +} +function searchArray(array, parseInfo, start, end) { + const len = end - start; + // Early exit for impossible lengths + 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) + continue; + // Match character by character + let match = true; + const arrayItem = array[i]; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + match = false; + break; + } + } + if (match) { + return arrayItem; + } + } + return null; +} +/** + * tokenizer class + */ +class Tokenizer { + parseInfo; + input; + /** + * token type + */ + typ = null; + /** + * token kind + */ + kin = null; + /** + * token name + */ + nam = null; + /** + * token value + */ + val = null; + /** + * token unit + */ + unit = null; + /** + * source id + */ + srcId = null; + /** + * token start + */ + sta = null; + /** + * token end + */ + end = null; + /** + * bytes in + */ + bytesIn = null; + /** + * decode string + */ + decodeString = null; + /** + * token slice + */ + slice = null; + /** + * source file + */ + source = null; + /** + * token hint + */ + hint = null; + state = null; + constructor(parseInfo, input = null) { + this.parseInfo = parseInfo; + this.input = input; + if (typeof this.parseInfo == "string") { + if (typeof parseInfo == "string") { + this.parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + } + } + /** + * + * @param parseInfo + * @returns + */ + consumeString(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.advance(parseInfo); + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + } + if (isNewLine(charCode)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + } + this.advance(parseInfo); + } + // EOF - 'Unclosed-string' fixed + return this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + // return result; + } + /** + * + * @param parseInfo + * @returns + */ + consumeURLToken(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.advance(parseInfo); + let k = 1; + let end = parseInfo.stream.length - parseInfo.offset; + let position = parseInfo.currentPosition - parseInfo.offset; + while (position + k < end) { + charCode = parseInfo.stream.charCodeAt(position); + // NaN != NaN + if (charCode != charCode) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + if (isWhiteSpace(charCode)) { + this.advance(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + break; + } + // consume until the ')' + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.advance(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.advance(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + } + this.advance(parseInfo); + } + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + } + this.advance(parseInfo); + } + // EOF - bad url token + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + // return result; + } + /** + * consume number, dimension, or percentage + * @param parseInfo + * @returns + */ + consumeNumericToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let hasDigits = false; + let hasLetter = false; + let hasPercent = false; + let codepoint = parseInfo.stream.charCodeAt(position); + this.slice = null; + this.hint = null; + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + // consume digits + while (position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + hasDigits = true; + position++; + continue; + } + // '.' 'E' 'e' + if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + return 0; + } + if (!hasLetter && !hasPercent) { + // '.' + if (codepoint == 0x2e) { + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint) { + return !hasDigits ? 0 : position - offset; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; + } + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + } + else if (isLetter(codepoint)) { + hasLetter = true; + } + else { + return 0; + } + } + else { + position++; + hasDigits = true; + } + } + if (!hasLetter && !hasPercent) { + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; + } + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + return 0; + } + // 'E' 'e' - 'em' + if ((codepoint == 0x45 || codepoint == 0x65) && hasDigits && !hasLetter && !hasPercent) { + if (isLetter(parseInfo.stream.charCodeAt(position))) { + hasLetter = true; + } + } + if (!hasLetter && !hasPercent) { + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + codepoint = parseInfo.stream.charCodeAt(position + 1); + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + codepoint = position = parseInfo.stream.charCodeAt(position + 1); + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; } - break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + if (isLetter(codepoint)) { + hasLetter = true; } - break; - case "rad": - v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; } - break; - case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + else { + return 0; } - break; + } + } + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + // eof + if (codepoint != codepoint) { + break; + } + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; + } + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + else if (isLetter(codepoint)) { + hasLetter = true; + break; + } + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + else { + return 0; + } + } + if (!hasLetter && !hasPercent) { + return position - offset; + } + } + } + } + } + if (!hasDigits) { + return 0; + } + if (hasPercent) { + const slice = position; + codepoint = parseInfo.stream.charCodeAt(++position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = exports.EnumToken.PercentageTokenType; + return position - offset; + } + return 0; + } + if (hasLetter) { + codepoint = parseInfo.stream.charCodeAt(position - 1); + // 'E' 'e' + const slice = codepoint == 0x45 || codepoint == 0x65 ? position - 1 : position; + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(++position); + if (!isLetter(codepoint)) { + break; + } + } + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 43 /* TokenMap.PLUS */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = getSymbolHint(parseInfo, slice, position) ?? exports.EnumToken.DimensionTokenType; + return position - offset; + } + return 0; + } + return 0; + } + /** + * + * @param parseInfo + * @returns + */ + consumeIdentToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + if (codepoint == 45 /* TokenMap.MINUS */) { + position++; + codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + } + while ((codepoint = parseInfo.stream.charCodeAt(position)) == codepoint) { + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + // eof + if ((codepoint = parseInfo.stream.charCodeAt(position + 1)) != codepoint) { + // this.next(parseInfo, position); + return 0; + } + // \n \r \f \v + if (codepoint == 0xa || + codepoint == 0xb || + codepoint == 0xc || + codepoint == 0xd || + codepoint == 0x2028 || + codepoint == 0x2029) { + return 0; + } + position += 2; + continue; + } + if (codepoint == 0x2d || isIdentCodepoint(codepoint)) { + position++; + } + else { + switch (codepoint) { + case 58 /* TokenMap.COLON */: + case 123 /* TokenMap.LEFT_BRACE */: + case 125 /* TokenMap.RIGHT_BRACE */: + case 40 /* TokenMap.LEFT_PARENTHESIS */: + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + case 91 /* TokenMap.LEFT_BRACKETS */: + case 93 /* TokenMap.RIGHT_BRACKETS */: + case 59 /* TokenMap.SEMICOLON */: + case 33 /* TokenMap.EXCLAMATION */: + case 47 /* TokenMap.SLASH */: + case 35 /* TokenMap.HASH */: + case 42 /* TokenMap.STAR */: + case 61 /* TokenMap.EQUALS */: + case 126 /* TokenMap.TILDA */: + case 124 /* TokenMap.PIPE */: + case 94 /* TokenMap.CARET */: + case 36 /* TokenMap.DOLLAR */: + case 44 /* TokenMap.COMMA */: + case 62 /* TokenMap.GREATERTHAN */: + case 46 /* TokenMap.DOT */: + case 43 /* TokenMap.PLUS */: + return position - offset; + } + if (codepoint != codepoint || isWhiteSpace(codepoint)) { + return position - offset; + } + return 0; + } + } + return position - offset; + } + /** + * + * @param parseInfo + * @returns + */ + consumeColor(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != 35 /* TokenMap.HASH */) { + return 0; + } + position++; + let count = 0; + while (true) { + codepoint = parseInfo.stream.charCodeAt(position); + // 'a-f0-9' 'A-F0-9' + if ((codepoint >= 0x30 && codepoint <= 0x39) || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46)) { + position++; + count++; + continue; + } + break; + } + if (count != 3 && count != 4 && count != 6 && count != 8) { + return 0; + } + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + return 0; + } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peekCharCode(parseInfo))) { + this.advance(parseInfo); + } + charCode = this.peekCharCode(parseInfo); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + // if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + // } + } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ + makeToken(parseInfo, hint, options) { + let val = null; + this.typ = null; + this.nam = null; + this.val = null; + this.unit = null; + this.kin = null; + this.decodeString = null; + this.slice = null; + this.hint = null; + if (options?.slice) { + this.slice = options.slice; + } + if (options?.decodeSegments) { + this.decodeString = true; + } + if (hint != null) { + let array = null; + let hasUnit = false; + switch (hint) { + case exports.EnumToken.TransformFunctionTokenDefType: + array = transformFunctions; + break; + case exports.EnumToken.ColorFunctionTokenDefType: + array = colorsFunc; + break; + case exports.EnumToken.ContainerFunctionTokenDefType: + array = containerFunc; + break; + case exports.EnumToken.UrlFunctionTokenDefType: + array = urlFunc; + break; + case exports.EnumToken.GridTemplateFuncTokenDefType: + array = gridTemplateFunc; + break; + case exports.EnumToken.ImageFunctionTokenDefType: + array = imageFunc; + break; + case exports.EnumToken.TimelineFunctionTokenDefType: + array = timelineFunc; + break; + // case EnumToken.GeneralEnclosedFunctionTokenDefType: + // searchArray = generalEnclosedFunc; + // break; + case exports.EnumToken.SupportsFunctionTokenDefType: + array = supportFunc; + break; + case exports.EnumToken.TimingFunctionTokenDefType: + array = timingFunc; + break; + case exports.EnumToken.MathFunctionTokenDefType: + array = mathFuncs; + break; + case exports.EnumToken.WhenElseFunctionTokenDefType: + array = whenElseFunc; + break; + case exports.EnumToken.WildCardFunctionTokenDefType: + array = wildCardFuncs; + break; + case exports.EnumToken.FrequencyTokenType: + array = frequencyUnits; + hasUnit = true; + break; + case exports.EnumToken.ResolutionTokenType: + array = resolutionUnits; + hasUnit = true; + break; + case exports.EnumToken.LengthTokenType: + array = dimensionUnits; + hasUnit = true; + break; + case exports.EnumToken.FlexTokenType: + array = flexUnits; + hasUnit = true; + break; + case exports.EnumToken.AngleTokenType: + array = angleUnits; + hasUnit = true; + break; + case exports.EnumToken.TimeTokenType: + array = timeUnits; + hasUnit = true; + break; + case exports.EnumToken.DimensionTokenType: + hasUnit = true; + break; + } + if (array != null) { + val = searchArray(array, parseInfo, hasUnit ? options?.slice : parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + else if (!hintsEnum.has(hint)) { + val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + if (this.decodeString) { + val = decodeEscapeSequences(val); + } + if (hintsEnum.has(hint)) { + this.typ = hint; + } + else { + this.typ = hint; + if (hasUnit || hint == exports.EnumToken.PercentageTokenType || hint == exports.EnumToken.DimensionTokenType) { + this.val = parseFloat(parseInfo.stream.slice(parseInfo.position - parseInfo.offset, options?.slice)); + if (hint != exports.EnumToken.PercentageTokenType) { + this.unit = val; + } + } + else if (hint == exports.EnumToken.NumberTokenType) { + this.val = parseFloat(val); + } + else if (hint == exports.EnumToken.AtRuleTokenType) { + this.nam = val; + } + else { + this.val = val; + if (hint == exports.EnumToken.ColorTokenType) { + this.kin = exports.ColorType.HEX; } } } - if (val === "0") { - if (token.typ == exports.EnumToken.TimeTokenType) { - return "0s"; + } + else { + if (this.equalsIgnoreCase(parseInfo, "!important")) { + this.typ = exports.EnumToken.ImportantTokenType; + } + } + if (this.typ == null) { + val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + if (options?.decodeSegments) { + val = decodeEscapeSequences(val); + this.decodeString = true; + } + this.typ = exports.EnumToken.LiteralTokenType; + this.val = val; + } + this.srcId = parseInfo.source.id; + this.sta = parseInfo.position; + this.end = parseInfo.currentPosition; + this.bytesIn = parseInfo.currentPosition; + parseInfo.position = parseInfo.currentPosition; + return this; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + equalsIgnoreCase(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + let ca; + let cb; + for (let i = 0; i < input.length; i++) { + ca = parseInfo.stream.charCodeAt(position + i); + cb = input.charCodeAt(i); + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + match(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + for (let i = 0; i < input.length; i++) { + if (parseInfo.stream[position + i] != input.charAt(i)) { + return false; + } + } + return true; + } + /** + * Get the current character code without creating a string + * @param parseInfo + * @returns charCode at current position + */ + peekCharCode(parseInfo) { + return parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + peek(parseInfo, count = 1) { + if (count == 1) { + return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); + } + const position = parseInfo.currentPosition - parseInfo.offset; + return parseInfo.stream.slice(position, position + count); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + advance(parseInfo, count = 1) { + let position = parseInfo.currentPosition - parseInfo.offset; + let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); + let i = 0; + let codepoint; + const lineStarts = parseInfo.source.lineStarts.lineStarts; + for (; i < char.length; i++) { + codepoint = char.charCodeAt(i); + if (codepoint == 0xa || // \n + codepoint == 0xb || // \v + codepoint == 0xc || // \f + codepoint == 0xd || // \r + codepoint == 0x2028 || // \u2028 + codepoint == 0x2029 // \u2029 + ) { + // \r\n + if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; + else { + lineStarts.push(position + parseInfo.offset + i); + } + } + } + parseInfo.currentPosition += char.length; + return char; + } + /** + * + * @param parseInfo + * @param start + * @param end + * @returns + */ + isIdentToken(parseInfo, start, end) { + let j = parseInfo.currentPosition - parseInfo.offset; + let i = parseInfo.position - parseInfo.offset; + if (start != null) { + if (end == null) { + if (start < 0) { + j += start; + } + else { + i += start; + } + } + else { + if (end < 0) { + j += end; + } + else { + j = parseInfo.position + end; + } + } + } + j--; + let codepoint = parseInfo.stream.charCodeAt(i); + // - + if (codepoint == 0x2d) { + let nextCodepoint; + // NaN != NaN + if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { + return false; + } + if (!isIdentStart(nextCodepoint) && nextCodepoint != 0x2d) { + return false; + } + codepoint = nextCodepoint; + i++; + } + if (codepoint !== 0x2d && !isIdentStart(codepoint)) { + return false; + } + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + codepoint = parseInfo.stream.charCodeAt(i + 1); + i += String.fromCodePoint(codepoint).length; + } + while (i < j) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + continue; + } + if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isPseudo(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let endPosition = 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 + * @param input + * @returns + */ + startsWith(parseInfo, input) { + let i = 0; + let j = input.length; + while (i < j) { + if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { + return false; + } + i++; + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isURLToken(parseInfo) { + let i = parseInfo.position - parseInfo.offset; + let c; + while (++i < parseInfo.currentPosition) { + c = parseInfo.stream.charCodeAt(i); + // single quote or double quote or start parenthesis or close parenthesis + if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { + return false; + } + // valid escape + if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i++; + if (i >= parseInfo.currentPosition) { + return false; + } + c = parseInfo.stream.charCodeAt(i); + // c is not '\n' or '\r' or '\f' + if (c == 0x6e || c == 0x72 || c == 0x66) { + return false; + } + continue; + } + // is white space + if (c == 0x20 || c == 0x09) { + break; + } + } + return i == parseInfo.currentPosition; + } + done() { + return this.typ === exports.EnumToken.EOF; + } + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; + this.source = parseInfo.source; + let charCode; + let nextCharCode; + // const result: TokenizeResult[] = []; + // allow 10 characters buffer for the streaming parser to avoid incomplete tokens + const endPosition = parseInfo.stream.length - 1; // yieldEOFToken ? parseInfo.stream.length - 1 : parseInfo.stream.length - 10; + let tokensCount; + // NaN is not equal to NaN + while ((charCode = this.peekCharCode(parseInfo)) == charCode) { + if (this.state === exports.EnumToken.UrlFunctionTokenDefType) { + this.state = null; + return this.parseURLToken(parseInfo, endPosition); + } + if (parseInfo.position == parseInfo.currentPosition) { + if (charCode == 45 /* TokenMap.MINUS */ || + charCode == 43 /* TokenMap.PLUS */ || + charCode == 46 /* TokenMap.DOT */ || + 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: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + } } - if (token.typ == exports.EnumToken.FrequencyTokenType) { - return "0Hz"; + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + charCode = this.peekCharCode(parseInfo); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? exports.EnumToken.DashedIdenTokenType + : exports.EnumToken.IdenTokenType); + } + } } - // @ts-ignore - if (token.typ == exports.EnumToken.ResolutionTokenType) { - return "0x"; + if (charCode == 64 /* TokenMap.AT */) { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); + } + } } - return "0"; - } - if (token.typ == exports.EnumToken.TimeTokenType) { - if (unit == "ms") { - // @ts-ignore - const v = minifyNumber(val / 1000); - if (v.length + 1 <= val.length) { - return v + "s"; + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); + } + this.advance(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.HashTokenType); } - return val + "ms"; } - return val + "s"; - } - if (token.typ == exports.EnumToken.ResolutionTokenType && unit == "dppx") { - unit = "x"; - } - return val.includes("/") ? val.replace("/", unit + "/") : minifyNumber(toPrecisionValue(val)) + unit; - case exports.EnumToken.FlexTokenType: - case exports.EnumToken.PercentageTokenType: - const uni = token.typ == exports.EnumToken.PercentageTokenType ? "%" : "fr"; - 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; - case exports.EnumToken.NumberTokenType: - return token.val.typ == exports.EnumToken.FractionTokenType - ? renderValue(token.val, options, cache) - : minifyNumber(token.val); - case exports.EnumToken.AtRuleTokenType: - return "@" + token.nam; - case exports.EnumToken.CommentTokenType: - case exports.EnumToken.CDOCOMMNodeType: - if (options.removeComments && - (!options.preserveLicense || !token.val.startsWith("/*!"))) { - return ""; - } - case exports.EnumToken.PseudoClassTokenType: - case exports.EnumToken.PseudoElementTokenType: - // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == exports.EnumToken.PseudoElementTokenType && - pseudoElements.includes(token.val.slice(1))) { - return token.val.slice(1); } - case exports.EnumToken.UrlTokenTokenType: - case exports.EnumToken.HashTokenType: - case exports.EnumToken.IdenTokenType: - case exports.EnumToken.StringTokenType: - case exports.EnumToken.LiteralTokenType: - case exports.EnumToken.DashedIdenTokenType: - case exports.EnumToken.PseudoPageTokenType: - case exports.EnumToken.ClassSelectorTokenType: - return token.val; - case exports.EnumToken.NestingSelectorTokenType: - return "&"; - case exports.EnumToken.InvalidAttrTokenType: - return ("[" + - token.chi.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.InvalidClassSelectorTokenType: - return token.val; - case exports.EnumToken.SupportsQueryUnaryConditionTokenType: - case exports.EnumToken.WhenElseUnaryConditionTokenType: - return (renderValue(token.l, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); - case exports.EnumToken.SupportsQueryConditionTokenType: - case exports.EnumToken.WhenElseQueryConditionTokenType: - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - " " + - renderValue(token.op, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "")); - case exports.EnumToken.IfConditionTokenType: - return token.l.length == 0 - ? "" - : token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - ":" + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), ""); - case exports.EnumToken.IfElseConditionTokenType: - return renderValue(token.l) + renderValue(token.r); - case exports.EnumToken.DeclarationNodeType: - return (token.nam + - ":" + - (options.minify ? filterValues(token.val) : token.val).reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaQueryUnaryFeatureTokenType: - return (renderValue(token.l, options, cache, reducer, errors) + - " " + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaQueryConditionTokenType: { - const indent = token.op.typ == exports.EnumToken.LtTokenType || - token.op.typ == exports.EnumToken.GtTokenType || - token.op.typ == exports.EnumToken.ColonTokenType || - token.op.typ == exports.EnumToken.DelimTokenType || - token.op.typ == exports.EnumToken.LteTokenType || - token.op.typ == exports.EnumToken.GteTokenType - ? "" - : " "; - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - indent + - renderValue(token.op, options, cache, reducer, errors) + - indent + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - } - case exports.EnumToken.MediaRangeQueryTokenType: - return (token.l.reduce((acc, curr) => acc + renderValue(curr, options, cache), "") + - renderValue(token.op1) + - token.val.reduce((acc, curr) => acc + renderValue(curr, options, cache, reducer, errors), "") + - renderValue(token.op2) + - token.r.reduce((acc, curr) => acc + renderValue(curr, options, cache), "")); - case exports.EnumToken.MediaFeatureTokenType: - return token.val; - case exports.EnumToken.NotTokenType: - return "not"; - case exports.EnumToken.OnlyTokenType: - return "only"; - case exports.EnumToken.AndTokenType: - return "and"; - case exports.EnumToken.OrTokenType: - return "or"; - case exports.EnumToken.InvalidMediaQueryTokenType: - case exports.EnumToken.InvalidCommentTokenType: - case exports.EnumToken.BadCommentTokenType: - case exports.EnumToken.BadCdoTokenType: - case exports.EnumToken.BadStringTokenType: - case exports.EnumToken.BadUrlTokenType: - case exports.EnumToken.EOFTokenType: - return ""; - default: - console.debug({ token }); - throw new Error(`Unsupported token type for ${exports.EnumToken[token.typ]}`); - } - errors?.push({ action: "ignore", message: `render: unexpected token ${JSON.stringify(token, null, 1)}` }); - return ""; -} -/** - * Remove whitespace tokens that are not needed - * @param values - * - * @internal - */ -function filterValues(values) { - let i = 0; - for (; i < values.length; i++) { - if (values[i].typ == exports.EnumToken.ImportantTokenType && values[i - 1]?.typ === exports.EnumToken.WhitespaceTokenType) { - values.splice(i - 1, 1); + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + 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); + } + 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: "+", + }); + } + } + return this.makeToken(parseInfo, exports.EnumToken.Plus); + case 45 /* TokenMap.MINUS */: + if (parseInfo.position == parseInfo.currentPosition) { + nextCharCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + // not a number + if (isWhiteSpace(nextCharCode)) { + 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); + } + } + } + this.advance(parseInfo); + break; + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); + } + else if (this.isIdentToken(parseInfo)) { + const hint = this.startsWith(parseInfo, "--") + ? exports.EnumToken.CustomFunctionTokenDefType + : (getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset + 1) ?? exports.EnumToken.FunctionTokenDefType); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === exports.EnumToken.UrlFunctionTokenDefType) { + this.state = hint; + } + return this; + } + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + 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); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); + case 59 /* TokenMap.SEMICOLON */: + 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); + } + this.advance(parseInfo); + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); + } + return this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); + // \n \r \f \v \t space + case 0x9: + case 0x20: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x2028: + case 0x2029: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.advance(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); + case 44 /* TokenMap.COMMA */: + 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 (this.match(parseInfo, "$=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); + } + this.advance(parseInfo); + break; + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Tilda); + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); + } + this.advance(parseInfo); + break; + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Star); + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); + } + else if (this.match(parseInfo, "|=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Pipe); + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); + } + this.advance(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + 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)); + } + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); + } + } + } + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); + } + break; + case 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.GtTokenType); + case 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "<=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.LteTokenType); + } + this.advance(parseInfo); + if (this.match(parseInfo, "!--")) { + this.advance(parseInfo, 3); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + return this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + } + else { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + } + } + break; + case 35 /* TokenMap.HASH */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + 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; + } + this.advance(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + return this.consumeString(parseInfo); + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.advance(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); + } + } + 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; + // } } - else if (tokensfuncSet.has(values[i].typ) && - "chi" in values[i] && - values[i].typ != exports.EnumToken.WildCardFunctionTokenType && - values[i + 1]?.typ == exports.EnumToken.WhitespaceTokenType) { - values.splice(i + 1, 1); + // if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } + return this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); + // } + } + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async tokenizeStream() { + const decoder = new TextDecoder("utf-8"); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; + parseInfo.stream = ""; + while (true) { + const { done, value } = await reader.read(); + const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; + if (!done) { + parseInfo.source.append(stream); + } + else { + break; + } + } + parseInfo.stream = parseInfo.source.getContent(); + return this; // .next(); } - return values; } /** @@ -26078,7 +27017,9 @@ function parseSelector(tokens, context, options, errors) { filtered[0] = { typ: exports.EnumToken.PercentageTokenType, val: 0, - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } else if (filtered[0].typ === exports.EnumToken.PercentageTokenType && @@ -26086,7 +27027,9 @@ function parseSelector(tokens, context, options, errors) { filtered[0] = { typ: exports.EnumToken.IdenTokenType, val: "to", - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } part.splice(0, part.length, ...filtered); @@ -26097,7 +27040,9 @@ function parseSelector(tokens, context, options, errors) { if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, [])); return { @@ -26109,10 +27054,9 @@ function parseSelector(tokens, context, options, errors) { }, new Set()), ].join(), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? tokens[0]?.[LOC]?.end, - }, + [LOCSRCID]: tokens[0]?.[LOCSRCID], + [LOCSTA]: tokens[0]?.[LOCSTA], + [LOCEND]: tokens[tokens.length - 1]?.[LOCEND], [TOKENS]: tokens.length === 0 ? null : tokens, [STATE]: result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -26162,7 +27106,7 @@ function parseSelector(tokens, context, options, errors) { typ: exports.EnumToken.PseudoElementTokenType, val: ":" + tokens[i + 1].val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26174,7 +27118,7 @@ function parseSelector(tokens, context, options, errors) { : tokens[i + 1].typ, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26186,7 +27130,7 @@ function parseSelector(tokens, context, options, errors) { typ: exports.EnumToken.PseudoClassTokenType, val: (pseudoElements.includes(val) ? "" : ":") + val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26198,7 +27142,7 @@ function parseSelector(tokens, context, options, errors) { : exports.EnumToken.FunctionTokenDefType, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -26253,10 +27197,9 @@ function parseSelector(tokens, context, options, errors) { .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: exports.EnumAstNodeStatus.Invalid, [ERRORS]: [ @@ -26284,10 +27227,9 @@ function parseSelector(tokens, context, options, errors) { index = tokens.indexOf(stack.at(-1)); // @ts-expect-error const { val, ...attr } = stack.at(-1); - attr[LOC] = { - ...stack.at(-1)[LOC], - end: token[LOC].end, - }; + attr[LOCSRCID] = stack.at(-1)[LOCSRCID]; + attr[LOCSTA] = stack.at(-1)[LOCSTA]; + attr[LOCEND] = token[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: exports.EnumToken.AttrTokenType, @@ -26305,7 +27247,7 @@ function parseSelector(tokens, context, options, errors) { if (stack.at(-1)?.typ == exports.EnumToken.PseudoClassFunctionTokenDefType) { const func = stack.at(-1); index = tokens.indexOf(func); - stack.at(-1)[LOC].end = token[LOC].end; + stack.at(-1)[LOCEND] = token[LOCEND]; tokens.splice(i, 1); if (tokensfuncDefMap.has(func.typ)) { // @ts-expect-error @@ -26322,20 +27264,77 @@ function parseSelector(tokens, context, options, errors) { const list = []; let index; for (index = 0; index < func.chi.length; index++) { - if (func.chi[index].typ == exports.EnumToken.CommentTokenType || func.chi[index].typ == exports.EnumToken.WhitespaceTokenType) { + if (func.chi[index].typ == exports.EnumToken.CommentTokenType || + func.chi[index].typ == exports.EnumToken.WhitespaceTokenType) { continue; } - if (func.chi[index].typ == exports.EnumToken.IdenTokenType && equalsIgnoreCase('of', func.chi[index].val)) { + if (func.chi[index].typ == exports.EnumToken.IdenTokenType && + equalsIgnoreCase("of", func.chi[index].val)) { index--; break; } list.push(func.chi[index]); } + if (list.length == 2) { + if (list[1].typ == exports.EnumToken.NumberTokenType) { + if (list[1].val == 0) { + list.length = 1; + if (list[0].typ == exports.EnumToken.DimensionTokenType && + list[0].val == -2) { + list[0].val = 2; + } + } + else { + const sign = Math.sign(list[1].val); + // @ts-ignore + list[1].val *= sign; + list.splice(1, 0, { + typ: exports.EnumToken.LiteralTokenType, + val: sign > 0 ? "+" : "-", + }); + } + } + if (list.length == 3 && + list[2].typ == exports.EnumToken.NumberTokenType && + list[0].typ == exports.EnumToken.DimensionTokenType && + (list[0].val == 2 || + list[0].val == -2)) { + if (1 == list[2].val) { + list.splice(0, 3, { + typ: exports.EnumToken.IdenTokenType, + val: "odd", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + else if (0 == list[2].val) { + list.splice(0, 3, { + typ: exports.EnumToken.IdenTokenType, + val: "even", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + } + func.chi.splice(0, index, ...list); + } + if (list.length == 1) { + if (list[0].typ == exports.EnumToken.IdenTokenType && + equalsIgnoreCase("-n", list[0].val)) { + list[0].val = "n"; + } + } if (list.length == 3) { - if (list[0].typ == exports.EnumToken.IdenTokenType && ('n' == list[0].val || '-n' == list[0].val || '+n' == list[0].val)) { + if (list[0].typ == exports.EnumToken.IdenTokenType && + ("n" == list[0].val || + "-n" == list[0].val || + "+n" == list[0].val)) { if (list[1].typ == exports.EnumToken.NextSiblingCombinatorTokenType) { - if (list[2].typ == exports.EnumToken.NumberTokenType && (0 == list[2].val)) { - list[0].val = 'n'; + if (list[2].typ == exports.EnumToken.NumberTokenType && + 0 == list[2].val) { + list[0].val = "n"; func.chi.splice(0, index, list[0]); break; } @@ -26355,83 +27354,10 @@ function parseSelector(tokens, context, options, errors) { } } else { - // if (!/\d+$/.test((token as IdentToken | LiteralToken).val)) { - // let index = func.chi.indexOf(token); - // let i: number = index + 1; - // let sign: Token | null = null; - // let num: NumberToken | null = null; - // for (; i < func.chi.length; i++) { - // if ( - // func.chi[i].typ == EnumToken.WhitespaceTokenType || - // func.chi[i].typ == EnumToken.CommentTokenType - // ) { - // continue; - // } - // if (func.chi[i].typ == EnumToken.NumberTokenType) { - // num = func.chi[i] as NumberToken; - // break; - // } else { - // sign = func.chi[i] as Token; - // } - // } - // if (num != null) { - // if (num.val === 0) { - // func.chi.splice(index + 1, i - index); - // if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } - // if (sign == null) { - // func.chi.splice(index + 1, i - index - 1); - // if (Math.sign(num.val as number) === 1) { - // func.chi.splice(index + 1, 0, { - // typ: EnumToken.LiteralTokenType, - // val: "+", - // }); - // } - // } - // } else if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } const matches = /^(([+-]?[0-9]*)?n)?([+-]?[0-9]+)?$/.exec(token.val); if (matches != null) { const a1 = matches[2] === "" ? 1 : matches[2] === "-" ? -1 : +matches[2]; const b1 = +matches[3]; - // if (a1 === 0) { - // if (b1 === 1) { - // let hasSelector: boolean = false; - // let i: number = func.chi.indexOf(token); - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // Object.assign(token, { - // typ: EnumToken.NumberTokenType, - // val: b1, - // }); - // } else { - // // :first-child - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // Object.assign(token, { typ: EnumToken.NumberTokenType, val: b1 }); - // } - // } else if (b1 === 0) { Object.assign(token, Math.abs(a1) === 1 ? { @@ -26444,17 +27370,6 @@ function parseSelector(tokens, context, options, errors) { unit: "n", }); } - // else if (Math.abs(a1) === 2) { - // if (b1 === 0) { - // Object.assign(token, { - // typ: EnumToken.DimensionTokenType, - // val: a1, - // unit: "n", - // }); - // } else if (Math.abs(b1) === 1) { - // Object.assign(token, { typ: EnumToken.IdenTokenType, val: "odd" }); - // } - // } } } } @@ -26473,36 +27388,6 @@ function parseSelector(tokens, context, options, errors) { } } if (num != null) { - // if ((token as DimensionToken).val === 0) { - // if (num.val === 0) { - // func.chi.splice(0, i); - // } else if (num.val === 1) { - // let hasSelector: boolean = false; - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // func.chi.splice(0, i); - // } else { - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // func.chi.splice(0, i); - // } - // break; - // } else if (num.val === 0) { func.chi.splice(index + 1, i - index); if (token.val < 0) { @@ -26591,10 +27476,9 @@ function parseSelector(tokens, context, options, errors) { .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: result.success && allowed ? exports.EnumAstNodeStatus.Validated @@ -26646,6 +27530,7 @@ function parseGridTemplate(template) { * @param errors */ function parseDeclaration(tokens, parent, options, errors) { + // console.error(tokens); const name = tokens.shift(); let i; let rules = null; @@ -26666,16 +27551,15 @@ function parseDeclaration(tokens, parent, options, errors) { } if ((name.typ !== exports.EnumToken.IdenTokenType && name.typ !== exports.EnumToken.DashedIdenTokenType) || tokens[i]?.typ !== exports.EnumToken.ColonTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Unparsed; name[ERRORS] = [ { action: "drop", node: name, - location: name[LOC], + location: options.source.getSourceLocation(name[LOCSTA]), message: "invalid declaration", }, ]; @@ -26705,39 +27589,6 @@ function parseDeclaration(tokens, parent, options, errors) { rules.acceptAnyDeclaration && rules.acceptAnyRule ? getParsedSyntax(ValidationSyntaxGroupEnum.Declarations, name.val.toLowerCase()) : rules.getBlockRules(); - // if (syntaxRules == null) { - // // check rule in nested context - // let pr = parent[PARENT] as AstNode | null; - // while (pr != null && pr.typ !== EnumToken.RuleNodeType) { - // pr = pr[PARENT]; - // } - // if (pr != null) { - // syntaxRules = getParsedSyntax( - // ValidationSyntaxGroupEnum.Declarations, - // name.val.toLowerCase(), - // ); - // } - // if (syntaxRules == null) { - // errors.push({ - // action: "drop", - // message: "declaration not allowed in context", - // node: name, - // location: name[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1][LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Disallowed; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } - // } } } } @@ -26775,12 +27626,11 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: "declaration value missing", node: name, - location: options.source.getSourceLocation(name[LOC].sta), + location: options.source.getSourceLocation(name[LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC].end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Invalid; name[ERRORS] = [errors[errors.length - 1]]; // @ts-expect-error @@ -26812,7 +27662,9 @@ function parseDeclaration(tokens, parent, options, errors) { } } if (!doNotValidate && !result?.success && result.errors.length > 0) { - errors.push(...result.errors); + for (index = 0; index < result.errors.length; index++) { + errors.push(result.errors[index]); + } } } } @@ -26830,7 +27682,7 @@ function parseDeclaration(tokens, parent, options, errors) { // Object.assign(token, { // typ: EnumToken.FunctionTokenDefType, // }); - // token[LOC]!.end = tokens[i + 1][LOC]!.end; + // token[LOCEND] = tokens[i + 1][LOCEND]; // tokens.splice(i + 1, 1); // stack.push(token); // } @@ -26868,26 +27720,6 @@ function parseDeclaration(tokens, parent, options, errors) { } break; case exports.EnumToken.EndParensTokenType: - // if (stack.length == 0) { - // errors.push({ - // action: "drop", - // message: "unbalanced parentheses", - // node: token, - // location: token[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1]?.[LOC]!.end ?? name[LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Invalid; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } if (stack.at(-1)?.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(stack.at(-1)?.typ)) { index = tokens.indexOf(stack.at(-1)); tokens.splice(i, 1); @@ -26960,9 +27792,9 @@ function parseDeclaration(tokens, parent, options, errors) { // ((tokens[index] as FunctionToken).chi[l] as IdentToken | UrlToken).val + // ((tokens[index] as FunctionToken).chi[m] as ClassSelectorToken).val, // }); - // (tokens[index] as FunctionToken).chi[l][LOC]!.end = ( + // (tokens[index] as FunctionToken).chi[l][LOCEND] = ( // tokens[index] as FunctionToken - // ).chi[m][LOC]!.end; + // ).chi[m][LOCEND]; // (tokens[index] as FunctionToken).chi.splice(m, 1); // } // break; @@ -26992,7 +27824,7 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: `invalid color`, node: tokens[index], - location: options.source.getSourceLocation(tokens[index][LOC].sta), + location: options.source.getSourceLocation(tokens[index][LOCSTA]), }); } } @@ -27044,12 +27876,11 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: "unbalanced token", node: stack[stack.length - 1], - location: options.source.getSourceLocation(stack[stack.length - 1][LOC].sta), + location: options.source.getSourceLocation(stack[stack.length - 1][LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1][LOC].end, - }; + if (tokens[tokens.length - 1][LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Invalid; name[ERRORS] = result?.errors ?? []; //@ts-expect-error @@ -27082,10 +27913,9 @@ function parseDeclaration(tokens, parent, options, errors) { } } if (validate && syntaxRules == null && name.typ === exports.EnumToken.IdenTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = exports.EnumAstNodeStatus.Unknown; name[ERRORS] = result?.errors ?? []; // @ts-expect-error @@ -27094,14 +27924,6 @@ function parseDeclaration(tokens, parent, options, errors) { nam: name.val, val: tokens, }); - // if ((options.validation as ValidationLevel) & ValidationLevel.Declaration) { - // errors.push({ - // action: "drop", - // message: "unknown declaration", - // node: node, - // location: node[LOC], - // }); - // } return node; } if (equalsIgnoreCase("composes", name.val)) { @@ -27119,18 +27941,15 @@ function parseDeclaration(tokens, parent, options, errors) { typ: exports.EnumToken.ComposesSelectorNodeType, l: left, r: right?.[0] ?? null, - [LOC]: { - ...tokens[0][LOC], - sta: left[0]?.[LOC]?.sta, - end: index != -1 ? right[right.length - 1]?.[LOC]?.end : left[left.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: index != -1 ? right[right.length - 1]?.[LOCEND] : left[left.length - 1][LOCEND], }, ]; } - name[LOC] = { - ...name[LOC], - end: (tokens[tokens.length - 1] ?? name)[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = success ? result == null ? exports.EnumAstNodeStatus.Unvalidated @@ -27200,7 +28019,7 @@ function parseMediaqueryList(stream, options) { action: "drop", message: `expecting ''`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27210,7 +28029,7 @@ function parseMediaqueryList(stream, options) { action: "drop", message: `expecting '('`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27252,7 +28071,7 @@ function parseMediaqueryList(stream, options) { action: "drop", node: stream[i], message: ` is not allowed outside of parentheses`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); break; } @@ -27262,7 +28081,7 @@ function parseMediaqueryList(stream, options) { action: "drop", node: stream[i], message: `cannot mix and at the same level`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } currentScope.add(stream[i].typ); @@ -27273,7 +28092,7 @@ function parseMediaqueryList(stream, options) { case exports.EnumToken.EndParensTokenType: if (tokensfuncDefMap.has(stack.at(-1)?.typ)) { const index = tokens.indexOf(stack.at(-1)); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCEND] = stream[i][LOCEND]; Object.assign(tokens[index], { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), @@ -27284,7 +28103,9 @@ function parseMediaqueryList(stream, options) { scopes.pop(); currentScope = scopes.at(-1); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } success = false; } break; @@ -27316,7 +28137,9 @@ function parseMediaqueryList(stream, options) { val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -27351,7 +28174,9 @@ function parseMediaqueryList(stream, options) { op1: prevToken, op2: stack.at(-1), r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }); stack.pop(); stack.pop(); @@ -27379,7 +28204,9 @@ function parseMediaqueryList(stream, options) { val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -27395,7 +28222,7 @@ function parseMediaqueryList(stream, options) { errors.push({ action: "drop", node: arr[0], - location: options.source.getSourceLocation(arr[0]?.[LOC].sta), + location: options.source.getSourceLocation(arr[0]?.[LOCSTA]), message: `${mfValue.isValueAllowed === false ? "invalid " : "expected "}`, }); break; @@ -27416,13 +28243,15 @@ function parseMediaqueryList(stream, options) { val.splice(0, val.length, ...filteredValues); } } + // @ts-expect-error tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: exports.EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - // @ts-expect-error - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); } if (stack.length === 0) { @@ -27430,7 +28259,7 @@ function parseMediaqueryList(stream, options) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `unmatched ')'`, }); break; @@ -27440,8 +28269,9 @@ function parseMediaqueryList(stream, options) { tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - // @ts-expect-error - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; tokens.length = index + 1; scopes.pop(); @@ -27463,7 +28293,9 @@ function parseMediaqueryList(stream, options) { op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOrComma = true; @@ -27480,7 +28312,9 @@ function parseMediaqueryList(stream, options) { parts.splice(parts.indexOf(stream), 1); } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const t of trimArray(tokens)) { + stream.push(t); + } } } stream.length = 0; @@ -27490,7 +28324,9 @@ function parseMediaqueryList(stream, options) { if (acc.length > 0) { acc.push({ typ: exports.EnumToken.CommaTokenType }); } - acc.push(...b); + for (const t of b) { + acc.push(t); + } return acc; }, [])); return { @@ -27532,7 +28368,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { : exports.EnumToken.PseudoClassTokenType, val: ":" + val, }); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -27545,7 +28381,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { val, }); stack.push(stream[i]); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -27595,7 +28431,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: slice, - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); tokens.pop(); @@ -27609,7 +28447,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), val: stack.at(-1).val, chi: trimArray(tokens.splice(index + 1, tokens.length - index - 2)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; if (tokens[index].typ === exports.EnumToken.PseudoClassFuncTokenType) { // not a declaration @@ -27640,7 +28480,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { typ: exports.EnumToken.SupportsQueryUnaryConditionTokenType, l: stack.at(-1), r: trimArray(tokens.splice(index + 1, i - index - 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); } @@ -27655,7 +28497,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { op: stack.at(-1), l: left, r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -27676,7 +28520,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { if ("and" === val || "or" === val) { if ("or" === val && scopes.length === 1) { const fileName = options.source.getFileName() ?? ""; - const [line, column] = options.source.getOffsets(stream[i]?.[LOC]?.sta); + const [line, column] = options.source.getOffsets(stream[i]?.[LOCSTA]); return { success: false, errors: [ @@ -27700,7 +28544,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -27736,11 +28582,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { } } const slice = stream.slice(index + 1, k); - // @ts-expect-error - stream[0][LOC] = { - ...stream[0][LOC], - end: stream[1][LOC].end, - }; + stream[0][LOCEND] = stream[1][LOCEND]; tokens.push(Object.assign({ typ: tokensfuncDefMap.get(stream[0].typ), chi: trimArray(slice), @@ -27756,7 +28598,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: "Expected string or url()", syntax: "@import", node: stream[0], - location: stream[0]?.[LOC], + location: options.source.getSourceLocation(stream[0]?.[LOCSTA]), }, ], }; @@ -27786,7 +28628,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27813,7 +28655,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27855,7 +28697,9 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { { const result = parseAtRuleSupportSyntax(tokens[tokens.length - 1].chi, context, options); if (!result.success && result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -27865,15 +28709,21 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { } const splice = stream.splice(index, stream.length - index); const sliced = parseMediaqueryList(splice, options); - tokens.push(...splice); + for (const sp of splice) { + tokens.push(sp); + } if (sliced.errors.length > 0) { - errors.push(...sliced.errors); + for (const error of sliced.errors) { + errors.push(error); + } } if (!sliced.success) { success = false; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors, @@ -27936,7 +28786,9 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { const tokenList = [ { typ: exports.EnumToken.StartParensTokenType, - [LOC]: { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }, + [LOCSRCID]: stream[i][LOCSRCID], + [LOCSTA]: stream[i][LOCSTA], + [LOCEND]: stream[j]?.[LOCEND], }, // @ts-expect-error ].concat(slice.slice(1)); @@ -27959,32 +28811,13 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { return result; } } - // else { - // errors.push({ - // action: "ignore", - // message: `unknown function '${funcName}' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // node: stream[i], - // location: stream[i][LOC], - // }); - // } - stream[i][LOC] = { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }; + stream[i][LOCEND] = stream[j]?.[LOCEND]; Object.assign(stream[i], { typ: tokensfuncDefMap.get(stream[i].typ), chi: stream[i].typ === exports.EnumToken.SupportsFunctionTokenDefType ? trimArray(slice.slice(1, -1)) : tokenList[0].chi, }); - // if (stack.at(-1)?.typ === EnumToken.NotTokenType || stack.at(-1)?.typ === EnumToken.OnlyTokenType) { - // const index: number = tokens.indexOf(stack.at(-1)!); - // tokens[index] = { - // typ: EnumToken.WhenElseUnaryConditionTokenType, - // l: stack.at(-1)!, - // r: trimArray(tokens.slice(index + 1)), - // [LOC]: { ...stack.at(-1)![LOC], end: { ...stream[i]?.[LOC]?.end } }, - // } as WhenElseUnaryConditionToken; - // tokens.length = index + 1; - // stack.pop(); - // } if (stack.at(-1)?.typ === exports.EnumToken.AndTokenType || stack.at(-1)?.typ === exports.EnumToken.OrTokenType) { const index = tokens.indexOf(stack.at(-1)); const index2 = stack.length > 1 ? tokens.indexOf(stack.at(-2)) + 1 : 0; @@ -27993,7 +28826,9 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { op: stack.at(-1), l: trimArray(tokens.slice(index2, index)), r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -28004,22 +28839,10 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { break; } } - // if (stack.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${renderValue(stack.at(-1) as Token)}' at ${stack.at(-1)![LOC]!.src}:${ - // stack.at(-1)![LOC]!.sta.lin - // }:${stack.at(-1)![LOC]!.sta.col}`, - // }, - // ], - // }; - // } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -28047,7 +28870,9 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { }, [[]]); const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -28067,19 +28892,6 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { (stream[i]?.typ === exports.EnumToken.WhitespaceTokenType || stream[i]?.typ === exports.EnumToken.CommentTokenType)) { tokens.push(stream[i++]); } - // if (i >= stream.length) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: context, - // location: context[LOC], - // message: `expecting at ${context[LOC]?.src}:${context?.[LOC]?.sta.lin}:${context[LOC]?.sta.col}`, - // }, - // ], - // }; - // } if (stream[i].typ === exports.EnumToken.IdenTokenType) { tokens.push(stream[i++]); } @@ -28095,7 +28907,7 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { { action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), // ?? context[LOC], + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting `, }, ], @@ -28120,11 +28932,10 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { action: "drop", node: stream[i], message: `expecting , or comma`, - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), }); break; } - // expectAndOr = false; } if (stream[i].typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(stream[i].typ)) { scopes.push((currentScope = new Set())); @@ -28158,174 +28969,34 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: ` is not allowed outside of parentheses`, }); break; } - // if (currentScope.has(val === "or" ? EnumToken.AndTokenType : EnumToken.OrTokenType)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `cannot mix and at the same level at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } currentScope.add(stream[i].typ); stack.push(stream[i]); } - // else if (scopes.length === 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unexpected at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // return { - // success, - // errors, - // }; - // } } break; case exports.EnumToken.EndParensTokenType: - // feature - // if (mFLT.has(stack.at(-1)?.typ) || mFGT.has(stack.at(-1)?.typ)) { - // // | - // const index: number = tokens.indexOf(stack.at(-1)!); - // const prevToken: Token = stack[stack.length - 2]; - // if (mFLT.has(prevToken?.typ) || mFGT.has(prevToken?.typ)) { - // if (stack[stack.length - 3]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `unmatched '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!mFLT.has(stack.at(-1)?.typ) && mFLT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } else if (!mFGT.has(stack.at(-1)?.typ) && mFGT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } - // // - // // const index: number = tokens.indexOf(stack.at(-1)!); - // // | - // const index2: number = tokens.indexOf(prevToken); - // // '(' - // const index3: number = tokens.indexOf(stack.at(-3)!); - // const left: Token[] = trimArray(tokens.slice(index3 + 1, index2)); - // const right: Token[] = trimArray(tokens.slice(index + 1, tokens.length - 1)); - // const names: Token[] = trimArray(tokens.slice(index2 + 1, index)); - // if (!isStyleFeatureValue(left)) { - // success = false; - // errors.push({ - // action: "drop", - // node: left[0], - // message: `expected at ${left[0]?.[LOC]?.src}:${left[0]?.[LOC]?.sta.lin}:${left[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(right)) { - // success = false; - // errors.push({ - // action: "drop", - // node: right[0], - // message: `expected at ${right[0]?.[LOC]?.src}:${right[0]?.[LOC]?.sta.lin}:${right[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(names)) { - // success = false; - // errors.push({ - // action: "drop", - // node: names[0], - // message: `expected at ${names[0]?.[LOC]?.src}:${names[0]?.[LOC]?.sta.lin}:${names[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // tokens.splice(index3 + 1, tokens.length - index3 - 2, { - // typ: EnumToken.ContainerStyleRangeTokenType, - // l: left, - // op: names, - // r: right, - // [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, - // } as ContainerStyleRangeToken); - // // check or - // stack.pop(); - // stack.pop(); - // } else if (stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `expected '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // } if (mFGT.has(stack.at(-1)?.typ) || mFLT.has(stack.at(-1)?.typ) || stack.at(-1)?.typ === exports.EnumToken.DelimTokenType || stack.at(-1)?.typ === exports.EnumToken.ColonTokenType) { stack[stack.length - 2].val?.toLowerCase?.(); - // if ( - // stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType && - // !( - // stack[stack.length - 2]?.typ === EnumToken.ContainerFunctionTokenDefType && - // ("style" === funcName || "scroll-state" === funcName) - // ) - // ) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unmatched2 ')' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } const index2 = tokens.indexOf(stack.at(-1)); const index3 = tokens.indexOf(stack.at(-2)); let names = trimArray(tokens.slice(index3 + 1, index2)); let values = trimArray(tokens.slice(index2 + 1, tokens.length - 1)); - // if ( - // stack.at(-1)?.typ !== EnumToken.ColonTokenType && - // stack.at(-1)?.typ !== EnumToken.DelimTokenType - // ) { - // const filteredNames = names.filter( - // (n) => - // n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, - // ); - // if ( - // filteredNames.length !== 1 || - // (filteredNames[0].typ !== EnumToken.IdenTokenType && - // filteredNames[0].typ !== EnumToken.DashedIdenTokenType) - // ) { - // } - // } tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: exports.EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); // check or } @@ -28335,13 +29006,15 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), }); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCSRCID] = tokens[index][LOCSRCID]; + tokens[index][LOCSTA] = tokens[index][LOCSTA]; + tokens[index][LOCEND] = stream[i][LOCEND]; if (tokens[index].chi.every((t) => t.typ === exports.EnumToken.WhitespaceTokenType || t.typ === exports.EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting '<${tokens[index].val}-query>'`, }); break; @@ -28356,14 +29029,16 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { tokens[index] = { typ: exports.EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; if (tokens[index].chi.every((t) => t.typ === exports.EnumToken.WhitespaceTokenType || t.typ === exports.EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting ''`, }); break; @@ -28385,21 +29060,12 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { errors.push({ action: "drop", node: tokens[k], - location: options.source.getSourceLocation(tokens[k]?.[LOC].sta), + location: options.source.getSourceLocation(tokens[k]?.[LOCSTA]), message: `unexpected token 'not'`, }); break; } } - // const index = tokens.indexOf(stack.at(-1)!); - // const slice = trimArray(tokens.slice(index + 1)); - // tokens[index] = { - // typ: EnumToken.MediaQueryUnaryFeatureTokenType, - // l: stack.pop()!, - // r: slice, - // [LOC]: { ...tokens[index][LOC]!, end: slice.at(-1)![LOC]!.end }, - // }; - // tokens.length = index + 1; } if (stack.at(-1)?.typ === exports.EnumToken.AndTokenType || stack.at(-1)?.typ === exports.EnumToken.OrTokenType) { @@ -28417,31 +29083,19 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOr = true; } break; - // default: - // if (tokensfuncDefMap.has(stream[i]?.typ)) { - // stack.push(stream[i]); - // scopes.push((currentScope = new Set())); - // } - // break; } if (!success) { break; } } - // if (success && stack.length > 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${EnumToken[stack.at(-1)?.typ]}' at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // } if (!success) { return { success, @@ -28449,17 +29103,18 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { }; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } } } stream.length = 0; stream.push(...parts .filter((p) => p.length > 0 && p[0].typ !== exports.EnumToken.InvalidMediaQueryTokenType) .reduce((acc, b) => { - // if (acc.length > 0) { - // acc.push({ typ: EnumToken.CommaTokenType }); - // } - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { @@ -28473,24 +29128,6 @@ function matchAtRuleSyntax(atRule, stream, options) { const syntax = syntaxRules?.getPreludeRules()?.slice?.(1); trimArray(stream); if (syntax.length === 0) { - // const filtered = stream.filter( - // (token) => token.typ !== EnumToken.WhitespaceTokenType && token.typ !== EnumToken.CommentTokenType, - // ); - // if (filtered.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // message: `unexpected token ${EnumToken[filtered[0].typ]} at ${filtered[0][LOC]!.src}:${ - // filtered[0][LOC]!.sta.lin - // }:${filtered[0][LOC]!.sta.col}`, - // node: filtered[0], - // location: filtered[0][LOC]!, - // }, - // ], - // }; - // } return { success: true, errors: [] }; } const { success, errors } = matchAllSyntaxes(syntax, createValidationContext(stream), options); @@ -28531,7 +29168,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28546,7 +29183,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28562,7 +29199,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28578,7 +29215,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${exports.EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -28598,8 +29235,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${exports.EnumToken[stack.at(-1)?.typ]}`, node: stack.at(-1), - // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)?.[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)?.[LOCSTA]), }); success = false; } @@ -28934,7 +29570,9 @@ function parseVisitors(visitorsDef, errors) { } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { @@ -28951,7 +29589,6 @@ function parseVisitors(visitorsDef, errors) { .push(value); } else if (typeof value == "object") { - // visitors.push(...Object.entries(value)); if ("type" in value && "handler" in value && value.type in exports.WalkerEvent) { if (value.type == exports.WalkerEvent.Enter) { if (!preVisitorsHandlersMap.has(key)) { @@ -29019,7 +29656,7 @@ function parseVisitors(visitorsDef, errors) { * @throws Error * @private */ -function doParseSync(iter, options = {}) { +function doParseSync(tokenizer, options = {}) { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -29081,46 +29718,78 @@ function doParseSync(iter, options = {}) { // @ts-ignore ignore error let parensMatch = 0; let curlyBracketMatch = 0; - let currentItemIndex; - // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - for (currentItemIndex = 0; currentItemIndex < iter.length; currentItemIndex++) { - item = iter[currentItemIndex]; - stats.bytesIn = item.bytesIn; + // let currentItemIndex: number; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); + // item = (iter as Array)[currentItemIndex]; + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + if (item.typ === exports.EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === exports.EnumToken.SemiColonTokenType || - item.token.typ === exports.EnumToken.BlockStartTokenType || - item.token.typ === exports.EnumToken.EOFTokenType)) { + (item.typ === exports.EnumToken.SemiColonTokenType || + item.typ === exports.EnumToken.BlockStartTokenType || + item.typ === exports.EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -29128,37 +29797,67 @@ function doParseSync(iter, options = {}) { context = node; } } - else if (item.token.typ == exports.EnumToken.BlockStartTokenType) { + else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = iter[++currentItemIndex]; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === exports.EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -29167,7 +29866,7 @@ function doParseSync(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -29210,17 +29909,23 @@ function doParseSync(iter, options = {}) { case exports.EnumToken.AtRuleNodeType: case exports.EnumToken.KeyframesRuleNodeType: case exports.EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case exports.EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (const child of nodes[i].chi) { + subNodes.push(child); + } } if (subNodes.length > 0) { if (freeBlock <= i) { @@ -29382,7 +30087,7 @@ function doParseSync(iter, options = {}) { ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -29411,7 +30116,7 @@ function doParseSync(iter, options = {}) { : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & exports.ModuleCaseTransformEnum.CamelCase) { @@ -29456,7 +30161,7 @@ function doParseSync(iter, options = {}) { for (const { node, parent } of walk(ast)) { if (node.typ == exports.EnumToken.CssVariableImportTokenType) { throw new Error("css variable import not supported by parseSync() or transformSync(). use parse() or transform() instead.\nat " + - options.source.getSourceLocation(node[LOC].sta).join(":")); + options.source.getSourceLocation(node[LOCSTA]).join(":")); } // @ts-ignore if (node.typ == exports.EnumToken.CssVariableDeclarationMapTokenType) { @@ -29575,7 +30280,7 @@ function doParseSync(iter, options = {}) { } // composes: a b c from 'file.css'; else if (token.r.typ == exports.EnumToken.String) { - throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOC].sta).join(":")}`); + throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOCSTA]).join(":")}`); } // composes: a b c from global; else if (token.r.typ == exports.EnumToken.IdenTokenType) { @@ -29809,7 +30514,7 @@ function doParseSync(iter, options = {}) { } if (moduleSettings.scoped & exports.ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOC]?.sta).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOCSTA]).join(":")}'`); } } node.sel = ""; @@ -29942,56 +30647,84 @@ async function doParse(iter, options = {}) { const imports = []; let item; let node; - // @ts-ignore ignore error - let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - if (Array.isArray(iter)) { - // @ts-expect-error - iter = iter[Symbol.iterator](); - } - while ((item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value)) { - stats.bytesIn = item.bytesIn; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + ast[LOCEND] = 0; + // if (Array.isArray(iter)) { + // // @ts-expect-error + // iter = iter[Symbol.iterator]() as Iterator; + // } + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === exports.EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + if (item.typ === exports.EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === exports.EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === exports.EnumToken.SemiColonTokenType || - item.token.typ === exports.EnumToken.BlockStartTokenType || - item.token.typ === exports.EnumToken.EOFTokenType)) { + (item.typ === exports.EnumToken.SemiColonTokenType || + item.typ === exports.EnumToken.BlockStartTokenType || + item.typ === exports.EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -30002,41 +30735,67 @@ async function doParse(iter, options = {}) { imports.push(node); } } - else if (item.token.typ == exports.EnumToken.BlockStartTokenType) { + else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === exports.EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === exports.EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -30045,7 +30804,7 @@ async function doParse(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -30084,8 +30843,11 @@ async function doParse(iter, options = {}) { source, position: 0, currentPosition: 0, + time: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { minify: false, setParent: false, src: options.resolve(url, options.src || options.cwd).relative, @@ -30097,7 +30859,9 @@ async function doParse(iter, options = {}) { // @ts-ignore node[PARENT].chi.splice(node[PARENT].chi.indexOf(node), 1, ...root.ast.chi); if (root.errors.length > 0) { - errors.push(...root.errors); + for (const error of root.errors) { + errors.push(error); + } } } catch (error) { @@ -30134,17 +30898,24 @@ async function doParse(iter, options = {}) { case exports.EnumToken.AtRuleNodeType: case exports.EnumToken.KeyframesRuleNodeType: case exports.EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case exports.EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (k = 0; k < nodes[i].chi.length; k++) { + // @ts-ignore + subNodes.push(nodes[i].chi[k]); + } } if (subNodes.length > 0) { if (freeblock <= i) { @@ -30309,7 +31080,7 @@ async function doParse(iter, options = {}) { ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -30338,7 +31109,7 @@ async function doParse(iter, options = {}) { : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & exports.ModuleCaseTransformEnum.CamelCase) { @@ -30399,13 +31170,15 @@ async function doParse(iter, options = {}) { position: 0, currentPosition: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { source, minify: false, setParent: false, src: src.relative, })); - options.parseInfo.time += parseInfo.time; + // options.parseInfo!.time += parseInfo.time; cssVariablesMap[node.nam] = root.cssModuleVariables; parent.chi.splice(parent.chi.indexOf(node), 1); continue; @@ -30540,13 +31313,13 @@ async function doParse(iter, options = {}) { ? await result : result; const root = await doParse(stream instanceof ReadableStream - ? tokenizeStream(stream, { + ? new Tokenizer({ offset: 0, source: new SourceFile("", [], src.relative), position: 0, currentPosition: 0, - }) - : tokenize({ + }, stream).tokenizeStream() + : new Tokenizer({ stream, offset: 0, position: 0, @@ -30845,7 +31618,7 @@ async function doParse(iter, options = {}) { } if (moduleSettings.scoped & exports.ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOC]?.sta) ?? []).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOCSTA]) ?? []).join(":")}'`); } } node.sel = ""; @@ -30882,31 +31655,6 @@ async function doParse(iter, options = {}) { } node.val = renderTokens(node[TOKENS]); } - // else { - // let isReplaced: boolean = false; - // for (const { value, parent } of walkValues(node[TOKENS], node)) { - // if ( - // EnumToken.MediaQueryConditionTokenType == parent.typ && - // // @ts-expect-error - // value != (parent as MediaQueryConditionToken).l - // ) { - // if ( - // (value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && - // (value as IdentToken).val in importedCssVariables - // ) { - // isReplaced = true; - // (parent as MediaQueryConditionToken).r.splice( - // (parent as MediaQueryConditionToken).r.indexOf(value), - // 1, - // ...importedCssVariables[(value as IdentToken).val].val, - // ); - // } - // } - // } - // if (isReplaced) { - // node.val = renderTokens(node[TOKENS]!); - // } - // } } } if (moduleSettings.naming != exports.ModuleCaseTransformEnum.IgnoreCase) { @@ -30938,7 +31686,6 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { tokens.pop(); // check parenthesis are balanced let matchCount = 0; - let position = tokens.at(-1)?.[LOC]; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.typ === exports.EnumToken.StartParensTokenType || tokensfuncDefMap.has(token.typ)) { @@ -30959,7 +31706,9 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { while (matchCount > 0) { tokens.push({ typ: exports.EnumToken.EndParensTokenType, - [LOC]: { ...position }, + [LOCSRCID]: tokens[k]?.[LOCSRCID], + [LOCSTA]: tokens[k]?.[LOCSTA], + [LOCEND]: tokens[k]?.[LOCEND], }); matchCount--; } @@ -30971,7 +31720,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = exports.EnumToken.InvalidCommentTokenType; continue; @@ -30994,7 +31743,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = exports.EnumToken.InvalidCommentTokenType; continue; @@ -31075,7 +31824,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { message: " not allowed in ", action: "drop", node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); } else if (options.lenient || node.typ === exports.EnumToken.DeclarationNodeType) { @@ -31114,7 +31863,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "unknown at-rule", }); const result = matchGenericSyntax(stream, options); @@ -31135,7 +31884,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -31153,8 +31902,8 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${exports.EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); atRule[TOKENS] = parseTokens(stream); atRule[STATE] = exports.EnumAstNodeStatus.Invalid; @@ -31174,7 +31923,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -31197,7 +31946,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[0] ?? atRule, - location: options.source.getSourceLocation((stream[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[0] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -31206,7 +31955,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -31215,7 +31964,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting double-quoted string", }); } @@ -31223,7 +31972,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[TOKENS] = stream; atRule[STATE] = exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? exports.EnumToken.AtRuleNodeType : exports.EnumToken.InvalidRuleNodeType, @@ -31236,7 +31985,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[TOKENS] = stream; atRule[STATE] = exports.EnumAstNodeStatus.Validated; atRule[ERRORS] = []; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? exports.EnumToken.AtRuleNodeType : exports.EnumToken.InvalidRuleNodeType, @@ -31246,12 +31995,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "font-feature-values": { const result = parseAtRuleFontFeatureValues(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } atRule[TOKENS] = stream; atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: exports.EnumToken.AtRuleNodeType, @@ -31270,7 +32021,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: `unexpected at-rule ${atRule.nam}`, }); } @@ -31281,13 +32032,13 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${exports.EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); } } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; @@ -31301,9 +32052,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "container": { const result = parseAtRuleContainerQueryList(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31318,11 +32071,13 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { const tokens = trimArray(stream.slice(1)); const result = matchAllSyntaxes(syntax, createValidationContext(tokens), options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.ValidationFailed; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31342,14 +32097,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), - message: `expected at ${atRule[LOC].srcId}:${atRule[LOC].sta}:${atRule[LOC].sta}`, + location: options.source.getSourceLocation(atRule[LOCSTA]), + message: `expected `, }); success = false; } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31363,7 +32118,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "namespace": { const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // else { // parseUrlToken(stream); @@ -31392,7 +32149,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { stream.splice(start - 1, end - start + 2, ...stream.slice(start, end)); } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = valid ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = valid ? [] : result.errors; @@ -31412,7 +32169,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "import": { const result = matchAtRuleImportSyntax(atRule, stream, context, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } else { if (stream[0]?.typ == exports.EnumToken.UrlFunctionTokenType && @@ -31420,8 +32179,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { stream.splice(0, 1, ...stream[0].chi); } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31445,7 +32203,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { ? parseAtRuleSupportSyntax(stream, atRule, options) : matchAtRuleWhenElseSyntax(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } let success = result.success; if (atRule.nam === "else") { @@ -31482,7 +32242,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @when is required before @else block", }); } @@ -31491,14 +32251,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @else block is defined after last @else block", }); } } // @ts-expect-error options = { ...options, minify: false, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : [errors[errors.length - 1]].concat(result.errors); @@ -31513,9 +32273,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { options = { ...options, parseColor: false }; const result = parseMediaqueryList(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -31535,7 +32297,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range[0] ?? atRule, - location: options.source.getSourceLocation((range[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range[0] ?? atRule)[LOCSTA]), message: "expected '(' at start of @scope block", }); success = false; @@ -31544,7 +32306,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -31570,7 +32332,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -31583,7 +32345,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -31596,7 +32358,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -31615,8 +32377,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31629,7 +32390,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } case "page": { trimArray(stream); - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31660,7 +32421,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "node is allowed only in @page rule", }); } @@ -31673,14 +32434,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: "expected whitespace or comment", }); break; } } } - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -31702,7 +32463,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { }); stream.splice(index, 0, { typ: exports.EnumToken.ColonTokenType, - [LOC]: { ...stream[index][LOC], end: stream[index]?.[LOC]?.end }, + [LOCSRCID]: stream[index][LOCSRCID], + [LOCSTA]: stream[index][LOCSTA], + [LOCEND]: stream[index][LOCEND], }); isVarDeclaration = true; break; @@ -31724,14 +32487,15 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[STATE] = success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { typ: exports.EnumToken.AtRuleNodeType, val: renderTokens(stream, options), - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -31746,10 +32510,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { typ: exports.EnumToken.CssVariableImportTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Validated, [ERRORS]: [], @@ -31760,19 +32523,15 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { typ: exports.EnumToken.CssVariableTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: exports.EnumAstNodeStatus.Validated, [ERRORS]: [], }; } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[STATE] = exports.EnumAstNodeStatus.Validated; atRule[ERRORS] = []; // @ts-expect-error @@ -31792,13 +32551,17 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { // check or and and result = matchGenericSyntax(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } else { result = matchAtRuleSyntax(atRule, stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } if (result.success) { let i = 0; @@ -31810,7 +32573,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } if (stream[i].typ === exports.EnumToken.EndParensTokenType && stack.length > 0) { const index = stream.indexOf(stack[stack.length - 1]); - stream[index][LOC].end = stream[i][LOC].end; + stream[index][LOCEND] = stream[i][LOCEND]; Object.assign(stream[index], { typ: tokensfuncDefMap.get(stream[index].typ), chi: stream.splice(index + 1, i - index - 1), @@ -31818,15 +32581,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? exports.EnumAstNodeStatus.Validated : exports.EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.errors; @@ -31852,7 +32611,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { */ async function parseDeclarations(declaration) { const stream = `.x{${declaration}}`; - return doParse(tokenize({ + return doParse(new Tokenizer({ stream, offset: 0, position: 0, @@ -31885,18 +32644,57 @@ async function parseDeclarations(declaration) { * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const tokenizer = new Tokenizer({ stream: src, + buffer: "", + src: options?.src ?? "", offset: 0, time: 0, - source: new SourceFile(src, [], ""), + source: new SourceFile(src, [], options?.src ?? ""), position: 0, currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + }); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.val === null) { + token = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + token[LOCSRCID] = tokenizer.source.id; + token[LOCEND] = tokenizer.end; + token[LOCSTA] = tokenizer.sta; + mapped.push(token); } const result = parseTokens(mapped, options, errors); // remove EOF token @@ -31942,7 +32740,7 @@ function parseTokens(tokens, options, errors) { val: (tokens[i - 1].typ === exports.EnumToken.ColonTokenType ? ":" : "::") + tokens[i].val, }); - t[LOC].end = tokens[i][LOC].end; + t[LOCEND] = tokens[i][LOCEND]; tokens.splice(i--, 1); } } @@ -31961,7 +32759,7 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token ')'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); // return []; continue; @@ -31989,13 +32787,13 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token ']'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); continue; } index = tokens.indexOf(stack.at(-1)); const attr = stack.at(-1); - attr[LOC].end = t[LOC].end; + attr[LOCEND] = t[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: exports.EnumToken.AttrTokenType, @@ -32111,9 +32909,8 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token. Expecting ${node.typ === exports.EnumToken.AttrStartTokenType ? "']'" : ")"}'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } @@ -32135,6 +32932,10 @@ exports.ResponseType = void 0; * return an arraybuffer */ ResponseType[ResponseType["ArrayBuffer"] = 2] = "ArrayBuffer"; + /** + * return a json object + */ + ResponseType[ResponseType["JSON"] = 3] = "JSON"; })(exports.ResponseType || (exports.ResponseType = {})); /** @@ -32154,7 +32955,26 @@ function parseResult(result, options) { const token = result.ast.chi.at(-1); if (token?.typ == exports.EnumToken.CommentTokenType && token.val.startsWith("/*# sourceMappingURL=")) { - options.source.setInputSourceMap(token.val.slice(21, -2).trim()); + let data = token.val.slice(21, -2).trim(); + if (data.endsWith(".map")) { + if (options.load == null) { + data = ""; + } + else { + options + .load(options.resolve(data, dirname(options.src)).absolute, ".", exports.ResponseType.JSON) + .catch((error) => console.error({ error })) + .then((res) => { + if (res != null) { + // @ts-expect-error + options.source.setInputSourceMap(res); + } + }); + } + } + else { + options.source.setInputSourceMap(data); + } } } } @@ -32197,7 +33017,7 @@ function getNodeProperty(node, key) { case "parent": return node[PARENT]; case "location": - return node[LOC]; + return node[LOCSRCID] == null && node[LOCSTA] == null && node[LOCEND] == null ? null : { srcId: node[LOCSRCID], sta: node[LOCSTA], end: node[LOCEND] }; case "state": return node[STATE]; case "errors": @@ -32219,7 +33039,9 @@ function setNodeProperty(node, key, value) { node[PARENT] = value; break; case "location": - node[LOC] = value; + node[LOCSRCID] = value.srcId; + node[LOCSTA] = value.sta; + node[LOCEND] = value.end; break; case "state": node[STATE] = value; @@ -32258,6 +33080,9 @@ async function load(url, currentDirectory = ".", responseType = false) { if (responseType == exports.ResponseType.ArrayBuffer) { return response.arrayBuffer(); } + if (responseType == exports.ResponseType.JSON) { + return response.json(); + } return responseType == exports.ResponseType.ReadableStream ? response.body : response.text(); @@ -32266,8 +33091,8 @@ async function load(url, currentDirectory = ".", responseType = false) { try { const stats = await promises.lstat(resolved.absolute); if (stats.isFile()) { - if (responseType == exports.ResponseType.Text) { - return promises.readFile(resolved.absolute, "utf-8"); + if (responseType == exports.ResponseType.Text || responseType == exports.ResponseType.JSON) { + return promises.readFile(resolved.absolute, "utf-8").then((buffer) => responseType == exports.ResponseType.JSON ? JSON.parse(buffer) : buffer); } if (responseType == exports.ResponseType.ArrayBuffer) { return promises.readFile(resolved.absolute).then((buffer) => buffer.buffer); @@ -32278,9 +33103,7 @@ async function load(url, currentDirectory = ".", responseType = false) { })); } } - catch (error) { - console.warn(error); - } + catch (error) { } throw new Error(`File not found: '${resolved.absolute || url}'`); } /** @@ -32396,8 +33219,10 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -32554,7 +33379,11 @@ async function parse(...args) { position: 0, currentPosition: 0, }; - return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS file diff --git a/dist/index.d.ts b/dist/index.d.ts index e918a136..c505142f 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -966,6 +966,15 @@ declare enum ModuleScopeEnumOptions { Shortest = 512 } +/** + * Location source id + */ +declare const LOCSRCID: unique symbol; +declare const LOCSTA: unique symbol; +declare const LOCEND: unique symbol; +/** + * Used by the validation parser + */ declare const LOC: unique symbol; declare const RAW: unique symbol; declare const STATE: unique symbol; @@ -978,7 +987,7 @@ declare const OPTIMIZED: unique symbol; /** * Literal token */ -export declare interface LiteralToken extends BaseToken { +declare interface LiteralToken extends BaseToken { /** * @inheritdoc */ @@ -992,7 +1001,7 @@ export declare interface LiteralToken extends BaseToken { /** * Class selector token */ -export declare interface ClassSelectorToken extends BaseToken { +declare interface ClassSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1006,7 +1015,7 @@ export declare interface ClassSelectorToken extends BaseToken { /** * Invalid class selector token */ -export declare interface InvalidClassSelectorToken extends BaseToken { +declare interface InvalidClassSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1020,7 +1029,7 @@ export declare interface InvalidClassSelectorToken extends BaseToken { /** * Universal selector token */ -export declare interface UniversalSelectorToken extends BaseToken { +declare interface UniversalSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1030,7 +1039,7 @@ export declare interface UniversalSelectorToken extends BaseToken { /** * Ident token */ -export declare interface IdentToken extends BaseToken { +declare interface IdentToken extends BaseToken { /** * @inheritdoc */ @@ -1044,7 +1053,7 @@ export declare interface IdentToken extends BaseToken { /** * Ident list token */ -export declare interface IdentListToken extends BaseToken { +declare interface IdentListToken extends BaseToken { /** * @inheritdoc */ @@ -1058,7 +1067,7 @@ export declare interface IdentListToken extends BaseToken { /** * Dashed ident token */ -export declare interface DashedIdentToken extends BaseToken { +declare interface DashedIdentToken extends BaseToken { /** * @inheritdoc */ @@ -1072,7 +1081,7 @@ export declare interface DashedIdentToken extends BaseToken { /** * Comma token */ -export declare interface CommaToken extends BaseToken { +declare interface CommaToken extends BaseToken { /** * @inheritdoc */ @@ -1082,7 +1091,7 @@ export declare interface CommaToken extends BaseToken { /** * Colon token */ -export declare interface ColonToken extends BaseToken { +declare interface ColonToken extends BaseToken { /** * @inheritdoc */ @@ -1092,7 +1101,7 @@ export declare interface ColonToken extends BaseToken { /** * Double colon token */ -export declare interface DoubleColonToken extends BaseToken { +declare interface DoubleColonToken extends BaseToken { /** * @inheritdoc */ @@ -1102,7 +1111,7 @@ export declare interface DoubleColonToken extends BaseToken { /** * Semicolon token */ -export declare interface SemiColonToken extends BaseToken { +declare interface SemiColonToken extends BaseToken { /** * @inheritdoc */ @@ -1112,7 +1121,7 @@ export declare interface SemiColonToken extends BaseToken { /** * Nesting selector token */ -export declare interface NestingSelectorToken extends BaseToken { +declare interface NestingSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1122,7 +1131,7 @@ export declare interface NestingSelectorToken extends BaseToken { /** * Number token */ -export declare interface NumberToken extends BaseToken { +declare interface NumberToken extends BaseToken { /** * @inheritdoc */ @@ -1140,7 +1149,7 @@ export declare interface NumberToken extends BaseToken { /** * At rule token */ -export declare interface AtRuleToken extends BaseToken { +declare interface AtRuleToken extends BaseToken { /** * @inheritdoc */ @@ -1158,7 +1167,7 @@ export declare interface AtRuleToken extends BaseToken { /** * Percentage token */ -export declare interface PercentageToken extends BaseToken { +declare interface PercentageToken extends BaseToken { /** * @inheritdoc */ @@ -1172,7 +1181,7 @@ export declare interface PercentageToken extends BaseToken { /** * Flex token */ -export declare interface FlexToken extends BaseToken { +declare interface FlexToken extends BaseToken { /** * @inheritdoc */ @@ -1186,7 +1195,7 @@ export declare interface FlexToken extends BaseToken { /** * Function token */ -export declare interface FunctionToken extends BaseToken { +declare interface FunctionToken extends BaseToken { /** * function type */ @@ -1216,7 +1225,7 @@ export declare interface FunctionToken extends BaseToken { /** * Grid template function token */ -export declare interface GridTemplateFuncToken extends BaseToken { +declare interface GridTemplateFuncToken extends BaseToken { /** * @inheritdoc */ @@ -1234,7 +1243,7 @@ export declare interface GridTemplateFuncToken extends BaseToken { /** * Function URL token */ -export declare interface FunctionURLToken extends BaseToken { +declare interface FunctionURLToken extends BaseToken { /** * @inheritdoc */ @@ -1252,7 +1261,7 @@ export declare interface FunctionURLToken extends BaseToken { /** * Function image token */ -export declare interface FunctionImageToken extends BaseToken { +declare interface FunctionImageToken extends BaseToken { /** * @inheritdoc */ @@ -1279,7 +1288,7 @@ export declare interface FunctionImageToken extends BaseToken { /** * Timing function token */ -export declare interface TimingFunctionToken extends BaseToken { +declare interface TimingFunctionToken extends BaseToken { /** * @inheritdoc */ @@ -1297,7 +1306,7 @@ export declare interface TimingFunctionToken extends BaseToken { /** * Timeline function token */ -export declare interface TimelineFunctionToken extends BaseToken { +declare interface TimelineFunctionToken extends BaseToken { /** * @inheritdoc */ @@ -1315,7 +1324,7 @@ export declare interface TimelineFunctionToken extends BaseToken { /** * String token */ -export declare interface StringToken extends BaseToken { +declare interface StringToken extends BaseToken { /** * @inheritdoc */ @@ -1329,7 +1338,7 @@ export declare interface StringToken extends BaseToken { /** * Bad string token */ -export declare interface BadStringToken extends BaseToken { +declare interface BadStringToken extends BaseToken { /** * @inheritdoc */ @@ -1343,7 +1352,7 @@ export declare interface BadStringToken extends BaseToken { /** * Unclosed string token */ -export declare interface UnclosedStringToken extends BaseToken { +declare interface UnclosedStringToken extends BaseToken { /** * @inheritdoc */ @@ -1357,7 +1366,7 @@ export declare interface UnclosedStringToken extends BaseToken { /** * Dimension token */ -export declare interface DimensionToken extends BaseToken { +declare interface DimensionToken extends BaseToken { /** * @inheritdoc */ @@ -1375,7 +1384,7 @@ export declare interface DimensionToken extends BaseToken { /** * Length token */ -export declare interface LengthToken extends BaseToken { +declare interface LengthToken extends BaseToken { /** * @inheritdoc */ @@ -1393,7 +1402,7 @@ export declare interface LengthToken extends BaseToken { /** * Angle token */ -export declare interface AngleToken extends BaseToken { +declare interface AngleToken extends BaseToken { /** * @inheritdoc */ @@ -1411,7 +1420,7 @@ export declare interface AngleToken extends BaseToken { /** * Time token */ -export declare interface TimeToken extends BaseToken { +declare interface TimeToken extends BaseToken { /** * @inheritdoc */ @@ -1429,7 +1438,7 @@ export declare interface TimeToken extends BaseToken { /** * Frequency token */ -export declare interface FrequencyToken extends BaseToken { +declare interface FrequencyToken extends BaseToken { /** * @inheritdoc */ @@ -1447,7 +1456,7 @@ export declare interface FrequencyToken extends BaseToken { /** * Resolution token */ -export declare interface ResolutionToken extends BaseToken { +declare interface ResolutionToken extends BaseToken { /** * @inheritdoc */ @@ -1465,7 +1474,7 @@ export declare interface ResolutionToken extends BaseToken { /** * Hash token */ -export declare interface HashToken extends BaseToken { +declare interface HashToken extends BaseToken { /** * @inheritdoc */ @@ -1479,7 +1488,7 @@ export declare interface HashToken extends BaseToken { /** * Block start token */ -export declare interface BlockStartToken extends BaseToken { +declare interface BlockStartToken extends BaseToken { /** * @inheritdoc */ @@ -1489,7 +1498,7 @@ export declare interface BlockStartToken extends BaseToken { /** * Block end token */ -export declare interface BlockEndToken extends BaseToken { +declare interface BlockEndToken extends BaseToken { /** * @inheritdoc */ @@ -1499,7 +1508,7 @@ export declare interface BlockEndToken extends BaseToken { /** * Attribute start token */ -export declare interface AttrStartToken extends BaseToken { +declare interface AttrStartToken extends BaseToken { /** * @inheritdoc */ @@ -1513,7 +1522,7 @@ export declare interface AttrStartToken extends BaseToken { /** * Attribute end token */ -export declare interface AttrEndToken extends BaseToken { +declare interface AttrEndToken extends BaseToken { /** * @inheritdoc */ @@ -1523,7 +1532,7 @@ export declare interface AttrEndToken extends BaseToken { /** * Parenthesis start token */ -export declare interface ParensStartToken extends BaseToken { +declare interface ParensStartToken extends BaseToken { /** * @inheritdoc */ @@ -1533,7 +1542,7 @@ export declare interface ParensStartToken extends BaseToken { /** * Parenthesis end token */ -export declare interface ParensEndToken extends BaseToken { +declare interface ParensEndToken extends BaseToken { /** * @inheritdoc */ @@ -1543,7 +1552,7 @@ export declare interface ParensEndToken extends BaseToken { /** * Parenthesis token */ -export declare interface ParensToken extends BaseToken { +declare interface ParensToken extends BaseToken { /** * @inheritdoc */ @@ -1557,7 +1566,7 @@ export declare interface ParensToken extends BaseToken { /** * Whitespace token */ -export declare interface WhitespaceToken extends BaseToken { +declare interface WhitespaceToken extends BaseToken { /** * @inheritdoc */ @@ -1571,7 +1580,7 @@ export declare interface WhitespaceToken extends BaseToken { /** * Comment token */ -export declare interface CommentToken extends BaseToken { +declare interface CommentToken extends BaseToken { /** * @inheritdoc */ @@ -1585,7 +1594,7 @@ export declare interface CommentToken extends BaseToken { /** * Bad comment token */ -export declare interface BadCommentToken extends BaseToken { +declare interface BadCommentToken extends BaseToken { /** * @inheritdoc */ @@ -1599,7 +1608,7 @@ export declare interface BadCommentToken extends BaseToken { /** * CDO comment token */ -export declare interface CDOCommentToken extends BaseToken { +declare interface CDOCommentToken extends BaseToken { /** * @inheritdoc */ @@ -1613,7 +1622,7 @@ export declare interface CDOCommentToken extends BaseToken { /** * Bad CDO comment token */ -export declare interface BadCDOCommentToken extends BaseToken { +declare interface BadCDOCommentToken extends BaseToken { /** * @inheritdoc */ @@ -1627,7 +1636,7 @@ export declare interface BadCDOCommentToken extends BaseToken { /** * Include match token */ -export declare interface IncludeMatchToken extends BaseToken { +declare interface IncludeMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1638,7 +1647,7 @@ export declare interface IncludeMatchToken extends BaseToken { /** * Dash match token */ -export declare interface DashMatchToken extends BaseToken { +declare interface DashMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1649,7 +1658,7 @@ export declare interface DashMatchToken extends BaseToken { /** * Equal match token */ -export declare interface EqualMatchToken extends BaseToken { +declare interface EqualMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1660,7 +1669,7 @@ export declare interface EqualMatchToken extends BaseToken { /** * Start match token */ -export declare interface StartMatchToken extends BaseToken { +declare interface StartMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1671,7 +1680,7 @@ export declare interface StartMatchToken extends BaseToken { /** * End match token */ -export declare interface EndMatchToken extends BaseToken { +declare interface EndMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1682,7 +1691,7 @@ export declare interface EndMatchToken extends BaseToken { /** * Contain match token */ -export declare interface ContainMatchToken extends BaseToken { +declare interface ContainMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1693,7 +1702,7 @@ export declare interface ContainMatchToken extends BaseToken { /** * Less than token */ -export declare interface LessThanToken extends BaseToken { +declare interface LessThanToken extends BaseToken { /** * @inheritdoc */ @@ -1703,7 +1712,7 @@ export declare interface LessThanToken extends BaseToken { /** * Less than or equal token */ -export declare interface LessThanOrEqualToken extends BaseToken { +declare interface LessThanOrEqualToken extends BaseToken { /** * @inheritdoc */ @@ -1713,7 +1722,7 @@ export declare interface LessThanOrEqualToken extends BaseToken { /** * Greater than token */ -export declare interface GreaterThanToken extends BaseToken { +declare interface GreaterThanToken extends BaseToken { /** * @inheritdoc */ @@ -1723,7 +1732,7 @@ export declare interface GreaterThanToken extends BaseToken { /** * Greater than or equal token */ -export declare interface GreaterThanOrEqualToken extends BaseToken { +declare interface GreaterThanOrEqualToken extends BaseToken { /** * @inheritdoc */ @@ -1733,7 +1742,7 @@ export declare interface GreaterThanOrEqualToken extends BaseToken { /** * Column combinator token */ -export declare interface ColumnCombinatorToken extends BaseToken { +declare interface ColumnCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -1743,7 +1752,7 @@ export declare interface ColumnCombinatorToken extends BaseToken { /** * Pseudo class token */ -export declare interface PseudoClassToken extends BaseToken { +declare interface PseudoClassToken extends BaseToken { /** * @inheritdoc */ @@ -1757,7 +1766,7 @@ export declare interface PseudoClassToken extends BaseToken { /** * Pseudo element token */ -export declare interface PseudoElementToken extends BaseToken { +declare interface PseudoElementToken extends BaseToken { /** * @inheritdoc */ @@ -1771,7 +1780,7 @@ export declare interface PseudoElementToken extends BaseToken { /** * Pseudo page token */ -export declare interface PseudoPageToken extends BaseToken { +declare interface PseudoPageToken extends BaseToken { /** * @inheritdoc */ @@ -1785,7 +1794,7 @@ export declare interface PseudoPageToken extends BaseToken { /** * Pseudo class function token */ -export declare interface PseudoClassFunctionToken extends BaseToken { +declare interface PseudoClassFunctionToken extends BaseToken { /** * @inheritdoc */ @@ -1803,7 +1812,7 @@ export declare interface PseudoClassFunctionToken extends BaseToken { /** * Delim token */ -export declare interface DelimToken extends BaseToken { +declare interface DelimToken extends BaseToken { /** * @inheritdoc */ @@ -1813,7 +1822,7 @@ export declare interface DelimToken extends BaseToken { /** * Bad URL token */ -export declare interface BadUrlToken extends BaseToken { +declare interface BadUrlToken extends BaseToken { /** * @inheritdoc */ @@ -1827,7 +1836,7 @@ export declare interface BadUrlToken extends BaseToken { /** * URL token */ -export declare interface UrlToken extends BaseToken { +declare interface UrlToken extends BaseToken { /** * @inheritdoc */ @@ -1841,7 +1850,7 @@ export declare interface UrlToken extends BaseToken { /** * EOF token */ -export declare interface EOFToken extends BaseToken { +declare interface EOFToken extends BaseToken { /** * @inheritdoc */ @@ -1851,7 +1860,7 @@ export declare interface EOFToken extends BaseToken { /** * Important token */ -export declare interface ImportantToken extends BaseToken { +declare interface ImportantToken extends BaseToken { /** * @inheritdoc */ @@ -1861,7 +1870,7 @@ export declare interface ImportantToken extends BaseToken { /** * Color token */ -export declare interface ColorToken extends BaseToken { +declare interface ColorToken extends BaseToken { /** * @inheritdoc */ @@ -1887,7 +1896,7 @@ export declare interface ColorToken extends BaseToken { /** * Attribute token */ -export declare interface AttrToken extends BaseToken { +declare interface AttrToken extends BaseToken { /** * @inheritdoc */ @@ -1901,7 +1910,7 @@ export declare interface AttrToken extends BaseToken { /** * Invalid attribute token */ -export declare interface InvalidAttrToken extends BaseToken { +declare interface InvalidAttrToken extends BaseToken { /** * @inheritdoc */ @@ -1915,7 +1924,7 @@ export declare interface InvalidAttrToken extends BaseToken { /** * Child combinator token */ -export declare interface ChildCombinatorToken extends BaseToken { +declare interface ChildCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -1925,7 +1934,7 @@ export declare interface ChildCombinatorToken extends BaseToken { /** * Media feature token */ -export declare interface MediaFeatureToken extends BaseToken { +declare interface MediaFeatureToken extends BaseToken { /** * @inheritdoc */ @@ -1939,7 +1948,7 @@ export declare interface MediaFeatureToken extends BaseToken { /** * Media feature not token */ -export declare interface NotToken extends BaseToken { +declare interface NotToken extends BaseToken { /** * @inheritdoc */ @@ -1953,7 +1962,7 @@ export declare interface NotToken extends BaseToken { /** * Media feature only token */ -export declare interface MediaFeatureOnlyToken extends BaseToken { +declare interface MediaFeatureOnlyToken extends BaseToken { /** * @inheritdoc */ @@ -1967,7 +1976,7 @@ export declare interface MediaFeatureOnlyToken extends BaseToken { /** * Media feature and token */ -export declare interface AndToken extends BaseToken { +declare interface AndToken extends BaseToken { /** * @inheritdoc */ @@ -1977,7 +1986,7 @@ export declare interface AndToken extends BaseToken { /** * Media feature or token */ -export declare interface OrToken extends BaseToken { +declare interface OrToken extends BaseToken { /** * @inheritdoc */ @@ -1987,7 +1996,7 @@ export declare interface OrToken extends BaseToken { /** * Media query condition token */ -export declare interface MediaQueryUnaryFeatureToken extends BaseToken { +declare interface MediaQueryUnaryFeatureToken extends BaseToken { /** * @inheritdoc */ @@ -2002,7 +2011,7 @@ export declare interface MediaQueryUnaryFeatureToken extends BaseToken { r: Token$1[]; } -export declare interface SupportsQueryUnaryConditionToken extends BaseToken { +declare interface SupportsQueryUnaryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2017,7 +2026,7 @@ export declare interface SupportsQueryUnaryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface SupportsQueryConditionToken extends BaseToken { +declare interface SupportsQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2036,7 +2045,7 @@ export declare interface SupportsQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface WhenElseQueryConditionToken extends BaseToken { +declare interface WhenElseQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2055,7 +2064,7 @@ export declare interface WhenElseQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface WhenElseUnaryConditionToken extends BaseToken { +declare interface WhenElseUnaryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2070,7 +2079,7 @@ export declare interface WhenElseUnaryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface MediaQueryConditionToken extends BaseToken { +declare interface MediaQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2097,7 +2106,7 @@ export declare interface MediaQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface IfConditionToken extends BaseToken { +declare interface IfConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2112,7 +2121,7 @@ export declare interface IfConditionToken extends BaseToken { r: Token$1[]; } -export declare interface IfElseConditionToken extends BaseToken { +declare interface IfElseConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2127,7 +2136,7 @@ export declare interface IfElseConditionToken extends BaseToken { r: IfConditionToken; } -export declare interface ContainerStyleRangeToken extends BaseToken { +declare interface ContainerStyleRangeToken extends BaseToken { /** * @inheritdoc */ @@ -2150,7 +2159,7 @@ export declare interface ContainerStyleRangeToken extends BaseToken { /** * @inheritdoc */ -export declare interface MediaRangeQueryToken extends BaseToken { +declare interface MediaRangeQueryToken extends BaseToken { /** * @inheritdoc */ @@ -2180,7 +2189,7 @@ export declare interface MediaRangeQueryToken extends BaseToken { /** * @inheritdoc */ -export declare interface InvalidMediaQueryToken extends BaseToken { +declare interface InvalidMediaQueryToken extends BaseToken { /** * @inheritdoc */ @@ -2195,7 +2204,7 @@ export declare interface InvalidMediaQueryToken extends BaseToken { /** * Descendant combinator token */ -export declare interface DescendantCombinatorToken extends BaseToken { +declare interface DescendantCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -2205,7 +2214,7 @@ export declare interface DescendantCombinatorToken extends BaseToken { /** * Next sibling combinator token */ -export declare interface NextSiblingCombinatorToken extends BaseToken { +declare interface NextSiblingCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -2215,7 +2224,7 @@ export declare interface NextSiblingCombinatorToken extends BaseToken { /** * Subsequent sibling combinator token */ -export declare interface SubsequentCombinatorToken extends BaseToken { +declare interface SubsequentCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -2225,7 +2234,7 @@ export declare interface SubsequentCombinatorToken extends BaseToken { /** * Add token */ -export declare interface AddToken extends BaseToken { +declare interface AddToken extends BaseToken { /** * @inheritdoc */ @@ -2235,7 +2244,7 @@ export declare interface AddToken extends BaseToken { /** * Sub token */ -export declare interface SubToken extends BaseToken { +declare interface SubToken extends BaseToken { /** * @inheritdoc */ @@ -2245,7 +2254,7 @@ export declare interface SubToken extends BaseToken { /** * Div token */ -export declare interface DivToken extends BaseToken { +declare interface DivToken extends BaseToken { /** * @inheritdoc */ @@ -2255,7 +2264,7 @@ export declare interface DivToken extends BaseToken { /** * Mul token */ -export declare interface MulToken extends BaseToken { +declare interface MulToken extends BaseToken { /** * @inheritdoc */ @@ -2265,7 +2274,7 @@ export declare interface MulToken extends BaseToken { /** * Wrapped values token like {Arial, Helvetica, sans-serif} */ -export declare interface WrappedValuesToken extends BaseToken { +declare interface WrappedValuesToken extends BaseToken { /** * @inheritdoc */ @@ -2279,7 +2288,7 @@ export declare interface WrappedValuesToken extends BaseToken { /** * Unary expression token */ -export declare interface UnaryExpression extends BaseToken { +declare interface UnaryExpression extends BaseToken { /** * @inheritdoc */ @@ -2297,7 +2306,7 @@ export declare interface UnaryExpression extends BaseToken { /** * Fraction token */ -export declare interface FractionToken extends BaseToken { +declare interface FractionToken extends BaseToken { /** * @inheritdoc */ @@ -2315,7 +2324,7 @@ export declare interface FractionToken extends BaseToken { /** * Binary expression token */ -export declare interface BinaryExpressionToken extends BaseToken { +declare interface BinaryExpressionToken extends BaseToken { /** * @inheritdoc */ @@ -2337,7 +2346,7 @@ export declare interface BinaryExpressionToken extends BaseToken { /** * Match expression token */ -export declare interface MatchExpressionToken extends BaseToken { +declare interface MatchExpressionToken extends BaseToken { /** * @inheritdoc */ @@ -2363,7 +2372,7 @@ export declare interface MatchExpressionToken extends BaseToken { /** * Name space attribute token */ -export declare interface NameSpaceAttributeToken extends BaseToken { +declare interface NameSpaceAttributeToken extends BaseToken { /** * @inheritdoc */ @@ -2381,7 +2390,7 @@ export declare interface NameSpaceAttributeToken extends BaseToken { /** * List token */ -export declare interface ListToken extends BaseToken { +declare interface ListToken extends BaseToken { /** * @inheritdoc */ @@ -2395,7 +2404,7 @@ export declare interface ListToken extends BaseToken { /** * Composes selector token */ -export declare interface ComposesSelectorToken extends BaseToken { +declare interface ComposesSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -2413,7 +2422,7 @@ export declare interface ComposesSelectorToken extends BaseToken { /** * Css variable token */ -export declare interface CssVariableToken extends BaseToken { +declare interface CssVariableToken extends BaseToken { /** * @inheritdoc */ @@ -2431,7 +2440,7 @@ export declare interface CssVariableToken extends BaseToken { /** * Css variable import token */ -export declare interface CssVariableImportTokenType extends BaseToken { +declare interface CssVariableImportTokenType extends BaseToken { /** * @inheritdoc */ @@ -2449,7 +2458,7 @@ export declare interface CssVariableImportTokenType extends BaseToken { /** * Css variable map token */ -export declare interface CssVariableMapTokenType extends BaseToken { +declare interface CssVariableMapTokenType extends BaseToken { /** * @inheritdoc */ @@ -2467,7 +2476,7 @@ export declare interface CssVariableMapTokenType extends BaseToken { /** * Function definition token */ -export declare interface FunctionDefToken extends BaseToken { +declare interface FunctionDefToken extends BaseToken { /** * @inheritdoc */ @@ -2495,7 +2504,7 @@ export declare interface FunctionDefToken extends BaseToken { /** * Raw node token */ -export declare interface RawNodeToken extends BaseToken, EnumAstNodeStatus$1 { +declare interface RawNodeToken extends BaseToken, EnumAstNodeStatus$1 { /** * @inheritdoc */ @@ -2509,7 +2518,7 @@ export declare interface RawNodeToken extends BaseToken, EnumAstNodeStatus$1 { /** * Unary expression node */ -export declare type UnaryExpressionNode = +declare type UnaryExpressionNode = | BinaryExpressionNode | NumberToken | DimensionToken @@ -2521,7 +2530,7 @@ export declare type UnaryExpressionNode = /** * Binary expression node */ -export declare type BinaryExpressionNode = +declare type BinaryExpressionNode = | NumberToken | DimensionToken | PercentageToken @@ -2537,7 +2546,7 @@ export declare type BinaryExpressionNode = /** * Token */ -export declare type Token$1 = +declare type Token$1 = | InvalidClassSelectorToken | InvalidAttrToken | LiteralToken @@ -2645,7 +2654,7 @@ export declare type Token$1 = /** * token or node location */ -export declare interface SourceLocation { +declare interface SourceLocation { /** * start position */ @@ -2663,16 +2672,27 @@ export declare interface SourceLocation { /** * Common token interface */ -export declare interface BaseToken { +declare interface BaseToken { /** * token type */ typ: EnumToken; + /** - * location info - * @private + * source src */ - [LOC]?: SourceLocation | null; + [LOCSRCID]?: number; + + /** + * source start offset + */ + [LOCSTA]?: number; + + /** + * source end offset + */ + [LOCEND]?: number; + /** * parent node * @private @@ -2725,7 +2745,7 @@ export declare interface BaseToken { /** * Ast node state */ -export declare interface AstNodeStatus { +declare interface AstNodeStatus { /** * Node state */ @@ -2739,7 +2759,7 @@ export declare interface AstNodeStatus { /** * comment node */ -export declare interface AstComment extends BaseToken { +declare interface AstComment extends BaseToken { /** * token type */ @@ -2753,7 +2773,7 @@ export declare interface AstComment extends BaseToken { /** * declaration node */ -export declare interface AstDeclaration extends BaseToken, AstNodeStatus { +declare interface AstDeclaration extends BaseToken, AstNodeStatus { /** * token name */ @@ -2771,7 +2791,7 @@ export declare interface AstDeclaration extends BaseToken, AstNodeStatus { /** * rule node */ -export declare interface AstRule extends BaseToken, AstNodeStatus { +declare interface AstRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2800,7 +2820,7 @@ export declare interface AstRule extends BaseToken, AstNodeStatus { * Invalid rule node * @deprecated */ -export declare interface AstInvalidRule extends BaseToken, AstNodeStatus { +declare interface AstInvalidRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2819,7 +2839,7 @@ export declare interface AstInvalidRule extends BaseToken, AstNodeStatus { * invalid declaration node * @deprecated */ -export declare interface AstInvalidDeclaration extends BaseToken, AstNodeStatus { +declare interface AstInvalidDeclaration extends BaseToken, AstNodeStatus { /** * token type */ @@ -2838,7 +2858,7 @@ export declare interface AstInvalidDeclaration extends BaseToken, AstNodeStatus * invalid at rule node * @deprecated */ -export declare interface AstInvalidAtRule extends BaseToken, AstNodeStatus { +declare interface AstInvalidAtRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2860,14 +2880,14 @@ export declare interface AstInvalidAtRule extends BaseToken, AstNodeStatus { /** * raw selector tokens */ -export declare type RawSelectorTokens = string[][]; +declare type RawSelectorTokens = string[][]; /** * optimized selector * * @private */ -export declare interface OptimizedSelector { +declare interface OptimizedSelector { /** * matched selector */ @@ -2891,7 +2911,7 @@ export declare interface OptimizedSelector { * * @private */ -export declare interface OptimizedSelectorToken { +declare interface OptimizedSelectorToken { /** * match */ @@ -2913,7 +2933,7 @@ export declare interface OptimizedSelectorToken { /** * at rule node */ -export declare interface AstAtRule extends BaseToken, AstNodeStatus { +declare interface AstAtRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2935,7 +2955,7 @@ export declare interface AstAtRule extends BaseToken, AstNodeStatus { /** * keyframe rule node */ -export declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { +declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2965,7 +2985,7 @@ export declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { /** * keyframe rule node */ -export declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { +declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -2991,7 +3011,7 @@ export declare interface AstKeyframesRule extends BaseToken, AstNodeStatus { /** * keyframe at rule node */ -export declare interface AstKeyframesAtRule extends BaseToken, AstNodeStatus { +declare interface AstKeyframesAtRule extends BaseToken, AstNodeStatus { /** * token type */ @@ -3013,7 +3033,7 @@ export declare interface AstKeyframesAtRule extends BaseToken, AstNodeStatus { /** * rule list node */ -export declare type AstRuleList = +declare type AstRuleList = | AstStyleSheet | AstAtRule | AstRule @@ -3024,7 +3044,7 @@ export declare type AstRuleList = /** * stylesheet node */ -export declare interface AstStyleSheet extends BaseToken { +declare interface AstStyleSheet extends BaseToken { /** * token type */ @@ -3038,7 +3058,7 @@ export declare interface AstStyleSheet extends BaseToken { /** * ast node */ -export declare type AstNode$1 = +declare type AstNode$1 = | AstStyleSheet | AstRuleList | AstComment @@ -3318,20 +3338,20 @@ declare function walkValues(values: Token$1[], root?: AstNode$1 | Token$1 | null /** * Generic visitor result */ -export declare type GenericVisitorSyncResult = T | T[] | null; +declare type GenericVisitorSyncResult = T | T[] | null; /** * Generic visitor result */ -export declare type GenericVisitorAsyncResult = Promise | Promise | Promise; +declare type GenericVisitorAsyncResult = Promise | Promise | Promise; /** * Generic visitor result */ -export declare type GenericVisitorResult = GenericVisitorSyncResult | GenericVisitorAsyncResult; +declare type GenericVisitorResult = GenericVisitorSyncResult | GenericVisitorAsyncResult; /** * Generic visitor handler */ -export declare type GenericVisitorSyncHandler = ( +declare type GenericVisitorSyncHandler = ( node: T, parent?: AstNode | Token, root?: AstNode | Token, @@ -3340,7 +3360,7 @@ export declare type GenericVisitorSyncHandler = ( /** * Generic visitor handler */ -export declare type GenericVisitorAstNodeSyncHandlerMap = +declare type GenericVisitorAstNodeSyncHandlerMap = | Record> | GenericVisitorSyncHandler | { type: WalkerEvent; handler: GenericVisitorSyncHandler } @@ -3349,13 +3369,13 @@ export declare type GenericVisitorAstNodeSyncHandlerMap = /** * Generic visitor handler */ -export declare type ValueVisitorSyncHandler = GenericVisitorSyncHandler; +declare type ValueVisitorSyncHandler = GenericVisitorSyncHandler; /** * node visitor callback map * */ -export declare interface VisitorSyncNodeMap { +declare interface VisitorSyncNodeMap { /** * at rule visitor * @@ -3614,7 +3634,7 @@ export declare interface VisitorSyncNodeMap { /** * Generic visitor handler */ -export declare type GenericVisitorHandler = ( +declare type GenericVisitorHandler = ( node: T, parent?: AstNode | Token, root?: AstNode | Token, @@ -3623,7 +3643,7 @@ export declare type GenericVisitorHandler = ( /** * Generic visitor handler */ -export declare type GenericVisitorAstNodeHandlerMap = +declare type GenericVisitorAstNodeHandlerMap = | Record> | GenericVisitorHandler | { type: WalkerEvent; handler: GenericVisitorHandler } @@ -3632,41 +3652,41 @@ export declare type GenericVisitorAstNodeHandlerMap = /** * Generic visitor handler */ -export declare type ValueVisitorHandler = GenericVisitorHandler; +declare type ValueVisitorHandler = GenericVisitorHandler; /** * Declaration visitor handler */ -export declare type DeclarationVisitorHandler = GenericVisitorHandler; +declare type DeclarationVisitorHandler = GenericVisitorHandler; /** * Declaration visitor handler */ -export declare type DeclarationVisitorHandler = GenericVisitorHandler; +declare type DeclarationVisitorHandler = GenericVisitorHandler; /** * Rule visitor handler */ -export declare type RuleVisitorHandler = GenericVisitorHandler; +declare type RuleVisitorHandler = GenericVisitorHandler; /** * Rule visitor handler */ -export declare type RuleVisitorHandler = GenericVisitorHandler; +declare type RuleVisitorHandler = GenericVisitorHandler; /** * AtRule visitor handler */ -export declare type AtRuleVisitorHandler = GenericVisitorHandler; +declare type AtRuleVisitorHandler = GenericVisitorHandler; /** * AtRule visitor handler */ -export declare type AtRuleVisitorHandler = GenericVisitorHandler; +declare type AtRuleVisitorHandler = GenericVisitorHandler; /** * node visitor callback map * */ -export declare interface VisitorNodeMap { +declare interface VisitorNodeMap { /** * at rule visitor * @@ -3981,21 +4001,12 @@ declare class SourceMap { * @returns */ addSourceContent(id: number, fileName: string | null, content: string | null): void; - /** - * Add sourcemap - * @param newLine - * @param newColumn - * @param srcId - * @param ln - * @param col - */ - add(newLine: number, newColumn: number, srcId: number, ln: number, col: number): void; /** * Add multiple sourcemaps * @param maps * @throws */ - add(...maps: Array<[newLine: number, newColumn: number, srcId: number, ln: number, col: number]>): void; + add(maps: Array<[newLine: number, newColumn: number, srcId: number, ln: number, col: number]>): void; /** * compute original positions */ @@ -4072,7 +4083,7 @@ declare class SourceFile { /** * Source file content */ - private content; + content: string; /** * Constructor * @param content @@ -4136,7 +4147,7 @@ declare class SourceFile { getInputSourceMap(): SourceMap | null; } -export declare interface PropertyListOptions { +declare interface PropertyListOptions { removeDuplicateDeclarations?: boolean | string | string[]; computeShorthand?: boolean; } @@ -4144,7 +4155,7 @@ export declare interface PropertyListOptions { /** * parse info */ -export declare interface ParseInfo$1 { +declare interface ParseInfo$1 { /** * stream */ @@ -4392,6 +4403,28 @@ interface ValidationDimensionToken extends ValidationToken$1 { unit: keyof EnumToken; } +/** + * response type + */ +declare enum ResponseType { + /** + * return text + */ + Text = 0, + /** + * return a readable stream + */ + ReadableStream = 1, + /** + * return an arraybuffer + */ + ArrayBuffer = 2, + /** + * return a json object + */ + JSON = 3 +} + interface PropertyType { shorthand: string; } @@ -4498,7 +4531,7 @@ interface ShorthandType { /** * @private */ -export declare interface PropertiesConfig { +declare interface PropertiesConfig { /** * shorthand property minification rules */ @@ -4907,8 +4940,7 @@ interface BorderRadius { /** * node walker options */ -export declare interface WalkerOptions { - +declare interface WalkerOptions { /** * walk in reverse */ @@ -4927,7 +4959,7 @@ export declare interface WalkerOptions { /** * node walker option */ -export declare type WalkerOption = WalkerOptionEnum | AstNode$1 | Token$1 | null; +declare type WalkerOption = WalkerOptionEnum | AstNode$1 | Token$1 | null; /** * returned value: * - {@link WalkerOptionEnum.Ignore}: ignore this node and its children @@ -4937,7 +4969,7 @@ export declare type WalkerOption = WalkerOptionEnum | AstNode$1 | Token$1 | null * - {@link AstNode}: * - {@link Token}: */ -export declare type WalkerFilter = (node: AstNode$1) => WalkerOption; +declare type WalkerFilter = (node: AstNode$1) => WalkerOption; /** * returned value: @@ -4948,17 +4980,17 @@ export declare type WalkerFilter = (node: AstNode$1) => WalkerOption; * - {@link AstNode}: * - {@link Token}: */ -export declare type WalkerValueFilter = ( +declare type WalkerValueFilter = ( node: AstNode$1 | Token$1, parent?: AstNode$1 | Token$1 | AstNode$1[] | Token$1[] | null, event?: WalkerEvent, parents?: Generator, -) => WalkerOption | null; +) => WalkerOption | AstNode$1 | Token$1 | AstNode$1[] | Token$1[] | null; /** * walker result */ -export declare interface WalkResult { +declare interface WalkResult { /** * current node */ @@ -4980,7 +5012,7 @@ export declare interface WalkResult { /** * walker result */ -export declare interface WalkAttributesResult { +declare interface WalkAttributesResult { /** * current node */ @@ -5010,7 +5042,7 @@ export declare interface WalkAttributesResult { /** * Error description */ -export declare interface ErrorDescription$1 { +declare interface ErrorDescription$1 { /** * Drop rule or declaration */ @@ -5188,16 +5220,16 @@ interface MinifyOptions { /** * Result of options.load() function call. */ -export declare type LoadResult = +declare type LoadResult = | Promise> | ReadableStream | string - | Promise; + | Promise | object; /** * CSS module parser options */ -export declare interface ModuleSyncOptions { +declare interface ModuleSyncOptions { /** * Use local scope vs global scope */ @@ -5307,7 +5339,7 @@ export declare interface ModuleSyncOptions { generateScopedName?: (localName: string, filePath: string, pattern: string, hashLength?: number) => string; } -export declare interface ModuleAsyncOptions extends ModuleSyncOptions { +declare interface ModuleAsyncOptions extends ModuleSyncOptions { /** * The pattern used to generate scoped names. the supported placeholders are: * - name: the file base name without the extension @@ -5402,7 +5434,7 @@ export declare interface ModuleAsyncOptions extends ModuleSyncOptions { /** * Input file options */ -export declare interface ParseInputFileOptions { +declare interface ParseInputFileOptions { /** * File path or url */ @@ -5417,7 +5449,7 @@ export declare interface ParseInputFileOptions { /** * Input options for string or stream */ -export declare interface ParseInputOptions { +declare interface ParseInputOptions { /** * Input string or stream */ @@ -5426,7 +5458,7 @@ export declare interface ParseInputOptions { /** * Input options for string or stream */ -export declare interface ParseInputStreamOptions { +declare interface ParseInputStreamOptions { /** * Input string or stream */ @@ -5437,7 +5469,7 @@ export declare interface ParseInputStreamOptions { * Input options for string or stream * @internal */ -export declare interface ParseSourceOptions { +declare interface ParseSourceOptions { /** * Source file to be used for sourcemap * @internal @@ -5453,7 +5485,7 @@ export declare interface ParseSourceOptions { /** * Parser sourcemap options */ -export declare interface ParserSourceMapOptions { +declare interface ParserSourceMapOptions { /** * Include sourcemap in the ast. Sourcemap info is always generated */ @@ -5467,7 +5499,7 @@ export declare interface ParserSourceMapOptions { /** * Sync parseroptions */ -export declare interface ParserSyncOptions +declare interface ParserSyncOptions extends MinifyOptions, ParserSourceMapOptions, @@ -5578,7 +5610,7 @@ export declare interface ParserSyncOptions /** * Parser options */ -export declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOptions { +declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOptions { /** * Resolve import */ @@ -5613,7 +5645,7 @@ export declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOpt * * @internal */ -export declare interface MinifyFeatureOptions { +declare interface MinifyFeatureOptions { /** * Minify features * @@ -5627,7 +5659,7 @@ export declare interface MinifyFeatureOptions { * * @internal */ -export declare interface MinifyFeature { +declare interface MinifyFeature { /** * Accepted tokens */ @@ -5669,7 +5701,7 @@ export declare interface MinifyFeature { * Resolved path * @internal */ -export declare interface ResolvedPath { +declare interface ResolvedPath { /** * Absolute path */ @@ -5683,7 +5715,7 @@ export declare interface ResolvedPath { /** * Ast node render options */ -export declare interface RenderOptions { +declare interface RenderOptions { /** * Source file to be used as CSS input file for sourcemap resolution */ @@ -5775,17 +5807,17 @@ export declare interface RenderOptions { /** * Transform options */ -export declare interface TransformSyncOptions extends ParserSyncOptions, RenderOptions {} +declare interface TransformSyncOptions extends ParserSyncOptions, RenderOptions {} /** * Transform options */ -export declare interface TransformOptions extends ParserOptions, RenderOptions {} +declare interface TransformOptions extends ParserOptions, RenderOptions {} /** * Parse result stats object */ -export declare interface ParseResultStats { +declare interface ParseResultStats { /** * Source file */ @@ -5839,7 +5871,7 @@ export declare interface ParseResultStats { /** * Parse result object */ -export declare interface ParseResult { +declare interface ParseResult { /** * Parsed ast tree */ @@ -5880,7 +5912,7 @@ export declare interface ParseResult { /** * Render result object */ -export declare interface RenderResult { +declare interface RenderResult { /** * Rendered CSS */ @@ -5907,7 +5939,7 @@ export declare interface RenderResult { /** * Transform result object */ -export declare interface TransformResult extends ParseResult, RenderResult { +declare interface TransformResult extends ParseResult, RenderResult { /** * Transform stats */ @@ -5954,13 +5986,13 @@ export declare interface TransformResult extends ParseResult, RenderResult { /** * Parse token options */ -export declare interface ParseTokenOptions extends ParserOptions {} +declare interface ParseTokenOptions extends ParserOptions {} /** * Tokenize result object * @internal */ -export declare interface TokenizeResult { +declare interface TokenizeResult { /** * Token */ @@ -5975,7 +6007,7 @@ export declare interface TokenizeResult { * Matched selector object * @internal */ -export declare interface MatchedSelector { +declare interface MatchedSelector { /** * Matched selector */ @@ -5998,7 +6030,7 @@ export declare interface MatchedSelector { * Variable scope info object * @internal */ -export declare interface VariableScopeInfo { +declare interface VariableScopeInfo { /** * Global scope */ @@ -6029,7 +6061,7 @@ export declare interface VariableScopeInfo { * Source map object * @internal */ -export declare interface SourceMapObject { +declare interface SourceMapObject { /** * Source map version */ @@ -6080,29 +6112,11 @@ declare const resolve: (url: string, currentDirectory?: string, cwd?: string) => relative: string; }; -/** - * response type - */ -declare enum ResponseType$1 { - /** - * return text - */ - Text = 0, - /** - * return a readable stream - */ - ReadableStream = 1, - /** - * return an arraybuffer - */ - ArrayBuffer = 2 -} - /** * Validation syntax * @internal */ -export declare interface ValidationSyntaxNode { +declare interface ValidationSyntaxNode { /** * mdn data syntax */ @@ -6132,7 +6146,7 @@ interface ValidationSelectorOptions extends ValidationOptions { * Validation media feature * @internal */ -export declare interface ValidationMediaFeature { +declare interface ValidationMediaFeature { /** * media feature type */ @@ -6155,7 +6169,7 @@ export declare interface ValidationMediaFeature { * Validation configuration * @internal */ -export declare type ValidationConfiguration = Record< +declare type ValidationConfiguration = Record< ValidationSyntaxGroupEnum, ValidationSyntaxNode | Record | Record >; @@ -6551,7 +6565,7 @@ declare function setNodeProperty(node: AstNode$1, key: 'tokens', value: Token$1[ declare function load(url: string | { absolute: string; relative: string; -}, currentDirectory?: string, responseType?: boolean | ResponseType$1): Promise>>; +}, currentDirectory?: string, responseType?: boolean | ResponseType): Promise>>; /** * Render the ast tree * @param data @@ -6923,5 +6937,5 @@ declare function transform(options: ParseInputStreamOptions & TransformOptions): */ declare function transform(options: ParseInputFileOptions & TransformOptions): Promise; -export { ColorType$1 as ColorType, EnumAstNodeStatus$1 as EnumAstNodeStatus, EnumToken, FeatureWalkMode, ModuleCaseTransformEnum, ModuleScopeEnumOptions, ResponseType$1 as ResponseType, SourceMap, ValidationLevel, WalkerEvent, WalkerOptionEnum, cloneNode, convertColor, dirname, expand, find, findAll, findByValue, findLast, getNodeProperty, isOkLabClose, load, minify, okLabDistance, parse, parseDeclarations, parseFile, parseString, parseSync, render, renderValue as renderToken, replaceNodeOrValue, resolve, setNodeProperty, transform, transformFile, transformSync, walk, walkValues }; +export { ColorType$1 as ColorType, EnumAstNodeStatus$1 as EnumAstNodeStatus, EnumToken, FeatureWalkMode, ModuleCaseTransformEnum, ModuleScopeEnumOptions, ResponseType, SourceMap, ValidationLevel, WalkerEvent, WalkerOptionEnum, cloneNode, convertColor, dirname, expand, find, findAll, findByValue, findLast, getNodeProperty, isOkLabClose, load, minify, okLabDistance, parse, parseDeclarations, parseFile, parseString, parseSync, render, renderValue as renderToken, replaceNodeOrValue, resolve, setNodeProperty, transform, transformFile, transformSync, walk, walkValues }; export type { AddToken, AndToken, AngleToken, AstAtRule, AstComment, AstDeclaration, AstInvalidAtRule, AstInvalidDeclaration, AstInvalidRule, AstKeyframesAtRule, AstKeyframesRule, AstNode$1 as AstNode, AstNodeStatus, AstRule, AstRuleList, AstStyleSheet, AstValueMatcher, AtRuleToken, AtRuleVisitorHandler, AttrEndToken, AttrStartToken, AttrToken, Background, BackgroundAttachmentMapping, BackgroundPosition, BackgroundPositionClass, BackgroundPositionConstraints, BackgroundPositionMapping, BackgroundProperties, BackgroundRepeat, BackgroundRepeatMapping, BackgroundSize, BackgroundSizeMapping, BadCDOCommentToken, BadCommentToken, BadStringToken, BadUrlToken, BaseToken, BinaryExpressionNode, BinaryExpressionToken, BlockEndToken, BlockStartToken, Border, BorderColor, BorderColorClass, BorderProperties, BorderRadius, CDOCommentToken, ChildCombinatorToken, ClassSelectorToken, ColonToken, ColorToken, ColumnCombinatorToken, CommaToken, CommentToken, ComposesSelectorToken, ConstraintsMapping, ContainMatchToken, ContainerStyleRangeToken, CssVariableImportTokenType, CssVariableMapTokenType, CssVariableToken, DashMatchToken, DashedIdentToken, DeclarationVisitorHandler, DelimToken, DescendantCombinatorToken, DimensionToken, DivToken, DoubleColonToken, EOFToken, EndMatchToken, EqualMatchToken, ErrorDescription$1 as ErrorDescription, FlexToken, Font, FontFamily, FontProperties, FontWeight, FontWeightConstraints, FontWeightMapping, FractionToken, FrequencyToken, FunctionDefToken, FunctionImageToken, FunctionToken, FunctionURLToken, GenericVisitorAstNodeHandlerMap, GenericVisitorAstNodeSyncHandlerMap, GenericVisitorAsyncResult, GenericVisitorHandler, GenericVisitorResult, GenericVisitorSyncHandler, GenericVisitorSyncResult, GreaterThanOrEqualToken, GreaterThanToken, GridTemplateFuncToken, HashToken, IdentListToken, IdentToken, IfConditionToken, IfElseConditionToken, ImportantToken, IncludeMatchToken, InvalidAttrToken, InvalidClassSelectorToken, InvalidMediaQueryToken, LengthToken, LessThanOrEqualToken, LessThanToken, LineHeight, ListToken, LiteralToken, LoadResult, Map$1 as Map, MatchExpressionToken, MatchedSelector, MediaFeatureOnlyToken, MediaFeatureToken, MediaQueryConditionToken, MediaQueryUnaryFeatureToken, MediaRangeQueryToken, MinifyFeature, MinifyFeatureOptions, MinifyOptions, ModuleAsyncOptions, ModuleSyncOptions, MulToken, NameSpaceAttributeToken, NestingSelectorToken, NextSiblingCombinatorToken, NotToken, NumberToken, OptimizedSelector, OptimizedSelectorToken, OrToken, Outline, OutlineProperties, ParensEndToken, ParensStartToken, ParensToken, ParseInfo$1 as ParseInfo, ParseInputFileOptions, ParseInputOptions, ParseInputStreamOptions, ParseResult, ParseResultStats, ParseSourceOptions, ParseTokenOptions, ParserOptions, ParserSourceMapOptions, ParserSyncOptions, PercentageToken, Prefix, PropertiesConfig, PropertiesConfigProperties, PropertyListOptions, PropertyMapType, PropertySetType, PropertyType, PseudoClassFunctionToken, PseudoClassToken, PseudoElementToken, PseudoPageToken, PurpleBackgroundAttachment, RawNodeToken, RawSelectorTokens, RenderOptions, RenderResult, ResolutionToken, ResolvedPath, RuleVisitorHandler, SemiColonToken, Separator, ShorthandDef, ShorthandMapType, ShorthandProperties, ShorthandPropertyType, ShorthandType, SinglePropertyType, SinglePropertyTypeMapping, SourceLocation, SourceMapObject, StartMatchToken, StringToken, SubToken, SubsequentCombinatorToken, SupportsQueryConditionToken, SupportsQueryUnaryConditionToken, TimeToken, TimelineFunctionToken, TimingFunctionToken, Token$1 as Token, TokenSearchResult, TokenizeResult, TransformOptions, TransformResult, TransformSyncOptions, UnaryExpression, UnaryExpressionNode, UnclosedStringToken, UniversalSelectorToken, UrlToken, ValidationConfiguration, ValidationMediaFeature, ValidationOptions, ValidationResult, ValidationSelectorOptions, ValidationSyntaxNode, ValidationSyntaxResult, ValidationToken$1 as ValidationToken, Value, ValueVisitorHandler, ValueVisitorSyncHandler, VariableScopeInfo, VisitorNodeMap, VisitorSyncNodeMap, WalkAttributesResult, WalkResult, WalkerFilter, WalkerOption, WalkerOptions, WalkerValueFilter, WhenElseQueryConditionToken, WhenElseUnaryConditionToken, WhitespaceToken, WrappedValuesToken }; diff --git a/dist/lib/ast/expand.js b/dist/lib/ast/expand.js index 08a2c2d3..fa1b6d38 100644 --- a/dist/lib/ast/expand.js +++ b/dist/lib/ast/expand.js @@ -28,9 +28,8 @@ function expand(ast) { children = expandRule(node); for (const child of children) { child[PARENT] = result; + result.chi.push(child); } - // @ts-ignore - result.chi.push(...children); } else if (node.typ == EnumToken.AtRuleNodeType && "chi" in node) { let hasRule = false; @@ -150,6 +149,13 @@ function expandRule(node) { } if (withCompound.length > 0) { if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { + // for (const w of withCompound) { + // for (let m = 0; m < w.length; m++) { + // // for (let n = 0; n < w[m].length; n++) { + // withoutCompound.push(w[m].slice(1)); + // // } + // } + // } withoutCompound.push(...withCompound.map((t) => t.slice(1))); withCompound.length = 0; } @@ -189,7 +195,9 @@ function expandRule(node) { rule.sel = selectors.reduce((acc, curr) => (curr.length == 0 ? acc : acc + (acc.length > 0 ? "," : "") + curr), ""); } ast.chi.splice(i--, 1); - result.push(...expandRule(rule)); + for (const s of expandRule(rule)) { + result.push(s); + } } else if (ast.chi[i].typ == EnumToken.AtRuleNodeType) { let astAtRule = ast.chi[i]; @@ -224,13 +232,19 @@ function expandRule(node) { values.push(r); } else if (r.typ == EnumToken.RuleNodeType) { - // @ts-ignore - astAtRule.chi.push(...expandRule(r)); + for (const rule of expandRule(r)) { + // @ts-ignore + astAtRule.chi.push(rule); + } } } } - // @ts-ignore - result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); + if (astAtRule.chi.length > 0) { + result.push(astAtRule); + } + for (const r of values) { + result.push(r); + } ast.chi.splice(i--, 1); } } diff --git a/dist/lib/ast/features/calc.js b/dist/lib/ast/features/calc.js index 53efdac9..9ac0aa9c 100644 --- a/dist/lib/ast/features/calc.js +++ b/dist/lib/ast/features/calc.js @@ -1,9 +1,9 @@ import { EnumToken } from '../types.js'; -import { walkValues, WalkerEvent, WalkerOptionEnum } from '../walk.js'; +import { walkValues } from '../walk.js'; import { evaluate } from '../math/expression.js'; -import { renderValue } from '../../renderer/render.js'; import { FeatureWalkMode } from './type.js'; -import { mathFuncs, tokensfuncSet, LOC } from '../../syntax/constants.js'; +import { tokensfuncSet, mathFuncs, LOCEND, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; +import { replaceNodeOrValue } from '../../parser/utils/token.js'; class ComputeCalcExpressionFeature { accept = new Set([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType]); @@ -28,57 +28,15 @@ class ComputeCalcExpressionFeature { continue; } const set = new Set(); - for (const { value, parent } of walkValues(node.val, node, { - event: WalkerEvent.Enter, - // @ts-ignore - fn(node, parent) { - if (parent != null && - // @ts-ignore - parent.typ == EnumToken.DeclarationNodeType && - // @ts-ignore - parent.val.length == 1 && - (node.typ === EnumToken.MathFunctionTokenType || node.typ === EnumToken.FunctionTokenType) && - mathFuncs.includes(node.val) && - node.chi.length == 1 && - node.chi[0].typ == EnumToken.IdenTokenType) { - return WalkerOptionEnum.Ignore; - } - if ((node.typ === EnumToken.WildCardFunctionTokenType && node.val == "var") || - (!mathFuncs.includes(parent.val) && - [ - EnumToken.MathFunctionTokenType, - EnumToken.ColorTokenType, - EnumToken.DeclarationNodeType, - EnumToken.ImageFunc, - EnumToken.RuleNodeType, - EnumToken.AtRuleNodeType, - EnumToken.StyleSheetNodeType, - ].includes(parent?.typ))) { - return null; - } + for (const { value, parent } of walkValues(node.val, node)) { + if (parent?.typ == EnumToken.BinaryExpressionTokenType) { + continue; + } + if (value.typ == EnumToken.BinaryExpressionTokenType) { // @ts-ignore - const slice = (node.typ == EnumToken.FunctionTokenType || node.typ == EnumToken.MathFunctionTokenType - ? node.chi - : node.typ == EnumToken.DeclarationNodeType - ? node.val - : node.chi)?.slice(); - if (slice != null && - (node.typ === EnumToken.MathFunctionTokenType || - (node.typ == EnumToken.FunctionTokenType && - mathFuncs.includes(node.val)))) { - // @ts-ignore - const key = "chi" in node ? "chi" : "val"; - const str1 = renderValue({ ...node, [key]: slice }); - const str2 = renderValue(node); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); - if (str1.length < str2.length) { - // @ts-ignore - node[key] = slice; - } - return WalkerOptionEnum.Ignore; - } - return null; - }, - })) { + replaceNodeOrValue(parent, value, evaluate([value])); + continue; + } if (value != null && tokensfuncSet.has(value.typ)) { if (!set.has(value)) { set.add(value); @@ -125,7 +83,9 @@ class ComputeCalcExpressionFeature { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], } : values[0]); break; @@ -139,7 +99,9 @@ class ComputeCalcExpressionFeature { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; } diff --git a/dist/lib/ast/features/if.js b/dist/lib/ast/features/if.js index 5c58b2a5..d5c55041 100644 --- a/dist/lib/ast/features/if.js +++ b/dist/lib/ast/features/if.js @@ -1,7 +1,7 @@ import { EnumToken } from '../types.js'; import { renderValue } from '../../renderer/render.js'; import { FeatureWalkMode } from './type.js'; -import { PARENT, LOC, TOKENS } from '../../syntax/constants.js'; +import { PARENT, LOCSRCID, LOCSTA, LOCEND, TOKENS } from '../../syntax/constants.js'; import { equalsIgnoreCase } from '../../parser/utils/text.js'; import { replaceNodeOrValue } from '../../parser/utils/token.js'; import { cloneNode } from '../clone.js'; @@ -87,7 +87,9 @@ function substituteIfElseNode(declaration, node, wrapper, parentWrapper, cache) chi: [], }); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } atRule[TOKENS] = [{ typ: EnumToken.ParensTokenType, chi: left.chi.slice() }]; const minify = atRule.nam !== "supports"; @@ -112,7 +114,9 @@ function substituteIfElseNode(declaration, node, wrapper, parentWrapper, cache) atRule[TOKENS] = [left]; atRule.val = atRule[TOKENS].reduce((acc, curr) => acc + renderValue(curr), ""); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]; + atRule[LOCEND] = declaration[PARENT][LOCEND]; } clonedDeclaration = cloneNode(declaration, true, nodeMap); replaceNodeOrValue(nodeMap.get(targetWrapper.typ === EnumToken.WildCardFunctionTokenType ? targetParentWrapper : targetWrapper), nodeMap.get(targetWrapper.typ === EnumToken.WildCardFunctionTokenType ? targetWrapper : node), node.r.at(-1)?.typ === EnumToken.SemiColonTokenType diff --git a/dist/lib/ast/features/inlinecssvariables.js b/dist/lib/ast/features/inlinecssvariables.js index 00be2011..33c8e1fd 100644 --- a/dist/lib/ast/features/inlinecssvariables.js +++ b/dist/lib/ast/features/inlinecssvariables.js @@ -8,13 +8,14 @@ import { RAW, mathFuncs } from '../../syntax/constants.js'; function inlineExpression(token) { const result = []; if (token.typ == EnumToken.BinaryExpressionTokenType) { + const chi = inlineExpression(token.l); + chi.push({ typ: token.op }); + for (const child of inlineExpression(token.r)) { + chi.push(child); + } result.push({ typ: EnumToken.ParensTokenType, - chi: [ - ...inlineExpression(token.l), - { typ: token.op }, - ...inlineExpression(token.r), - ], + chi, }); } else { diff --git a/dist/lib/ast/features/prefix.js b/dist/lib/ast/features/prefix.js index 44b5031f..6445b996 100644 --- a/dist/lib/ast/features/prefix.js +++ b/dist/lib/ast/features/prefix.js @@ -67,8 +67,8 @@ function replaceAstNodes(tokens, root) { // typ: EnumToken.ResolutionTokenType, // unit: "x", // }); - // } - // else + // } + // else if (isPseudClass && value.typ == EnumToken.PseudoElementTokenType) { // @ts-ignore value.typ = EnumToken.PseudoClassTokenType; @@ -81,7 +81,7 @@ function replaceAstNodes(tokens, root) { const set = new Set(); const split = splitTokenList(tokens, [EnumToken.CommaTokenType]); tokens.length = 0; - tokens.push(...split.reduce((acc, curr) => { + for (const token of split.reduce((acc, curr) => { const str = curr.reduce((acc, curr) => acc + renderValue(curr), ""); if (set.has(str)) { return acc; @@ -93,7 +93,9 @@ function replaceAstNodes(tokens, root) { }); } return acc.concat(curr); - }, [])); + }, [])) { + tokens.push(token); + } } return result; } @@ -311,52 +313,28 @@ class ComputePrefixFeature { // right bottom → left top to top left const replacements = []; if (key === "left top left bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "bottom" }); } else if (key === "left bottom left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "top" }); } else if (key === "left top right top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "left" }); } else if (key === "left top right bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "bottom" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "right" }); } else if (key === "right top left bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "bottom" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "left" }); } else if (key === "left bottom right top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "top" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "right" }); } else if (key === "right bottom left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "top" }, { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "left" }); } tokens.splice(0, i, ...replacements); let checkStop = true; @@ -369,7 +347,10 @@ class ComputePrefixFeature { } if (tokens[i].typ === EnumToken.FunctionTokenType) { if (equalsIgnoreCase(tokens[i].val, "to")) { - colorStop.push(tokens[checkStopIndex], ...tokens[i].chi); + colorStop.push(tokens[checkStopIndex]); + for (const token of tokens[i].chi) { + colorStop.push(token); + } tokens.splice(checkStopIndex, i - checkStopIndex + 1); i = checkStopIndex; checkStop = false; @@ -397,12 +378,16 @@ class ComputePrefixFeature { } } if (colorStop.length > 0) { - tokens.push(...colorStop); + for (const t of colorStop) { + tokens.push(t); + } } if (type !== "") { token.val = type; token.chi.length = 0; - token.chi.push(...tokens); + for (const t of tokens) { + token.chi.push(t); + } } } /** @@ -473,7 +458,9 @@ class ComputePrefixFeature { i++; } } - colorStops.push(...tokens.slice(i)); + for (let m = i; m < tokens.length; m++) { + colorStops.push(tokens[m]); + } tokens.length = 0; if (form.length > 0 || size.length > 0) { if (form.length === 0) { @@ -481,17 +468,27 @@ class ComputePrefixFeature { } if (size.length > 0) { form.push({ typ: EnumToken.WhitespaceTokenType }); - form.push(...size); + for (const token of size) { + form.push(token); + } } if (positions.length > 0) { - form.push({ typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, ...positions); + form.push({ typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }); + for (const position of positions) { + form.push(position); + } } - tokens.push(...form, { typ: EnumToken.CommaTokenType }); + for (const token of form) { + tokens.push(token); + } + tokens.push({ typ: EnumToken.CommaTokenType }); } token.val = equalsIgnoreCase(token.val, "-webkit-repeating-radial-gradient") ? "repeating-radial-gradient" : "radial-gradient"; - tokens.push(...colorStops); + for (const colorStop of colorStops) { + tokens.push(colorStop); + } return tokens; } } diff --git a/dist/lib/ast/features/shorthand.js b/dist/lib/ast/features/shorthand.js index 2843a483..ff287d03 100644 --- a/dist/lib/ast/features/shorthand.js +++ b/dist/lib/ast/features/shorthand.js @@ -20,7 +20,7 @@ class ComputeShorthandFeature { options.features.push(new ComputeShorthandFeature(options)); } } - run(ast, options = {}, parent, context) { + run(ast, options) { if (!("chi" in ast)) { return null; } @@ -46,15 +46,20 @@ class ComputeShorthandFeature { // @ts-ignore const node = ast.chi[l]; if (node.typ == EnumToken.DeclarationNodeType) { - properties.add(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + properties.add(ast.chi[m]); + } } else { - rules.push(...ast.chi.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + rules.push(ast.chi[m]); + } } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi.length = 0; + // @ts-expect-error + ast.chi.push(...properties, ...rules); return ast; } } diff --git a/dist/lib/ast/features/transform.js b/dist/lib/ast/features/transform.js index a0306f8a..d528102a 100644 --- a/dist/lib/ast/features/transform.js +++ b/dist/lib/ast/features/transform.js @@ -25,7 +25,7 @@ class TransformCssFeature { } } run(ast) { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } let i = 0; diff --git a/dist/lib/ast/math/expression.js b/dist/lib/ast/math/expression.js index 793bf50e..5c0bab0a 100644 --- a/dist/lib/ast/math/expression.js +++ b/dist/lib/ast/math/expression.js @@ -1,4 +1,4 @@ -import { mathFuncs, LOC } from '../../syntax/constants.js'; +import { mathFuncs, LOCEND, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; import { EnumToken } from '../types.js'; import { rem, compute } from './math.js'; @@ -28,7 +28,9 @@ function evaluate(tokens) { if (acc.length > 0) { acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }); const result = evaluateFunc(tokens[0]); @@ -58,7 +60,9 @@ function evaluate(tokens) { // @ts-ignore val: Math[nodes[0].val.toUpperCase()], typ: EnumToken.NumberTokenType, - [LOC]: nodes[0][LOC], + [LOCSRCID]: nodes[0][LOCSRCID], + [LOCSTA]: nodes[0][LOCSTA], + [LOCEND]: nodes[0][LOCEND], }, ]; } @@ -78,11 +82,19 @@ function evaluate(tokens) { token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]], - [LOC]: { ...nodes[i][LOC], end: nodes[i + 1][LOC].end }, + [LOCSRCID]: nodes[i][LOCSRCID], + [LOCSTA]: nodes[i][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], }; } else { - token = doEvaluate(nodes[i + 1], { typ: EnumToken.NumberTokenType, val: -1, [LOC]: nodes[i + 1][LOC] }, EnumToken.Mul); + token = doEvaluate(nodes[i + 1], { + typ: EnumToken.NumberTokenType, + val: -1, + [LOCSRCID]: nodes[i + 1][LOCSRCID], + [LOCSTA]: nodes[i + 1][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], + }, EnumToken.Mul); } i++; } @@ -97,16 +109,28 @@ function evaluate(tokens) { const token = curr[1].reduce((acc, curr) => doEvaluate(acc, curr, EnumToken.Add)); if (token.typ != EnumToken.BinaryExpressionTokenType) { if ("val" in token && +token.val < 0) { - acc.push({ typ: EnumToken.Sub, [LOC]: token[LOC] }, { + acc.push({ + typ: EnumToken.Sub, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, { ...token, val: -token.val, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }); return acc; } } if (acc.length > 0 && curr[0] != EnumToken.ListToken) { - acc.push({ typ: EnumToken.Add, [LOC]: token[LOC] }); + acc.push({ + typ: EnumToken.Add, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); } acc.push(token); return acc; @@ -124,7 +148,9 @@ function doEvaluate(l, r, op) { op, l, r, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { return defaultReturn; @@ -162,15 +188,39 @@ function doEvaluate(l, r, op) { if (typeof v1 == "number" && l.typ == EnumToken.PercentageTokenType) { v1 = { typ: EnumToken.FractionTokenType, - l: { typ: EnumToken.NumberTokenType, val: v1, [LOC]: l[LOC] }, - r: { typ: EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: EnumToken.NumberTokenType, + val: v1, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } else if (typeof v2 == "number" && r.typ == EnumToken.PercentageTokenType) { v2 = { typ: EnumToken.FractionTokenType, - l: { typ: EnumToken.NumberTokenType, val: v2, [LOC]: l[LOC] }, - r: { typ: EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: EnumToken.NumberTokenType, + val: v2, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } } @@ -181,7 +231,9 @@ function doEvaluate(l, r, op) { ...(l.typ === EnumToken.NumberTokenType || l.typ === EnumToken.IdenTokenType ? r : l), typ, val /* : typeof val == 'number' ? minifyNumber(val) : val */, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l?.[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (token.typ == EnumToken.IdenTokenType) { // @ts-ignore @@ -210,25 +262,64 @@ function evaluateFunc(token) { case "sign": case "sqrt": case "exp": { + if (token.val == "tan" || token.val == "atan") { + for (let i = 0; i < values.length; i++) { + if (values[i].typ == EnumToken.NumberTokenType) { + values[i] = Object.assign(values[i], { typ: EnumToken.AngleTokenType, unit: "rad" }); + } + else if (values[i].typ == EnumToken.AngleTokenType && values[i].unit != "rad") { + switch (values[i].unit) { + case "deg": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(values[i], { + unit: "rad", + val: values[i].val * (2 * Math.PI), + }); + break; + } + } + } + } const value = evaluate(values); // @ts-ignore - let val = value[0].typ == EnumToken.NumberTokenType + let val = value[0].typ == EnumToken.NumberTokenType || value[0].typ == EnumToken.AngleTokenType ? +value[0].val : // @ts-expect-error value[0].l.val / value[0].r.val; return [ - { - typ: EnumToken.NumberTokenType, - val: Math[token.val](val), - [LOC]: value[0][LOC], - }, + token.val == "tan" || token.val == "atan" + ? { + typ: EnumToken.AngleTokenType, + val: Math[token.val](val), + unit: "rad", + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + } + : { + typ: EnumToken.NumberTokenType, + val: Math[token.val](val), + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + }, ]; } case "hypot": { const chi = values.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType, EnumToken.CommaTokenType].includes(t.typ)); let all = []; let ref = chi[0]; - let value = 0; for (let i = 0; i < chi.length; i++) { // @ts-ignore const val = getValue(chi[i]); @@ -236,13 +327,14 @@ function evaluateFunc(token) { return null; } all.push(val); - value += val * val; } return [ { ...ref, - val: +Math.sqrt(value).toFixed(rem(...all)), - [LOC]: token[LOC], + val: Math.hypot(...all), + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -251,6 +343,35 @@ function evaluateFunc(token) { case "rem": case "mod": { const chi = values.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)); + if (token.val == "atan2") { + for (let i = 0; i < chi.length; i++) { + if (chi[i].typ == EnumToken.NumberTokenType) { + chi[i] = Object.assign(chi[i], { typ: EnumToken.AngleTokenType, unit: "rad" }); + } + else if (chi[i].typ == EnumToken.AngleTokenType && chi[i].unit != "rad") { + switch (chi[i].unit) { + case "deg": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(chi[i], { + unit: "rad", + val: chi[i].val * (2 * Math.PI), + }); + break; + } + } + } + } // https://developer.mozilla.org/en-US/docs/Web/CSS/mod const v1 = evaluate([chi[0]]); const v2 = evaluate([chi[2]]); @@ -271,7 +392,9 @@ function evaluateFunc(token) { { ...v1[0], val: Math.pow(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -280,8 +403,12 @@ function evaluateFunc(token) { { ...{}, ...v1[0], + typ: EnumToken.AngleTokenType, + unit: "rad", val: Math.atan2(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -289,7 +416,9 @@ function evaluateFunc(token) { { ...v1[0], val: val2 == 0 ? val1 : val1 - Math.floor(val1 / val2) * val2, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -326,7 +455,9 @@ function evaluateFunc(token) { { ...values[0], val: Math.log(val1) / Math.log(val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -362,7 +493,15 @@ function evaluateFunc(token) { : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOC]: token[LOC] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -380,7 +519,18 @@ function inlineExpression(token) { result.push(token); } else { - result.push(...inlineExpression(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression(token.r)); + for (const child of inlineExpression(token.l)) { + result.push(child); + } + result.push({ + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); + for (const child of inlineExpression(token.r)) { + result.push(child); + } } } else { @@ -443,7 +593,13 @@ function factorToken(token) { token.val == "calc")) { if ((token.typ == EnumToken.MathFunctionTokenType || token.typ == EnumToken.FunctionTokenType) && token.val == "calc") { - token = { ...token, typ: EnumToken.ParensTokenType, [LOC]: token[LOC] }; + token = { + ...token, + typ: EnumToken.ParensTokenType, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }; // @ts-ignore delete token.val; } @@ -481,7 +637,9 @@ function factor(tokens, ops) { : getArithmeticOperation(tokens[i].val), l: factorToken(tokens[i - 1]), r: factorToken(tokens[i + 1]), - [LOC]: { ...tokens[i - 1][LOC], end: tokens[i + 1][LOC]?.end }, + [LOCSRCID]: tokens[i - 1][LOCSRCID], + [LOCSTA]: tokens[i - 1][LOCSTA], + [LOCEND]: tokens[i + 1][LOCEND], }); i--; } diff --git a/dist/lib/ast/minify.js b/dist/lib/ast/minify.js index fb0a66aa..3004ef6b 100644 --- a/dist/lib/ast/minify.js +++ b/dist/lib/ast/minify.js @@ -6,10 +6,9 @@ import { EnumToken } from './types.js'; import { isWhiteSpace, isIdent, isFunction, isIdentStart } from '../syntax/syntax.js'; import { FeatureWalkMode } from './features/type.js'; import { trimArray } from '../validation/match.js'; -import { TOKENS, PARENT, OPTIMIZED, RAW, combinators, LOC } from '../syntax/constants.js'; +import { TOKENS, PARENT, OPTIMIZED, RAW, combinators, LOCEND, LOCSTA, LOCSRCID } from '../syntax/constants.js'; import { replaceNodeOrValue } from '../parser/utils/token.js'; import { parseString } from '../parser/parse.js'; -import { tokenize } from '../parser/tokenize.js'; import { replaceCompound } from './expand.js'; const notEndingWith = ["(", "["].concat(combinators); @@ -219,7 +218,9 @@ function transformAtRuleMediaPrelude(values) { }, l: val1, r: val2, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }, ], }; @@ -286,7 +287,9 @@ function minifyAtRuleMedia(tokens) { typ: EnumToken.CommaTokenType, }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }, [])); } @@ -366,7 +369,9 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, node.sel === previous.sel) { // do not merge keyframes // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates - previous.chi.push(...node.chi); + for (const child of node.chi) { + previous.chi.push(child); + } // @ts-ignore ast.chi.splice(i, 1); previous = ast?.chi?.[nodeIndex] ?? null; @@ -398,7 +403,9 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, minifyAtRuleMedia(slice); if (slice.length !== node[TOKENS].length) { node[TOKENS].length = 0; - node[TOKENS].push(...slice); + for (const token of slice) { + node[TOKENS].push(token); + } node.val = slice.reduce((acc, curr, index, arr) => acc + (curr.typ === EnumToken.CommentTokenType || (curr.typ === EnumToken.WhitespaceTokenType && @@ -450,8 +457,9 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, previous.nam === node.nam && previous.val === node.val) { if ("chi" in node) { - // @ts-ignore - previous.chi.push(...node.chi); + for (const child of node.chi) { + previous.chi.push(child); + } if (!hasDeclaration(previous)) { context.nodes.delete(previous); doMinify(previous, options, recursive, errors, nestingContent, context); @@ -666,8 +674,15 @@ function doMinify(ast, options = {}, recursive = false, errors, nestingContent, node.nam !== "font-face" && // @ts-ignore node.nam === previous.nam)) { + const array = []; + for (let i = 0; i < previous.chi.length; i++) { + array.push(previous.chi[i]); + } + for (let i = 0; i < node.chi.length; i++) { + array.push(node.chi[i]); + } // @ts-ignore - node.chi.unshift(...previous.chi); + node.chi = array; doMinify(node, options, recursive, errors, nestingContent, context); ast.chi.splice(nodeIndex, 1); previous = ast.chi[--i]; @@ -1016,7 +1031,9 @@ function reduceSelector(acc, curr) { if (acc.length > 0) { acc.push(","); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); } @@ -1144,7 +1161,7 @@ function matchSelectors(selector1, selector2) { */ function fixSelector(node) { if (node.sel.includes("&")) { - const attributes = [...tokenize(node.sel)].map((t) => t.token); // parseString(node.sel); + const attributes = parseString(node.sel); for (const attr of walkValues(attributes)) { if (attr.value.typ == EnumToken.PseudoClassFuncTokenType && attr.value.val == ":is") { @@ -1185,9 +1202,13 @@ function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) { [RAW]: match.match.map((t) => t.slice()), }; if (pSel == "&" || pSel === "") { - wrapper.chi.push(...previous.chi); + for (const child of previous.chi) { + wrapper.chi.push(child); + } if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); + for (const child of node.chi) { + wrapper.chi.push(child); + } } else { wrapper.chi.push(node); @@ -1426,7 +1447,9 @@ function reduceRuleSelector(node) { acc.push(","); } unique.add(sig); - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } } return acc; }, []); diff --git a/dist/lib/ast/node.js b/dist/lib/ast/node.js index 134448da..99b65287 100644 --- a/dist/lib/ast/node.js +++ b/dist/lib/ast/node.js @@ -1,4 +1,4 @@ -import { TOKENS, ERRORS, STATE, LOC, PARENT } from '../syntax/constants.js'; +import { TOKENS, ERRORS, STATE, LOCSRCID, LOCSTA, LOCEND, PARENT } from '../syntax/constants.js'; /** * @@ -11,7 +11,7 @@ function getNodeProperty(node, key) { case "parent": return node[PARENT]; case "location": - return node[LOC]; + return node[LOCSRCID] == null && node[LOCSTA] == null && node[LOCEND] == null ? null : { srcId: node[LOCSRCID], sta: node[LOCSTA], end: node[LOCEND] }; case "state": return node[STATE]; case "errors": @@ -33,7 +33,9 @@ function setNodeProperty(node, key, value) { node[PARENT] = value; break; case "location": - node[LOC] = value; + node[LOCSRCID] = value.srcId; + node[LOCSTA] = value.sta; + node[LOCEND] = value.end; break; case "state": node[STATE] = value; diff --git a/dist/lib/ast/transform/compute.js b/dist/lib/ast/transform/compute.js index 409a15c7..ddd93996 100644 --- a/dist/lib/ast/transform/compute.js +++ b/dist/lib/ast/transform/compute.js @@ -1,4 +1,4 @@ -import { multiply, toZero, identity } from './utils.js'; +import { identity, multiply, toZero } from './utils.js'; import { EnumToken } from '../types.js'; import { stripCommaToken } from '../../validation/utils/list.js'; import { translateX, translateY, translateZ, translate, translate3d } from './translate.js'; @@ -17,6 +17,7 @@ function compute(transformLists) { stripCommaToken(transformLists); let matrix = identity(); let mat; + let transforms; const cumulative = []; for (const transformList of splitTransformList(transformLists)) { mat = computeMatrix(transformList, identity()); @@ -24,7 +25,10 @@ function compute(transformLists) { return null; } matrix = multiply(matrix, mat); - cumulative.push(...(minify(mat) ?? transformList)); + transforms = minify(mat) ?? transformList; + for (let i = 0; i < transforms.length; i++) { + cumulative.push(transforms[i]); + } } const serialized = serialize(matrix); if (cumulative.length > 0) { @@ -40,11 +44,66 @@ function compute(transformLists) { }); } } - return { + const result = { matrix: serialize(toZero(matrix)), cumulative, minified: minify(matrix) ?? [serialized], }; + // valid identity matrix + if ((result.minified.length == 1 && + result.minified[0].typ == EnumToken.IdenTokenType && + result.minified[0].val == "none") || + (result.cumulative.length == 1 && + result.cumulative[0].typ == EnumToken.IdenTokenType && + result.cumulative[0].val == "none") || + (result.matrix?.typ == EnumToken.IdenTokenType && result.matrix.val == "none")) { + // all transform function arguments must be 0 or scale(1) + for (const transform of transformLists) { + switch (transform.val) { + case "translate": + case "translateX": + case "translateY": + case "translateZ": + case "translate3d": + case "rotate": + case "rotateX": + case "rotateY": + case "rotateZ": + case "rotate3d": + case "skew": + case "skewX": + case "skewY": + for (const child of transform.chi) { + if (child.typ == EnumToken.WhitespaceTokenType || child.typ == EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != EnumToken.AngleTokenType && + child.typ != EnumToken.NumberTokenType && + child.typ != EnumToken.PercentageTokenType) || + getNumber(child) != 0) { + return null; + } + } + break; + case "scale": + case "scaleX": + case "scaleY": + case "scaleZ": + case "scale3d": + for (const child of transform.chi) { + if (child.typ == EnumToken.WhitespaceTokenType || child.typ == EnumToken.CommaTokenType) { + continue; + } + if ((child.typ != EnumToken.NumberTokenType && child.typ != EnumToken.PercentageTokenType) || + getNumber(child) != 1) { + return null; + } + } + break; + } + } + } + return result; } function computeMatrix(transformList, matrixVar) { let values = []; @@ -166,7 +225,7 @@ function computeMatrix(transformList, matrixVar) { if (values.length != 3) { return null; } - matrixVar = scale3d(...values, matrixVar); + matrixVar = scale3d(values[0], values[1], values[2], matrixVar); break; } if (transformList[i].val == "scale") { diff --git a/dist/lib/ast/transform/minify.js b/dist/lib/ast/transform/minify.js index bb83a9e6..b1113e22 100644 --- a/dist/lib/ast/transform/minify.js +++ b/dist/lib/ast/transform/minify.js @@ -1,4 +1,4 @@ -import { multiply, decompose, round, toZero, identity } from './utils.js'; +import { identity, multiply, decompose, round, toZero } from './utils.js'; import { epsilon } from '../../syntax/constants.js'; import { EnumToken } from '../types.js'; import { computeMatrix } from './compute.js'; @@ -245,7 +245,7 @@ function minify(matrix) { function eqMatrix(a, b) { let mat = identity(); let tmp = identity(); - const data = (Array.isArray(a) ? a : parseMatrix(a)); + const data = (Array.isArray(a) || ArrayBuffer.isView(a) ? a : parseMatrix(a)); for (const transform of b) { tmp = computeMatrix([transform], identity()); if (tmp == null) { @@ -267,7 +267,7 @@ function eqMatrix(a, b) { } function minifyTransformFunctions(transform) { const name = transform.val.toLowerCase(); - if ("skewx" == name) { + if ("skewX" == name) { transform.val = "skew"; return transform; } @@ -307,10 +307,10 @@ function minifyTransformFunctions(transform) { } const ignoredValue = name.startsWith("scale") ? 1 : 0; const t = new Set(["x", "y", "z"]); - let i = 3; - while (i--) { + for (let i = 0; i < 3; i++) { + const axis = i == 0 ? "x" : i == 1 ? "y" : "z"; if (values.length <= i || values[i].val == ignoredValue) { - t.delete(i == 0 ? "x" : i == 1 ? "y" : "z"); + t.delete(axis); } } if (name == "translate3d" || name == "translate") { diff --git a/dist/lib/ast/transform/perspective.js b/dist/lib/ast/transform/perspective.js index 5c972475..923af940 100644 --- a/dist/lib/ast/transform/perspective.js +++ b/dist/lib/ast/transform/perspective.js @@ -1,4 +1,4 @@ -import { multiply, identity } from './utils.js'; +import { identity, multiply } from './utils.js'; function perspective(x, from) { const matrix = identity(); diff --git a/dist/lib/ast/transform/rotate.js b/dist/lib/ast/transform/rotate.js index 555f2d30..637e3080 100644 --- a/dist/lib/ast/transform/rotate.js +++ b/dist/lib/ast/transform/rotate.js @@ -1,4 +1,4 @@ -import { multiply, identity } from './utils.js'; +import { identity, multiply } from './utils.js'; /** * angle in radian diff --git a/dist/lib/ast/transform/scale.js b/dist/lib/ast/transform/scale.js index 53055fbf..b83072c5 100644 --- a/dist/lib/ast/transform/scale.js +++ b/dist/lib/ast/transform/scale.js @@ -1,4 +1,4 @@ -import { multiply, identity } from './utils.js'; +import { identity, multiply } from './utils.js'; function scaleX(x, from) { const matrix = identity(); diff --git a/dist/lib/ast/transform/skew.js b/dist/lib/ast/transform/skew.js index 3356a621..c15baa38 100644 --- a/dist/lib/ast/transform/skew.js +++ b/dist/lib/ast/transform/skew.js @@ -1,4 +1,4 @@ -import { multiply, identity } from './utils.js'; +import { identity, multiply } from './utils.js'; function skewX(x, from) { const matrix = identity(); diff --git a/dist/lib/ast/transform/translate.js b/dist/lib/ast/transform/translate.js index 5c4b8a32..9ec60679 100644 --- a/dist/lib/ast/transform/translate.js +++ b/dist/lib/ast/transform/translate.js @@ -1,4 +1,4 @@ -import { multiply, identity } from './utils.js'; +import { identity, multiply } from './utils.js'; function translateX(x, from) { const matrix = identity(); diff --git a/dist/lib/ast/transform/utils.js b/dist/lib/ast/transform/utils.js index 8c1be932..a1b5140c 100644 --- a/dist/lib/ast/transform/utils.js +++ b/dist/lib/ast/transform/utils.js @@ -1,7 +1,8 @@ import { epsilon } from '../../syntax/constants.js'; +const identityMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); function identity() { - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; + return identityMatrix.slice(); } function normalize(point) { const [x, y, z] = point; @@ -15,37 +16,64 @@ function dot(point1, point2) { return point1[0] * point2[0] + point1[1] * point2[1] + point1[2] * point2[2]; } function multiply(matrixA, matrixB) { - let result = new Array(16).fill(0); - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - for (let k = 0; k < 4; k++) { - // Utiliser l'indexation linéaire pour accéder aux éléments - // Pour une matrice 4x4, l'index est (row * 4 + col) - result[j * 4 + i] += matrixA[k * 4 + i] * matrixB[j * 4 + k]; - } - } - } + const result = new Float32Array(16); + result[0] = matrixA[0] * matrixB[0] + matrixA[4] * matrixB[1] + matrixA[8] * matrixB[2] + matrixA[12] * matrixB[3]; + result[1] = matrixA[1] * matrixB[0] + matrixA[5] * matrixB[1] + matrixA[9] * matrixB[2] + matrixA[13] * matrixB[3]; + result[2] = matrixA[2] * matrixB[0] + matrixA[6] * matrixB[1] + matrixA[10] * matrixB[2] + matrixA[14] * matrixB[3]; + result[3] = matrixA[3] * matrixB[0] + matrixA[7] * matrixB[1] + matrixA[11] * matrixB[2] + matrixA[15] * matrixB[3]; + result[4] = matrixA[0] * matrixB[4] + matrixA[4] * matrixB[5] + matrixA[8] * matrixB[6] + matrixA[12] * matrixB[7]; + result[5] = matrixA[1] * matrixB[4] + matrixA[5] * matrixB[5] + matrixA[9] * matrixB[6] + matrixA[13] * matrixB[7]; + result[6] = matrixA[2] * matrixB[4] + matrixA[6] * matrixB[5] + matrixA[10] * matrixB[6] + matrixA[14] * matrixB[7]; + result[7] = matrixA[3] * matrixB[4] + matrixA[7] * matrixB[5] + matrixA[11] * matrixB[6] + matrixA[15] * matrixB[7]; + result[8] = + matrixA[0] * matrixB[8] + matrixA[4] * matrixB[9] + matrixA[8] * matrixB[10] + matrixA[12] * matrixB[11]; + result[9] = + matrixA[1] * matrixB[8] + matrixA[5] * matrixB[9] + matrixA[9] * matrixB[10] + matrixA[13] * matrixB[11]; + result[10] = + matrixA[2] * matrixB[8] + matrixA[6] * matrixB[9] + matrixA[10] * matrixB[10] + matrixA[14] * matrixB[11]; + result[11] = + matrixA[3] * matrixB[8] + matrixA[7] * matrixB[9] + matrixA[11] * matrixB[10] + matrixA[15] * matrixB[11]; + result[12] = + matrixA[0] * matrixB[12] + matrixA[4] * matrixB[13] + matrixA[8] * matrixB[14] + matrixA[12] * matrixB[15]; + result[13] = + matrixA[1] * matrixB[12] + matrixA[5] * matrixB[13] + matrixA[9] * matrixB[14] + matrixA[13] * matrixB[15]; + result[14] = + matrixA[2] * matrixB[12] + matrixA[6] * matrixB[13] + matrixA[10] * matrixB[14] + matrixA[14] * matrixB[15]; + result[15] = + matrixA[3] * matrixB[12] + matrixA[7] * matrixB[13] + matrixA[11] * matrixB[14] + matrixA[15] * matrixB[15]; return result; } function inverse(matrix) { // Create augmented matrix [matrix | identity] let augmented = [ - ...matrix.slice(0, 4), + matrix[0], + matrix[1], + matrix[2], + matrix[3], 1, 0, 0, 0, - ...matrix.slice(4, 8), + matrix[4], + matrix[5], + matrix[6], + matrix[7], 0, 1, 0, 0, - ...matrix.slice(8, 12), + matrix[8], + matrix[9], + matrix[10], + matrix[11], 0, 0, 1, 0, - ...matrix.slice(12, 16), + matrix[12], + matrix[13], + matrix[14], + matrix[15], 0, 0, 0, @@ -141,11 +169,11 @@ function decompose(original) { row1[0] * row2[1] - row1[1] * row2[0], ]; // Compute scale - const scaleX = Math.hypot(...row0); + const scaleX = Math.hypot(row0[0], row0[1], row0[2]); const row0Norm = normalize(row0); const skewXY = dot(row0Norm, row1); const row1Proj = [row1[0] - skewXY * row0Norm[0], row1[1] - skewXY * row0Norm[1], row1[2] - skewXY * row0Norm[2]]; - const scaleY = Math.hypot(...row1Proj); + const scaleY = Math.hypot(row1Proj[0], row1Proj[1], row1Proj[2]); const row1Norm = normalize(row1Proj); const skewXZ = dot(row0Norm, row2); const skewYZ = dot(row1Norm, row2); @@ -156,7 +184,7 @@ function decompose(original) { ]; const row2Norm = normalize(row2Proj); const determinant = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2]; - const scaleZ = Math.hypot(...row2Proj) * (determinant < 0 ? -1 : 1); + const scaleZ = Math.hypot(row2Proj[0], row2Proj[1], row2Proj[2]) * (determinant < 0 ? -1 : 1); // Build rotation matrix from orthonormalized vectors const r00 = row0Norm[0], r01 = row1Norm[0], r02 = row2Norm[0]; const r10 = row0Norm[1], r11 = row1Norm[1], r12 = row2Norm[1]; diff --git a/dist/lib/ast/walk.js b/dist/lib/ast/walk.js index 007b0984..2cf0cba1 100644 --- a/dist/lib/ast/walk.js +++ b/dist/lib/ast/walk.js @@ -259,6 +259,7 @@ function* walkValues(values, root = null, filter, reverse) { (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value) ?? root, WalkerEvent.Enter, // @ts-expect-error function* () { @@ -281,8 +282,13 @@ function* walkValues(values, root = null, filter, reverse) { const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } @@ -313,8 +319,13 @@ function* walkValues(values, root = null, filter, reverse) { const sliced = value.chi.slice(); for (const child of sliced) { map.set(child, value); + if (reverse) { + stack.unshift(child); + } + else { + stack.push(child); + } } - stack[reverse ? "push" : "unshift"](...sliced); } else { const values = []; @@ -347,7 +358,14 @@ function* walkValues(values, root = null, filter, reverse) { } } if (values.length > 0) { - stack[reverse ? "push" : "unshift"](...values); + for (const v of values) { + if (reverse) { + stack.unshift(v); + } + else { + stack.push(v); + } + } } } } @@ -357,14 +375,20 @@ function* walkValues(values, root = null, filter, reverse) { (Array.isArray(filter.type) && filter.type.includes(value.typ)) || (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value), WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { const op = Array.isArray(option) ? option : [option]; for (const o of op) { map.set(o, map.get(value) ?? root); + if (reverse) { + stack.unshift(o); + } + else { + stack.push(o); + } } - stack[reverse ? "push" : "unshift"](...op); } } } diff --git a/dist/lib/fs/resolve.js b/dist/lib/fs/resolve.js index f1f9255a..ea362750 100644 --- a/dist/lib/fs/resolve.js +++ b/dist/lib/fs/resolve.js @@ -4,6 +4,7 @@ import { memoize } from '../parser/utils/cache.js'; * match url */ const matchUrl = /^(https?:)?\/\//; +const windowsPathnameRegexp = /^\/?[a-zA-Z]:/; /** * return the directory name of a path * @param path @@ -76,6 +77,9 @@ const normalize = memoize(function (path) { if (path.includes("\\")) { path = path.replace(/(\\)/g, "/"); } + if (windowsPathnameRegexp.test(path)) { + path = path.replace(windowsPathnameRegexp, ""); + } for (; i < path.length; i++) { const chr = path.charAt(i); if (chr == "/") { @@ -148,8 +152,13 @@ const resolve = memoize(function (url, currentDirectory, cwd) { if (currentDirectory !== "") { currentDirectory = normalize(currentDirectory); } - const dir = cwd || currentDirectory; - const absolute = dir == "" || url.startsWith("/") || url.match(/^[a-zA-Z]:/) ? resolvePath(url) : resolvePath(dir, url); + let dir = cwd || currentDirectory; + if (windowsPathnameRegexp.test(dir)) { + dir = dir.replace(windowsPathnameRegexp, ""); + } + const absolute = dir == "" || url.startsWith("/") || url.startsWith(dir) || windowsPathnameRegexp.test(url) + ? resolvePath(url) + : resolvePath(dir, url); return { absolute, relative: dir === "" ? absolute : diff(absolute, dir), diff --git a/dist/lib/parser/declaration/list.js b/dist/lib/parser/declaration/list.js index e693bd67..7b0f6498 100644 --- a/dist/lib/parser/declaration/list.js +++ b/dist/lib/parser/declaration/list.js @@ -8,11 +8,13 @@ import { ValidationSyntaxGroupEnum } from '../../validation/parser/typedef.js'; import { matchAllSyntaxes, createValidationContext } from '../../validation/match.js'; import { STATE } from '../../syntax/constants.js'; import { objectHash } from '../utils/hash.js'; +import { equalsIgnoreCase } from '../utils/text.js'; const config = getConfig(); class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; + // ketsey = new Map; constructor(options = {}) { this.options = options; this.declarations = new Map(); @@ -29,15 +31,12 @@ class PropertyList { let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != EnumToken.DeclarationNodeType - ? null - : declaration.nam.toLowerCase(); + name = declaration.typ != EnumToken.DeclarationNodeType ? null : declaration.nam; if (declaration[STATE] == EnumAstNodeStatus.Invalid || declaration[STATE] == EnumAstNodeStatus.Unknown || declaration[STATE] == EnumAstNodeStatus.ValidationFailed || declaration.typ != EnumToken.DeclarationNodeType || - "composes" === name || + equalsIgnoreCase("composes", name) || (typeof this.options.removeDuplicateDeclarations === "string" && this.options.removeDuplicateDeclarations === name) || (Array.isArray(this.options.removeDuplicateDeclarations) @@ -65,7 +64,21 @@ class PropertyList { } // do not compute shorthand for invalid declarations if (declaration[STATE] !== EnumAstNodeStatus.Validated) { - this.declarations.set(declaration.nam, declaration); + // const key = objectHash(declaration); + // if (!this.ketsey.has(key)) { + // this.ketsey.set(key, [declaration.nam]); + // console.error( + // `Adding declaration : ${(declaration).nam} with key : ${key}` + // ) + // } + // else { + // console.error( + // `Duplicate declaration found: ${(declaration).nam} with key : [ ${key} => ${this.ketsey.get(key)} ]` + // ) + // console.error(JSON.stringify(toSortedString(declaration))) + // this.ketsey.get(key).push(declaration.nam); + // } + this.declarations.set(objectHash(declaration), declaration); return this; } let propertyName = declaration.nam; @@ -181,7 +194,9 @@ class PropertyList { } if (values != declaration.val) { declaration.val.length = 0; - declaration.val.push(...values); + for (const v of values) { + declaration.val.push(v); + } } } [Symbol.iterator]() { diff --git a/dist/lib/parser/declaration/map.js b/dist/lib/parser/declaration/map.js index 1f703256..20cc1e21 100644 --- a/dist/lib/parser/declaration/map.js +++ b/dist/lib/parser/declaration/map.js @@ -123,10 +123,17 @@ class PropertyMap { else { if (current == tokens[property].length) { tokens[property].push([]); - tokens[property][current].push(...defaults); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } else { - tokens[property][current].push({ typ: EnumToken.WhitespaceTokenType }, ...defaults); + tokens[property][current].push({ + typ: EnumToken.WhitespaceTokenType, + }); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } } } @@ -143,7 +150,9 @@ class PropertyMap { if (acc.length > 0) { acc.push({ ...separator }); } - acc.push(...curr); + for (let i = 0; i < curr.length; i++) { + acc.push(curr[i]); + } return acc; }, []), }); @@ -278,7 +287,9 @@ class PropertyMap { }; const values = [...this.declarations.values()].reduce((acc, curr) => { if (curr instanceof PropertySet) { - acc.push(...curr); + for (const declaration of curr) { + acc.push(declaration); + } } else { acc.push(curr); @@ -500,7 +511,7 @@ class PropertyMap { else if (acc[i].length > 0) { acc[i].push({ typ: EnumToken.WhitespaceTokenType }); } - acc[i].push(...values.reduce((acc, curr) => { + for (const v of values.reduce((acc, curr) => { if (acc.length > 0) { // @ts-ignore acc.push({ @@ -514,7 +525,9 @@ class PropertyMap { // @ts-ignore acc.push(curr); return acc; - }, [])); + }, [])) { + acc[i].push(v); + } } } return acc; @@ -532,7 +545,9 @@ class PropertyMap { return acc; }, [])); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); if (this.config.mapping != null) { @@ -600,10 +615,13 @@ class PropertyMap { } matchTypes(declaration) { const patterns = this.pattern.slice(); - const values = [...declaration.val]; + const values = []; let i; let j; const map = new Map(); + for (i = 0; i < declaration.val.length; i++) { + values.push(declaration.val[i]); + } for (i = 0; i < patterns.length; i++) { for (j = 0; j < values.length; j++) { if (!map.has(patterns[i])) { diff --git a/dist/lib/parser/declaration/set.js b/dist/lib/parser/declaration/set.js index d7f2bd27..8cc9b30d 100644 --- a/dist/lib/parser/declaration/set.js +++ b/dist/lib/parser/declaration/set.js @@ -182,7 +182,9 @@ class PropertySet { // @ts-ignore acc.push({ ...this.config.separator, typ: EnumToken.LiteralTokenType }); } - acc.push(...curr); + for (const token of curr) { + acc.push(token); + } return acc; }, []), }, diff --git a/dist/lib/parser/linesmap.js b/dist/lib/parser/linesmap.js index 54d8aec1..4212e077 100644 --- a/dist/lib/parser/linesmap.js +++ b/dist/lib/parser/linesmap.js @@ -23,11 +23,9 @@ class LineMap { */ getOffsets(offset) { const line = this.search(offset); - // if (offset < 0 || line < 0) { - // return [1, 1]; - // } + const column = offset - this.lineStarts[line]; // [line, column] - return [line + 1, offset - this.lineStarts[line] + 1]; + return [line + 1, line == 0 ? column + 1 : column]; } /** * search the greatest index of the value less than or equal to offset diff --git a/dist/lib/parser/parse.js b/dist/lib/parser/parse.js index 95d367d8..1ab703dd 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -5,8 +5,8 @@ import { EnumToken, EnumAstNodeStatus, ModuleCaseTransformEnum, ModuleScopeEnumO import { minify } from '../ast/minify.js'; import { expand } from '../ast/expand.js'; import { walk, walkValues, WalkerEvent } from '../ast/walk.js'; -import { tokenizeStream, tokenize } from './tokenize.js'; -import { LOC, tokensfuncDefMap, STATE, PARENT, TOKENS, ROOT, ERRORS, pageMarginBoxType } from '../syntax/constants.js'; +import { Tokenizer } from './tokenize.js'; +import { LOCSRCID, LOCSTA, LOCEND, tokensfuncDefMap, STATE, PARENT, TOKENS, ROOT, ERRORS, pageMarginBoxType } from '../syntax/constants.js'; import { hashAlgorithms, hash, syncHash } from './utils/hash.js'; import { parseSelector } from './utils/selector.js'; import { parseDeclaration } from './utils/declaration.js'; @@ -354,7 +354,9 @@ function parseVisitors(visitorsDef, errors) { } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { @@ -371,7 +373,6 @@ function parseVisitors(visitorsDef, errors) { .push(value); } else if (typeof value == "object") { - // visitors.push(...Object.entries(value)); if ("type" in value && "handler" in value && value.type in WalkerEvent) { if (value.type == WalkerEvent.Enter) { if (!preVisitorsHandlersMap.has(key)) { @@ -439,7 +440,7 @@ function parseVisitors(visitorsDef, errors) { * @throws Error * @private */ -function doParseSync(iter, options = {}) { +function doParseSync(tokenizer, options = {}) { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -501,46 +502,78 @@ function doParseSync(iter, options = {}) { // @ts-ignore ignore error let parensMatch = 0; let curlyBracketMatch = 0; - let currentItemIndex; - // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - for (currentItemIndex = 0; currentItemIndex < iter.length; currentItemIndex++) { - item = iter[currentItemIndex]; - stats.bytesIn = item.bytesIn; + // let currentItemIndex: number; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); + // item = (iter as Array)[currentItemIndex]; + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === EnumToken.BlockStartTokenType) { + if (item.typ === EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === EnumToken.SemiColonTokenType || - item.token.typ === EnumToken.BlockStartTokenType || - item.token.typ === EnumToken.EOFTokenType)) { + (item.typ === EnumToken.SemiColonTokenType || + item.typ === EnumToken.BlockStartTokenType || + item.typ === EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -548,37 +581,67 @@ function doParseSync(iter, options = {}) { context = node; } } - else if (item.token.typ == EnumToken.BlockStartTokenType) { + else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = iter[++currentItemIndex]; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; } - tokens.push(item.token); - if (item.token.typ === EnumToken.BlockStartTokenType) { + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === EnumToken.BlockEndTokenType) { + else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -587,7 +650,7 @@ function doParseSync(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -630,17 +693,23 @@ function doParseSync(iter, options = {}) { case EnumToken.AtRuleNodeType: case EnumToken.KeyframesRuleNodeType: case EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (const child of nodes[i].chi) { + subNodes.push(child); + } } if (subNodes.length > 0) { if (freeBlock <= i) { @@ -802,7 +871,7 @@ function doParseSync(iter, options = {}) { ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -831,7 +900,7 @@ function doParseSync(iter, options = {}) { : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & ModuleCaseTransformEnum.CamelCase) { @@ -876,7 +945,7 @@ function doParseSync(iter, options = {}) { for (const { node, parent } of walk(ast)) { if (node.typ == EnumToken.CssVariableImportTokenType) { throw new Error("css variable import not supported by parseSync() or transformSync(). use parse() or transform() instead.\nat " + - options.source.getSourceLocation(node[LOC].sta).join(":")); + options.source.getSourceLocation(node[LOCSTA]).join(":")); } // @ts-ignore if (node.typ == EnumToken.CssVariableDeclarationMapTokenType) { @@ -995,7 +1064,7 @@ function doParseSync(iter, options = {}) { } // composes: a b c from 'file.css'; else if (token.r.typ == EnumToken.String) { - throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOC].sta).join(":")}`); + throw new Error(`composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source.getSourceLocation(node[LOCSTA]).join(":")}`); } // composes: a b c from global; else if (token.r.typ == EnumToken.IdenTokenType) { @@ -1229,7 +1298,7 @@ function doParseSync(iter, options = {}) { } if (moduleSettings.scoped & ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOC]?.sta).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${options.source.getOffsets(node[LOCSTA]).join(":")}'`); } } node.sel = ""; @@ -1362,56 +1431,84 @@ async function doParse(iter, options = {}) { const imports = []; let item; let node; - // @ts-ignore ignore error - let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source.id, - }; - if (Array.isArray(iter)) { - // @ts-expect-error - iter = iter[Symbol.iterator](); - } - while ((item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value)) { - stats.bytesIn = item.bytesIn; + ast[LOCSRCID] = options.source.id; + ast[LOCSTA] = 0; + ast[LOCEND] = 0; + // if (Array.isArray(iter)) { + // // @ts-expect-error + // iter = iter[Symbol.iterator]() as Iterator; + // } + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source.getSourceLocation(item.token[LOC].sta), + node: item, + location: options.source.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; } - else if (item.token.typ === EnumToken.EndParensTokenType && parensMatch > 0) { + else if (item.typ === EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === EnumToken.BlockStartTokenType) { + if (item.typ === EnumToken.BlockStartTokenType) { curlyBracketMatch++; } - else if (item.token.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + else if (item.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if (parensMatch === 0 && - (item.token.typ === EnumToken.SemiColonTokenType || - item.token.typ === EnumToken.BlockStartTokenType || - item.token.typ === EnumToken.EOFTokenType)) { + (item.typ === EnumToken.SemiColonTokenType || + item.typ === EnumToken.BlockStartTokenType || + item.typ === EnumToken.EOFTokenType)) { node = parseNode(tokens, context, options, errors, stats, invalidNodes); if (node != null) { if ("chi" in node) { @@ -1422,41 +1519,67 @@ async function doParse(iter, options = {}) { imports.push(node); } } - else if (item.token.typ == EnumToken.BlockStartTokenType) { + else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { - break; + tokenizer.next(); + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ, + nam: tokenizer.nam, + }; + } + else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; } - tokens.push(item.token); - if (item.token.typ === EnumToken.BlockStartTokenType) { + else { + item = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + item[LOCSRCID] = tokenizer.srcId; + item[LOCSTA] = tokenizer.sta; + item[LOCEND] = tokenizer.end; + tokens.push(item); + if (item.typ === EnumToken.BlockStartTokenType) { inBlock++; } - else if (item.token.typ === EnumToken.BlockEndTokenType) { + else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source.getSourceLocation(tokens[0][LOC].sta), + location: options.source.getSourceLocation(tokens[0][LOCSTA]), }); } } - tokens = []; + tokens.length = 0; } - else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === EnumToken.BlockEndTokenType) { + else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC].end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop(); context = (stack[stack.length - 1] ?? ast); if (options.removeEmpty && @@ -1465,7 +1588,7 @@ async function doParse(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -1504,8 +1627,11 @@ async function doParse(iter, options = {}) { source, position: 0, currentPosition: 0, + time: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { minify: false, setParent: false, src: options.resolve(url, options.src || options.cwd).relative, @@ -1517,7 +1643,9 @@ async function doParse(iter, options = {}) { // @ts-ignore node[PARENT].chi.splice(node[PARENT].chi.indexOf(node), 1, ...root.ast.chi); if (root.errors.length > 0) { - errors.push(...root.errors); + for (const error of root.errors) { + errors.push(error); + } } } catch (error) { @@ -1554,17 +1682,24 @@ async function doParse(iter, options = {}) { case EnumToken.AtRuleNodeType: case EnumToken.KeyframesRuleNodeType: case EnumToken.KeyframesAtRuleNodeType: - subNodes.push(...nodes[i][TOKENS]); + for (const token of nodes[i][TOKENS]) { + subNodes.push(token); + } break; case EnumToken.DeclarationNodeType: - subNodes.push(...nodes[i].val); + for (const token of nodes[i].val) { + subNodes.push(token); + } break; } } // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (k = 0; k < nodes[i].chi.length; k++) { + // @ts-ignore + subNodes.push(nodes[i].chi[k]); + } } if (subNodes.length > 0) { if (freeblock <= i) { @@ -1729,7 +1864,7 @@ async function doParse(iter, options = {}) { ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, }; @@ -1758,7 +1893,7 @@ async function doParse(iter, options = {}) { : (moduleSettings.filePath ?? options.src); filePath = filePath === "" - ? options.src + ? options.resolve(options.src, options.cwd).relative : options.resolve(filePath, options.dirname(options.src), options.cwd).relative; if (typeof options.module == "number") { if (options.module & ModuleCaseTransformEnum.CamelCase) { @@ -1819,13 +1954,15 @@ async function doParse(iter, options = {}) { position: 0, currentPosition: 0, }; - const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { + const root = await doParse(stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { source, minify: false, setParent: false, src: src.relative, })); - options.parseInfo.time += parseInfo.time; + // options.parseInfo!.time += parseInfo.time; cssVariablesMap[node.nam] = root.cssModuleVariables; parent.chi.splice(parent.chi.indexOf(node), 1); continue; @@ -1960,13 +2097,13 @@ async function doParse(iter, options = {}) { ? await result : result; const root = await doParse(stream instanceof ReadableStream - ? tokenizeStream(stream, { + ? new Tokenizer({ offset: 0, source: new SourceFile("", [], src.relative), position: 0, currentPosition: 0, - }) - : tokenize({ + }, stream).tokenizeStream() + : new Tokenizer({ stream, offset: 0, position: 0, @@ -2265,7 +2402,7 @@ async function doParse(iter, options = {}) { } if (moduleSettings.scoped & ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { - throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOC]?.sta) ?? []).join(":")}'`); + throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOCSTA]) ?? []).join(":")}'`); } } node.sel = ""; @@ -2302,31 +2439,6 @@ async function doParse(iter, options = {}) { } node.val = renderTokens(node[TOKENS]); } - // else { - // let isReplaced: boolean = false; - // for (const { value, parent } of walkValues(node[TOKENS], node)) { - // if ( - // EnumToken.MediaQueryConditionTokenType == parent.typ && - // // @ts-expect-error - // value != (parent as MediaQueryConditionToken).l - // ) { - // if ( - // (value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && - // (value as IdentToken).val in importedCssVariables - // ) { - // isReplaced = true; - // (parent as MediaQueryConditionToken).r.splice( - // (parent as MediaQueryConditionToken).r.indexOf(value), - // 1, - // ...importedCssVariables[(value as IdentToken).val].val, - // ); - // } - // } - // } - // if (isReplaced) { - // node.val = renderTokens(node[TOKENS]!); - // } - // } } } if (moduleSettings.naming != ModuleCaseTransformEnum.IgnoreCase) { @@ -2358,7 +2470,6 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { tokens.pop(); // check parenthesis are balanced let matchCount = 0; - let position = tokens.at(-1)?.[LOC]; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(token.typ)) { @@ -2379,7 +2490,9 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { while (matchCount > 0) { tokens.push({ typ: EnumToken.EndParensTokenType, - [LOC]: { ...position }, + [LOCSRCID]: tokens[k]?.[LOCSRCID], + [LOCSTA]: tokens[k]?.[LOCSTA], + [LOCEND]: tokens[k]?.[LOCEND], }); matchCount--; } @@ -2391,7 +2504,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = EnumToken.InvalidCommentTokenType; continue; @@ -2414,7 +2527,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source.getSourceLocation(tokens[i][LOC].sta), + location: options.source.getSourceLocation(tokens[i][LOCSTA]), }); tokens[i].typ = EnumToken.InvalidCommentTokenType; continue; @@ -2495,7 +2608,7 @@ function parseNode(tokens, context, options, errors, stats, invalidNodes) { message: " not allowed in ", action: "drop", node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); } else if (options.lenient || node.typ === EnumToken.DeclarationNodeType) { @@ -2534,7 +2647,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "unknown at-rule", }); const result = matchGenericSyntax(stream, options); @@ -2555,7 +2668,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -2573,8 +2686,8 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); atRule[TOKENS] = parseTokens(stream); atRule[STATE] = EnumAstNodeStatus.Invalid; @@ -2594,7 +2707,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); atRule[TOKENS] = parseTokens(stream); @@ -2617,7 +2730,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[0] ?? atRule, - location: options.source.getSourceLocation((stream[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[0] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -2626,7 +2739,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting ", }); } @@ -2635,7 +2748,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source.getSourceLocation((stream[1] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((stream[1] ?? atRule)[LOCSTA]), message: "expecting double-quoted string", }); } @@ -2643,7 +2756,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[TOKENS] = stream; atRule[STATE] = EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? EnumToken.AtRuleNodeType : EnumToken.InvalidRuleNodeType, @@ -2656,7 +2769,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[TOKENS] = stream; atRule[STATE] = EnumAstNodeStatus.Validated; atRule[ERRORS] = []; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: success ? EnumToken.AtRuleNodeType : EnumToken.InvalidRuleNodeType, @@ -2666,12 +2779,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "font-feature-values": { const result = parseAtRuleFontFeatureValues(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } atRule[TOKENS] = stream; atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { typ: EnumToken.AtRuleNodeType, @@ -2690,7 +2805,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: `unexpected at-rule ${atRule.nam}`, }); } @@ -2701,13 +2816,13 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: token, - location: options.source.getSourceLocation(token[LOC].sta), - message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC].srcId}:${token[LOC].sta}:${token[LOC].sta}`, + location: options.source.getSourceLocation(token[LOCSTA]), + message: `unexpected token`, }); } } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; @@ -2721,9 +2836,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "container": { const result = parseAtRuleContainerQueryList(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -2738,11 +2855,13 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { const tokens = trimArray(stream.slice(1)); const result = matchAllSyntaxes(syntax, createValidationContext(tokens), options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.ValidationFailed; atRule[ERRORS] = result.success ? [] : result.errors; @@ -2762,14 +2881,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), - message: `expected at ${atRule[LOC].srcId}:${atRule[LOC].sta}:${atRule[LOC].sta}`, + location: options.source.getSourceLocation(atRule[LOCSTA]), + message: `expected `, }); success = false; } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1) ?? atRule)[LOC].end }; + atRule[LOCEND] = (tokens.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -2783,7 +2902,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "namespace": { const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // else { // parseUrlToken(stream); @@ -2812,7 +2933,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { stream.splice(start - 1, end - start + 2, ...stream.slice(start, end)); } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = valid ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = valid ? [] : result.errors; @@ -2832,7 +2953,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { case "import": { const result = matchAtRuleImportSyntax(atRule, stream, context, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } else { if (stream[0]?.typ == EnumToken.UrlFunctionTokenType && @@ -2840,8 +2963,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { stream.splice(0, 1, ...stream[0].chi); } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -2865,7 +2987,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { ? parseAtRuleSupportSyntax(stream, atRule, options) : matchAtRuleWhenElseSyntax(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } let success = result.success; if (atRule.nam === "else") { @@ -2902,7 +3026,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @when is required before @else block", }); } @@ -2911,14 +3035,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "at-rule @else block is defined after last @else block", }); } } // @ts-expect-error options = { ...options, minify: false, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : [errors[errors.length - 1]].concat(result.errors); @@ -2933,9 +3057,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { options = { ...options, parseColor: false }; const result = parseMediaqueryList(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -2955,7 +3081,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range[0] ?? atRule, - location: options.source.getSourceLocation((range[0] ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range[0] ?? atRule)[LOCSTA]), message: "expected '(' at start of @scope block", }); success = false; @@ -2964,7 +3090,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -2990,7 +3116,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -3003,7 +3129,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), message: "expected 'to' at end of @scope block", }); success = false; @@ -3016,7 +3142,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOC].sta), + location: options.source.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]), message: "expected ')' at end of @scope block", }); success = false; @@ -3035,8 +3161,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3049,7 +3174,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } case "page": { trimArray(stream); - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3080,7 +3205,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: atRule, - location: options.source.getSourceLocation(atRule[LOC].sta), + location: options.source.getSourceLocation(atRule[LOCSTA]), message: "node is allowed only in @page rule", }); } @@ -3093,14 +3218,14 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: "expected whitespace or comment", }); break; } } } - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3122,7 +3247,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { }); stream.splice(index, 0, { typ: EnumToken.ColonTokenType, - [LOC]: { ...stream[index][LOC], end: stream[index]?.[LOC]?.end }, + [LOCSRCID]: stream[index][LOCSRCID], + [LOCSTA]: stream[index][LOCSTA], + [LOCEND]: stream[index][LOCEND], }); isVarDeclaration = true; break; @@ -3144,14 +3271,15 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { typ: EnumToken.AtRuleNodeType, val: renderTokens(stream, options), - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -3166,10 +3294,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { typ: EnumToken.CssVariableImportTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Validated, [ERRORS]: [], @@ -3180,19 +3307,15 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { typ: EnumToken.CssVariableTokenType, nam: nam.val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Validated, [ERRORS]: [], }; } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[STATE] = EnumAstNodeStatus.Validated; atRule[ERRORS] = []; // @ts-expect-error @@ -3212,13 +3335,17 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { // check or and and result = matchGenericSyntax(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } else { result = matchAtRuleSyntax(atRule, stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } if (result.success) { let i = 0; @@ -3230,7 +3357,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } if (stream[i].typ === EnumToken.EndParensTokenType && stack.length > 0) { const index = stream.indexOf(stack[stack.length - 1]); - stream[index][LOC].end = stream[i][LOC].end; + stream[index][LOCEND] = stream[i][LOCEND]; Object.assign(stream[index], { typ: tokensfuncDefMap.get(stream[index].typ), chi: stream.splice(index + 1, i - index - 1), @@ -3238,15 +3365,11 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC].end, - }; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.errors; @@ -3272,7 +3395,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { */ async function parseDeclarations(declaration) { const stream = `.x{${declaration}}`; - return doParse(tokenize({ + return doParse(new Tokenizer({ stream, offset: 0, position: 0, @@ -3305,18 +3428,57 @@ async function parseDeclarations(declaration) { * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const tokenizer = new Tokenizer({ stream: src, + buffer: "", + src: options?.src ?? "", offset: 0, time: 0, - source: new SourceFile(src, [], ""), + source: new SourceFile(src, [], options?.src ?? ""), position: 0, currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + }); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + unit: tokenizer.unit, + }; + } + else if (tokenizer.val === null) { + token = { + typ: tokenizer.typ, + }; + } + else if (tokenizer.kin != null) { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + kin: tokenizer.kin, + }; + } + else { + token = { + typ: tokenizer.typ, + val: tokenizer.val, + }; + } + token[LOCSRCID] = tokenizer.source.id; + token[LOCEND] = tokenizer.end; + token[LOCSTA] = tokenizer.sta; + mapped.push(token); } const result = parseTokens(mapped, options, errors); // remove EOF token @@ -3362,7 +3524,7 @@ function parseTokens(tokens, options, errors) { val: (tokens[i - 1].typ === EnumToken.ColonTokenType ? ":" : "::") + tokens[i].val, }); - t[LOC].end = tokens[i][LOC].end; + t[LOCEND] = tokens[i][LOCEND]; tokens.splice(i--, 1); } } @@ -3381,7 +3543,7 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token ')'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); // return []; continue; @@ -3409,13 +3571,13 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token ']'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); continue; } index = tokens.indexOf(stack.at(-1)); const attr = stack.at(-1); - attr[LOC].end = t[LOC].end; + attr[LOCEND] = t[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: EnumToken.AttrTokenType, @@ -3531,9 +3693,8 @@ function parseTokens(tokens, options, errors) { action: "drop", message: `Unbalanced token. Expecting ${node.typ === EnumToken.AttrStartTokenType ? "']'" : ")"}'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index efd932cb..3d76a7a8 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -1,97 +1,81 @@ import { EnumToken, ColorType } from '../ast/types.js'; -import { LOC, wildCardFuncs, whenElseFunc, transformFunctions, mathFuncs, colorsFunc, timingFunc, supportFunc, timelineFunc, imageFunc, gridTemplateFunc, urlFunc, containerFunc, pseudoElements } from '../syntax/constants.js'; -import { isDigit, isWhiteSpace, isIdent, isHexColor, isHash, isNumber, isPercentage, parseDimension, isNewLine, isIdentStart, isIdentCodepoint, isNonPrintable } from '../syntax/syntax.js'; +import { wildCardFuncs, whenElseFunc, mathFuncs, timingFunc, supportFunc, timelineFunc, imageFunc, gridTemplateFunc, urlFunc, containerFunc, colorsFunc, transformFunctions, pseudoElements } from '../syntax/constants.js'; +import { isWhiteSpace, isNewLine, isDigit, isLetter, isIdentStart, isIdentCodepoint, isNonPrintable, timeUnits, angleUnits, flexUnits, dimensionUnits, resolutionUnits, frequencyUnits } from '../syntax/syntax.js'; import { SourceFile } from './source.js'; -import { equalsIgnoreCase } from './utils/text.js'; -const SymbolsMapTokens = { - "+": EnumToken.Plus, - "=": EnumToken.DelimTokenType, - "|": EnumToken.Pipe, - "||": EnumToken.ColumnCombinatorTokenType, - "|=": EnumToken.DashMatchTokenType, - "&": EnumToken.NestingSelectorTokenType, - "*": EnumToken.Star, - "*=": EnumToken.ContainMatchTokenType, - "~": EnumToken.Tilda, - "~=": EnumToken.IncludeMatchTokenType, - "^=": EnumToken.StartMatchTokenType, - "$=": EnumToken.EndMatchTokenType, - ",": EnumToken.Comma, - ":": EnumToken.ColonTokenType, - "::": EnumToken.DoubleColonTokenType, - ";": EnumToken.SemiColonTokenType, - "(": EnumToken.StartParensTokenType, - ")": EnumToken.EndParensTokenType, - "[": EnumToken.AttrStartTokenType, - "]": EnumToken.AttrEndTokenType, - "{": EnumToken.BlockStartTokenType, - "}": EnumToken.BlockEndTokenType, - "<=": EnumToken.LteTokenType, - ">": EnumToken.GtTokenType, - ">=": EnumToken.GteTokenType, - " ": EnumToken.Whitespace, - "\t": EnumToken.Whitespace, - "\r": EnumToken.Whitespace, - "\n": EnumToken.Whitespace, - "\f": EnumToken.Whitespace, - ...pseudoElements.reduce((acc, curr) => { - acc[curr] = EnumToken.PseudoElementTokenType; - return acc; - }, Object.create(null)), - ...containerFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.ContainerFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...urlFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.UrlFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...gridTemplateFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.GridTemplateFuncTokenDefType; - return acc; - }, Object.create(null)), - ...imageFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.ImageFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timelineFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.TimelineFunctionTokenDefType; - return acc; - }, Object.create(null)), - // ...generalEnclosedFunc.reduce((acc, curr: string) => { - // acc[curr + "("] = EnumToken.GeneralEnclosedFunctionTokenDefType; - // return acc; - // }, Object.create(null)), - ...supportFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.SupportsFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timingFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.TimingFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...colorsFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.ColorFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...mathFuncs.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.MathFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...transformFunctions.reduce((acc, curr) => { - acc[curr.toLowerCase() + "("] = EnumToken.TransformFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...whenElseFunc.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.WhenElseFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...wildCardFuncs.reduce((acc, curr) => { - acc[curr + "("] = EnumToken.WildCardFunctionTokenDefType; - return acc; - }, Object.create(null)), -}; +const SymbolsMapTokens = Object.create(null); +// Regex for escape sequence decoding - compile once, reuse many times +const ESCAPE_SEQUENCE_REGEX = /\\([0-9a-fA-F]{1,6})(?:\s)?/g; +function decodeEscapeSequences(value) { + return value.replace(ESCAPE_SEQUENCE_REGEX, (_, sequence) => { + const codepoint = parseInt(sequence, 16); + if (codepoint == 0 || + // leading surrogate + (0xd800 <= codepoint && codepoint <= 0xdbff) || + // trailing surrogate + (0xdc00 <= codepoint && codepoint <= 0xdfff) || + codepoint > 0x10ffff) { + return "\uFFFD"; + } + return String.fromCodePoint(codepoint); + }); +} +function assignTokenMap(entries, tokenType, suffix = "", lowercase = false) { + for (const entry of entries) { + SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + } +} +SymbolsMapTokens[""] = EnumToken.DelimTokenType; +SymbolsMapTokens["+"] = EnumToken.Plus; +SymbolsMapTokens["="] = EnumToken.DelimTokenType; +SymbolsMapTokens["|"] = EnumToken.Pipe; +SymbolsMapTokens["||"] = EnumToken.ColumnCombinatorTokenType; +SymbolsMapTokens["|="] = EnumToken.DashMatchTokenType; +SymbolsMapTokens["&"] = EnumToken.NestingSelectorTokenType; +SymbolsMapTokens["*"] = EnumToken.Star; +SymbolsMapTokens["*="] = EnumToken.ContainMatchTokenType; +SymbolsMapTokens["~"] = EnumToken.Tilda; +SymbolsMapTokens["~="] = EnumToken.IncludeMatchTokenType; +SymbolsMapTokens["^="] = EnumToken.StartMatchTokenType; +SymbolsMapTokens["$="] = EnumToken.EndMatchTokenType; +SymbolsMapTokens[","] = EnumToken.Comma; +SymbolsMapTokens[":"] = EnumToken.ColonTokenType; +SymbolsMapTokens["::"] = EnumToken.DoubleColonTokenType; +SymbolsMapTokens[";"] = EnumToken.SemiColonTokenType; +SymbolsMapTokens["("] = EnumToken.StartParensTokenType; +SymbolsMapTokens[")"] = EnumToken.EndParensTokenType; +SymbolsMapTokens["["] = EnumToken.AttrStartTokenType; +SymbolsMapTokens["]"] = EnumToken.AttrEndTokenType; +SymbolsMapTokens["{"] = EnumToken.BlockStartTokenType; +SymbolsMapTokens["}"] = EnumToken.BlockEndTokenType; +SymbolsMapTokens["<="] = EnumToken.LteTokenType; +SymbolsMapTokens[">"] = EnumToken.GtTokenType; +SymbolsMapTokens[">="] = EnumToken.GteTokenType; +SymbolsMapTokens[" "] = EnumToken.Whitespace; +SymbolsMapTokens["\t"] = EnumToken.Whitespace; +SymbolsMapTokens["\r"] = EnumToken.Whitespace; +SymbolsMapTokens["\n"] = EnumToken.Whitespace; +SymbolsMapTokens["\f"] = EnumToken.Whitespace; +assignTokenMap(flexUnits, EnumToken.FlexTokenType); +assignTokenMap(dimensionUnits, EnumToken.LengthTokenType); +assignTokenMap(resolutionUnits, EnumToken.ResolutionTokenType); +assignTokenMap(angleUnits, EnumToken.AngleTokenType); +assignTokenMap(timeUnits, EnumToken.TimeTokenType); +assignTokenMap(frequencyUnits, EnumToken.FrequencyTokenType); +assignTokenMap(pseudoElements, EnumToken.PseudoElementTokenType); +assignTokenMap(containerFunc, EnumToken.ContainerFunctionTokenDefType, "("); +assignTokenMap(urlFunc, EnumToken.UrlFunctionTokenDefType, "("); +assignTokenMap(gridTemplateFunc, EnumToken.GridTemplateFuncTokenDefType, "("); +assignTokenMap(imageFunc, EnumToken.ImageFunctionTokenDefType, "("); +assignTokenMap(timelineFunc, EnumToken.TimelineFunctionTokenDefType, "("); +assignTokenMap(supportFunc, EnumToken.SupportsFunctionTokenDefType, "("); +assignTokenMap(timingFunc, EnumToken.TimingFunctionTokenDefType, "("); +assignTokenMap(colorsFunc, EnumToken.ColorFunctionTokenDefType, "("); +assignTokenMap(mathFuncs, EnumToken.MathFunctionTokenDefType, "("); +assignTokenMap(transformFunctions, EnumToken.TransformFunctionTokenDefType, "(", true); +assignTokenMap(whenElseFunc, EnumToken.WhenElseFunctionTokenDefType, "("); +assignTokenMap(wildCardFuncs, EnumToken.WildCardFunctionTokenDefType, "("); +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); // do not capture the value const hintsEnum = new Set([ EnumToken.CommaTokenType, @@ -134,818 +118,1494 @@ var TokenMap; TokenMap[TokenMap["PLUS"] = 43] = "PLUS"; TokenMap[TokenMap["MINUS"] = 45] = "MINUS"; TokenMap[TokenMap["GREATERTHAN"] = 62] = "GREATERTHAN"; + TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; })(TokenMap || (TokenMap = {})); -function consumeString(parseInfo) { - const quote = next(parseInfo).charCodeAt(0); - let charCode; - let decodeSegments = false; - const result = []; - while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { - if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { - next(parseInfo, 2); - continue; - } - const sequence = peek(parseInfo, 7); - let escapeSequence = ""; - let codepoint; - let i; - for (i = 1; i < sequence.length; i++) { - codepoint = sequence.charCodeAt(i); - if (codepoint == 0x20 || - (codepoint >= 0x61 && codepoint <= 0x66) || - (codepoint >= 0x41 && codepoint <= 0x46) || - (codepoint >= 0x30 && codepoint <= 0x39)) { - escapeSequence += sequence[i]; - if (codepoint == 0x20) { - break; - } - continue; - } +function getSymbolHint(parseInfo, start, end) { + const len = end - start; + const keysLength = SymbolsMapTokensKeys.length; + // Early exit for impossible lengths + if (len < 0) + return null; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca !== cb) { + match = false; break; } - if (escapeSequence.trimEnd().length > 0) { - // const codepoint = parseInt(escapeSequence, 16); - // TODO set decode flag ON - // if ( - // codepoint == 0 || - // // leading surrogate - // (0xd800 <= codepoint && codepoint <= 0xdbff) || - // // trailing surrogate - // (0xdc00 <= codepoint && codepoint <= 0xdfff) - // ) { - // buffer += String.fromCodePoint(0xfffd); - // } else { - // buffer += String.fromCodePoint(codepoint); - // } - const length = escapeSequence.length + - 1 + - (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) - ? 1 - : 0); - decodeSegments = true; - next(parseInfo, length); - continue; - } - next(parseInfo, 2); - continue; } - if (charCode == quote) { - next(parseInfo); - result.push(yieldResult(parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null)); - return result; + if (match) { + return SymbolsMapTokens[key]; } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BadStringTokenType)); - return result; - } - next(parseInfo); } - // EOF - 'Unclosed-string' fixed - result.push(yieldResult(parseInfo, EnumToken.StringTokenType)); - return result; + return null; } -function yieldResult(parseInfo, hint, options) { - let val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); - let token = null; - let dimension; - if (options?.decodeSegments) { - val = val.replace(/\\([0-9a-fA-F]{1,6})(?:\s)?/g, (_, sequence) => { - const codepoint = parseInt(sequence, 16); - if (codepoint == 0 || - // leading surrogate - (0xd800 <= codepoint && codepoint <= 0xdbff) || - // trailing surrogate - (0xdc00 <= codepoint && codepoint <= 0xdfff) || - codepoint > 0x10ffff) { - return "\uFFFD"; - } - return String.fromCodePoint(codepoint); - }); - } - if (hint != null) { - let searchArray = null; - switch (hint) { - case EnumToken.TransformFunctionTokenDefType: - searchArray = transformFunctions; - break; - case EnumToken.ColorFunctionTokenDefType: - searchArray = colorsFunc; - break; - case EnumToken.ContainerFunctionTokenDefType: - searchArray = containerFunc; - break; - case EnumToken.UrlFunctionTokenDefType: - searchArray = urlFunc; - break; - case EnumToken.GridTemplateFuncTokenDefType: - searchArray = gridTemplateFunc; - break; - case EnumToken.ImageFunctionTokenDefType: - searchArray = imageFunc; - break; - case EnumToken.TimelineFunctionTokenDefType: - searchArray = timelineFunc; - break; - // case EnumToken.GeneralEnclosedFunctionTokenDefType: - // searchArray = generalEnclosedFunc; - // break; - case EnumToken.SupportsFunctionTokenDefType: - searchArray = supportFunc; - break; - case EnumToken.TimingFunctionTokenDefType: - searchArray = timingFunc; - break; - case EnumToken.MathFunctionTokenDefType: - searchArray = mathFuncs; - break; - case EnumToken.WhenElseFunctionTokenDefType: - searchArray = whenElseFunc; - break; - case EnumToken.WildCardFunctionTokenDefType: - searchArray = wildCardFuncs; +function searchArray(array, parseInfo, start, end) { + const len = end - start; + // Early exit for impossible lengths + 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) + continue; + // Match character by character + let match = true; + const arrayItem = array[i]; + 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 + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + match = false; break; - } - if (searchArray != null) { - val = searchArray.find((v) => equalsIgnoreCase(v, val)); - } - token = hintsEnum.has(hint) ? { typ: hint } : { typ: hint, val }; - } - else { - let slice = val.slice(1); - const chr = val.charAt(0); - if (chr == "!" && equalsIgnoreCase("!important", val)) { - token = { - typ: EnumToken.ImportantTokenType, - }; - } - else if (chr == "@" && isIdent(slice)) { - token = { - typ: EnumToken.AtRuleTokenType, - nam: slice, - }; - } - else if (chr == "." && isIdent(slice)) { - token = { - typ: EnumToken.ClassSelectorTokenType, - val, - }; - } - else if (chr == "#") { - if (isHexColor(val)) { - token = { - typ: EnumToken.ColorTokenType, - val: val, - kin: ColorType.HEX, - }; - } - else if (isHash(val)) { - token = { - typ: EnumToken.HashTokenType, - val: val, - }; } } - else if ("\"'".includes(chr)) { - token = { - typ: EnumToken.UnclosedStringTokenType, - val: val, - }; - } - else if (isNumber(val)) { - token = - val[0] === "-" || val[0] === "+" - ? { - typ: EnumToken.NumberTokenType, - sign: val[0], - val: +val, - } - : { - typ: EnumToken.NumberTokenType, - val: +val, - }; - } - else if (isPercentage(val)) { - token = { - typ: EnumToken.PercentageTokenType, - val: +val.slice(0, -1), - }; - } - else if ((dimension = parseDimension(val))) { - token = dimension; - } - else if (isIdent(val)) { - token = { - typ: val.startsWith("--") ? EnumToken.DashedIdenTokenType : EnumToken.IdenTokenType, - val, - }; + if (match) { + return arrayItem; } } - if (token == null) { - token = { - typ: EnumToken.LiteralTokenType, - val, - }; - } - // return token; - token[LOC] = { - srcId: parseInfo.source.id, - sta: parseInfo.position, - end: parseInfo.currentPosition, - }; - parseInfo.position = parseInfo.currentPosition; - return { token, bytesIn: parseInfo.currentPosition }; -} -function match(parseInfo, input) { - let position = parseInfo.currentPosition - parseInfo.offset; - for (let i = 0; i < input.length; i++) { - if (parseInfo.stream[position + i] != input.charAt(i)) { - return false; - } - } - return true; -} -function peek(parseInfo, count = 1) { - if (count == 1) { - return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); - } - const position = parseInfo.currentPosition - parseInfo.offset; - return parseInfo.stream.slice(position, position + count); + return null; } -function next(parseInfo, count = 1) { - let position = parseInfo.currentPosition - parseInfo.offset; - let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); - let i = 0; - let codepoint; - for (; i < char.length; i++) { - codepoint = char[i].charCodeAt(0); - if (codepoint == 0xa || // \n - codepoint == 0xb || // \v - codepoint == 0xc || // \f - codepoint == 0xd || // \r - codepoint == 0x2028 || // \u2028 - codepoint == 0x2029 // \u2029 - ) { - // \r\n - if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; - else { - parseInfo.source.lineStarts.lineStarts.push(position + i); +/** + * tokenizer class + */ +class Tokenizer { + parseInfo; + input; + /** + * token type + */ + typ = null; + /** + * token kind + */ + kin = null; + /** + * token name + */ + nam = null; + /** + * token value + */ + val = null; + /** + * token unit + */ + unit = null; + /** + * source id + */ + srcId = null; + /** + * token start + */ + sta = null; + /** + * token end + */ + end = null; + /** + * bytes in + */ + bytesIn = null; + /** + * decode string + */ + decodeString = null; + /** + * token slice + */ + slice = null; + /** + * source file + */ + source = null; + /** + * token hint + */ + hint = null; + state = null; + constructor(parseInfo, input = null) { + this.parseInfo = parseInfo; + this.input = input; + if (typeof this.parseInfo == "string") { + if (typeof parseInfo == "string") { + this.parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; } } } - parseInfo.currentPosition += char.length; - return char; -} -function isIdentToken(parseInfo, start, end) { - let j = parseInfo.currentPosition - parseInfo.offset; - let i = parseInfo.position - parseInfo.offset; - if (start != null) { - if (end == null) { - if (start < 0) { - j += start; - } - else { - i += start; + /** + * + * @param parseInfo + * @returns + */ + consumeString(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; } - } - else { - if (end < 0) { - j += end; + if (charCode == quote) { + this.advance(parseInfo); + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); } - else { - j = parseInfo.position + end; + if (isNewLine(charCode)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } + this.advance(parseInfo); } + // EOF - 'Unclosed-string' fixed + return this.makeToken(parseInfo, EnumToken.StringTokenType); + // return result; } - j--; - let codepoint = parseInfo.stream.charCodeAt(i); - // - - if (codepoint == 0x2d) { - let nextCodepoint; - if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { - return false; - } - if (isDigit(nextCodepoint)) { - return false; - } - codepoint = nextCodepoint; - i++; - } - if (codepoint !== 0x2d && !isIdentStart(codepoint)) { - return false; - } - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - codepoint = parseInfo.stream.charCodeAt(i + 1); - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - i += String.fromCodePoint(codepoint).length; - // if (i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - // } - } - while (i < j) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - continue; - } - if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { - return false; - } - } - return true; -} -function isPseudo(parseInfo) { - let position = parseInfo.currentPosition - parseInfo.offset; - let endPosition = parseInfo.currentPosition - parseInfo.offset; - return (parseInfo.stream.charAt(position) == ":" && - parseInfo.stream.charAt(endPosition - 1) == "(" && - (parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2, -1) - : isIdentToken(parseInfo, 1, -1))) || - parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2) - : isIdentToken(parseInfo, 1); -} -function startsWith(parseInfo, input) { - let i = 0; - let j = input.length; - while (i < j) { - if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { - return false; + /** + * + * @param parseInfo + * @returns + */ + consumeURLToken(parseInfo) { + const quote = this.advance(parseInfo).charCodeAt(0); + let charCode; + let decodeSegments = false; + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } + const sequence = this.peek(parseInfo, 7); + let escapeSequence = ""; + let codepoint; + let i; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); + if (codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39)) { + escapeSequence += sequence[i]; + if (codepoint == 0x20) { + break; + } + continue; + } + break; + } + if (escapeSequence.trimEnd().length > 0) { + const length = escapeSequence.length + + 1 + + (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) + ? 1 + : 0); + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } + this.advance(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.advance(parseInfo); + let k = 1; + let end = parseInfo.stream.length - parseInfo.offset; + let position = parseInfo.currentPosition - parseInfo.offset; + while (position + k < end) { + charCode = parseInfo.stream.charCodeAt(position); + // NaN != NaN + if (charCode != charCode) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } + if (isWhiteSpace(charCode)) { + this.advance(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } + break; + } + // consume until the ')' + return this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.advance(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.advance(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } + this.advance(parseInfo); + } + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); + } + this.advance(parseInfo); } - i++; + // EOF - bad url token + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + // return result; } - return true; -} -function isURLToken(parseInfo) { - let i = parseInfo.position - parseInfo.offset; - let c; - while (++i < parseInfo.currentPosition) { - c = parseInfo.stream.charCodeAt(i); - // single quote or double quote or start parenthesis or close parenthesis - if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { - return false; + /** + * consume number, dimension, or percentage + * @param parseInfo + * @returns + */ + consumeNumericToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let hasDigits = false; + let hasLetter = false; + let hasPercent = false; + let codepoint = parseInfo.stream.charCodeAt(position); + this.slice = null; + this.hint = null; + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; } - // valid escape - if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { - i++; - if (i >= parseInfo.currentPosition) { - return false; + // consume digits + while (position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + hasDigits = true; + position++; + continue; } - c = parseInfo.stream.charCodeAt(i); - // c is not '\n' or '\r' or '\f' - if (c == 0x6e || c == 0x72 || c == 0x66) { - return false; + // '.' 'E' 'e' + if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { + position++; + break; } - continue; - } - // is white space - if (c == 0x20 || c == 0x09) { - break; - } - } - return i == parseInfo.currentPosition; -} -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -function tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } - let charCode; - let nextCharCode; - const startTime = performance.now(); - const result = []; - // allow 10 characters buffer for the streaming parser to avoid incomplete tokens - const endPosition = parseInfo.stream.length - 1; - // NaN is not equal to NaN - while ((charCode = peek(parseInfo).charCodeAt(0)) == charCode) { - switch (charCode) { - case 61 /* TokenMap.EQUALS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.DelimTokenType)); + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; break; - // '+' or '-' - case 43 /* TokenMap.PLUS */: - case 45 /* TokenMap.MINUS */: - nextCharCode = peek(parseInfo).charCodeAt(0); - // not a number - if (charCode === 43 /* TokenMap.PLUS */ && !(nextCharCode >= 0x30 && nextCharCode <= 0x39)) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase()])); - break; - } - next(parseInfo); + } + if (isLetter(codepoint)) { + hasLetter = true; break; - // '{' - case 123 /* TokenMap.LEFT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + } + return 0; + } + if (!hasLetter && !hasPercent) { + // '.' + if (codepoint == 0x2e) { + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint) { + return !hasDigits ? 0 : position - offset; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return !hasDigits ? 0 : position - offset; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BlockEndTokenType)); - break; - // '(' - case 40 /* TokenMap.LEFT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && isPseudo(parseInfo)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.PseudoClassFunctionTokenDefType)); + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + } + else if (isLetter(codepoint)) { + hasLetter = true; + } + else { + return 0; + } + } + else { + position++; + hasDigits = true; + } + } + if (!hasLetter && !hasPercent) { + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; + } + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + position++; break; } - else if (isIdentToken(parseInfo)) { - const hint = startsWith(parseInfo, "--") - ? EnumToken.CustomFunctionTokenDefType - : (SymbolsMapTokens[parseInfo.stream - .slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset) - .toLowerCase() + "("] ?? EnumToken.FunctionTokenDefType); - result.push(yieldResult(parseInfo, hint)); - next(parseInfo); - // consume '(' - parseInfo.position = parseInfo.currentPosition; - if (hint === EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(peek(parseInfo).charCodeAt(0))) { - next(parseInfo); + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + return 0; + } + // 'E' 'e' - 'em' + if ((codepoint == 0x45 || codepoint == 0x65) && hasDigits && !hasLetter && !hasPercent) { + if (isLetter(parseInfo.stream.charCodeAt(position))) { + hasLetter = true; + } + } + if (!hasLetter && !hasPercent) { + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + codepoint = parseInfo.stream.charCodeAt(position + 1); + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + codepoint = position = parseInfo.stream.charCodeAt(position + 1); + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; + } + if (isLetter(codepoint)) { + hasLetter = true; } - charCode = peek(parseInfo).charCodeAt(0); - let values = null; - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - values = consumeString(parseInfo); + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; } else { - do { - next(parseInfo); - // value = peek(parseInfo); - charCode = peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); + return 0; } - if (values != null) { - // NaN is not equal to NaN - if ((charCode = peek(parseInfo).charCodeAt(0)) != charCode) { - for (let i = 0; i < values.length; i++) { - values[i].token.typ = EnumToken.BadUrlTokenType; - } - } - result.push(...values); + } + } + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + // eof + if (codepoint != codepoint) { + break; + } + if (isDigit(codepoint)) { + position++; + continue; + } + if (!hasDigits) { + return 0; } - else if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = peek(parseInfo).charCodeAt(0)) != charCode || !isURLToken(parseInfo) - ? EnumToken.BadUrlTokenType - : EnumToken.UrlTokenTokenType)); + if (isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + else if (isLetter(codepoint)) { + hasLetter = true; + break; + } + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; + } + else { + return 0; } } - break; + if (!hasLetter && !hasPercent) { + return position - offset; + } } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.StartParensTokenType)); - break; - // ')' - case 41 /* TokenMap.RIGHT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + } + } + if (!hasDigits) { + return 0; + } + if (hasPercent) { + const slice = position; + codepoint = parseInfo.stream.charCodeAt(++position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = EnumToken.PercentageTokenType; + return position - offset; + } + return 0; + } + if (hasLetter) { + codepoint = parseInfo.stream.charCodeAt(position - 1); + // 'E' 'e' + const slice = codepoint == 0x45 || codepoint == 0x65 ? position - 1 : position; + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(++position); + if (!isLetter(codepoint)) { + break; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.EndParensTokenType)); - break; - // '[' - case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + } + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 43 /* TokenMap.PLUS */ || + codepoint == 47 /* TokenMap.SLASH */ || + codepoint == 42 /* TokenMap.STAR */ || + codepoint == 44 /* TokenMap.COMMA */) { + this.slice = slice; + this.hint = getSymbolHint(parseInfo, slice, position) ?? EnumToken.DimensionTokenType; + return position - offset; + } + return 0; + } + return 0; + } + /** + * + * @param parseInfo + * @returns + */ + consumeIdentToken(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + if (codepoint == 45 /* TokenMap.MINUS */) { + position++; + codepoint = parseInfo.stream.charCodeAt(position); + if (!isIdentStart(codepoint) && codepoint != 45 /* TokenMap.MINUS */) { + return 0; + } + } + while ((codepoint = parseInfo.stream.charCodeAt(position)) == codepoint) { + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + // eof + if ((codepoint = parseInfo.stream.charCodeAt(position + 1)) != codepoint) { + // this.next(parseInfo, position); + return 0; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrStartTokenType)); - break; - // ']' - case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // \n \r \f \v + if (codepoint == 0xa || + codepoint == 0xb || + codepoint == 0xc || + codepoint == 0xd || + codepoint == 0x2028 || + codepoint == 0x2029) { + return 0; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrEndTokenType)); - break; - case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + position += 2; + continue; + } + if (codepoint == 0x2d || isIdentCodepoint(codepoint)) { + position++; + } + else { + switch (codepoint) { + case 58 /* TokenMap.COLON */: + case 123 /* TokenMap.LEFT_BRACE */: + case 125 /* TokenMap.RIGHT_BRACE */: + case 40 /* TokenMap.LEFT_PARENTHESIS */: + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + case 91 /* TokenMap.LEFT_BRACKETS */: + case 93 /* TokenMap.RIGHT_BRACKETS */: + case 59 /* TokenMap.SEMICOLON */: + case 33 /* TokenMap.EXCLAMATION */: + case 47 /* TokenMap.SLASH */: + case 35 /* TokenMap.HASH */: + case 42 /* TokenMap.STAR */: + case 61 /* TokenMap.EQUALS */: + case 126 /* TokenMap.TILDA */: + case 124 /* TokenMap.PIPE */: + case 94 /* TokenMap.CARET */: + case 36 /* TokenMap.DOLLAR */: + case 44 /* TokenMap.COMMA */: + case 62 /* TokenMap.GREATERTHAN */: + case 46 /* TokenMap.DOT */: + case 43 /* TokenMap.PLUS */: + return position - offset; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.SemiColonTokenType)); - break; - case 58 /* TokenMap.COLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (codepoint != codepoint || isWhiteSpace(codepoint)) { + return position - offset; } - next(parseInfo); - if (peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.DoubleColonTokenType)); + return 0; + } + } + return position - offset; + } + /** + * + * @param parseInfo + * @returns + */ + consumeColor(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let offset = position; + let codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != 35 /* TokenMap.HASH */) { + return 0; + } + position++; + let count = 0; + while (true) { + codepoint = parseInfo.stream.charCodeAt(position); + // 'a-f0-9' 'A-F0-9' + if ((codepoint >= 0x30 && codepoint <= 0x39) || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46)) { + position++; + count++; + continue; + } + break; + } + if (count != 3 && count != 4 && count != 6 && count != 8) { + return 0; + } + codepoint = parseInfo.stream.charCodeAt(position); + if (codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == 41 /* TokenMap.RIGHT_PARENTHESIS */ || + codepoint == 59 /* TokenMap.SEMICOLON */ || + codepoint == 125 /* TokenMap.RIGHT_BRACE */ || + codepoint == 44 /* TokenMap.COMMA */) { + return position - offset; + } + return 0; + } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peekCharCode(parseInfo))) { + this.advance(parseInfo); + } + charCode = this.peekCharCode(parseInfo); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + // if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType); + // } + } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ + makeToken(parseInfo, hint, options) { + let val = null; + this.typ = null; + this.nam = null; + this.val = null; + this.unit = null; + this.kin = null; + this.decodeString = null; + this.slice = null; + this.hint = null; + if (options?.slice) { + this.slice = options.slice; + } + if (options?.decodeSegments) { + this.decodeString = true; + } + if (hint != null) { + let array = null; + let hasUnit = false; + switch (hint) { + case EnumToken.TransformFunctionTokenDefType: + array = transformFunctions; break; - } - result.push(yieldResult(parseInfo, EnumToken.ColonTokenType)); - break; - // \n \r \f \v \t space - case 0x9: - case 0x20: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0x2028: - case 0x2029: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - while (nextCharCode == 0x20 || - (nextCharCode >= 0x9 && nextCharCode <= 0xd) || - nextCharCode == 0x2028 || - nextCharCode == 0x2029) { - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - } - result.push(yieldResult(parseInfo, EnumToken.WhitespaceTokenType)); - break; - case 44 /* TokenMap.COMMA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommaTokenType)); - break; - case 36 /* TokenMap.DOLLAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "$=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.EndMatchTokenType)); + case EnumToken.ColorFunctionTokenDefType: + array = colorsFunc; break; - } - next(parseInfo); - break; - case 126 /* TokenMap.TILDA */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "~=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.IncludeMatchTokenType)); + case EnumToken.ContainerFunctionTokenDefType: + array = containerFunc; + break; + case EnumToken.UrlFunctionTokenDefType: + array = urlFunc; + break; + case EnumToken.GridTemplateFuncTokenDefType: + array = gridTemplateFunc; + break; + case EnumToken.ImageFunctionTokenDefType: + array = imageFunc; + break; + case EnumToken.TimelineFunctionTokenDefType: + array = timelineFunc; + break; + // case EnumToken.GeneralEnclosedFunctionTokenDefType: + // searchArray = generalEnclosedFunc; + // break; + case EnumToken.SupportsFunctionTokenDefType: + array = supportFunc; + break; + case EnumToken.TimingFunctionTokenDefType: + array = timingFunc; + break; + case EnumToken.MathFunctionTokenDefType: + array = mathFuncs; break; + case EnumToken.WhenElseFunctionTokenDefType: + array = whenElseFunc; + break; + case EnumToken.WildCardFunctionTokenDefType: + array = wildCardFuncs; + break; + case EnumToken.FrequencyTokenType: + array = frequencyUnits; + hasUnit = true; + break; + case EnumToken.ResolutionTokenType: + array = resolutionUnits; + hasUnit = true; + break; + case EnumToken.LengthTokenType: + array = dimensionUnits; + hasUnit = true; + break; + case EnumToken.FlexTokenType: + array = flexUnits; + hasUnit = true; + break; + case EnumToken.AngleTokenType: + array = angleUnits; + hasUnit = true; + break; + case EnumToken.TimeTokenType: + array = timeUnits; + hasUnit = true; + break; + case EnumToken.DimensionTokenType: + hasUnit = true; + break; + } + if (array != null) { + val = searchArray(array, parseInfo, hasUnit ? options?.slice : parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + else if (!hintsEnum.has(hint)) { + val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + } + if (this.decodeString) { + val = decodeEscapeSequences(val); + } + if (hintsEnum.has(hint)) { + this.typ = hint; + } + else { + this.typ = hint; + if (hasUnit || hint == EnumToken.PercentageTokenType || hint == EnumToken.DimensionTokenType) { + this.val = parseFloat(parseInfo.stream.slice(parseInfo.position - parseInfo.offset, options?.slice)); + if (hint != EnumToken.PercentageTokenType) { + this.unit = val; + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Tilda)); - break; - // case '^': - case 94 /* TokenMap.CARET */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + else if (hint == EnumToken.NumberTokenType) { + this.val = parseFloat(val); } - if (match(parseInfo, "^=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.StartMatchTokenType)); - break; + else if (hint == EnumToken.AtRuleTokenType) { + this.nam = val; } - next(parseInfo); - break; - case 42 /* TokenMap.STAR */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + else { + this.val = val; + if (hint == EnumToken.ColorTokenType) { + this.kin = ColorType.HEX; + } } - if (match(parseInfo, "*=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ContainMatchTokenType)); - break; + } + } + else { + if (this.equalsIgnoreCase(parseInfo, "!important")) { + this.typ = EnumToken.ImportantTokenType; + } + } + if (this.typ == null) { + val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + if (options?.decodeSegments) { + val = decodeEscapeSequences(val); + this.decodeString = true; + } + this.typ = EnumToken.LiteralTokenType; + this.val = val; + } + this.srcId = parseInfo.source.id; + this.sta = parseInfo.position; + this.end = parseInfo.currentPosition; + this.bytesIn = parseInfo.currentPosition; + parseInfo.position = parseInfo.currentPosition; + return this; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + equalsIgnoreCase(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + let ca; + let cb; + for (let i = 0; i < input.length; i++) { + ca = parseInfo.stream.charCodeAt(position + i); + cb = input.charCodeAt(i); + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) + ca += 32; + if (cb >= 65 && cb <= 90) + cb += 32; + if (ca != cb) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @param input + * @returns + */ + match(parseInfo, input) { + let position = parseInfo.currentPosition - parseInfo.offset; + for (let i = 0; i < input.length; i++) { + if (parseInfo.stream[position + i] != input.charAt(i)) { + return false; + } + } + return true; + } + /** + * Get the current character code without creating a string + * @param parseInfo + * @returns charCode at current position + */ + peekCharCode(parseInfo) { + return parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + peek(parseInfo, count = 1) { + if (count == 1) { + return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); + } + const position = parseInfo.currentPosition - parseInfo.offset; + return parseInfo.stream.slice(position, position + count); + } + /** + * + * @param parseInfo + * @param count + * @returns + */ + advance(parseInfo, count = 1) { + let position = parseInfo.currentPosition - parseInfo.offset; + let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); + let i = 0; + let codepoint; + const lineStarts = parseInfo.source.lineStarts.lineStarts; + for (; i < char.length; i++) { + codepoint = char.charCodeAt(i); + if (codepoint == 0xa || // \n + codepoint == 0xb || // \v + codepoint == 0xc || // \f + codepoint == 0xd || // \r + codepoint == 0x2028 || // \u2028 + codepoint == 0x2029 // \u2029 + ) { + // \r\n + if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; + else { + lineStarts.push(position + parseInfo.offset + i); } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Star)); - break; - case 38 /* TokenMap.AMPERSAND */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + } + } + parseInfo.currentPosition += char.length; + return char; + } + /** + * + * @param parseInfo + * @param start + * @param end + * @returns + */ + isIdentToken(parseInfo, start, end) { + let j = parseInfo.currentPosition - parseInfo.offset; + let i = parseInfo.position - parseInfo.offset; + if (start != null) { + if (end == null) { + if (start < 0) { + j += start; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.NestingSelectorTokenType)); - break; - case 124 /* TokenMap.PIPE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + else { + i += start; } - // '||' - if (match(parseInfo, "||")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ColumnCombinatorTokenType)); - break; + } + else { + if (end < 0) { + j += end; } - else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.DashMatchTokenType)); - break; + else { + j = parseInfo.position + end; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Pipe)); - break; - case 33 /* TokenMap.EXCLAMATION */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + } + } + j--; + let codepoint = parseInfo.stream.charCodeAt(i); + // - + if (codepoint == 0x2d) { + let nextCodepoint; + // NaN != NaN + if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { + return false; + } + if (!isIdentStart(nextCodepoint) && nextCodepoint != 0x2d) { + return false; + } + codepoint = nextCodepoint; + i++; + } + if (codepoint !== 0x2d && !isIdentStart(codepoint)) { + return false; + } + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + codepoint = parseInfo.stream.charCodeAt(i + 1); + i += String.fromCodePoint(codepoint).length; + } + while (i < j) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + if (codepoint == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i); + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + continue; + } + if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { + return false; + } + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isPseudo(parseInfo) { + let position = parseInfo.currentPosition - parseInfo.offset; + let endPosition = 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 + * @param input + * @returns + */ + startsWith(parseInfo, input) { + let i = 0; + let j = input.length; + while (i < j) { + if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { + return false; + } + i++; + } + return true; + } + /** + * + * @param parseInfo + * @returns + */ + isURLToken(parseInfo) { + let i = parseInfo.position - parseInfo.offset; + let c; + while (++i < parseInfo.currentPosition) { + c = parseInfo.stream.charCodeAt(i); + // single quote or double quote or start parenthesis or close parenthesis + if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { + return false; + } + // valid escape + if (c == 92 /* TokenMap.REVERSE_SOLIDUS */) { + i++; + if (i >= parseInfo.currentPosition) { + return false; } - if (match(parseInfo, "!important")) { - next(parseInfo, 10); - result.push(yieldResult(parseInfo, EnumToken.ImportantTokenType)); - break; + c = parseInfo.stream.charCodeAt(i); + // c is not '\n' or '\r' or '\f' + if (c == 0x6e || c == 0x72 || c == 0x66) { + return false; } - next(parseInfo); + continue; + } + // is white space + if (c == 0x20 || c == 0x09) { break; - case 47 /* TokenMap.SLASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (!match(parseInfo, "/*")) { - next(parseInfo); - result.push(yieldResult(parseInfo, SymbolsMapTokens[parseInfo.stream.slice(parseInfo.position, parseInfo.currentPosition)])); - break; + } + } + return i == parseInfo.currentPosition; + } + done() { + return this.typ === EnumToken.EOF; + } + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; + this.source = parseInfo.source; + let charCode; + let nextCharCode; + // const result: TokenizeResult[] = []; + // allow 10 characters buffer for the streaming parser to avoid incomplete tokens + const endPosition = parseInfo.stream.length - 1; // yieldEOFToken ? parseInfo.stream.length - 1 : parseInfo.stream.length - 10; + let tokensCount; + // NaN is not equal to NaN + while ((charCode = this.peekCharCode(parseInfo)) == charCode) { + if (this.state === EnumToken.UrlFunctionTokenDefType) { + this.state = null; + return this.parseURLToken(parseInfo, endPosition); + } + if (parseInfo.position == parseInfo.currentPosition) { + if (charCode == 45 /* TokenMap.MINUS */ || + charCode == 43 /* TokenMap.PLUS */ || + charCode == 46 /* TokenMap.DOT */ || + 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: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + } } - next(parseInfo, 2); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 42 /* TokenMap.STAR */) { - if (match(parseInfo, "/")) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommentTokenType)); - break; + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + charCode = this.peekCharCode(parseInfo); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? EnumToken.DashedIdenTokenType + : EnumToken.IdenTokenType); } } - // else { - // buffer += value; - // } } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCommentTokenType)); + if (charCode == 64 /* TokenMap.AT */) { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.AtRuleTokenType); + } + } } - break; - case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ColorTokenType); + } + this.advance(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.HashTokenType); + } } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.GteTokenType)); + } + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + 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); + } + 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: "+", + }); + } + } + return this.makeToken(parseInfo, EnumToken.Plus); + case 45 /* TokenMap.MINUS */: + if (parseInfo.position == parseInfo.currentPosition) { + nextCharCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + // not a number + if (isWhiteSpace(nextCharCode)) { + 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); + } + } + } + this.advance(parseInfo); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.GtTokenType)); - break; - case 60 /* TokenMap.LOWERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, "<=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.LteTokenType)); + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockStartTokenType); + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockEndTokenType); + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); + } + else if (this.isIdentToken(parseInfo)) { + const hint = this.startsWith(parseInfo, "--") + ? EnumToken.CustomFunctionTokenDefType + : (getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset + 1) ?? EnumToken.FunctionTokenDefType); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === EnumToken.UrlFunctionTokenDefType) { + this.state = hint; + } + return this; + } + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.StartParensTokenType); + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.EndParensTokenType); + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + 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); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrEndTokenType); + case 59 /* TokenMap.SEMICOLON */: + 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); + } + this.advance(parseInfo); + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); + } + return this.makeToken(parseInfo, EnumToken.ColonTokenType); + // \n \r \f \v \t space + case 0x9: + case 0x20: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x2028: + case 0x2029: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.advance(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + return this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); + case 44 /* TokenMap.COMMA */: + 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 (this.match(parseInfo, "$=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.EndMatchTokenType); + } + this.advance(parseInfo); break; - } - next(parseInfo); - if (match(parseInfo, "!--")) { - next(parseInfo, 3); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == 45 /* TokenMap.MINUS */ && match(parseInfo, "->")) { - break; + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Tilda); + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.StartMatchTokenType); + } + this.advance(parseInfo); + break; + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Star); + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); + } + else if (this.match(parseInfo, "|=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.DashMatchTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Pipe); + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, EnumToken.ImportantTokenType); + } + this.advance(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + 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)); + } + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommentTokenType); + } } } - if (parseInfo.currentPosition >= endPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCdoTokenType)); + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, EnumToken.BadCommentTokenType); } - else { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.CDOCOMMTokenType)); + break; + case 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.GteTokenType); + } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.GtTokenType); + case 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + if (this.match(parseInfo, "<=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.LteTokenType); + } + this.advance(parseInfo); + if (this.match(parseInfo, "!--")) { + this.advance(parseInfo, 3); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + return this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + } + else { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); + } } - } - break; - case 35 /* TokenMap.HASH */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - break; - case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { break; - } - next(parseInfo); - // EOF - if (!peek(parseInfo)) { - if (!yieldEOFToken) { + case 35 /* TokenMap.HASH */: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + 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 \\ + this.advance(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + return this.makeToken(parseInfo); } + return this.consumeString(parseInfo); + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.advance(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); + } + } + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; + } + this.advance(parseInfo); break; - } - next(parseInfo); - break; - case 39 /* TokenMap.SINGLE_QUOTE */: - case 34 /* TokenMap.DOUBLE_QUOTE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - result.push(...consumeString(parseInfo)); - break; - case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - next(parseInfo, 2); + default: + this.advance(parseInfo); break; - } - next(parseInfo); - break; - default: - next(parseInfo); - break; - } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + } + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - } - if (yieldEOFToken) { + // if (yieldEOFToken) { if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + return this.makeToken(parseInfo); } - result.push(yieldResult(parseInfo, EnumToken.EOFTokenType)); + return this.makeToken(parseInfo, EnumToken.EOFTokenType); + // } } - parseInfo.time += performance.now() - startTime; - return result; -} -/** - * tokenize readable stream - * @param input - * @param parseInfo - */ -async function* tokenizeStream(input, parseInfo) { - const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); - parseInfo.stream = ""; - while (true) { - const { done, value } = await reader.read(); - const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; - if (!done) { - parseInfo.source.append(stream); - parseInfo.stream = (parseInfo.stream.slice(parseInfo.position - parseInfo.offset) + stream); - parseInfo.offset = parseInfo.offset = parseInfo.position; - } - else { - parseInfo.stream = ""; - } - yield* tokenize(parseInfo, done); - if (done) { - break; + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async tokenizeStream() { + const decoder = new TextDecoder("utf-8"); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; + parseInfo.stream = ""; + while (true) { + const { done, value } = await reader.read(); + const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; + if (!done) { + parseInfo.source.append(stream); + } + else { + break; + } } + parseInfo.stream = parseInfo.source.getContent(); + return this; // .next(); } } -export { SymbolsMapTokens, TokenMap, consumeString, hintsEnum, match, next, peek, tokenize, tokenizeStream, yieldResult }; +export { TokenMap, Tokenizer, hintsEnum }; diff --git a/dist/lib/parser/utils/at-rule-container.js b/dist/lib/parser/utils/at-rule-container.js index 3fab097b..c70b54cb 100644 --- a/dist/lib/parser/utils/at-rule-container.js +++ b/dist/lib/parser/utils/at-rule-container.js @@ -1,5 +1,5 @@ import { EnumToken } from '../../ast/types.js'; -import { tokensfuncDefMap, LOC, mFGT, mFLT } from '../../syntax/constants.js'; +import { tokensfuncDefMap, LOCSTA, mFGT, mFLT, LOCEND, LOCSRCID } from '../../syntax/constants.js'; import { matchAllSyntaxes, createValidationContext, trimArray } from '../../validation/match.js'; import { ValidationSyntaxGroupEnum } from '../../validation/parser/typedef.js'; import { getSyntaxRule } from '../../validation/config.js'; @@ -28,7 +28,9 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { }, [[]]); const result = matchAllSyntaxes(syntax, createValidationContext(stream), options); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -48,19 +50,6 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { (stream[i]?.typ === EnumToken.WhitespaceTokenType || stream[i]?.typ === EnumToken.CommentTokenType)) { tokens.push(stream[i++]); } - // if (i >= stream.length) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: context, - // location: context[LOC], - // message: `expecting at ${context[LOC]?.src}:${context?.[LOC]?.sta.lin}:${context[LOC]?.sta.col}`, - // }, - // ], - // }; - // } if (stream[i].typ === EnumToken.IdenTokenType) { tokens.push(stream[i++]); } @@ -76,7 +65,7 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { { action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), // ?? context[LOC], + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting `, }, ], @@ -101,11 +90,10 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { action: "drop", node: stream[i], message: `expecting , or comma`, - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), }); break; } - // expectAndOr = false; } if (stream[i].typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(stream[i].typ)) { scopes.push((currentScope = new Set())); @@ -139,174 +127,34 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), message: ` is not allowed outside of parentheses`, }); break; } - // if (currentScope.has(val === "or" ? EnumToken.AndTokenType : EnumToken.OrTokenType)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `cannot mix and at the same level at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } currentScope.add(stream[i].typ); stack.push(stream[i]); } - // else if (scopes.length === 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unexpected at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // return { - // success, - // errors, - // }; - // } } break; case EnumToken.EndParensTokenType: - // feature - // if (mFLT.has(stack.at(-1)?.typ) || mFGT.has(stack.at(-1)?.typ)) { - // // | - // const index: number = tokens.indexOf(stack.at(-1)!); - // const prevToken: Token = stack[stack.length - 2]; - // if (mFLT.has(prevToken?.typ) || mFGT.has(prevToken?.typ)) { - // if (stack[stack.length - 3]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `unmatched '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!mFLT.has(stack.at(-1)?.typ) && mFLT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } else if (!mFGT.has(stack.at(-1)?.typ) && mFGT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // break; - // } - // // - // // const index: number = tokens.indexOf(stack.at(-1)!); - // // | - // const index2: number = tokens.indexOf(prevToken); - // // '(' - // const index3: number = tokens.indexOf(stack.at(-3)!); - // const left: Token[] = trimArray(tokens.slice(index3 + 1, index2)); - // const right: Token[] = trimArray(tokens.slice(index + 1, tokens.length - 1)); - // const names: Token[] = trimArray(tokens.slice(index2 + 1, index)); - // if (!isStyleFeatureValue(left)) { - // success = false; - // errors.push({ - // action: "drop", - // node: left[0], - // message: `expected at ${left[0]?.[LOC]?.src}:${left[0]?.[LOC]?.sta.lin}:${left[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(right)) { - // success = false; - // errors.push({ - // action: "drop", - // node: right[0], - // message: `expected at ${right[0]?.[LOC]?.src}:${right[0]?.[LOC]?.sta.lin}:${right[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // if (!isStyleFeatureValue(names)) { - // success = false; - // errors.push({ - // action: "drop", - // node: names[0], - // message: `expected at ${names[0]?.[LOC]?.src}:${names[0]?.[LOC]?.sta.lin}:${names[0]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // tokens.splice(index3 + 1, tokens.length - index3 - 2, { - // typ: EnumToken.ContainerStyleRangeTokenType, - // l: left, - // op: names, - // r: right, - // [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, - // } as ContainerStyleRangeToken); - // // check or - // stack.pop(); - // stack.pop(); - // } else if (stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `expected '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // } if (mFGT.has(stack.at(-1)?.typ) || mFLT.has(stack.at(-1)?.typ) || stack.at(-1)?.typ === EnumToken.DelimTokenType || stack.at(-1)?.typ === EnumToken.ColonTokenType) { stack[stack.length - 2].val?.toLowerCase?.(); - // if ( - // stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType && - // !( - // stack[stack.length - 2]?.typ === EnumToken.ContainerFunctionTokenDefType && - // ("style" === funcName || "scroll-state" === funcName) - // ) - // ) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unmatched2 ')' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } const index2 = tokens.indexOf(stack.at(-1)); const index3 = tokens.indexOf(stack.at(-2)); let names = trimArray(tokens.slice(index3 + 1, index2)); let values = trimArray(tokens.slice(index2 + 1, tokens.length - 1)); - // if ( - // stack.at(-1)?.typ !== EnumToken.ColonTokenType && - // stack.at(-1)?.typ !== EnumToken.DelimTokenType - // ) { - // const filteredNames = names.filter( - // (n) => - // n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, - // ); - // if ( - // filteredNames.length !== 1 || - // (filteredNames[0].typ !== EnumToken.IdenTokenType && - // filteredNames[0].typ !== EnumToken.DashedIdenTokenType) - // ) { - // } - // } tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); // check or } @@ -316,13 +164,15 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), }); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCSRCID] = tokens[index][LOCSRCID]; + tokens[index][LOCSTA] = tokens[index][LOCSTA]; + tokens[index][LOCEND] = stream[i][LOCEND]; if (tokens[index].chi.every((t) => t.typ === EnumToken.WhitespaceTokenType || t.typ === EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting '<${tokens[index].val}-query>'`, }); break; @@ -337,14 +187,16 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { tokens[index] = { typ: EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; if (tokens[index].chi.every((t) => t.typ === EnumToken.WhitespaceTokenType || t.typ === EnumToken.CommentTokenType)) { success = false; errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `expecting ''`, }); break; @@ -366,21 +218,12 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { errors.push({ action: "drop", node: tokens[k], - location: options.source.getSourceLocation(tokens[k]?.[LOC].sta), + location: options.source.getSourceLocation(tokens[k]?.[LOCSTA]), message: `unexpected token 'not'`, }); break; } } - // const index = tokens.indexOf(stack.at(-1)!); - // const slice = trimArray(tokens.slice(index + 1)); - // tokens[index] = { - // typ: EnumToken.MediaQueryUnaryFeatureTokenType, - // l: stack.pop()!, - // r: slice, - // [LOC]: { ...tokens[index][LOC]!, end: slice.at(-1)![LOC]!.end }, - // }; - // tokens.length = index + 1; } if (stack.at(-1)?.typ === EnumToken.AndTokenType || stack.at(-1)?.typ === EnumToken.OrTokenType) { @@ -398,31 +241,19 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOr = true; } break; - // default: - // if (tokensfuncDefMap.has(stream[i]?.typ)) { - // stack.push(stream[i]); - // scopes.push((currentScope = new Set())); - // } - // break; } if (!success) { break; } } - // if (success && stack.length > 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${EnumToken[stack.at(-1)?.typ]}' at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // } if (!success) { return { success, @@ -430,17 +261,18 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { }; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } } } stream.length = 0; stream.push(...parts .filter((p) => p.length > 0 && p[0].typ !== EnumToken.InvalidMediaQueryTokenType) .reduce((acc, b) => { - // if (acc.length > 0) { - // acc.push({ typ: EnumToken.CommaTokenType }); - // } - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { diff --git a/dist/lib/parser/utils/at-rule-generic.js b/dist/lib/parser/utils/at-rule-generic.js index c2ce5e64..56f49e13 100644 --- a/dist/lib/parser/utils/at-rule-generic.js +++ b/dist/lib/parser/utils/at-rule-generic.js @@ -1,5 +1,5 @@ import { EnumToken } from '../../ast/types.js'; -import { tokensfuncDefMap, LOC } from '../../syntax/constants.js'; +import { tokensfuncDefMap, LOCSTA } from '../../syntax/constants.js'; import { equalsIgnoreCase } from './text.js'; function matchGenericSyntax(stream, options) { @@ -28,7 +28,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -43,7 +43,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -59,7 +59,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -75,7 +75,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }); success = false; break; @@ -95,8 +95,7 @@ function matchGenericSyntax(stream, options) { action: "drop", message: `unexpected token ${EnumToken[stack.at(-1)?.typ]}`, node: stack.at(-1), - // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)?.[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)?.[LOCSTA]), }); success = false; } diff --git a/dist/lib/parser/utils/at-rule-import.js b/dist/lib/parser/utils/at-rule-import.js index 39995e80..69c21674 100644 --- a/dist/lib/parser/utils/at-rule-import.js +++ b/dist/lib/parser/utils/at-rule-import.js @@ -2,7 +2,7 @@ import { EnumToken } from '../../ast/types.js'; import { getSyntaxRule } from '../../validation/config.js'; import { trimArray } from '../../validation/match.js'; import { ValidationSyntaxGroupEnum } from '../../validation/parser/typedef.js'; -import { tokensfuncDefMap, LOC } from '../../syntax/constants.js'; +import { tokensfuncDefMap, LOCEND, LOCSTA } from '../../syntax/constants.js'; import { parseMediaqueryList } from './at-rule-media.js'; import { parseAtRuleSupportSyntax } from './at-rule-support.js'; @@ -38,11 +38,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { } } const slice = stream.slice(index + 1, k); - // @ts-expect-error - stream[0][LOC] = { - ...stream[0][LOC], - end: stream[1][LOC].end, - }; + stream[0][LOCEND] = stream[1][LOCEND]; tokens.push(Object.assign({ typ: tokensfuncDefMap.get(stream[0].typ), chi: trimArray(slice), @@ -58,7 +54,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: "Expected string or url()", syntax: "@import", node: stream[0], - location: stream[0]?.[LOC], + location: options.source.getSourceLocation(stream[0]?.[LOCSTA]), }, ], }; @@ -88,7 +84,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -115,7 +111,7 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -157,7 +153,9 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { { const result = parseAtRuleSupportSyntax(tokens[tokens.length - 1].chi, context, options); if (!result.success && result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, errors, @@ -167,15 +165,21 @@ function matchAtRuleImportSyntax(atRule, stream, context, options) { } const splice = stream.splice(index, stream.length - index); const sliced = parseMediaqueryList(splice, options); - tokens.push(...splice); + for (const sp of splice) { + tokens.push(sp); + } if (sliced.errors.length > 0) { - errors.push(...sliced.errors); + for (const error of sliced.errors) { + errors.push(error); + } } if (!sliced.success) { success = false; } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors, diff --git a/dist/lib/parser/utils/at-rule-media.js b/dist/lib/parser/utils/at-rule-media.js index 94a81b32..f971a3f3 100644 --- a/dist/lib/parser/utils/at-rule-media.js +++ b/dist/lib/parser/utils/at-rule-media.js @@ -1,7 +1,7 @@ import { EnumToken } from '../../ast/types.js'; import { evaluate } from '../../ast/math/expression.js'; import { gcd } from '../../ast/math/math.js'; -import { tokensfuncDefMap, mediaTypes, LOC, mFLT, mFGT } from '../../syntax/constants.js'; +import { tokensfuncDefMap, mediaTypes, LOCSTA, LOCEND, mFLT, mFGT, LOCSRCID } from '../../syntax/constants.js'; import { trimArray, matchAllSyntaxes, createValidationContext, getMFInfo, isMFValue } from '../../validation/match.js'; import { ValidationSyntaxGroupEnum, MediaFeatureType } from '../../validation/parser/typedef.js'; import { getParsedSyntax } from '../../validation/config.js'; @@ -61,7 +61,7 @@ function parseMediaqueryList(stream, options) { action: "drop", message: `expecting ''`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -71,7 +71,7 @@ function parseMediaqueryList(stream, options) { action: "drop", message: `expecting '('`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -113,7 +113,7 @@ function parseMediaqueryList(stream, options) { action: "drop", node: stream[i], message: ` is not allowed outside of parentheses`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); break; } @@ -123,7 +123,7 @@ function parseMediaqueryList(stream, options) { action: "drop", node: stream[i], message: `cannot mix and at the same level`, - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } currentScope.add(stream[i].typ); @@ -134,7 +134,7 @@ function parseMediaqueryList(stream, options) { case EnumToken.EndParensTokenType: if (tokensfuncDefMap.has(stack.at(-1)?.typ)) { const index = tokens.indexOf(stack.at(-1)); - tokens[index][LOC] = { ...tokens[index][LOC], end: stream[i][LOC].end }; + tokens[index][LOCEND] = stream[i][LOCEND]; Object.assign(tokens[index], { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), @@ -145,7 +145,9 @@ function parseMediaqueryList(stream, options) { scopes.pop(); currentScope = scopes.at(-1); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } success = false; } break; @@ -177,7 +179,9 @@ function parseMediaqueryList(stream, options) { val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -212,7 +216,9 @@ function parseMediaqueryList(stream, options) { op1: prevToken, op2: stack.at(-1), r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }); stack.pop(); stack.pop(); @@ -240,7 +246,9 @@ function parseMediaqueryList(stream, options) { val[l].val === "calc") { const value = evaluate([val[l]]); if (value.length == 1) { - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -256,7 +264,7 @@ function parseMediaqueryList(stream, options) { errors.push({ action: "drop", node: arr[0], - location: options.source.getSourceLocation(arr[0]?.[LOC].sta), + location: options.source.getSourceLocation(arr[0]?.[LOCSTA]), message: `${mfValue.isValueAllowed === false ? "invalid " : "expected "}`, }); break; @@ -277,13 +285,15 @@ function parseMediaqueryList(stream, options) { val.splice(0, val.length, ...filteredValues); } } + // @ts-expect-error tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop(), r: values, - // @ts-expect-error - [LOC]: { ...names[0][LOC], end: values.at(-1)[LOC].end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)[LOCEND], }); } if (stack.length === 0) { @@ -291,7 +301,7 @@ function parseMediaqueryList(stream, options) { errors.push({ action: "drop", node: stream[i], - location: options.source.getSourceLocation(stream[i]?.[LOC].sta), + location: options.source.getSourceLocation(stream[i]?.[LOCSTA]), message: `unmatched ')'`, }); break; @@ -301,8 +311,9 @@ function parseMediaqueryList(stream, options) { tokens[index] = { typ: EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - // @ts-expect-error - [LOC]: { ...tokens[index][LOC], end: stream[i][LOC].end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i][LOCEND], }; tokens.length = index + 1; scopes.pop(); @@ -324,7 +335,9 @@ function parseMediaqueryList(stream, options) { op: stack.pop(), l: left, r: right, - [LOC]: { ...left[0][LOC], end: right.at(-1)[LOC].end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)[LOCEND], }; tokens.length = l + 1; expectAndOrComma = true; @@ -341,7 +354,9 @@ function parseMediaqueryList(stream, options) { parts.splice(parts.indexOf(stream), 1); } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const t of trimArray(tokens)) { + stream.push(t); + } } } stream.length = 0; @@ -351,7 +366,9 @@ function parseMediaqueryList(stream, options) { if (acc.length > 0) { acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...b); + for (const t of b) { + acc.push(t); + } return acc; }, [])); return { diff --git a/dist/lib/parser/utils/at-rule-support.js b/dist/lib/parser/utils/at-rule-support.js index d1a0f235..9751c7d5 100644 --- a/dist/lib/parser/utils/at-rule-support.js +++ b/dist/lib/parser/utils/at-rule-support.js @@ -1,5 +1,5 @@ import { EnumToken } from '../../ast/types.js'; -import { pseudoElements, LOC, tokensfuncDefMap } from '../../syntax/constants.js'; +import { pseudoElements, LOCEND, tokensfuncDefMap, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; import { getSyntaxConfig, getParsedSyntax } from '../../validation/config.js'; import { trimArray, matchAllSyntaxes, createValidationContext } from '../../validation/match.js'; import { ValidationSyntaxGroupEnum } from '../../validation/parser/typedef.js'; @@ -34,7 +34,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { : EnumToken.PseudoClassTokenType, val: ":" + val, }); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -47,7 +47,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { val, }); stack.push(stream[i]); - stream[i][LOC].end = stream[i + 1][LOC].end; + stream[i][LOCEND] = stream[i + 1][LOCEND]; stream.splice(i + 1, 1); continue; } @@ -97,7 +97,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { tokens[index] = { typ: EnumToken.ParensTokenType, chi: slice, - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); tokens.pop(); @@ -111,7 +113,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), val: stack.at(-1).val, chi: trimArray(tokens.splice(index + 1, tokens.length - index - 2)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; if (tokens[index].typ === EnumToken.PseudoClassFuncTokenType) { // not a declaration @@ -142,7 +146,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { typ: EnumToken.SupportsQueryUnaryConditionTokenType, l: stack.at(-1), r: trimArray(tokens.splice(index + 1, i - index - 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; stack.pop(); } @@ -157,7 +163,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { op: stack.at(-1), l: left, r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -178,7 +186,7 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { if ("and" === val || "or" === val) { if ("or" === val && scopes.length === 1) { const fileName = options.source.getFileName() ?? ""; - const [line, column] = options.source.getOffsets(stream[i]?.[LOC]?.sta); + const [line, column] = options.source.getOffsets(stream[i]?.[LOCSTA]); return { success: false, errors: [ @@ -202,7 +210,9 @@ function parseAtRuleSupportSyntax(stream, context, options = {}) { } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } diff --git a/dist/lib/parser/utils/at-rule-when-else.js b/dist/lib/parser/utils/at-rule-when-else.js index 57babcef..954f5fee 100644 --- a/dist/lib/parser/utils/at-rule-when-else.js +++ b/dist/lib/parser/utils/at-rule-when-else.js @@ -1,6 +1,6 @@ import { EnumToken } from '../../ast/types.js'; import { trimArray } from '../../validation/match.js'; -import { tokensfuncDefMap, LOC } from '../../syntax/constants.js'; +import { tokensfuncDefMap, LOCEND, LOCSTA, LOCSRCID } from '../../syntax/constants.js'; import { parseMediaqueryList } from './at-rule-media.js'; import { parseAtRuleSupportSyntax } from './at-rule-support.js'; @@ -60,7 +60,9 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { const tokenList = [ { typ: EnumToken.StartParensTokenType, - [LOC]: { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }, + [LOCSRCID]: stream[i][LOCSRCID], + [LOCSTA]: stream[i][LOCSTA], + [LOCEND]: stream[j]?.[LOCEND], }, // @ts-expect-error ].concat(slice.slice(1)); @@ -83,32 +85,13 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { return result; } } - // else { - // errors.push({ - // action: "ignore", - // message: `unknown function '${funcName}' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // node: stream[i], - // location: stream[i][LOC], - // }); - // } - stream[i][LOC] = { ...stream[i][LOC], end: stream[j]?.[LOC]?.end }; + stream[i][LOCEND] = stream[j]?.[LOCEND]; Object.assign(stream[i], { typ: tokensfuncDefMap.get(stream[i].typ), chi: stream[i].typ === EnumToken.SupportsFunctionTokenDefType ? trimArray(slice.slice(1, -1)) : tokenList[0].chi, }); - // if (stack.at(-1)?.typ === EnumToken.NotTokenType || stack.at(-1)?.typ === EnumToken.OnlyTokenType) { - // const index: number = tokens.indexOf(stack.at(-1)!); - // tokens[index] = { - // typ: EnumToken.WhenElseUnaryConditionTokenType, - // l: stack.at(-1)!, - // r: trimArray(tokens.slice(index + 1)), - // [LOC]: { ...stack.at(-1)![LOC], end: { ...stream[i]?.[LOC]?.end } }, - // } as WhenElseUnaryConditionToken; - // tokens.length = index + 1; - // stack.pop(); - // } if (stack.at(-1)?.typ === EnumToken.AndTokenType || stack.at(-1)?.typ === EnumToken.OrTokenType) { const index = tokens.indexOf(stack.at(-1)); const index2 = stack.length > 1 ? tokens.indexOf(stack.at(-2)) + 1 : 0; @@ -117,7 +100,9 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { op: stack.at(-1), l: trimArray(tokens.slice(index2, index)), r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)[LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)[LOCSRCID], + [LOCSTA]: stack.at(-1)[LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], }; tokens.length = index2 + 1; stack.pop(); @@ -128,22 +113,10 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { break; } } - // if (stack.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${renderValue(stack.at(-1) as Token)}' at ${stack.at(-1)![LOC]!.src}:${ - // stack.at(-1)![LOC]!.sta.lin - // }:${stack.at(-1)![LOC]!.sta.col}`, - // }, - // ], - // }; - // } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } diff --git a/dist/lib/parser/utils/at-rule.js b/dist/lib/parser/utils/at-rule.js index 875d6cd5..8d759461 100644 --- a/dist/lib/parser/utils/at-rule.js +++ b/dist/lib/parser/utils/at-rule.js @@ -7,24 +7,6 @@ function matchAtRuleSyntax(atRule, stream, options) { const syntax = syntaxRules?.getPreludeRules()?.slice?.(1); trimArray(stream); if (syntax.length === 0) { - // const filtered = stream.filter( - // (token) => token.typ !== EnumToken.WhitespaceTokenType && token.typ !== EnumToken.CommentTokenType, - // ); - // if (filtered.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // message: `unexpected token ${EnumToken[filtered[0].typ]} at ${filtered[0][LOC]!.src}:${ - // filtered[0][LOC]!.sta.lin - // }:${filtered[0][LOC]!.sta.col}`, - // node: filtered[0], - // location: filtered[0][LOC]!, - // }, - // ], - // }; - // } return { success: true, errors: [] }; } const { success, errors } = matchAllSyntaxes(syntax, createValidationContext(stream), options); diff --git a/dist/lib/parser/utils/declaration.js b/dist/lib/parser/utils/declaration.js index b9150bc4..c093ee84 100644 --- a/dist/lib/parser/utils/declaration.js +++ b/dist/lib/parser/utils/declaration.js @@ -1,5 +1,5 @@ import { EnumToken, EnumAstNodeStatus, ColorType, ValidationLevel } from '../../ast/types.js'; -import { LOC, STATE, ERRORS, tokensfuncDefMap, COLORS_NAMES, nonStandardColors, systemColors, deprecatedSystemColors, tokensMap, trimTokenSpace } from '../../syntax/constants.js'; +import { LOCEND, STATE, ERRORS, LOCSTA, tokensfuncDefMap, COLORS_NAMES, nonStandardColors, systemColors, deprecatedSystemColors, tokensMap, trimTokenSpace, LOCSRCID } from '../../syntax/constants.js'; import { renamedStandardProperties, isColor, parseColor, isWhiteSpace } from '../../syntax/syntax.js'; import { getSyntaxRule, getParsedSyntax } from '../../validation/config.js'; import { trimArray, matchAllSyntaxes, createValidationContext } from '../../validation/match.js'; @@ -50,6 +50,7 @@ function parseGridTemplate(template) { * @param errors */ function parseDeclaration(tokens, parent, options, errors) { + // console.error(tokens); const name = tokens.shift(); let i; let rules = null; @@ -70,16 +71,15 @@ function parseDeclaration(tokens, parent, options, errors) { } if ((name.typ !== EnumToken.IdenTokenType && name.typ !== EnumToken.DashedIdenTokenType) || tokens[i]?.typ !== EnumToken.ColonTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND]; + } name[STATE] = EnumAstNodeStatus.Unparsed; name[ERRORS] = [ { action: "drop", node: name, - location: name[LOC], + location: options.source.getSourceLocation(name[LOCSTA]), message: "invalid declaration", }, ]; @@ -109,39 +109,6 @@ function parseDeclaration(tokens, parent, options, errors) { rules.acceptAnyDeclaration && rules.acceptAnyRule ? getParsedSyntax(ValidationSyntaxGroupEnum.Declarations, name.val.toLowerCase()) : rules.getBlockRules(); - // if (syntaxRules == null) { - // // check rule in nested context - // let pr = parent[PARENT] as AstNode | null; - // while (pr != null && pr.typ !== EnumToken.RuleNodeType) { - // pr = pr[PARENT]; - // } - // if (pr != null) { - // syntaxRules = getParsedSyntax( - // ValidationSyntaxGroupEnum.Declarations, - // name.val.toLowerCase(), - // ); - // } - // if (syntaxRules == null) { - // errors.push({ - // action: "drop", - // message: "declaration not allowed in context", - // node: name, - // location: name[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1][LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Disallowed; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } - // } } } } @@ -179,12 +146,11 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: "declaration value missing", node: name, - location: options.source.getSourceLocation(name[LOC].sta), + location: options.source.getSourceLocation(name[LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC].end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = [errors[errors.length - 1]]; // @ts-expect-error @@ -216,7 +182,9 @@ function parseDeclaration(tokens, parent, options, errors) { } } if (!doNotValidate && !result?.success && result.errors.length > 0) { - errors.push(...result.errors); + for (index = 0; index < result.errors.length; index++) { + errors.push(result.errors[index]); + } } } } @@ -234,7 +202,7 @@ function parseDeclaration(tokens, parent, options, errors) { // Object.assign(token, { // typ: EnumToken.FunctionTokenDefType, // }); - // token[LOC]!.end = tokens[i + 1][LOC]!.end; + // token[LOCEND] = tokens[i + 1][LOCEND]; // tokens.splice(i + 1, 1); // stack.push(token); // } @@ -272,26 +240,6 @@ function parseDeclaration(tokens, parent, options, errors) { } break; case EnumToken.EndParensTokenType: - // if (stack.length == 0) { - // errors.push({ - // action: "drop", - // message: "unbalanced parentheses", - // node: token, - // location: token[LOC], - // }); - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1]?.[LOC]!.end ?? name[LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Invalid; - // name[ERRORS] = [errors[errors.length - 1]]; - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } if (stack.at(-1)?.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(stack.at(-1)?.typ)) { index = tokens.indexOf(stack.at(-1)); tokens.splice(i, 1); @@ -364,9 +312,9 @@ function parseDeclaration(tokens, parent, options, errors) { // ((tokens[index] as FunctionToken).chi[l] as IdentToken | UrlToken).val + // ((tokens[index] as FunctionToken).chi[m] as ClassSelectorToken).val, // }); - // (tokens[index] as FunctionToken).chi[l][LOC]!.end = ( + // (tokens[index] as FunctionToken).chi[l][LOCEND] = ( // tokens[index] as FunctionToken - // ).chi[m][LOC]!.end; + // ).chi[m][LOCEND]; // (tokens[index] as FunctionToken).chi.splice(m, 1); // } // break; @@ -396,7 +344,7 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: `invalid color`, node: tokens[index], - location: options.source.getSourceLocation(tokens[index][LOC].sta), + location: options.source.getSourceLocation(tokens[index][LOCSTA]), }); } } @@ -448,12 +396,11 @@ function parseDeclaration(tokens, parent, options, errors) { action: "drop", message: "unbalanced token", node: stack[stack.length - 1], - location: options.source.getSourceLocation(stack[stack.length - 1][LOC].sta), + location: options.source.getSourceLocation(stack[stack.length - 1][LOCSTA]), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1][LOC].end, - }; + if (tokens[tokens.length - 1][LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = result?.errors ?? []; //@ts-expect-error @@ -486,10 +433,9 @@ function parseDeclaration(tokens, parent, options, errors) { } } if (validate && syntaxRules == null && name.typ === EnumToken.IdenTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = EnumAstNodeStatus.Unknown; name[ERRORS] = result?.errors ?? []; // @ts-expect-error @@ -498,14 +444,6 @@ function parseDeclaration(tokens, parent, options, errors) { nam: name.val, val: tokens, }); - // if ((options.validation as ValidationLevel) & ValidationLevel.Declaration) { - // errors.push({ - // action: "drop", - // message: "unknown declaration", - // node: node, - // location: node[LOC], - // }); - // } return node; } if (equalsIgnoreCase("composes", name.val)) { @@ -523,18 +461,15 @@ function parseDeclaration(tokens, parent, options, errors) { typ: EnumToken.ComposesSelectorNodeType, l: left, r: right?.[0] ?? null, - [LOC]: { - ...tokens[0][LOC], - sta: left[0]?.[LOC]?.sta, - end: index != -1 ? right[right.length - 1]?.[LOC]?.end : left[left.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: index != -1 ? right[right.length - 1]?.[LOCEND] : left[left.length - 1][LOCEND], }, ]; } - name[LOC] = { - ...name[LOC], - end: (tokens[tokens.length - 1] ?? name)[LOC].end, - }; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = success ? result == null ? EnumAstNodeStatus.Unvalidated diff --git a/dist/lib/parser/utils/hash.js b/dist/lib/parser/utils/hash.js index 5a9d6ec9..27ca4f1f 100644 --- a/dist/lib/parser/utils/hash.js +++ b/dist/lib/parser/utils/hash.js @@ -29,7 +29,7 @@ function hashId(input, length = 6) { chars.push(FIRST_ALPHABET[n % FIRST_ALPHABET.length]); // Remaining characters for (let i = 1; i < length; i++) { - n = (n + chars.length + i) % FULL_ALPHABET.length; + n = (n + chars.length * i) % FULL_ALPHABET.length; chars.push(FULL_ALPHABET[n]); } return chars.join(""); @@ -60,13 +60,13 @@ function toSortedString(input) { * @returns */ function objectHash(object) { - return hashId(toSortedString(object)); + return hashCode(toSortedString(object)).toString(16); } /** * convert input to hex * @param input */ -function toHex(input) { +function toHex(input, length) { let result = ""; if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) { for (const byte of Array.from(new Uint8Array(input))) { @@ -136,4 +136,4 @@ function syncHash(input, length = 6, algo) { return hashId(input, length); } -export { DIGITS, FIRST_ALPHABET, FULL_ALPHABET, LOWER, hash, hashAlgorithms, hashId, objectHash, syncHash }; +export { DIGITS, FIRST_ALPHABET, FULL_ALPHABET, LOWER, hash, hashAlgorithms, hashId, objectHash, syncHash, toSortedString }; diff --git a/dist/lib/parser/utils/selector.js b/dist/lib/parser/utils/selector.js index d3650aac..560cd9e8 100644 --- a/dist/lib/parser/utils/selector.js +++ b/dist/lib/parser/utils/selector.js @@ -1,6 +1,6 @@ import { EnumToken, EnumAstNodeStatus } from '../../ast/types.js'; import { renderValue } from '../../renderer/render.js'; -import { LOC, ERRORS, STATE, TOKENS, pseudoElements, combinators, tokensfuncDefMap, PARENT } from '../../syntax/constants.js'; +import { LOCEND, LOCSTA, LOCSRCID, ERRORS, STATE, TOKENS, pseudoElements, combinators, tokensfuncDefMap, PARENT } from '../../syntax/constants.js'; import { isHash } from '../../syntax/syntax.js'; import { getParsedSyntax, getSyntaxRule, getSyntaxConfig } from '../../validation/config.js'; import { matchAllSyntaxes, createValidationContext, trimArray, matchSelectorSyntax } from '../../validation/match.js'; @@ -26,7 +26,9 @@ function parseSelector(tokens, context, options, errors) { filtered[0] = { typ: EnumToken.PercentageTokenType, val: 0, - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } else if (filtered[0].typ === EnumToken.PercentageTokenType && @@ -34,7 +36,9 @@ function parseSelector(tokens, context, options, errors) { filtered[0] = { typ: EnumToken.IdenTokenType, val: "to", - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } part.splice(0, part.length, ...filtered); @@ -45,7 +49,9 @@ function parseSelector(tokens, context, options, errors) { if (acc.length > 0) { acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, [])); return { @@ -57,10 +63,9 @@ function parseSelector(tokens, context, options, errors) { }, new Set()), ].join(), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? tokens[0]?.[LOC]?.end, - }, + [LOCSRCID]: tokens[0]?.[LOCSRCID], + [LOCSTA]: tokens[0]?.[LOCSTA], + [LOCEND]: tokens[tokens.length - 1]?.[LOCEND], [TOKENS]: tokens.length === 0 ? null : tokens, [STATE]: result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -110,7 +115,7 @@ function parseSelector(tokens, context, options, errors) { typ: EnumToken.PseudoElementTokenType, val: ":" + tokens[i + 1].val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -122,7 +127,7 @@ function parseSelector(tokens, context, options, errors) { : tokens[i + 1].typ, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -134,7 +139,7 @@ function parseSelector(tokens, context, options, errors) { typ: EnumToken.PseudoClassTokenType, val: (pseudoElements.includes(val) ? "" : ":") + val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -146,7 +151,7 @@ function parseSelector(tokens, context, options, errors) { : EnumToken.FunctionTokenDefType, val, }); - tokens[i][LOC].end = tokens[i + 1][LOC].end; + tokens[i][LOCEND] = tokens[i + 1][LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -201,10 +206,9 @@ function parseSelector(tokens, context, options, errors) { .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: EnumAstNodeStatus.Invalid, [ERRORS]: [ @@ -232,10 +236,9 @@ function parseSelector(tokens, context, options, errors) { index = tokens.indexOf(stack.at(-1)); // @ts-expect-error const { val, ...attr } = stack.at(-1); - attr[LOC] = { - ...stack.at(-1)[LOC], - end: token[LOC].end, - }; + attr[LOCSRCID] = stack.at(-1)[LOCSRCID]; + attr[LOCSTA] = stack.at(-1)[LOCSTA]; + attr[LOCEND] = token[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { typ: EnumToken.AttrTokenType, @@ -253,7 +256,7 @@ function parseSelector(tokens, context, options, errors) { if (stack.at(-1)?.typ == EnumToken.PseudoClassFunctionTokenDefType) { const func = stack.at(-1); index = tokens.indexOf(func); - stack.at(-1)[LOC].end = token[LOC].end; + stack.at(-1)[LOCEND] = token[LOCEND]; tokens.splice(i, 1); if (tokensfuncDefMap.has(func.typ)) { // @ts-expect-error @@ -270,20 +273,77 @@ function parseSelector(tokens, context, options, errors) { const list = []; let index; for (index = 0; index < func.chi.length; index++) { - if (func.chi[index].typ == EnumToken.CommentTokenType || func.chi[index].typ == EnumToken.WhitespaceTokenType) { + if (func.chi[index].typ == EnumToken.CommentTokenType || + func.chi[index].typ == EnumToken.WhitespaceTokenType) { continue; } - if (func.chi[index].typ == EnumToken.IdenTokenType && equalsIgnoreCase('of', func.chi[index].val)) { + if (func.chi[index].typ == EnumToken.IdenTokenType && + equalsIgnoreCase("of", func.chi[index].val)) { index--; break; } list.push(func.chi[index]); } + if (list.length == 2) { + if (list[1].typ == EnumToken.NumberTokenType) { + if (list[1].val == 0) { + list.length = 1; + if (list[0].typ == EnumToken.DimensionTokenType && + list[0].val == -2) { + list[0].val = 2; + } + } + else { + const sign = Math.sign(list[1].val); + // @ts-ignore + list[1].val *= sign; + list.splice(1, 0, { + typ: EnumToken.LiteralTokenType, + val: sign > 0 ? "+" : "-", + }); + } + } + if (list.length == 3 && + list[2].typ == EnumToken.NumberTokenType && + list[0].typ == EnumToken.DimensionTokenType && + (list[0].val == 2 || + list[0].val == -2)) { + if (1 == list[2].val) { + list.splice(0, 3, { + typ: EnumToken.IdenTokenType, + val: "odd", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + else if (0 == list[2].val) { + list.splice(0, 3, { + typ: EnumToken.IdenTokenType, + val: "even", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + }); + } + } + func.chi.splice(0, index, ...list); + } + if (list.length == 1) { + if (list[0].typ == EnumToken.IdenTokenType && + equalsIgnoreCase("-n", list[0].val)) { + list[0].val = "n"; + } + } if (list.length == 3) { - if (list[0].typ == EnumToken.IdenTokenType && ('n' == list[0].val || '-n' == list[0].val || '+n' == list[0].val)) { + if (list[0].typ == EnumToken.IdenTokenType && + ("n" == list[0].val || + "-n" == list[0].val || + "+n" == list[0].val)) { if (list[1].typ == EnumToken.NextSiblingCombinatorTokenType) { - if (list[2].typ == EnumToken.NumberTokenType && (0 == list[2].val)) { - list[0].val = 'n'; + if (list[2].typ == EnumToken.NumberTokenType && + 0 == list[2].val) { + list[0].val = "n"; func.chi.splice(0, index, list[0]); break; } @@ -303,83 +363,10 @@ function parseSelector(tokens, context, options, errors) { } } else { - // if (!/\d+$/.test((token as IdentToken | LiteralToken).val)) { - // let index = func.chi.indexOf(token); - // let i: number = index + 1; - // let sign: Token | null = null; - // let num: NumberToken | null = null; - // for (; i < func.chi.length; i++) { - // if ( - // func.chi[i].typ == EnumToken.WhitespaceTokenType || - // func.chi[i].typ == EnumToken.CommentTokenType - // ) { - // continue; - // } - // if (func.chi[i].typ == EnumToken.NumberTokenType) { - // num = func.chi[i] as NumberToken; - // break; - // } else { - // sign = func.chi[i] as Token; - // } - // } - // if (num != null) { - // if (num.val === 0) { - // func.chi.splice(index + 1, i - index); - // if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } - // if (sign == null) { - // func.chi.splice(index + 1, i - index - 1); - // if (Math.sign(num.val as number) === 1) { - // func.chi.splice(index + 1, 0, { - // typ: EnumToken.LiteralTokenType, - // val: "+", - // }); - // } - // } - // } else if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } const matches = /^(([+-]?[0-9]*)?n)?([+-]?[0-9]+)?$/.exec(token.val); if (matches != null) { const a1 = matches[2] === "" ? 1 : matches[2] === "-" ? -1 : +matches[2]; const b1 = +matches[3]; - // if (a1 === 0) { - // if (b1 === 1) { - // let hasSelector: boolean = false; - // let i: number = func.chi.indexOf(token); - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // Object.assign(token, { - // typ: EnumToken.NumberTokenType, - // val: b1, - // }); - // } else { - // // :first-child - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // Object.assign(token, { typ: EnumToken.NumberTokenType, val: b1 }); - // } - // } else if (b1 === 0) { Object.assign(token, Math.abs(a1) === 1 ? { @@ -392,17 +379,6 @@ function parseSelector(tokens, context, options, errors) { unit: "n", }); } - // else if (Math.abs(a1) === 2) { - // if (b1 === 0) { - // Object.assign(token, { - // typ: EnumToken.DimensionTokenType, - // val: a1, - // unit: "n", - // }); - // } else if (Math.abs(b1) === 1) { - // Object.assign(token, { typ: EnumToken.IdenTokenType, val: "odd" }); - // } - // } } } } @@ -421,36 +397,6 @@ function parseSelector(tokens, context, options, errors) { } } if (num != null) { - // if ((token as DimensionToken).val === 0) { - // if (num.val === 0) { - // func.chi.splice(0, i); - // } else if (num.val === 1) { - // let hasSelector: boolean = false; - // let j: number = i + 1; - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - // if (hasSelector) { - // func.chi.splice(0, i); - // } else { - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - // break; - // } else { - // func.chi.splice(0, i); - // } - // break; - // } else if (num.val === 0) { func.chi.splice(index + 1, i - index); if (token.val < 0) { @@ -539,10 +485,9 @@ function parseSelector(tokens, context, options, errors) { .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC].end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: result.success && allowed ? EnumAstNodeStatus.Validated diff --git a/dist/lib/parser/utils/text.js b/dist/lib/parser/utils/text.js index 851c0b50..5e96cee1 100644 --- a/dist/lib/parser/utils/text.js +++ b/dist/lib/parser/utils/text.js @@ -7,9 +7,11 @@ function camelize(value) { function equalsIgnoreCase(a, b) { if (a.length !== b.length) return false; + let ca; + let cb; for (let i = 0; i < a.length; i++) { - let ca = a.charCodeAt(i); - let cb = b.charCodeAt(i); + ca = a.charCodeAt(i); + cb = b.charCodeAt(i); // Normalize A-Z to a-z if (ca >= 65 && ca <= 90) ca += 32; diff --git a/dist/lib/renderer/render.js b/dist/lib/renderer/render.js index fe00492a..000f21c0 100644 --- a/dist/lib/renderer/render.js +++ b/dist/lib/renderer/render.js @@ -3,12 +3,13 @@ import { reduceHexValue } from '../syntax/color/hex.js'; import { EnumToken, ColorType } from '../ast/types.js'; import { expand } from '../ast/expand.js'; import { SourceMap } from './sourcemap/sourcemap.js'; -import { pseudoElements, urlTokenMatcher, PARENT, tokensfuncSet, LOC, colorPrecision } from '../syntax/constants.js'; -import { minifyNumber, reducegradientBackgroundPosition, reduceConicColorStops, reduceColorStops, parseColor, toPrecisionAngle, toPrecisionValue } from '../syntax/syntax.js'; +import { pseudoElements, anglePrecision, urlTokenMatcher, PARENT, tokensfuncSet, LOCSTA, LOCSRCID } from '../syntax/constants.js'; +import { minifyNumber, toPrecisionAngle, reducegradientBackgroundPosition, reduceConicColorStops, reduceColorStops, parseColor, isWhiteSpace, toPrecisionValue } from '../syntax/syntax.js'; import { equalsIgnoreCase } from '../parser/utils/text.js'; import { toDegrees } from '../parser/utils/angle.js'; import { LineMap } from '../parser/linesmap.js'; import { dirname } from '../fs/resolve.js'; +import { SourceFile } from '../parser/source.js'; /** * render ast @@ -114,7 +115,7 @@ function doRender(data, options = {}, mapping) { source = options.sourcesMap.get(sourceId); sourcemap.addSourceContent(source.id, source.getFileName(), source.getContent()); } - sourcemap.add(...sourcemaps.maps); + sourcemap.add(sourcemaps.maps); result.map = sourcemap; if (options.sourcemap === "inline") { result.code += `\n/*# sourceMappingURL=${result.map.toUrl()} */`; @@ -136,43 +137,33 @@ function doRender(data, options = {}, mapping) { */ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str) { let offset = 0; - while (true) { - if (str.charAt(offset) == options.newLine) { - offset += options.newLine.length; - continue; - } - if (str.charAt(offset) == options.indent) { - offset += options.indent.length; - continue; - } - break; + // eat leanding whitespace + while (offset < str.length && isWhiteSpace(str.charCodeAt(offset))) { + offset++; } if (offset > 0) { - move(sourceLocation, linesMap, str.slice(0, offset)); + move(sourceLocation, linesMap, str, 0, offset + 1); } - if (node[LOC] != null && - [ - EnumToken.RuleNodeType, - EnumToken.AtRuleNodeType, - EnumToken.KeyframesRuleNodeType, - EnumToken.KeyframesAtRuleNodeType, - ].includes(node.typ)) { - const source = options.sourcesMap.get(node[LOC].srcId); + if (node[LOCSTA] != null) { + const source = options.sourcesMap.get(node[LOCSRCID]); const inputSourceMap = source.getInputSourceMap(); - const offsets = source.getOffsets(node[LOC].sta); + const offsets = source.getOffsets(node[LOCSTA]); const [newLine, newColumn] = linesMap.getOffsets(sourceLocation.end); let records = null; - let srcId = node[LOC].srcId; + let srcId = node[LOCSRCID]; let sourceFileName = source.getFileName() || null; - source.getContent() || null; + let sourceContent; // = (source.getContent() as string) || null; if (inputSourceMap != null && (records = inputSourceMap.find(offsets[0], offsets[1])) != null) { + let newId = null; for (const record of records) { + newId = null; // @ts-ignore sourceFileName = record[0] || null; // @ts-ignore offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; + sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { const absolute = options.resolve(dirname(options.output), options.cwd) @@ -185,30 +176,46 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } sourceFileName = cache[sourceFileName]; } + for (const [id, file] of options.sourcesMap.entries()) { + if (file.getFileName() === sourceFileName) { + newId = id; + break; + } + if (sourceFileName == null && file.getContent() === sourceContent) { + newId = id; + break; + } + } + if (newId == null) { + const source = new SourceFile(sourceContent, [], sourceFileName); + options.sourcesMap.set(source.id, source); + newId = source.id; + } + srcId = newId; if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } else { - if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { - if (cache[sourceFileName] == null) { - const absolute = options.resolve(dirname(options.output), options.cwd) - .absolute; - const absoluteSourceFileName = options.resolve(sourceFileName, options.cwd) - .absolute; - cache[sourceFileName] = options.resolve(absoluteSourceFileName, absolute).relative; - } - sourceFileName = cache[sourceFileName]; - } + // if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { + // if (cache[sourceFileName] == null) { + // const absolute = options.resolve!(dirname(options.output as string), options.cwd as string) + // .absolute as string; + // const absoluteSourceFileName = options.resolve!(sourceFileName, options.cwd as string) + // .absolute as string; + // cache[sourceFileName] = options.resolve!(absoluteSourceFileName, absolute).relative as string; + // } + // sourceFileName = cache[sourceFileName] as string; + // } if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -216,11 +223,12 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines * @param linesMap * @param str */ -function move(sourceLocation, linesMap, str) { - let i = 0; +function move(sourceLocation, linesMap, str, start, end) { + let i = start ?? 0; + let j = end ?? str.length; let codepoint; let char; - for (; i < str.length; i++) { + for (; i < j; i++) { char = str.charAt(i); codepoint = char.charCodeAt(0); sourceLocation.end += char.length; @@ -344,7 +352,6 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro str = options.newLine + indentSub + str; children += str; if (sourcemaps != null && str !== "") { - move(sourceLocation, linesMap, str); if (node.typ == EnumToken.DeclarationNodeType && recordDeclarationSourceMap) { // if declaration is child of at-rule, then record it // .rule { @@ -352,15 +359,11 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro // color: red; // } // } - const source = options.sourcesMap.get(node[LOC].srcId); - if (!sourcemaps.sources.includes(node[LOC].srcId)) { - sourcemaps.sources.push(node[LOC].srcId); - } - sourcemaps.maps.push([ - ...linesMap.getOffsets(sourceLocation.end - str.length + options.newLine.length + indentSub.length), - node[LOC].srcId, - ...source.getOffsets(node[LOC].sta), - ]); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } @@ -665,7 +668,9 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, // } } if (slice[i]?.typ === EnumToken.ColorTokenType) { - slice.push(...reduceColorStops(slice.splice(i, slice.length - i))); + for (const token of reduceColorStops(slice.splice(i, slice.length - i))) { + slice.push(token); + } } } break; @@ -856,32 +861,45 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, } const result = []; if (form.length > 0) { - result.push(...form); + for (const token of form) { + result.push(token); + } } if (size.length > 0) { if (result.length > 0) { result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...size); + for (const token of size) { + result.push(token); + } } if (positions.length > 0) { if (result.length > 0) { result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, ...positions); + result.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }); + for (const token of positions) { + result.push(token); + } } if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } if (result.length > 0) { result.push({ typ: EnumToken.CommaTokenType }); } - result.push(...reduceColorStops(slice.slice(i))); + for (const token of reduceColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (const token of result) { + slice.push(token); + } } break; case "conic-gradient": @@ -986,24 +1004,36 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, if (angles.length > 0) { angles.push({ typ: EnumToken.WhitespaceTokenType }); } - angles.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, ...positions); + angles.push({ typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }); + for (const position of positions) { + angles.push(position); + } } } if (angles.length > 0) { - result.push(...angles, { typ: EnumToken.CommaTokenType }); + for (const angle of angles) { + result.push(angle); + } + result.push({ typ: EnumToken.CommaTokenType }); } if (colorSpaceDef.length > 0) { if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } result.push({ typ: EnumToken.CommaTokenType }); } - result.push(...reduceConicColorStops(slice.slice(i))); + for (const token of reduceConicColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + for (let j = 0; j < result.length; j++) { + slice.push(result[j]); + } } break; } @@ -1137,29 +1167,29 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, const angle = getAngle(token); let v; let value = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { + for (const u of ["deg", "turn", "rad", "grad"]) { if (token.unit == u) { continue; } switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); - if (v.length + 4 < value.length) { + case "deg": + v = minifyNumber(toPrecisionAngle(angle * 360, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 3 < value.length) { val = v; unit = u; value = v + u; } break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); - if (v.length + 3 < value.length) { + case "turn": + v = minifyNumber(toPrecisionAngle(angle, anglePrecision, false).toFixed(anglePrecision)); + if (v.length + 4 < value.length) { val = v; unit = u; value = v + u; } break; case "rad": - v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), colorPrecision, false)); + v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), anglePrecision, false).toFixed(anglePrecision)); if (v.length + 3 < value.length) { val = v; unit = u; @@ -1167,7 +1197,7 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, } break; case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); + v = minifyNumber(toPrecisionAngle(angle * 400, anglePrecision, false).toFixed(anglePrecision)); if (v.length + 4 < value.length) { val = v; unit = u; diff --git a/dist/lib/renderer/sourcemap/sourcemap.js b/dist/lib/renderer/sourcemap/sourcemap.js index ff28f482..b5fd3905 100644 --- a/dist/lib/renderer/sourcemap/sourcemap.js +++ b/dist/lib/renderer/sourcemap/sourcemap.js @@ -107,15 +107,12 @@ class SourceMap { this.sourcesContent[this.sourcesContent.length] = content || null; } /** - * Add all location + * Add multiple sourcemaps * @param maps * @throws */ - add(...maps) { + add(maps) { let srcIndex; - if (typeof maps[0] === "number") { - maps = [maps]; - } for (let [newLine, newColumn, srcId, ln, col] of maps) { const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; if (this.keys.has(key)) { diff --git a/dist/lib/syntax/color/a98rgb.js b/dist/lib/syntax/color/a98rgb.js index 41d84e25..87fd4de9 100644 --- a/dist/lib/syntax/color/a98rgb.js +++ b/dist/lib/syntax/color/a98rgb.js @@ -3,12 +3,22 @@ import { multiplyMatrices } from './utils/matrix.js'; import { srgb2xyz } from './xyz.js'; function a98rgb2srgbvalues(r, g, b, a = null) { - // @ts-ignore - return xyz2srgb(...la98rgb2xyz(...a98rgb2la98(r, g, b, a))); + let values = a98rgb2la98(r, g, b); + values = la98rgb2xyz(values[0], values[1], values[2]); + values = xyz2srgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; } function srgb2a98values(r, g, b, a = null) { - // @ts-ignore - return la98rgb2a98rgb(...xyz2la98rgb(...srgb2xyz(r, g, b, a))); + let values = srgb2xyz(r, g, b); + values = xyz2la98rgb(values[0], values[1], values[2]); + values = la98rgb2a98rgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; } // a98-rgb functions function a98rgb2la98(r, g, b, a = null) { diff --git a/dist/lib/syntax/color/cmyk.js b/dist/lib/syntax/color/cmyk.js index 03476851..7b09361b 100644 --- a/dist/lib/syntax/color/cmyk.js +++ b/dist/lib/syntax/color/cmyk.js @@ -4,68 +4,60 @@ import { lch2srgbvalues, lab2srgbvalues, oklch2srgbvalues, oklab2srgbvalues, hwb import { hsl2srgbvalues } from './rgb.js'; function rgb2cmykToken(token) { - const components = rgb2srgbvalues(token); + let components = rgb2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function hsl2cmykToken(token) { - const values = hsl2srgbvalues(token); + let values = hsl2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function hwb2cmykToken(token) { const values = hwb2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function lab2cmykToken(token) { const components = lab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function lch2cmykToken(token) { const components = lch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklab2cmyk(token) { const components = oklab2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function oklch2cmykToken(token) { const components = oklch2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } function color2cmykToken(token) { const values = color2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } function srgb2cmykvalues(r, g, b, a = null) { const k = 1 - Math.max(r, g, b); diff --git a/dist/lib/syntax/color/color-mix.js b/dist/lib/syntax/color/color-mix.js index 0a81fea3..63be0a57 100644 --- a/dist/lib/syntax/color/color-mix.js +++ b/dist/lib/syntax/color/color-mix.js @@ -16,6 +16,7 @@ import { XYZ_D65_to_D50, xyzd502lch } from './xyzd50.js'; import { srgb2rec2020values } from './rec2020.js'; import { isRectangularOrthogonalColorspace, isPolarColorspace } from '../syntax.js'; import { equalsIgnoreCase } from '../../parser/utils/text.js'; +import { srgb2a98values } from './a98rgb.js'; function interpolateHue(interpolationMethod, h1, h2) { switch (interpolationMethod) { @@ -124,65 +125,53 @@ function colorMix(...args) { case "srgb": break; case "display-p3": - // @ts-ignore - values = srgb2p3values(...values); + values = srgb2p3values(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = srgb2lp3values(...values); + values = srgb2lp3values(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = srgb2a98values(...values); + values = srgb2a98values(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = srgb2prophotorgbvalues(...values); + values = srgb2prophotorgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = srgb2lsrgbvalues(...values); + values = srgb2lsrgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = srgb2rec2020values(...values); + values = srgb2rec2020values(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = srgb2xyz_d65(...values); + values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = XYZ_D65_to_D50(...srgb2xyz_d65(...values)); + 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": - // @ts-ignore - values = srgb2rgb(...values); + for (let j = 0; j < values.length; j++) { + values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + } break; case "hsl": - // @ts-ignore - values = srgb2hslvalues(...values); + values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; case "hwb": - // @ts-ignore - values = srgb2hwb(...values); + values = srgb2hwb(values[0], values[1], values[2], values[3]); break; case "lab": - // @ts-ignore - values = srgb2labvalues(...values); + values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; case "lch": - // @ts-ignore - values = srgb2lch(...values); + values = srgb2lch(values[0], values[1], values[2], values[3]); break; case "oklab": - // @ts-ignore - values = srgb2oklab(...values); + values = srgb2oklab(values[0], values[1], values[2], values[3]); break; case "oklch": - // @ts-ignore - values = srgb2oklch(...values); + values = srgb2oklch(values[0], values[1], values[2], values[3]); break; default: return null; @@ -331,12 +320,10 @@ function colorMix(...args) { case "xyz-d65": case "xyz-d50": if (colorSpace == "xyz-d50") { - // @ts-ignore - values = xyzd502lch(...values); + values = xyzd502lch(values[0], values[1], values[2], values[3]); } else { - // @ts-ignore - values = xyz2lchvalues(...values); + values = xyz2lchvalues(values[0], values[1], values[2], values[3]); } // @ts-ignore return { diff --git a/dist/lib/syntax/color/color.js b/dist/lib/syntax/color/color.js index 4027b6b7..b4a0e6cb 100644 --- a/dist/lib/syntax/color/color.js +++ b/dist/lib/syntax/color/color.js @@ -19,7 +19,7 @@ import { parseRelativeColorComponents } from './relative-color.js'; import { isIdentColor } from '../syntax.js'; import { color2cmykToken, lch2cmykToken, lab2cmykToken, oklch2cmykToken, oklab2cmyk, hwb2cmykToken, hsl2cmykToken, rgb2cmykToken } from './cmyk.js'; import { a98rgb2srgbvalues, srgb2a98values } from './a98rgb.js'; -import { LOC, colorFuncColorSpace } from '../constants.js'; +import { LOCSRCID, LOCSTA, LOCEND, colorFuncColorSpace } from '../constants.js'; import { trimArray } from '../../validation/match.js'; import { alpha } from './alpha.js'; import { equalsIgnoreCase } from '../../parser/utils/text.js'; @@ -47,8 +47,8 @@ function convertColor(token, to) { if (args.at(-2)?.typ === EnumToken.LiteralTokenType && "/" === args.at(-2)?.val) { args.splice(args.length - 2, 1); } - // @ts-expect-error - token = alpha(...trimArray(args.slice(1))); + let values = trimArray(args.slice(1)); + token = alpha(values[0], values[1]); if (token == null) { return null; } @@ -83,10 +83,15 @@ function convertColor(token, to) { } let { cal, ...tk } = { ...token, - chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], + chi: token.val == "color" ? [chi[offset]] : [], kin: ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + for (const t of Object.values(components)) { + tk.chi.push(t); + } + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } @@ -437,46 +442,28 @@ function color2colorToken(token, to) { return values2colortoken(values, to); } function srgb2srgbcolorspace(val, to) { - const values = []; switch (to) { case ColorType.SRGB: - values.push(...val); - break; + return val; case ColorType.SRGB_LINEAR: - // @ts-ignore - values.push(...srgb2lsrgbvalues(...val)); - break; + return srgb2lsrgbvalues(val[0], val[1], val[2], val[3]); case ColorType.DISPLAY_P3: - // @ts-ignore - values.push(...srgb2p3values(...val)); - break; + return srgb2p3values(val[0], val[1], val[2], val[3]); case ColorType.DISPLAY_P3_LINEAR: - // @ts-ignore - values.push(...srgb2lp3values(...val)); - break; + return srgb2lp3values(val[0], val[1], val[2], val[3]); case ColorType.PROPHOTO_RGB: - // @ts-ignore - values.push(...srgb2prophotorgbvalues(...val)); - break; + return srgb2prophotorgbvalues(val[0], val[1], val[2], val[3]); case ColorType.A98_RGB: - // @ts-ignore - values.push(...srgb2a98values(...val)); - break; + return srgb2a98values(val[0], val[1], val[2], val[3]); case ColorType.REC2020: - // @ts-ignore - values.push(...srgb2rec2020values(...val)); - break; + return srgb2rec2020values(val[0], val[1], val[2], val[3]); case ColorType.XYZ: case ColorType.XYZ_D65: - // @ts-ignore - values.push(...srgb2xyz(...val)); - break; + return srgb2xyz(val[0], val[1], val[2], val[3]); case ColorType.XYZ_D50: - // @ts-ignore - values.push(...srgb2xyz_d65(...val)); - break; + return srgb2xyz_d65(val[0], val[1], val[2], val[3]); } - return values; + return null; } function minmax(value, min, max) { return value < min ? min : value > max ? max : value; @@ -490,37 +477,29 @@ function color2srgbvalues(token) { let values = components.map((val) => getNumber(val)); switch (colorSpace.val) { case "display-p3": - // @ts-ignore - values = p32srgbvalues(...values); + values = p32srgbvalues(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = lp32srgbvalues(...values); + values = lp32srgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = lsrgb2srgbvalues(...values); + values = lsrgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = prophotorgb2srgbvalues(...values); + values = prophotorgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = a98rgb2srgbvalues(...values); + values = a98rgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = rec20202srgb(...values); + values = rec20202srgb(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = xyz2srgb(...values); + values = xyz2srgb(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = xyzd502srgb(...values); + values = xyzd502srgb(values[0], values[1], values[2], values[3]); break; } if (values.length == 4) { @@ -529,7 +508,11 @@ function color2srgbvalues(token) { return values; } function values2colortoken(values, to) { + // @ts-expect-error values = srgb2srgbcolorspace(values, to); + if (values == null) { + return null; + } const chi = [ { typ: EnumToken.NumberTokenType, val: values[0] }, { typ: EnumToken.NumberTokenType, val: values[1] }, diff --git a/dist/lib/syntax/color/hsl.js b/dist/lib/syntax/color/hsl.js index d034be5f..d8f6f2ef 100644 --- a/dist/lib/syntax/color/hsl.js +++ b/dist/lib/syntax/color/hsl.js @@ -6,8 +6,11 @@ import { hex2srgbvalues, oklch2srgbvalues, oklab2srgbvalues, hslvalues } from '. import { EnumToken, ColorType } from '../../ast/types.js'; function hex2HslToken(token) { - // @ts-ignore - return hslToken(srgb2hslvalues(...hex2srgbvalues(token))); + let values = hex2srgbvalues(token); + if (values == null) { + return null; + } + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function rgb2HslToken(token) { const values = rgb2hslvalues(token); @@ -63,8 +66,7 @@ function color2HslToken(token) { if (values == null) { return null; } - // @ts-ignore - return hslToken(srgb2hslvalues(...values)); + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function hslToken(values) { values[0] = values[0] * 360; @@ -112,8 +114,7 @@ function rgb2hslvalues(token) { if (a != null && a != 1) { values.push(a); } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } // https://gist.github.com/defims/0ca2ef8832833186ed396a2f8a204117#file-annotated-js function hsv2hsl(h, s, v, a) { @@ -135,20 +136,19 @@ function hsv2hsl(h, s, v, a) { } function cmyk2hslvalues(token) { const values = cmyk2rgbvalues(token); - // @ts-ignore - return values == null ? null : rgbvalues2hslvalues(...values); + return values == null ? null : rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function hwb2hslvalues(token) { - // @ts-ignore - return hsv2hsl(...hwb2hsv(...Object.values(hslvalues(token)))); + const hsla = hslvalues(token); + const hwba = hwb2hsv(hsla.h, hsla.s, hsla.l, hsla.a); + return hsv2hsl(hwba[0], hwba[1], hwba[2], hwba[3]); } function lab2hslvalues(token) { const values = lab2rgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function lch2hslvalues(token) { const values = lch2rgbvalues(token); @@ -156,17 +156,17 @@ function lch2hslvalues(token) { return null; } // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } function oklab2hslvalues(token) { const t = oklab2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function oklch2hslvalues(token) { const t = oklch2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } function rgbvalues2hslvalues(r, g, b, a = null) { return srgb2hslvalues(r / 255, g / 255, b / 255, a); diff --git a/dist/lib/syntax/color/hwb.js b/dist/lib/syntax/color/hwb.js index 2842aa17..7ee41fdc 100644 --- a/dist/lib/syntax/color/hwb.js +++ b/dist/lib/syntax/color/hwb.js @@ -70,7 +70,7 @@ function hwbToken(values) { if (values.length == 4) { chi.push({ typ: EnumToken.LiteralTokenType, val: "/" }, { typ: EnumToken.PercentageTokenType, - val: values[3] * 100 + val: values[3] * 100, }); } return { @@ -81,21 +81,21 @@ function hwbToken(values) { }; } function rgb2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3) { return getNumber(t); } return getNumber(t) / 255; - })); + }); + // @ts-ignore + return srgb2hwb(values[0], values[1], values[2], values[3]); } function cmyk2hwbvalues(token) { - // @ts-ignore - return srgb2hwb(...cmyk2srgbvalues(token)); + const values = cmyk2srgbvalues(token); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function hsl2hwbvalues(token) { - // @ts-ignore - return hslvalues2hwbvalues(...getColorComponents(token).map((t, index) => { + const values = getColorComponents(token).map((t, index) => { if (index == 3 && t.typ == EnumToken.IdenTokenType && t.val == "none") { return 1; } @@ -103,23 +103,23 @@ function hsl2hwbvalues(token) { return getAngle(t); } return getNumber(t); - })); + }); + // @ts-ignore + return hslvalues2hwbvalues(values[0], values[1], values[2], values[3]); } function lab2hwbvalues(token) { const values = lab2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function lch2hwbvalues(token) { const values = lch2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklab2hwbvalues(token) { const values = oklab2srgbvalues(token); @@ -127,12 +127,12 @@ function oklab2hwbvalues(token) { return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function oklch2hwbvalues(token) { const values = oklch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2hwb(...values); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function rgb2hue(r, g, b, fallback = 0) { let value = rgb2value(r, g, b); @@ -160,7 +160,7 @@ function color2hwbvalues(token) { return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } function srgb2hwb(r, g, b, a = null, fallback = 0) { r *= 100; @@ -184,8 +184,9 @@ function hsv2hwb(h, s, v, a = null) { return result; } function hslvalues2hwbvalues(h, s, l, a = null) { + let values = hsl2hsv(h, s, l); // @ts-ignore - return hsv2hwb(...hsl2hsv(h, s, l, a)); + return hsv2hwb(values[0], values[1], values[2], a); } export { cmyk2hwbToken, cmyk2hwbvalues, color2hwbToken, color2hwbvalues, hsl2hwbToken, hsl2hwbvalues, hslvalues2hwbvalues, hsv2hwb, hwbToken, lab2hwbToken, lab2hwbvalues, lch2hwbToken, lch2hwbvalues, oklab2hwbToken, oklab2hwbvalues, oklch2hwbToken, oklch2hwbvalues, rgb2hwbToken, rgb2hwbvalues, srgb2hwb }; diff --git a/dist/lib/syntax/color/lab.js b/dist/lib/syntax/color/lab.js index af4dbcb8..72da31a6 100644 --- a/dist/lib/syntax/color/lab.js +++ b/dist/lib/syntax/color/lab.js @@ -90,19 +90,19 @@ function labToken(values) { // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 function hex2labvalues(token) { - const values = hex2srgbvalues(token); + let values = hex2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function rgb2labvalues(token) { const values = rgb2srgb(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function cmyk2labvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } function hsl2labvalues(token) { const values = hsl2srgb(token); @@ -110,7 +110,7 @@ function hsl2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function hwb2labvalues(token) { const values = hwb2srgbvalues(token); @@ -118,20 +118,21 @@ function hwb2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function lch2labvalues(token) { const values = getLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function oklab2labvalues(token) { - const values = getOKLABComponents(token); + let values = getOKLABComponents(token); if (values == null) { return null; } - // @ts-ignore - return xyz2lab(...XYZ_D65_to_D50(...OKLab_to_XYZ(...values))); + values = OKLab_to_XYZ(values[0], values[1], values[2], values[3]); + values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); + return xyz2lab(values[0], values[1], values[2], values[3]); } function oklch2labvalues(token) { const values = oklch2srgbvalues(token); @@ -139,19 +140,18 @@ function oklch2labvalues(token) { return null; } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } function color2labvalues(token) { const val = color2srgbvalues(token); if (val == null) { return null; } - // @ts-ignore - return srgb2labvalues(...val); + return srgb2labvalues(val[0], val[1], val[2], val[3]); } function srgb2labvalues(r, g, b, a) { - // @ts-ignore */ - const result = xyz2lab(...srgb2xyz_d65(r, g, b)); + let result = srgb2xyz_d65(r, g, b); + result = xyz2lab(result[0], result[1], result[2]); // Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors // and approximated computations in sRGB <-> CIELab. // See: https://github.com/d3/d3-color/pull/46 @@ -233,9 +233,9 @@ function getLABComponents(token) { function Lab_to_sRGB(l, a, b) { const xyz_d50 = Lab_to_XYZ(l, a, b); // @ts-ignore - const xyz_d65 = XYZ_D50_to_D65(...xyz_d50); + const xyz_d65 = XYZ_D50_to_D65(xyz_d50[0], xyz_d50[1], xyz_d50[2]); // @ts-ignore - return xyz2srgb(...xyz_d65); + return xyz2srgb(xyz_d65[0], xyz_d65[1], xyz_d65[2]); } // from https://www.w3.org/TR/css-color-4/#color-conversion-code function Lab_to_XYZ(l, a, b) { diff --git a/dist/lib/syntax/color/lch.js b/dist/lib/syntax/color/lch.js index bc0aba52..2d587e29 100644 --- a/dist/lib/syntax/color/lch.js +++ b/dist/lib/syntax/color/lch.js @@ -90,41 +90,41 @@ function lchToken(values) { function hex2lchvalues(token) { const values = hex2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2lchvalues(token) { const values = rgb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2lchvalues(token) { const values = hsl2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2lchvalues(token) { const values = hwb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lab2lchvalues(token) { const values = getLABComponents(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2lch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2labvalues(r, g, blue, alpha)); + let values = srgb2labvalues(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2lchvalues(token) { const values = oklab2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2lchvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2lch(...values); + return values == null ? null : srgb2lch(values[0], values[1], values[2], values[3]); } function oklch2lchvalues(token) { const values = oklch2labvalues(token); @@ -132,7 +132,7 @@ function oklch2lchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function color2lchvalues(token) { const values = color2srgbvalues(token); @@ -140,7 +140,7 @@ function color2lchvalues(token) { return null; } // @ts-ignore - return srgb2lch(...values); + return srgb2lch(values[0], values[1], values[2], values[3]); } function labvalues2lchvalues(l, a, b, alpha = null) { let c = Math.sqrt(a * a + b * b); @@ -154,8 +154,8 @@ function labvalues2lchvalues(l, a, b, alpha = null) { return alpha == null ? [l, c, h] : [l, c, h, alpha]; } function xyz2lchvalues(x, y, z, alpha) { - // @ts-ignore( - const lch = labvalues2lchvalues(...xyz2lab(x, y, z)); + const values = xyz2lab(x, y, z); + const lch = labvalues2lchvalues(values[0], values[1], values[2]); return alpha == null || alpha == 1 ? lch : lch.concat(alpha); } function getLCHComponents(token) { diff --git a/dist/lib/syntax/color/oklab.js b/dist/lib/syntax/color/oklab.js index 27f0a6a0..aa6a6d7b 100644 --- a/dist/lib/syntax/color/oklab.js +++ b/dist/lib/syntax/color/oklab.js @@ -94,15 +94,14 @@ function hex2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function rgb2oklabvalues(token) { const values = rgb2srgb(token); if (values == null) { return null; } - // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hsl2oklabvalues(token) { const values = hsl2srgb(token); @@ -110,16 +109,16 @@ function hsl2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function hwb2oklabvalues(token) { - // @ts-ignore - return srgb2oklab(...hwb2srgbvalues(token)); + const values = hwb2srgbvalues(token); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function cmyk2oklabvalues(token) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function lab2oklabvalues(token) { const values = lab2srgbvalues(token); @@ -127,22 +126,22 @@ function lab2oklabvalues(token) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } function lch2oklabvalues(token) { const values = lch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function oklch2oklabvalues(token) { const values = getOKLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function color2oklabvalues(token) { const values = color2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } function srgb2oklab(r, g, blue, alpha) { [r, g, blue] = srgb2lsrgbvalues(r, g, blue); diff --git a/dist/lib/syntax/color/oklch.js b/dist/lib/syntax/color/oklch.js index 0ca688f6..0199058c 100644 --- a/dist/lib/syntax/color/oklch.js +++ b/dist/lib/syntax/color/oklch.js @@ -7,7 +7,7 @@ import { cmyk2srgbvalues } from './srgb.js'; function hex2oklchToken(token) { const values = hex2oklchvalues(token); - return oklchToken(values); + return values == null ? null : oklchToken(values); } function rgb2oklchToken(token) { const values = rgb2oklchvalues(token); @@ -63,8 +63,7 @@ function color2oklchToken(token) { if (values == null) { return null; } - // @ts-ignore - return oklchToken(srgb2oklch(...values)); + return oklchToken(srgb2oklch(values[0], values[1], values[2], values[3])); } function oklchToken(values) { values[2] = values[2]; @@ -87,29 +86,27 @@ function oklchToken(values) { }; } function hex2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hex2oklabvalues(token)); + const values = hex2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function rgb2oklchvalues(token) { const values = rgb2oklabvalues(token); if (values == null) { return null; } - // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hsl2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hsl2oklabvalues(token)); + const values = hsl2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function hwb2oklchvalues(token) { - // @ts-ignore - return labvalues2lchvalues(...hwb2oklabvalues(token)); + const values = hwb2oklabvalues(token); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function cmyk2oklchvalues(token) { const values = cmyk2srgbvalues(token); - // @ts-ignore - return values == null ? null : srgb2oklch(...values); + return values == null ? null : srgb2oklch(values[0], values[1], values[2], values[3]); } function lab2oklchvalues(token) { const values = lab2oklabvalues(token); @@ -117,7 +114,7 @@ function lab2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function lch2oklchvalues(token) { const values = lch2oklabvalues(token); @@ -125,7 +122,7 @@ function lch2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function oklab2oklchvalues(token) { const values = getOKLABComponents(token); @@ -133,11 +130,11 @@ function oklab2oklchvalues(token) { return null; } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function srgb2oklch(r, g, blue, alpha) { - // @ts-ignore - return labvalues2lchvalues(...srgb2oklab(r, g, blue, alpha)); + const values = srgb2oklab(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } function getOKLCHComponents(token) { const components = getColorComponents(token); diff --git a/dist/lib/syntax/color/p3.js b/dist/lib/syntax/color/p3.js index b1acc6aa..ead5bc02 100644 --- a/dist/lib/syntax/color/p3.js +++ b/dist/lib/syntax/color/p3.js @@ -3,20 +3,32 @@ import { multiplyMatrices } from './utils/matrix.js'; import { srgb2xyz } from './xyz.js'; function p32srgbvalues(r, g, b, alpha) { + let values = p32lp3(r, g, b); + values = lp32xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lp32xyz(...p32lp3(r, g, b, alpha))); + return xyz2srgb(values[0], values[1], values[2], alpha); } function srgb2p3values(r, g, b, alpha) { - // @ts-ignore - return lp32p3(...xyz2lp3(...srgb2xyz(r, g, b, alpha))); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + values = lp32p3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function srgb2lp3values(r, g, b, alpha) { - // @ts-ignore - return xyz2lp3(...srgb2xyz(r, g, b, alpha)); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } function lp32srgbvalues(r, g, b, alpha) { + let values = lp32xyz(r, g, b); // @ts-ignore - return xyz2srgb(...lp32xyz(r, g, b, alpha)); + return xyz2srgb(values[0], values[1], values[2], alpha); } function p32lp3(r, g, b, alpha) { // convert an array of display-p3 RGB values in the range 0.0 - 1.0 @@ -38,9 +50,6 @@ function lp32xyz(r, g, b, alpha) { [0, 32229 / 714400, 5220557 / 5000800], ]; const result = multiplyMatrices(M, [r, g, b]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } function xyz2lp3(x, y, z, alpha) { @@ -51,9 +60,6 @@ function xyz2lp3(x, y, z, alpha) { [11844 / 330415, -50337 / 660830, 316169 / 330415], ]; const result = multiplyMatrices(M, [x, y, z]); - if (alpha != null && alpha != 1) { - result.push(alpha); - } return result; } diff --git a/dist/lib/syntax/color/prophotorgb.js b/dist/lib/syntax/color/prophotorgb.js index 8672e587..1044619d 100644 --- a/dist/lib/syntax/color/prophotorgb.js +++ b/dist/lib/syntax/color/prophotorgb.js @@ -2,55 +2,53 @@ import { XYZ_D65_to_D50, xyzd502srgb } from './xyzd50.js'; import { srgb2xyz } from './xyz.js'; function prophotorgb2srgbvalues(r, g, b, a = null) { + let values = prophotorgb2xyz50(r, g, b); // @ts-ignore - return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); + return xyzd502srgb(values[0], values[1], values[2], a); } function srgb2prophotorgbvalues(r, g, b, a) { - // @ts-ignore - return xyz50_to_prophotorgb(...XYZ_D65_to_D50(...srgb2xyz(r, g, b, a))); + let values = srgb2xyz(r, g, b); + values = XYZ_D65_to_D50(values[0], values[1], values[2]); + values = xyz50_to_prophotorgb(values[0], values[1], values[2]); + if (a != null && a < 1) { + values.push(a); + } + return values; } function prophotorgb2lin_ProPhoto(r, g, b, a = null) { - return [r, g, b].map(v => { + return [r, g, b] + .map((v) => { let abs = Math.abs(v); if (abs >= 16 / 512) { return Math.sign(v) * Math.pow(abs, 1.8); } return v / 16; - }).concat(a == null || a == 1 ? [] : [a]); + }) + .concat(a == null || a == 1 ? [] : [a]); } function prophotorgb2xyz50(r, g, b, a = null) { [r, g, b, a] = prophotorgb2lin_ProPhoto(r, g, b, a); const xyz = [ - 0.7977666449006423 * r + - 0.1351812974005331 * g + - 0.0313477341283922 * b, - 0.2880748288194013 * r + - 0.7118352342418731 * g + - 0.0000899369387256 * b, - 0.8251046025104602 * b + 0.7977666449006423 * r + 0.1351812974005331 * g + 0.0313477341283922 * b, + 0.2880748288194013 * r + 0.7118352342418731 * g + 0.0000899369387256 * b, + 0.8251046025104602 * b, ]; return xyz.concat(a == null || a == 1 ? [] : [a]); } function xyz50_to_prophotorgb(x, y, z, a) { // @ts-ignore - return gam_prophotorgb(...[ - x * 1.3457868816471585 - - y * 0.2555720873797946 - - 0.0511018649755453 * z, - x * -0.5446307051249019 + - y * 1.5082477428451466 + - 0.0205274474364214 * z, - 1.2119675456389452 * z - ].concat(a == null || a == 1 ? [] : [a])); + return gam_prophotorgb(x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z, x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z, 1.2119675456389452 * z); +} +function gam_prophotorgbvalue(v) { + let abs = Math.abs(v); + if (abs >= 1 / 512) { + return Math.sign(v) * Math.pow(abs, 1 / 1.8); + } + return 16 * v; } function gam_prophotorgb(r, g, b, a) { - return [r, g, b].map(v => { - let abs = Math.abs(v); - if (abs >= 1 / 512) { - return Math.sign(v) * Math.pow(abs, 1 / 1.8); - } - return 16 * v; - }).concat(a == null || a == 1 ? [] : [a]); + const values = [gam_prophotorgbvalue(r), gam_prophotorgbvalue(g), gam_prophotorgbvalue(b)]; + return values; } export { prophotorgb2srgbvalues, srgb2prophotorgbvalues }; diff --git a/dist/lib/syntax/color/rec2020.js b/dist/lib/syntax/color/rec2020.js index 35a6ef32..49d7e49e 100644 --- a/dist/lib/syntax/color/rec2020.js +++ b/dist/lib/syntax/color/rec2020.js @@ -3,12 +3,16 @@ import { multiplyMatrices } from './utils/matrix.js'; import { srgb2xyz } from './xyz.js'; function rec20202srgb(r, g, b, a) { + let values = rec20202lrec2020(r, g, b); + values = lrec20202xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lrec20202xyz(...rec20202lrec2020(r, g, b)), a); + return xyz2srgb(values[0], values[1], values[2], a); } function srgb2rec2020values(r, g, b, a) { + let values = srgb2xyz(r, g, b); + values = xyz2lrec2020(values[0], values[1], values[2]); // @ts-ignore - return lrec20202rec2020(...xyz2lrec2020(...srgb2xyz(r, g, b)), a); + return lrec20202rec2020(values[0], values[1], values[2], a); } function rec20202lrec2020(r, g, b, a) { // convert an array of rec2020 RGB values in the range 0.0 - 1.0 @@ -54,7 +58,7 @@ function lrec20202xyz(r, g, b, a) { [0, 19567812 / 697040785, 295819943 / 278816314], ]; // 0 is actually calculated as 4.994106574466076e-17 - return multiplyMatrices(M, [r, g, b]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [r, g, b]).concat([] ); } function xyz2lrec2020(x, y, z, a) { // convert XYZ to linear-light rec2020 @@ -63,7 +67,7 @@ function xyz2lrec2020(x, y, z, a) { [-19765991 / 29648200, 47925759 / 29648200, 467509 / 29648200], [792561 / 44930125, -1921689 / 44930125, 42328811 / 44930125], ]; - return multiplyMatrices(M, [x, y, z]).concat(a == null || a == 1 ? [] : [a]); + return multiplyMatrices(M, [x, y, z]).concat([] ); } export { rec20202srgb, srgb2rec2020values }; diff --git a/dist/lib/syntax/color/relative-color.js b/dist/lib/syntax/color/relative-color.js index b5b34dfe..68e56a13 100644 --- a/dist/lib/syntax/color/relative-color.js +++ b/dist/lib/syntax/color/relative-color.js @@ -2,7 +2,7 @@ import { convertColor, getNumber } from './color.js'; import { EnumToken, ColorType } from '../../ast/types.js'; import { walkValues } from '../../ast/walk.js'; import { evaluateFunc, evaluate } from '../../ast/math/expression.js'; -import { colorsFunc, colorFuncColorSpace, LOC, colorRange, mathFuncs } from '../constants.js'; +import { colorsFunc, colorFuncColorSpace, LOCEND, LOCSTA, LOCSRCID, colorRange, mathFuncs } from '../constants.js'; import { equalsIgnoreCase } from '../../parser/utils/text.js'; import { getColorComponents } from './utils/components.js'; @@ -34,7 +34,9 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, const validKeys = names.split(""); let val = ""; if (components != null) { - allComponents.push(...components); + for (const component of components) { + allComponents.push(component); + } } // ensure all components are valid for the color space for (const component of allComponents) { @@ -103,19 +105,25 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, ? { typ: EnumToken.NumberTokenType, val: 1, - [LOC]: b[LOC], + [LOCSRCID]: b[LOCSRCID], + [LOCSTA]: b[LOCSTA], + [LOCEND]: b[LOCEND], } : alpha.typ == EnumToken.IdenTokenType && alpha.val == "none" ? { typ: EnumToken.NumberTokenType, val: 0, - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha.typ == EnumToken.PercentageTokenType ? { typ: EnumToken.NumberTokenType, val: getNumber(alpha), - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha, }; @@ -128,13 +136,17 @@ function parseRelativeColorComponents(relativeKeys, original, rExp, gExp, bExp, ? { typ: EnumToken.NumberTokenType, val: 1, - [LOC]: bExp[LOC], + [LOCSRCID]: bExp[LOCSRCID], + [LOCSTA]: bExp[LOCSTA], + [LOCEND]: bExp[LOCEND], } : aExp.typ == EnumToken.IdenTokenType && aExp.val == "none" ? { typ: EnumToken.NumberTokenType, val: 0, - [LOC]: aExp[LOC], + [LOCSRCID]: aExp[LOCSRCID], + [LOCSTA]: aExp[LOCSTA], + [LOCEND]: aExp[LOCEND], } : aExp), }; @@ -165,7 +177,9 @@ function getValue(t, converted, component) { return { typ: EnumToken.NumberTokenType, val: value, - [LOC]: t[LOC], + [LOCSRCID]: t[LOCSRCID], + [LOCSTA]: t[LOCSTA], + [LOCEND]: t[LOCEND], }; } return t; @@ -208,8 +222,10 @@ function computeComponentValue(expr, values) { { typ: EnumToken.NumberTokenType, // @ts-ignore - val: "" + Math[value.val.toUpperCase()], - [LOC]: value[LOC], + val: Math[value.val.toUpperCase()], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], // @ts-ignore }); } diff --git a/dist/lib/syntax/color/srgb.js b/dist/lib/syntax/color/srgb.js index bc4b4d9a..8523bc08 100644 --- a/dist/lib/syntax/color/srgb.js +++ b/dist/lib/syntax/color/srgb.js @@ -69,8 +69,9 @@ function hex2srgbvalues(token) { } // xyz d65 input function xyz2srgb(x, y, z, alpha = null) { + let values = XYZ_to_lin_sRGB(x, y, z); // @ts-ignore - return lsrgb2srgbvalues(...XYZ_to_lin_sRGB(x, y, z, alpha)); + return lsrgb2srgbvalues(values[0], values[1], values[2], alpha); } function hwb2srgbvalues(token) { const { h: hue, s: white, l: black, a: alpha } = hslvalues(token) ?? {}; @@ -141,8 +142,8 @@ function oklch2srgbvalues(token) { if (l == null || c == null || h == null) { return null; } - // @ts-ignore - const rgb = OKLab_to_sRGB(...lchvalues2labvalues(l, c, h)); + const values = lchvalues2labvalues(l, c, h); + const rgb = OKLab_to_sRGB(values[0], values[1], values[2]); if (alpha != 1) { rgb.push(alpha); } @@ -243,7 +244,7 @@ function lch2srgbvalues(token) { return null; } // @ts-ignore - const [l, a, b, alpha] = lchvalues2labvalues(...components); + const [l, a, b, alpha] = lchvalues2labvalues(components[0], components[1], components[2], components[3]); if (l == null || a == null || b == null) { return null; } diff --git a/dist/lib/syntax/color/utils/distance.js b/dist/lib/syntax/color/utils/distance.js index 06488fa8..74a2575a 100644 --- a/dist/lib/syntax/color/utils/distance.js +++ b/dist/lib/syntax/color/utils/distance.js @@ -28,7 +28,7 @@ function okLabDistance(color1, color2) { if (okLab1[3] != null || okLab2[3] != null) { diff.push((okLab1[3] ?? 1) - (okLab2[3] ?? 1)); } - return toPrecisionValue(Math.hypot(...diff)); + return toPrecisionValue(Math.hypot(diff[0], diff[1], diff[2], diff[3] ?? 0)); } /** * Check if two colors are close in okLab space. diff --git a/dist/lib/syntax/color/xyz.js b/dist/lib/syntax/color/xyz.js index a8130c21..c62fa159 100644 --- a/dist/lib/syntax/color/xyz.js +++ b/dist/lib/syntax/color/xyz.js @@ -41,8 +41,8 @@ function srgb2xyz(r, g, b, alpha) { // xyz d50 function srgb2xyz_d65(r, g, b, alpha) { // xyx d65 - // @ts-ignore - let rgb = XYZ_D65_to_D50(...srgb2xyz(r, g, b)); + let values = srgb2xyz(r, g, b); + let rgb = XYZ_D65_to_D50(values[0], values[1], values[2]); if (alpha != null && alpha != 1) { rgb.push(alpha); } diff --git a/dist/lib/syntax/color/xyzd50.js b/dist/lib/syntax/color/xyzd50.js index f0e8c19f..0edcdce6 100644 --- a/dist/lib/syntax/color/xyzd50.js +++ b/dist/lib/syntax/color/xyzd50.js @@ -7,8 +7,8 @@ import { labvalues2lchvalues } from './lch.js'; /* */ function xyzd502lch(x, y, z, alpha) { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + const values = XYZ_D50_to_D65(x, y, z); + const [l, a, b] = xyz2lab(values[0], values[1], values[2]); // L in range [0,100]. For use in CSS, add a percent return labvalues2lchvalues(l, a, b, alpha); } diff --git a/dist/lib/syntax/constants.js b/dist/lib/syntax/constants.js index 012fc72b..75f5d4d9 100644 --- a/dist/lib/syntax/constants.js +++ b/dist/lib/syntax/constants.js @@ -1,6 +1,15 @@ import { EnumToken } from '../ast/types.js'; import config from '../validation/config.json.js'; +/** + * Location source id + */ +const LOCSRCID = Symbol.for("locSrcId"); +const LOCSTA = Symbol.for("locSta"); +const LOCEND = Symbol.for("locEnd"); +/** + * Used by the validation parser + */ const LOC = Symbol.for("loc"); const RAW = Symbol.for("raw"); const STATE = Symbol.for("state"); @@ -53,7 +62,7 @@ const colorPrecision = 6; /** * Angle precision */ -const anglePrecision = 0.001; +const anglePrecision = 3; /** * Color range definitions */ @@ -109,6 +118,7 @@ const mathFuncs = [ "acos", "atan", "atan2", + "tan", "pow", "sqrt", "hypot", @@ -484,4 +494,4 @@ const trimTokenSpace = new Set([ ]); const combinators = ["+", ">", "~", "||", "|"]; -export { COLORS_NAMES, D50, ERRORS, LOC, NAMES_COLORS, OPTIMIZED, PARENT, PROPERTYNAME, RAW, ROOT, STATE, TOKENS, anglePrecision, colorDistancePrecision, colorFuncColorSpace, colorPrecision, colorRange, colorsFunc, combinators, containerFunc, deprecatedSystemColors, e, epsilon, funcLike, gridTemplateFunc, imageFunc, k, mFGT, mFLT, mathFuncs, mediaTypes, nonStandardColors, pageMarginBoxType, pseudoElements, regMatchLinearGradient, regMatchRadialGradient, supportFunc, systemColors, timelineFunc, timingFunc, tokensMap, tokensfuncDefMap, tokensfuncSet, transformFunctions, trimTokenSpace, urlFunc, urlTokenMatcher, whenElseFunc, wildCardFuncs }; +export { COLORS_NAMES, D50, ERRORS, LOC, LOCEND, LOCSRCID, LOCSTA, NAMES_COLORS, OPTIMIZED, PARENT, PROPERTYNAME, RAW, ROOT, STATE, TOKENS, anglePrecision, colorDistancePrecision, colorFuncColorSpace, colorPrecision, colorRange, colorsFunc, combinators, containerFunc, deprecatedSystemColors, e, epsilon, funcLike, gridTemplateFunc, imageFunc, k, mFGT, mFLT, mathFuncs, mediaTypes, nonStandardColors, pageMarginBoxType, pseudoElements, regMatchLinearGradient, regMatchRadialGradient, supportFunc, systemColors, timelineFunc, timingFunc, tokensMap, tokensfuncDefMap, tokensfuncSet, transformFunctions, trimTokenSpace, urlFunc, urlTokenMatcher, whenElseFunc, wildCardFuncs }; diff --git a/dist/lib/syntax/syntax.js b/dist/lib/syntax/syntax.js index aed77b24..38072456 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -8,14 +8,19 @@ import { trimArray } from '../validation/match.js'; import { splitTokenList } from '../validation/utils/list.js'; import { getColorSpace } from './color/utils/colorspace.js'; import { getColorComponents } from './color/utils/components.js'; -import { nonStandardColors, systemColors, deprecatedSystemColors, COLORS_NAMES, colorsFunc, colorFuncColorSpace, colorPrecision, epsilon, anglePrecision } from './constants.js'; +import { anglePrecision, nonStandardColors, systemColors, deprecatedSystemColors, COLORS_NAMES, colorsFunc, colorFuncColorSpace, colorPrecision, epsilon } from './constants.js'; import { getSyntaxConfig } from '../validation/config.js'; // https://www.w3.org/TR/CSS21/syndata.html#syntax // https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token // '\\' const REVERSE_SOLIDUS = 0x5c; -const dimensionUnits = new Set([ +const flexUnits = ["fr"]; +const frequencyUnits = ["hz", "khz"]; +const timeUnits = ["ms", "s"]; +const angleUnits = ["rad", "turn", "deg", "grad"]; +const resolutionUnits = ["dpi", "dpcm", "dppx", "x"]; +const dimensionUnits = [ "q", "cap", "ch", @@ -59,7 +64,7 @@ const dimensionUnits = new Set([ "vmax", "vmin", "vw", -]); +]; // https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions // https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions const pseudoAliasMap = { @@ -196,19 +201,19 @@ const pseudoAliasMap = { // renamed standard properties const renamedStandardProperties = new Map([["color-adjust", "print-color-adjust"]]); function isLength(dimension) { - return "unit" in dimension && dimensionUnits.has(dimension.unit.toLowerCase()); + return "unit" in dimension && dimensionUnits.includes(dimension.unit.toLowerCase()); } function isResolution(dimension) { - return "unit" in dimension && ["dpi", "dpcm", "dppx", "x"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && resolutionUnits.includes(dimension.unit.toLowerCase()); } function isAngle(dimension) { - return "unit" in dimension && ["rad", "turn", "deg", "grad"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && angleUnits.includes(dimension.unit.toLowerCase()); } function isTime(dimension) { - return "unit" in dimension && ["ms", "s"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && timeUnits.includes(dimension.unit.toLowerCase()); } function isFrequency(dimension) { - return "unit" in dimension && ["hz", "khz"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && frequencyUnits.includes(dimension.unit.toLowerCase()); } /** * Reduce color stops @@ -231,7 +236,9 @@ function reduceColorStops(stops) { if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.PercentageTokenType, val: ((k - 1) * 100) / n }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -255,7 +262,9 @@ function reduceColorStops(stops) { if (stops.length > 0) { stops.push({ typ: EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (let m = 0; m < parts[j].length; m++) { + stops.push(parts[j][m]); + } } } return stops; @@ -353,7 +362,9 @@ function reduceConicColorStops(stops) { if (parts[i - 1].length == 1) { parts[i - 1].push({ typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.AngleTokenType, val: ((k - 1) * 100) / n, unit: "deg" }); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } parts.splice(i--, 1); updated = true; continue; @@ -376,7 +387,9 @@ function reduceConicColorStops(stops) { if (stops.length > 0) { stops.push({ typ: EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + for (const token of parts[j]) { + stops.push(token); + } } } return stops; @@ -672,11 +685,10 @@ function isColor(token, errors) { return true; } else { - const keywords = ["from", "none"]; // @ts-ignore if (["rgb", "hsl", "hwb", "lab", "lch", "oklab", "oklch"].some((t) => equalsIgnoreCase(t, token.val))) { - // @ts-ignore - keywords.push("alpha", ...token.val.slice(-3).split("")); + for (const keyword of token.val.slice(-3).split("")) { + } } // @ts-ignore for (const v of token.chi) { @@ -841,75 +853,6 @@ function isPseudo(name) { function isHash(name) { return name.charAt(0) == "#" && isIdentStart(name.charCodeAt(1)); } -const isNumber = memoize(function (name) { - let codepoint = name.charCodeAt(0); - let i = 0; - const j = name.length; - if (j == 1 && !isDigit(codepoint)) { - return false; - } - // '+' '-' - if ([0x2b, 0x2d].includes(codepoint)) { - i++; - } - // consume digits - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // '.' 'E' 'e' - if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { - break; - } - return false; - } - // '.' - if (codepoint == 0x2e) { - if (!isDigit(name.charCodeAt(++i))) { - return false; - } - } - while (i < j) { - codepoint = name.charCodeAt(i); - if (isDigit(codepoint)) { - i++; - continue; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - i++; - break; - } - return false; - } - // 'E' 'e' - if (codepoint == 0x45 || codepoint == 0x65) { - // if (i == j) { - // return false; - // } - codepoint = name.charCodeAt(i + 1); - // '+' '-' - // if ([0x2b, 0x2d].includes(codepoint)) { - // i++; - // } - codepoint = name.charCodeAt(i + 1); - if (!isDigit(codepoint)) { - return false; - } - } - // while (++i < j) { - // codepoint = name.charCodeAt(i) as number; - // if (!isDigit(codepoint)) { - // return false; - // } - // } - return true; -}); -function isPercentage(name) { - return name.endsWith("%") && isNumber(name.slice(0, -1)); -} function isFlex(dimension) { return "unit" in dimension && "fr" == dimension.unit.toLowerCase(); } @@ -950,9 +893,9 @@ function parseDimension(name) { else if (isResolution(dimension)) { // @ts-ignore dimension.typ = EnumToken.ResolutionTokenType; - if (dimension.unit == "dppx") { - dimension.unit = "x"; - } + // if (dimension.unit == "dppx") { + // dimension.unit = "x"; + // } } else if (isFrequency(dimension)) { // @ts-ignore @@ -964,22 +907,6 @@ function parseDimension(name) { } return dimension; } -function isHexColor(name) { - if (name.charAt(0) != "#" || ![4, 5, 7, 9].includes(name.length)) { - return false; - } - for (let chr of name.slice(1)) { - let codepoint = chr.charCodeAt(0); - if (!isDigit(codepoint) && - // A-F - !(codepoint >= 0x41 && codepoint <= 0x46) && - // a-f - !(codepoint >= 0x61 && codepoint <= 0x66)) { - return false; - } - } - return true; -} function isFunction(name) { return name.endsWith("(") && isIdent(name.slice(0, -1)); } @@ -1074,18 +1001,15 @@ function toPrecisionValue(value, precision = colorPrecision) { value = Math.round(value * div) / div; return Math.abs(value) < epsilon ? 0 : value; } -function toPrecisionAngle(angle, precision = colorPrecision, correctValue = true) { +function toPrecisionAngle(angle, precision = anglePrecision, correctValue = true) { angle = toPrecisionValue(angle, precision); if (correctValue && Math.abs(angle) >= 360) { angle %= 360; } - if (Math.abs(angle) < anglePrecision) { - angle = 0; - } if (correctValue && angle < 0) { angle += 360; } return angle; } -export { dimensionUnits, isAngle, isColor, isDigit, isFlex, isFrequency, isFunction, isHash, isHexColor, isIdent, isIdentCodepoint, isIdentColor, isIdentStart, isLength, isLetter, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, length2Px, minifyNumber, parseColor, parseDimension, pseudoAliasMap, reduceColorStops, reduceConicColorStops, reducegradientBackgroundPosition, renamedStandardProperties, toPrecisionAngle, toPrecisionValue }; +export { angleUnits, dimensionUnits, flexUnits, frequencyUnits, isAngle, isColor, isDigit, isFlex, isFrequency, isFunction, isHash, isIdent, isIdentCodepoint, isIdentColor, isIdentStart, isLength, isLetter, isNewLine, isNonPrintable, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, length2Px, minifyNumber, parseColor, parseDimension, pseudoAliasMap, reduceColorStops, reduceConicColorStops, reducegradientBackgroundPosition, renamedStandardProperties, resolutionUnits, timeUnits, toPrecisionAngle, toPrecisionValue }; diff --git a/dist/lib/validation/config.json.js b/dist/lib/validation/config.json.js index ba64c343..c4f8f4aa 100644 --- a/dist/lib/validation/config.json.js +++ b/dist/lib/validation/config.json.js @@ -1814,6 +1814,9 @@ var declarations = { "text-emphasis-style": { syntax: "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | " }, + "text-fit": { + syntax: "[ none | grow | shrink ] [consistent | per-line | per-line-all]? ?" + }, "text-indent": { syntax: " && hanging? && each-line?" }, diff --git a/dist/lib/validation/match.js b/dist/lib/validation/match.js index 6ee6bc51..05d5cf88 100644 --- a/dist/lib/validation/match.js +++ b/dist/lib/validation/match.js @@ -1,7 +1,7 @@ import { getParsedSyntax, getSyntaxConfig } from './config.js'; import { EnumToken } from '../ast/types.js'; import { ValidationSyntaxGroupEnum, ValidationTokenEnum, MediaFeatureType } from './parser/typedef.js'; -import { LOC, tokensfuncDefMap, tokensfuncSet, funcLike, mFLT, mFGT } from '../syntax/constants.js'; +import { LOCSTA, tokensfuncDefMap, tokensfuncSet, funcLike, mFLT, mFGT } from '../syntax/constants.js'; import { isColor } from '../syntax/syntax.js'; import { equalsIgnoreCase } from '../parser/utils/text.js'; import { cloneNode } from '../ast/clone.js'; @@ -13,11 +13,8 @@ const allValues = config.declarations.all.syntax.split(/[\s|]+/g); /** * @type {Array.} */ -const funcTypes = [ - ...tokensfuncDefMap.values(), - EnumToken.FunctionTokenType, - EnumToken.PseudoClassFuncTokenType, -]; +const funcTypes = Array.from(tokensfuncDefMap.values()); +funcTypes.push(EnumToken.FunctionTokenType, EnumToken.PseudoClassFuncTokenType); /** * trim leading and trailing whitespace * @param tokens @@ -340,7 +337,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${EnumToken[stream[i].typ]}`, node: stream[i], // @ts-expect-error - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }, ], }; @@ -375,7 +372,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } } @@ -394,7 +393,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Nesting selector is not allowed`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -428,7 +427,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected combinator ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -472,7 +471,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -523,7 +522,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${EnumToken[slice[0].typ]}`, node: slice[0], // @ts-expect-error - location: options.source.getSourceLocation(slice[0][LOC].sta), + location: options.source.getSourceLocation(slice[0][LOCSTA]), }, ], }; @@ -535,8 +534,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOC]!.sta.lin}:${ - // slice[0][LOC]!.sta.col + // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOCSTA].lin}:${ + // slice[0][LOCSTA].col // }`, // node: slice[0], // location: slice[0][LOC], @@ -574,8 +573,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -607,8 +606,8 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -637,7 +636,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -666,7 +665,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { if (!result.success) { success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } stack.pop(); @@ -680,7 +681,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -702,7 +703,7 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unsupported selector token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source.getSourceLocation(token[LOC].sta), + location: options.source.getSourceLocation(token[LOCSTA]), }, ], }; @@ -728,13 +729,15 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { message: `Unmatched token ${EnumToken[stack.at(-1).typ]}`, node: stack.at(-1), // @ts-expect-error - location: options.source.getSourceLocation(stack.at(-1)[LOC].sta), + location: options.source.getSourceLocation(stack.at(-1)[LOCSTA]), }, ], }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** @@ -775,7 +778,7 @@ function matchAllSyntaxes(syntaxes, context, options) { message: result.errors[0]?.message || "could not match syntax", node: result.token, syntax: result.syntaxToken, - location: options.source.getSourceLocation((result.token?.[LOC] ?? context.tokens.at(-1)?.[LOC]).sta), + location: options.source.getSourceLocation((result.token?.[LOCSTA] ?? context.tokens.at(-1)?.[LOCSTA])), }, ] : result.errors, @@ -870,7 +873,7 @@ function matchOccurenceSyntax(syntax, context, options) { action: "drop", message: "could not match syntax", node: context.peek(), - // location: options.source!.getSourceLocation(context.peek()?.[LOC]!.sta), + // location: options.source!.getSourceLocation(context.peek()?.[LOCSTA]), }, ], syntaxToken: null, diff --git a/dist/node.js b/dist/node.js index 4433f7b4..11da34a5 100644 --- a/dist/node.js +++ b/dist/node.js @@ -8,7 +8,7 @@ import { doRender } from './lib/renderer/render.js'; export { renderValue as renderToken } from './lib/renderer/render.js'; import { ModuleScopeEnumOptions } from './lib/ast/types.js'; export { ColorType, EnumAstNodeStatus, EnumToken, ModuleCaseTransformEnum, ValidationLevel } from './lib/ast/types.js'; -import { tokenizeStream, tokenize } from './lib/parser/tokenize.js'; +import { Tokenizer } from './lib/parser/tokenize.js'; import { dirname, resolve, matchUrl } from './lib/fs/resolve.js'; import { ResponseType } from './types.js'; import { resolve as resolve$1 } from 'node:path'; @@ -52,6 +52,9 @@ async function load(url, currentDirectory = ".", responseType = false) { if (responseType == ResponseType.ArrayBuffer) { return response.arrayBuffer(); } + if (responseType == ResponseType.JSON) { + return response.json(); + } return responseType == ResponseType.ReadableStream ? response.body : response.text(); @@ -60,8 +63,8 @@ async function load(url, currentDirectory = ".", responseType = false) { try { const stats = await lstat(resolved.absolute); if (stats.isFile()) { - if (responseType == ResponseType.Text) { - return readFile(resolved.absolute, "utf-8"); + if (responseType == ResponseType.Text || responseType == ResponseType.JSON) { + return readFile(resolved.absolute, "utf-8").then((buffer) => responseType == ResponseType.JSON ? JSON.parse(buffer) : buffer); } if (responseType == ResponseType.ArrayBuffer) { return readFile(resolved.absolute).then((buffer) => buffer.buffer); @@ -72,9 +75,7 @@ async function load(url, currentDirectory = ".", responseType = false) { })); } } - catch (error) { - console.warn(error); - } + catch (error) { } throw new Error(`File not found: '${resolved.absolute || url}'`); } /** @@ -190,8 +191,10 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -348,7 +351,11 @@ async function parse(...args) { position: 0, currentPosition: 0, }; - return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS file diff --git a/dist/types.d.ts b/dist/types.d.ts index 7c6b4884..1910f17a 100644 --- a/dist/types.d.ts +++ b/dist/types.d.ts @@ -13,5 +13,9 @@ export declare enum ResponseType { /** * return an arraybuffer */ - ArrayBuffer = 2 + ArrayBuffer = 2, + /** + * return a json object + */ + JSON = 3 } diff --git a/dist/types.js b/dist/types.js index ced6b074..a4e52860 100644 --- a/dist/types.js +++ b/dist/types.js @@ -15,6 +15,10 @@ var ResponseType; * return an arraybuffer */ ResponseType[ResponseType["ArrayBuffer"] = 2] = "ArrayBuffer"; + /** + * return a json object + */ + ResponseType[ResponseType["JSON"] = 3] = "JSON"; })(ResponseType || (ResponseType = {})); export { ResponseType }; diff --git a/dist/utils/sync.js b/dist/utils/sync.js index 04900102..beaf894d 100644 --- a/dist/utils/sync.js +++ b/dist/utils/sync.js @@ -1,4 +1,6 @@ import { EnumToken } from '../lib/ast/types.js'; +import { dirname } from '../lib/fs/resolve.js'; +import { ResponseType } from '../types.js'; /** * parse result. process input sourcemap @@ -17,7 +19,26 @@ function parseResult(result, options) { const token = result.ast.chi.at(-1); if (token?.typ == EnumToken.CommentTokenType && token.val.startsWith("/*# sourceMappingURL=")) { - options.source.setInputSourceMap(token.val.slice(21, -2).trim()); + let data = token.val.slice(21, -2).trim(); + if (data.endsWith(".map")) { + if (options.load == null) { + data = ""; + } + else { + options + .load(options.resolve(data, dirname(options.src)).absolute, ".", ResponseType.JSON) + .catch((error) => console.error({ error })) + .then((res) => { + if (res != null) { + // @ts-expect-error + options.source.setInputSourceMap(res); + } + }); + } + } + else { + options.source.setInputSourceMap(data); + } } } } diff --git a/dist/web.js b/dist/web.js index 53779329..02428e45 100644 --- a/dist/web.js +++ b/dist/web.js @@ -4,7 +4,7 @@ import { doRender } from './lib/renderer/render.js'; export { renderValue as renderToken } from './lib/renderer/render.js'; import { ModuleScopeEnumOptions } from './lib/ast/types.js'; export { ColorType, EnumAstNodeStatus, EnumToken, ModuleCaseTransformEnum, ValidationLevel } from './lib/ast/types.js'; -import { tokenizeStream, tokenize } from './lib/parser/tokenize.js'; +import { Tokenizer } from './lib/parser/tokenize.js'; import { matchUrl, resolve, dirname } from './lib/fs/resolve.js'; import { ResponseType } from './types.js'; import { SourceFile } from './lib/parser/source.js'; @@ -58,6 +58,9 @@ async function load(url, currentDirectory = ".", responseType = false) { if (responseType == ResponseType.ArrayBuffer) { return response.arrayBuffer(); } + if (responseType == ResponseType.JSON) { + return response.json(); + } return responseType == ResponseType.ReadableStream ? response.body : response.text(); }); } @@ -184,8 +187,10 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -318,7 +323,11 @@ async function parse(...args) { position: 0, currentPosition: 0, }; - return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS file diff --git a/files/sourcemap.md b/files/sourcemap.md index c8568696..5b2e112e 100644 --- a/files/sourcemap.md +++ b/files/sourcemap.md @@ -107,5 +107,30 @@ result = await transform(css, { console.log(result.map.toJSON()); ``` +Parsing reference to the input sourcemap file is only supported when using the async api. + +```css +table.colortable { + width: 100%; + text-shadow: none; + border-collapse: collapse +} +table.colortable td { + text-align: center +} +table.colortable td.c { + text-transform: uppercase; + background: #ff0 +} +table.colortable th { + text-align: center; + color: green; + font-weight: 400; + padding: 2px 3px +} + +/*# sourceMappingURL=sourcemap.css.map */ +``` + ------ [← Custom Transform](./transform.md) | [Plugins API →](./plugins.md) \ No newline at end of file diff --git a/files/usage.md b/files/usage.md index eabdc87a..09cbe21e 100644 --- a/files/usage.md +++ b/files/usage.md @@ -11,11 +11,11 @@ The **synchronous API** is marginally faster than the asynchronous API, but it c | Function | Parses CSS | Async | CSS Output | | ----------------- | ---------- | ----- | ---------- | -| `parse()` | ✅ | ✅ | ✅ | ❌ | -| `parseSync()` | ✅ | ❌ | ❌ | -| `transform()` | ✅ | ✅ | ✅ | -| `transformSync()` | ✅ | ❌ | ✅ | -| `render()` | ❌ | ❌ | ✅ | +| `parse()` | ✅ | ✅ | ✅ | +| `parseSync()` | ✅ | ❌ | ❌ | +| `transform()` | ✅ | ✅ | ✅ | +| `transformSync()` | ✅ | ❌ | ✅ | +| `render()` | ❌ | ❌ | ✅ | > **Note:** `parse()` and `parseSync()` only produce the AST and do not generate CSS output. @@ -387,18 +387,18 @@ button { | Feature | parse() | transform() | transformSync() | ParseSync() | | ----------------------- | ------- | ----------- | --------------- | ----------- | -| Parse from stream | ✅ | ✅ | ❌ | ❌ | -| Parse from file | ✅ | ✅ | ❌ | ❌ | -| Flatten @import at-rule | ✅ | ✅ | ❌ | ❌ | -| transformSync() | ✅ | ✅ | ❌ | ❌ | +| Parse from stream | ✅ | ✅ | ❌ | ❌ | +| Parse from file | ✅ | ✅ | ❌ | ❌ | +| Flatten @import at-rule | ✅ | ✅ | ❌ | ❌ | +| transformSync() | ✅ | ✅ | ❌ | ❌ | ### CSS Module features comparison -| Feature | parse() | transform() | transformSync() | ParseSync() | -| ---------------------------------------------------------------------- | ------- | ----------- | --------------- | ----------- | -| Algorithms supported by `pattern`:
sha1, sha256, sha384, sha512 | ✅ | ✅ | ❌ | ❌ | -| CSS `composes` from file | ✅ | ✅ | ❌ | ❌ | -| import CSS variables from file | ✅ | ✅ | ❌ | ❌ | +| Feature | parse() | transform() | transformSync() | ParseSync() | +| -------------------------------------------------------------------- | ------- | ----------- | --------------- | ----------- | +| Algorithms supported by `pattern`:
sha1, sha256, sha384, sha512 | ✅ | ✅ | ❌ | ❌ | +| CSS `composes` from file | ✅ | ✅ | ❌ | ❌ | +| import CSS variables from file | ✅ | ✅ | ❌ | ❌ | ------ diff --git a/jsr.json b/jsr.json index 2828ebed..e3228e97 100644 --- a/jsr.json +++ b/jsr.json @@ -1,6 +1,6 @@ { "name": "@tbela99/css-parser", - "version": "1.5.0", + "version": "1.6.0", "publish": { "include": [ "src", diff --git a/package.json b/package.json index 3f0014e3..672455c3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tbela99/css-parser", "description": "CSS parser, minifier and validator for node and the browser", - "version": "1.5.0", + "version": "1.6.0", "exports": { ".": "./dist/node.js", "./node": "./dist/node.js", diff --git a/src/@types/ast.d.ts b/src/@types/ast.d.ts index 39e6b399..eb0bc209 100644 --- a/src/@types/ast.d.ts +++ b/src/@types/ast.d.ts @@ -1,5 +1,5 @@ import { EnumToken } from "../lib/ast/types.ts"; -import { ERRORS, LOC, OPTIMIZED, PARENT, RAW, ROOT, STATE, TOKENS } from "../lib/syntax/constants.ts"; +import { ERRORS, LOCSRCID, LOCSTA, LOCEND, OPTIMIZED, PARENT, RAW, ROOT, STATE, TOKENS } from "../lib/syntax/constants.ts"; import type { Token, CssVariableToken, CssVariableImportTokenType, WhitespaceToken } from "./token.d.ts"; /** @@ -28,11 +28,22 @@ export declare interface BaseToken { * token type */ typ: EnumToken; + /** - * location info - * @private + * source src + */ + [LOCSRCID]?: number; + + /** + * source start offset */ - [LOC]?: SourceLocation | null; + [LOCSTA]?: number; + + /** + * source end offset + */ + [LOCEND]?: number; + /** * parent node * @private diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index d1e49554..e2d073ed 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -12,6 +12,7 @@ import type { CssVariableToken, Token } from "./token.d.ts"; import { FeatureWalkMode } from "../lib/ast/features/type.ts"; import { ValidationToken } from "../lib/validation/parser/types"; import { SourceFile } from "../lib/parser/source.ts"; +import { ResponseType } from "../types.ts"; export * from "./ast.d.ts"; export * from "./token.d.ts"; @@ -206,7 +207,7 @@ export declare type LoadResult = | Promise> | ReadableStream | string - | Promise; + | Promise | object; /** * CSS module parser options diff --git a/src/@types/walker.d.ts b/src/@types/walker.d.ts index 6263d42a..65715f48 100644 --- a/src/@types/walker.d.ts +++ b/src/@types/walker.d.ts @@ -6,7 +6,6 @@ import { WalkerEvent, WalkerOptionEnum } from "../lib/ast/walk.ts"; * node walker options */ export declare interface WalkerOptions { - /** * walk in reverse */ @@ -51,7 +50,7 @@ export declare type WalkerValueFilter = ( parent?: AstNode | Token | AstNode[] | Token[] | null, event?: WalkerEvent, parents?: Generator, -) => WalkerOption | null; +) => WalkerOption | AstNode | Token | AstNode[] | Token[] | null; /** * walker result diff --git a/src/lib/ast/expand.ts b/src/lib/ast/expand.ts index 015d1382..75e1fa32 100644 --- a/src/lib/ast/expand.ts +++ b/src/lib/ast/expand.ts @@ -14,13 +14,12 @@ import { cloneNode } from "./clone.ts"; * @private */ export function expand(ast: AstStyleSheet | AstAtRule | AstRule): AstNode { - - if( - (ast as AstNode)[STATE] == EnumAstNodeStatus.Invalid || - (ast as AstNode)[STATE] == EnumAstNodeStatus.Disallowed || - (ast as AstNode)[STATE] == EnumAstNodeStatus.Unknown || - (ast as AstNode)[STATE] == EnumAstNodeStatus.Unparsed || - (ast as AstNode)[STATE] == EnumAstNodeStatus.Malformed + if ( + (ast as AstNode)[STATE] == EnumAstNodeStatus.Invalid || + (ast as AstNode)[STATE] == EnumAstNodeStatus.Disallowed || + (ast as AstNode)[STATE] == EnumAstNodeStatus.Unknown || + (ast as AstNode)[STATE] == EnumAstNodeStatus.Unparsed || + (ast as AstNode)[STATE] == EnumAstNodeStatus.Malformed ) { return ast; } @@ -36,10 +35,8 @@ export function expand(ast: AstStyleSheet | AstAtRule | AstRule): AstNode { for (const child of children) { child[PARENT] = result; + result.chi!.push(child); } - - // @ts-ignore - result.chi.push(...children); } else if (node.typ == EnumToken.AtRuleNodeType && "chi" in node) { let hasRule: boolean = false; let j: number = node!.chi!.length; @@ -79,18 +76,17 @@ export function expand(ast: AstStyleSheet | AstAtRule | AstRule): AstNode { } function expandRule(node: AstRule): Array { - - if( - (node as AstNode)[STATE] == EnumAstNodeStatus.Invalid || - (node as AstNode)[STATE] == EnumAstNodeStatus.Disallowed || - (node as AstNode)[STATE] == EnumAstNodeStatus.Unknown || - (node as AstNode)[STATE] == EnumAstNodeStatus.Unparsed || - (node as AstNode)[STATE] == EnumAstNodeStatus.Malformed + if ( + (node as AstNode)[STATE] == EnumAstNodeStatus.Invalid || + (node as AstNode)[STATE] == EnumAstNodeStatus.Disallowed || + (node as AstNode)[STATE] == EnumAstNodeStatus.Unknown || + (node as AstNode)[STATE] == EnumAstNodeStatus.Unparsed || + (node as AstNode)[STATE] == EnumAstNodeStatus.Malformed ) { return [node]; } - const ast: AstRule = Object.assign(cloneNode(node), {chi: node.chi.slice() }) as AstRule; + const ast: AstRule = Object.assign(cloneNode(node), { chi: node.chi.slice() }) as AstRule; const result: Array = []; if (ast.typ == EnumToken.RuleNodeType) { @@ -193,6 +189,15 @@ function expandRule(node: AstRule): Array { if (withCompound.length > 0) { if (withCompound.every((t) => t[0] == "&" && t.indexOf("&", 1) == -1)) { + // for (const w of withCompound) { + // for (let m = 0; m < w.length; m++) { + // // for (let n = 0; n < w[m].length; n++) { + + // withoutCompound.push(w[m].slice(1)); + // // } + // } + // } + withoutCompound.push(...withCompound.map((t) => t.slice(1))); withCompound.length = 0; } @@ -254,7 +259,9 @@ function expandRule(node: AstRule): Array { ast.chi.splice(i--, 1); - result.push(...(expandRule(rule))); + for (const s of expandRule(rule) as AstRule[]) { + result.push(s); + } } else if (ast.chi[i].typ == EnumToken.AtRuleNodeType) { let astAtRule: AstAtRule = ast.chi[i]; const values: Array = >[]; @@ -291,14 +298,22 @@ function expandRule(node: AstRule): Array { // @ts-ignore values.push(r); } else if (r.typ == EnumToken.RuleNodeType) { - // @ts-ignore - astAtRule.chi.push(...expandRule(r)); + for (const rule of expandRule(r)) { + // @ts-ignore + astAtRule.chi.push(rule); + } } } } - // @ts-ignore - result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); + if (astAtRule.chi!.length > 0) { + result.push(astAtRule); + } + + for (const r of values) { + result.push(r); + } + ast.chi.splice(i--, 1); } } diff --git a/src/lib/ast/features/calc.ts b/src/lib/ast/features/calc.ts index c7709d31..1b157fdb 100644 --- a/src/lib/ast/features/calc.ts +++ b/src/lib/ast/features/calc.ts @@ -7,17 +7,15 @@ import type { DimensionToken, FunctionToken, NumberToken, - ParensToken, ParserOptions, - Token, - WalkerOption, + Token } from "../../../@types/index.d.ts"; import { EnumToken } from "../types.ts"; -import { WalkerEvent, WalkerOptionEnum, walkValues } from "../walk.ts"; +import { walkValues } from "../walk.ts"; import { evaluate } from "../math/expression.ts"; -import { renderValue } from "../../renderer/render.ts"; import { FeatureWalkMode } from "./type.ts"; -import { LOC, mathFuncs, tokensfuncSet } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, mathFuncs, tokensfuncSet } from "../../syntax/constants.ts"; +import { replaceNodeOrValue } from "../../parser/utils/token.ts"; export class ComputeCalcExpressionFeature { public accept: Set = new Set([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType]); @@ -49,75 +47,104 @@ export class ComputeCalcExpressionFeature { const set: Set = new Set(); - for (const { value, parent } of walkValues((node).val, node, { - event: WalkerEvent.Enter, - // @ts-ignore - fn( - node: AstNode | Token, - parent: FunctionToken | ParensToken | BinaryExpressionToken, - ): WalkerOption | null { - if ( - parent != null && - // @ts-ignore - (parent as AstDeclaration).typ == EnumToken.DeclarationNodeType && - // @ts-ignore - (parent as AstDeclaration).val.length == 1 && - (node.typ === EnumToken.MathFunctionTokenType || node.typ === EnumToken.FunctionTokenType) && - mathFuncs.includes((node as FunctionToken).val) && - (node as FunctionToken).chi.length == 1 && - (node as FunctionToken).chi[0].typ == EnumToken.IdenTokenType - ) { - return WalkerOptionEnum.Ignore; - } - - if ( - (node.typ === EnumToken.WildCardFunctionTokenType && (node as FunctionToken).val == "var") || - (!mathFuncs.includes((parent as FunctionToken).val) && - [ - EnumToken.MathFunctionTokenType, - EnumToken.ColorTokenType, - EnumToken.DeclarationNodeType, - EnumToken.ImageFunc, - EnumToken.RuleNodeType, - EnumToken.AtRuleNodeType, - EnumToken.StyleSheetNodeType, - ].includes(parent?.typ)) - ) { - return null; - } - + for (const { value, parent } of walkValues( + (node).val, + node, + // { + // event: WalkerEvent.Enter, + // // @ts-ignore + // fn( + // node: AstNode | Token, + // parent: AstNode | Token | AstNode[] | Token[] | null, + // ): WalkerOption | AstNode | Token | AstNode[] | Token[] | null | void { + // if (node.typ == EnumToken.BinaryExpressionTokenType) { + // // @ts-ignore + // const children = evaluate([node]); + + // // @ts-ignore + // replaceNodeOrValue(parent, node, children); + + // return children; + // } + // }, + // // @ts-ignore + // // fn( + // // node: AstNode | Token, + // // parent: FunctionToken | ParensToken | BinaryExpressionToken, + // // ): WalkerOption | null { + // // if ( + // // parent != null && + // // // @ts-ignore + // // (parent as AstDeclaration).typ == EnumToken.DeclarationNodeType && + // // // @ts-ignore + // // (parent as AstDeclaration).val.length == 1 && + // // (node.typ === EnumToken.MathFunctionTokenType || node.typ === EnumToken.FunctionTokenType) && + // // mathFuncs.includes((node as FunctionToken).val) && + // // (node as FunctionToken).chi.length == 1 && + // // (node as FunctionToken).chi[0].typ == EnumToken.IdenTokenType + // // ) { + + // // return WalkerOptionEnum.Ignore; + // // } + + // // // if ( + // // // (node.typ === EnumToken.WildCardFunctionTokenType && (node as FunctionToken).val == "var") || + // // // (!mathFuncs.includes((parent as FunctionToken).val) && + // // // [ + // // // EnumToken.MathFunctionTokenType, + // // // EnumToken.ColorTokenType, + // // // EnumToken.DeclarationNodeType, + // // // EnumToken.ImageFunc, + // // // EnumToken.RuleNodeType, + // // // EnumToken.AtRuleNodeType, + // // // EnumToken.StyleSheetNodeType, + // // // ].includes(parent?.typ)) + // // // ) { + // // // return null; + // // // } + + // // // @ts-ignore + // // // const slice: Token[] = ( + // // // node.typ == EnumToken.FunctionTokenType || node.typ == EnumToken.MathFunctionTokenType + // // // ? (node as FunctionToken).chi + // // // : node.typ == EnumToken.DeclarationNodeType + // // // ? (node).val + // // // : (node as FunctionToken).chi + // // // )?.slice(); + + // // // if ( + // // // slice != null && + // // // (node.typ === EnumToken.MathFunctionTokenType || + // // // (node.typ == EnumToken.FunctionTokenType && + // // // mathFuncs.includes((node as FunctionToken).val))) + // // // ) { + // // // // @ts-ignore + // // // const key = "chi" in node ? "chi" : "val"; + + // // // const str1: string = renderValue({ ...node, [key]: slice } as Token); + // // // const str2: string = renderValue(node as Token); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); + + // // // if (str1.length < str2.length) { + // // // // @ts-ignore + // // // node[key] = slice; + // // // } + + // // // return WalkerOptionEnum.Ignore; + // // // } + + // // return null; + // // }, + // } + )) { + if (parent?.typ == EnumToken.BinaryExpressionTokenType) { + continue; + } + if (value.typ == EnumToken.BinaryExpressionTokenType) { // @ts-ignore - const slice: Token[] = ( - node.typ == EnumToken.FunctionTokenType || node.typ == EnumToken.MathFunctionTokenType - ? (node as FunctionToken).chi - : node.typ == EnumToken.DeclarationNodeType - ? (node).val - : (node as FunctionToken).chi - )?.slice(); - - if ( - slice != null && - (node.typ === EnumToken.MathFunctionTokenType || - (node.typ == EnumToken.FunctionTokenType && - mathFuncs.includes((node as FunctionToken).val))) - ) { - // @ts-ignore - const key = "chi" in node ? "chi" : "val"; - - const str1: string = renderValue({ ...node, [key]: slice } as Token); - const str2: string = renderValue(node as Token); // values.reduce((acc: string, curr: Token): string => acc + renderValue(curr), ''); - - if (str1.length < str2.length) { - // @ts-ignore - node[key] = slice; - } - - return WalkerOptionEnum.Ignore; - } + replaceNodeOrValue(parent, value, evaluate([value])); + continue; + } - return null; - }, - })) { if (value != null && tokensfuncSet.has(value.typ)) { if (!set.has(value as FunctionToken)) { set.add(value); @@ -184,7 +211,9 @@ export class ComputeCalcExpressionFeature { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], } : values[0], ); @@ -198,7 +227,9 @@ export class ComputeCalcExpressionFeature { typ: EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; diff --git a/src/lib/ast/features/if.ts b/src/lib/ast/features/if.ts index 3d853b66..2b977b31 100644 --- a/src/lib/ast/features/if.ts +++ b/src/lib/ast/features/if.ts @@ -13,7 +13,7 @@ import type { import { EnumToken } from "../types.ts"; import { renderValue } from "../../renderer/render.ts"; import { FeatureWalkMode } from "./type.ts"; -import { LOC, PARENT, TOKENS } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, PARENT, TOKENS } from "../../syntax/constants.ts"; import { equalsIgnoreCase } from "../../parser/utils/text.ts"; import { replaceNodeOrValue } from "../../parser/utils/token.ts"; import { cloneNode } from "../../ast/clone.ts"; @@ -156,7 +156,9 @@ function substituteIfElseNode( }) as AstAtRule; if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]!; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]!; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]!; + atRule[LOCEND] = declaration[PARENT][LOCEND]!; } atRule[TOKENS] = [{ typ: EnumToken.ParensTokenType, chi: (left as FunctionToken).chi.slice() }]; @@ -193,7 +195,10 @@ function substituteIfElseNode( atRule.val = atRule[TOKENS]!.reduce((acc: string, curr: Token) => acc + renderValue(curr), ""); if (declaration[PARENT] != null) { - atRule[LOC] = declaration[PARENT][LOC]!; + atRule[LOCSRCID] = declaration[PARENT][LOCSRCID]!; + atRule[LOCSTA] = declaration[PARENT][LOCSTA]!; + atRule[LOCEND] = declaration[PARENT][LOCEND]!; + } clonedDeclaration = cloneNode(declaration, true, nodeMap) as AstDeclaration; diff --git a/src/lib/ast/features/inlinecssvariables.ts b/src/lib/ast/features/inlinecssvariables.ts index 663c951b..1a70e7be 100644 --- a/src/lib/ast/features/inlinecssvariables.ts +++ b/src/lib/ast/features/inlinecssvariables.ts @@ -26,13 +26,15 @@ function inlineExpression(token: Token): Token[] { const result: Token[] = []; if (token.typ == EnumToken.BinaryExpressionTokenType) { + const chi = inlineExpression((token as BinaryExpressionToken).l); + chi.push({ typ: (token as BinaryExpressionToken).op } as Token); + + for (const child of inlineExpression((token as BinaryExpressionToken).r)) { + chi.push(child); + } result.push({ typ: EnumToken.ParensTokenType, - chi: [ - ...inlineExpression((token as BinaryExpressionToken).l), - { typ: (token as BinaryExpressionToken).op }, - ...inlineExpression((token as BinaryExpressionToken).r), - ], + chi, } as ParensToken); } else { result.push(token); diff --git a/src/lib/ast/features/prefix.ts b/src/lib/ast/features/prefix.ts index debe40d6..5932cfc2 100644 --- a/src/lib/ast/features/prefix.ts +++ b/src/lib/ast/features/prefix.ts @@ -100,9 +100,9 @@ function replaceAstNodes(tokens: Token[], root?: AstNode): boolean { // typ: EnumToken.ResolutionTokenType, // unit: "x", // }); - // } - // else - if (isPseudClass && value.typ == EnumToken.PseudoElementTokenType) { + // } + // else + if (isPseudClass && value.typ == EnumToken.PseudoElementTokenType) { // @ts-ignore value.typ = EnumToken.PseudoClassTokenType; } @@ -118,23 +118,24 @@ function replaceAstNodes(tokens: Token[], root?: AstNode): boolean { const split = splitTokenList(tokens, [EnumToken.CommaTokenType]); tokens.length = 0; - tokens.push( - ...split.reduce((acc, curr) => { - const str = curr.reduce((acc, curr) => acc + renderValue(curr), ""); - if (set.has(str)) { - return acc; - } - set.add(str); - if (acc.length > 0) { - acc.push({ - typ: EnumToken.CommaTokenType, - }); - } + for (const token of split.reduce((acc, curr) => { + const str = curr.reduce((acc, curr) => acc + renderValue(curr), ""); + if (set.has(str)) { + return acc; + } + set.add(str); + + if (acc.length > 0) { + acc.push({ + typ: EnumToken.CommaTokenType, + }); + } - return acc.concat(curr); - }, [] as Token[]), - ); + return acc.concat(curr); + }, [] as Token[])) { + tokens.push(token); + } } return result; @@ -395,7 +396,6 @@ export class ComputePrefixFeature { } tokens.splice(0, i + 1); - commaCount = 0; for (i = 0; i < tokens.length; i++) { @@ -425,45 +425,61 @@ export class ComputePrefixFeature { const replacements: Token[] = []; if (key === "left top left bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "bottom" }, + ); } else if (key === "left bottom left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "top" }, + ); } else if (key === "left top right top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "right" }, + ); } else if (key === "right top left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "left" }, + ); } else if (key === "left top right bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "bottom" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "right" }, + ); } else if (key === "right top left bottom") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "bottom" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "bottom" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "left" }, + ); } else if (key === "left bottom right top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "right" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "top" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "right" }, + ); } else if (key === "right bottom left top") { - replacements.push({ typ: EnumToken.IdenTokenType, val: "to" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "top" }); - replacements.push({ typ: EnumToken.WhitespaceTokenType }); - replacements.push({ typ: EnumToken.IdenTokenType, val: "left" }); + replacements.push( + { typ: EnumToken.IdenTokenType, val: "to" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "top" }, + { typ: EnumToken.WhitespaceTokenType }, + { typ: EnumToken.IdenTokenType, val: "left" }, + ); } tokens.splice(0, i, ...replacements); @@ -480,7 +496,12 @@ export class ComputePrefixFeature { if (tokens[i].typ === EnumToken.FunctionTokenType) { if (equalsIgnoreCase((tokens[i] as FunctionToken).val, "to")) { - colorStop.push(tokens[checkStopIndex], ...(tokens[i] as FunctionToken).chi); + colorStop.push(tokens[checkStopIndex]); + + for (const token of (tokens[i] as FunctionToken).chi) { + colorStop.push(token); + } + tokens.splice(checkStopIndex!, i - checkStopIndex! + 1); i = checkStopIndex!; @@ -519,14 +540,19 @@ export class ComputePrefixFeature { } if (colorStop.length > 0) { - tokens.push(...colorStop); + for (const t of colorStop) { + tokens.push(t); + } } if (type !== "") { token.val = type; token.chi.length = 0; - token.chi.push(...tokens); + + for (const t of tokens) { + token.chi.push(t); + } } } @@ -619,7 +645,9 @@ export class ComputePrefixFeature { } } - colorStops.push(...tokens.slice(i)); + for (let m = i; m < tokens.length; m++) { + colorStops.push(tokens[m]); + } tokens.length = 0; @@ -629,7 +657,10 @@ export class ComputePrefixFeature { } if (size.length > 0) { form.push({ typ: EnumToken.WhitespaceTokenType }); - form.push(...size); + + for (const token of size) { + form.push(token); + } } if (positions.length > 0) { @@ -637,18 +668,28 @@ export class ComputePrefixFeature { { typ: EnumToken.WhitespaceTokenType }, { typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, - ...positions, ); + + for (const position of positions) { + form.push(position); + } } - tokens.push(...form, { typ: EnumToken.CommaTokenType }); + for (const token of form) { + tokens.push(token); + } + + tokens.push({ typ: EnumToken.CommaTokenType }); } token.val = equalsIgnoreCase(token.val, "-webkit-repeating-radial-gradient") ? "repeating-radial-gradient" : "radial-gradient"; - tokens.push(...colorStops); + for (const colorStop of colorStops) { + tokens.push(colorStop); + } + return tokens; } } diff --git a/src/lib/ast/features/shorthand.ts b/src/lib/ast/features/shorthand.ts index daf97e2c..45f6649d 100644 --- a/src/lib/ast/features/shorthand.ts +++ b/src/lib/ast/features/shorthand.ts @@ -32,14 +32,7 @@ export class ComputeShorthandFeature { } } - run( - ast: AstRule | AstAtRule, - options: PropertyListOptions = {}, - parent: AstRule | AstAtRule | AstStyleSheet, - context: { - [key: string]: any; - }, - ): AstNode | null { + run(ast: AstRule | AstAtRule, options: PropertyListOptions): AstNode | null { if (!("chi" in ast)) { return null; } @@ -71,16 +64,21 @@ export class ComputeShorthandFeature { const node = ast.chi[l]; if (node.typ == EnumToken.DeclarationNodeType) { - properties.add(...ast.chi!.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + properties.add(ast.chi![m]); + } } else { - rules.push(...ast.chi!.slice(k, l + 1)); + for (let m = k; m <= l; m++) { + rules.push(ast.chi![m]); + } } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi!.length = 0; + // @ts-expect-error + ast.chi!.push(...properties, ...rules); return ast; } } diff --git a/src/lib/ast/features/transform.ts b/src/lib/ast/features/transform.ts index 88d5a1bf..0c2f7e80 100644 --- a/src/lib/ast/features/transform.ts +++ b/src/lib/ast/features/transform.ts @@ -38,7 +38,7 @@ export class TransformCssFeature { } run(ast: AstRule | AstAtRule): AstNode | null { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } diff --git a/src/lib/ast/math/expression.ts b/src/lib/ast/math/expression.ts index 3e918600..7e9abdb7 100644 --- a/src/lib/ast/math/expression.ts +++ b/src/lib/ast/math/expression.ts @@ -12,11 +12,12 @@ import type { LiteralToken, NumberToken, ParensToken, + PercentageToken, ResolutionToken, TimeToken, Token, } from "../../../@types/index.d.ts"; -import { LOC, mathFuncs } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, mathFuncs } from "../../syntax/constants.ts"; import { EnumToken } from "../types.ts"; import { compute, rem } from "./math.ts"; @@ -54,7 +55,9 @@ export function evaluate(tokens: Token[]): Token[] { acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }); @@ -96,7 +99,9 @@ export function evaluate(tokens: Token[]): Token[] { // @ts-ignore val: Math[(nodes[0]).val.toUpperCase()] as number, typ: EnumToken.NumberTokenType, - [LOC]: nodes[0][LOC], + [LOCSRCID]: nodes[0][LOCSRCID], + [LOCSTA]: nodes[0][LOCSTA], + [LOCEND]: nodes[0][LOCEND], }, ]; } @@ -121,12 +126,20 @@ export function evaluate(tokens: Token[]): Token[] { token = { typ: EnumToken.ListToken, chi: [nodes[i], nodes[i + 1]], - [LOC]: { ...nodes[i][LOC], end: nodes[i + 1]![LOC]!.end as number }, + [LOCSRCID]: nodes[i][LOCSRCID], + [LOCSTA]: nodes[i][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], } as ListToken; } else { token = doEvaluate( nodes[i + 1] as Token, - { typ: EnumToken.NumberTokenType, val: -1, [LOC]: nodes[i + 1][LOC] }, + { + typ: EnumToken.NumberTokenType, + val: -1, + [LOCSRCID]: nodes[i + 1][LOCSRCID], + [LOCSTA]: nodes[i + 1][LOCSTA], + [LOCEND]: nodes[i + 1][LOCEND], + }, EnumToken.Mul, ); } @@ -146,17 +159,32 @@ export function evaluate(tokens: Token[]): Token[] { if (token.typ != EnumToken.BinaryExpressionTokenType) { if ("val" in token && +(token as NumberToken).val < 0) { - acc.push({ typ: EnumToken.Sub, [LOC]: token[LOC] }, { - ...token, - val: -(token as NumberToken).val, - [LOC]: token[LOC], - } as Token); + acc.push( + { + typ: EnumToken.Sub, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + { + ...token, + val: -(token as NumberToken).val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + } as Token, + ); return acc; } } if (acc.length > 0 && curr[0] != EnumToken.ListToken) { - acc.push({ typ: EnumToken.Add, [LOC]: token[LOC] }); + acc.push({ + typ: EnumToken.Add, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }); } acc.push(token); @@ -180,7 +208,9 @@ function doEvaluate( op, l, r, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], }; if (!isScalarToken(l) || !isScalarToken(r) || (l.typ == r.typ && "unit" in l && "unit" in r && l.unit != r.unit)) { @@ -228,14 +258,38 @@ function doEvaluate( if (typeof v1 == "number" && l.typ == EnumToken.PercentageTokenType) { v1 = { typ: EnumToken.FractionTokenType, - l: { typ: EnumToken.NumberTokenType, val: v1, [LOC]: l[LOC] }, - r: { typ: EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: EnumToken.NumberTokenType, + val: v1, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } else if (typeof v2 == "number" && r.typ == EnumToken.PercentageTokenType) { v2 = { typ: EnumToken.FractionTokenType, - l: { typ: EnumToken.NumberTokenType, val: v2, [LOC]: l[LOC] }, - r: { typ: EnumToken.NumberTokenType, val: 100, [LOC]: r[LOC] }, + l: { + typ: EnumToken.NumberTokenType, + val: v2, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: l[LOCEND], + }, + r: { + typ: EnumToken.NumberTokenType, + val: 100, + [LOCSRCID]: r[LOCSRCID], + [LOCSTA]: r[LOCSTA], + [LOCEND]: r[LOCEND], + }, }; } } @@ -248,7 +302,9 @@ function doEvaluate( ...(l.typ === EnumToken.NumberTokenType || l.typ === EnumToken.IdenTokenType ? r : l), typ, val /* : typeof val == 'number' ? minifyNumber(val) : val */, - [LOC]: { ...l[LOC], end: (r?.[LOC] ?? l?.[LOC])?.end }, + [LOCSRCID]: l[LOCSRCID], + [LOCSTA]: l[LOCSTA], + [LOCEND]: r?.[LOCEND] ?? l[LOCEND], } as Token; if (token.typ == EnumToken.IdenTokenType) { @@ -283,21 +339,61 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { case "sign": case "sqrt": case "exp": { + if (token.val == "tan" || token.val == "atan") { + for (let i = 0; i < values.length; i++) { + if (values[i].typ == EnumToken.NumberTokenType) { + values[i] = Object.assign(values[i], { typ: EnumToken.AngleTokenType, unit: "rad" }); + } else if (values[i].typ == EnumToken.AngleTokenType && (values[i] as AngleToken).unit != "rad") { + switch ((values[i] as AngleToken).unit) { + case "deg": + Object.assign(values[i], { + unit: "rad", + val: ((values[i] as AngleToken).val as number) * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(values[i], { + unit: "rad", + val: ((values[i] as AngleToken).val as number) * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(values[i], { + unit: "rad", + val: ((values[i] as AngleToken).val as number) * (2 * Math.PI), + }); + break; + } + } + } + } + const value: Token[] = evaluate(values); // @ts-ignore let val: number = - value[0].typ == EnumToken.NumberTokenType + value[0].typ == EnumToken.NumberTokenType || value[0].typ == EnumToken.AngleTokenType ? (+(value[0] as NumberToken | DimensionToken).val as number) : // @ts-expect-error ((value[0] as FractionToken).l.val as number) / (value[0] as FractionToken).r.val; return [ - { - typ: EnumToken.NumberTokenType, - val: Math[token.val](val), - [LOC]: value[0][LOC], - }, + token.val == "tan" || token.val == "atan" + ? { + typ: EnumToken.AngleTokenType, + val: Math[token.val](val), + unit: "rad", + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + } + : { + typ: EnumToken.NumberTokenType, + val: Math[token.val](val), + [LOCSRCID]: value[0][LOCSRCID], + [LOCSTA]: value[0][LOCSTA], + [LOCEND]: value[0][LOCEND], + }, ]; } @@ -328,8 +424,10 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { return [ { ...ref, - val: +Math.sqrt(value).toFixed(rem(...all)), - [LOC]: token[LOC], + val: Math.hypot(...all), + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], } as | DimensionToken | AngleToken @@ -349,6 +447,35 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { (t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ), ); + if (token.val == "atan2") { + for (let i = 0; i < chi.length; i++) { + if (chi[i].typ == EnumToken.NumberTokenType) { + chi[i] = Object.assign(chi[i], { typ: EnumToken.AngleTokenType, unit: "rad" }); + } else if (chi[i].typ == EnumToken.AngleTokenType && (chi[i] as AngleToken).unit != "rad") { + switch ((chi[i] as AngleToken).unit) { + case "deg": + Object.assign(chi[i], { + unit: "rad", + val: ((chi[i] as AngleToken).val as number) * (Math.PI / 180), + }); + break; + case "grad": + Object.assign(chi[i], { + unit: "rad", + val: ((chi[i] as AngleToken).val as number) * (Math.PI / 200), + }); + break; + case "turn": + Object.assign(chi[i], { + unit: "rad", + val: ((chi[i] as AngleToken).val as number) * (2 * Math.PI), + }); + break; + } + } + } + } + // https://developer.mozilla.org/en-US/docs/Web/CSS/mod const v1: Token[] = evaluate([chi[0]]); const v2: Token[] = evaluate([chi[2]]); @@ -378,7 +505,9 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { { ...v1[0], val: Math.pow(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], } as | DimensionToken | AngleToken @@ -395,8 +524,12 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { { ...{}, ...v1[0], + typ: EnumToken.AngleTokenType, + unit: "rad", val: Math.atan2(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], } as | DimensionToken | AngleToken @@ -412,7 +545,9 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { { ...v1[0], val: val2 == 0 ? val1 : val1 - Math.floor(val1 / val2) * val2, - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], } as | DimensionToken | AngleToken @@ -470,7 +605,9 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { { ...values[0], val: Math.log(val1) / Math.log(val2 as number), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], } as | DimensionToken | AngleToken @@ -518,7 +655,15 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { } // @ts-ignore - return [{ ...values[0], val, [LOC]: token[LOC] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + } as NumberToken | PercentageToken | DimensionToken | AngleToken, + ]; } } } @@ -538,11 +683,22 @@ export function inlineExpression(token: Token): Token[] { if ([EnumToken.Mul, EnumToken.Div].includes((token as BinaryExpressionToken).op)) { result.push(token); } else { - result.push( - ...inlineExpression((token as BinaryExpressionToken).l), - { typ: (token as BinaryExpressionToken).op, [LOC]: (token as BinaryExpressionToken)[LOC] } as Token, - ...inlineExpression((token as BinaryExpressionToken).r), - ); + + for (const child of inlineExpression((token as BinaryExpressionToken).l)) { + result.push(child); + } + + result.push({ + typ: (token as BinaryExpressionToken).op, + [LOCSRCID]: (token as BinaryExpressionToken)[LOCSRCID], + [LOCSTA]: (token as BinaryExpressionToken)[LOCSTA], + [LOCEND]: (token as BinaryExpressionToken)[LOCEND], + } as Token); + + for (const child of inlineExpression((token as BinaryExpressionToken).r)) { + result.push(child); + } + } } else { result.push(token); @@ -638,7 +794,13 @@ function factorToken(token: Token): Token { (token.typ == EnumToken.MathFunctionTokenType || token.typ == EnumToken.FunctionTokenType) && (token as FunctionToken).val == "calc" ) { - token = { ...token, typ: EnumToken.ParensTokenType, [LOC]: token[LOC] } as ParensToken; + token = { + ...token, + typ: EnumToken.ParensTokenType, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + } as ParensToken; // @ts-ignore delete token.val; @@ -686,7 +848,9 @@ function factor(tokens: Array, ops: Array<"+" | " : getArithmeticOperation(<"-" | "+" | "/" | "*">(tokens[i] as LiteralToken).val), l: factorToken(tokens[i - 1]), r: factorToken(tokens[i + 1]), - [LOC]: { ...tokens[i - 1][LOC], end: tokens[i + 1]![LOC]?.end }, + [LOCSRCID]: tokens[i - 1][LOCSRCID], + [LOCSTA]: tokens[i - 1][LOCSTA], + [LOCEND]: tokens[i + 1]![LOCEND], }); i--; diff --git a/src/lib/ast/minify.ts b/src/lib/ast/minify.ts index d232bd67..e3f65511 100644 --- a/src/lib/ast/minify.ts +++ b/src/lib/ast/minify.ts @@ -28,10 +28,9 @@ import { EnumToken } from "./types.ts"; import { isFunction, isIdent, isIdentStart, isWhiteSpace } from "../syntax/syntax.ts"; import { FeatureWalkMode } from "./features/type.ts"; import { trimArray } from "../validation/match.ts"; -import { combinators, LOC, OPTIMIZED, PARENT, RAW, TOKENS } from "../syntax/constants.ts"; +import { combinators, LOCEND, LOCSRCID, LOCSTA, OPTIMIZED, PARENT, RAW, TOKENS } from "../syntax/constants.ts"; import { replaceNodeOrValue } from "../parser/utils/token.ts"; import { parseString } from "../parser/parse.ts"; -import { tokenize } from "../parser/tokenize.ts"; import { replaceCompound } from "./expand.ts"; const notEndingWith: string[] = ["(", "["].concat(combinators); @@ -338,7 +337,9 @@ function transformAtRuleMediaPrelude(values: Token[]) { }, l: val1, r: val2, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], } as MediaRangeQueryToken, ], } as ParensToken; @@ -426,7 +427,10 @@ function minifyAtRuleMedia(tokens: Token[]): Token[] { } as Token); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } + return acc; }, [] as Token[]), ); @@ -535,7 +539,9 @@ function doMinify( ) { // do not merge keyframes // https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@keyframes#resolving_duplicates - (previous).chi.push(...(node).chi); + for (const child of (node).chi) { + (previous).chi.push(child); + } // @ts-ignore ast.chi.splice(i, 1); @@ -580,7 +586,11 @@ function doMinify( if (slice.length !== (node as AstAtRule)[TOKENS]!.length) { (node as AstAtRule)[TOKENS]!.length = 0; - (node as AstAtRule)[TOKENS]!.push(...slice); + + for (const token of slice) { + (node as AstAtRule)[TOKENS]!.push(token); + } + (node as AstAtRule).val = slice.reduce( (acc: string, curr: Token, index: number, arr: Token[]): string => acc + @@ -650,8 +660,9 @@ function doMinify( (previous).val === (node).val ) { if ("chi" in node) { - // @ts-ignore - previous.chi!.push(...(node as AstAtRule).chi!); + for (const child of (node as AstAtRule).chi!) { + previous.chi!.push(child); + } if (!hasDeclaration(previous as AstAtRule)) { context.nodes.delete(previous); @@ -928,8 +939,18 @@ function doMinify( // @ts-ignore (node as AstAtRule).nam === (previous as AstAtRule).nam) ) { + + const array = []; + + for (let i = 0; i < previous.chi!.length; i++) { + array.push(previous.chi![i]); + } + for (let i = 0; i < node.chi!.length; i++) { + array.push(node.chi![i]); + } + // @ts-ignore - node.chi.unshift(...previous.chi); + node.chi = array; doMinify(node, options, recursive, errors, nestingContent, context); @@ -1362,7 +1383,9 @@ function reduceSelector(acc: string[][], curr: string[]): string[][] | null { acc.push(","); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); @@ -1526,7 +1549,7 @@ function matchSelectors(selector1: string[][], selector2: string[][]): null | Ma */ function fixSelector(node: AstRule): void { if (node.sel.includes("&")) { - const attributes: Token[] = [...tokenize(node.sel as string)].map((t) => t.token) as Token[]; // parseString(node.sel); + const attributes: Token[] = parseString(node.sel); for (const attr of walkValues(attributes)) { if ( @@ -1584,10 +1607,14 @@ function wrapNodes( } as AstRule; if (pSel == "&" || pSel === "") { - wrapper.chi.push(...previous.chi); + for (const child of previous.chi) { + wrapper.chi.push(child); + } if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); + for (const child of node.chi) { + wrapper.chi.push(child); + } } else { wrapper.chi.push(node); } @@ -1895,7 +1922,10 @@ function reduceRuleSelector(node: AstRule) { } unique.add(sig); - acc.push(...curr); + + for (const c of curr) { + acc.push(c); + } } return acc; diff --git a/src/lib/ast/node.ts b/src/lib/ast/node.ts index 7d98c19c..5bd65ce3 100644 --- a/src/lib/ast/node.ts +++ b/src/lib/ast/node.ts @@ -1,5 +1,5 @@ import type { AstNode, ErrorDescription, SourceLocation, Token } from "../../@types/index.d.ts"; -import { ERRORS, LOC, PARENT, STATE, TOKENS } from "../syntax/constants.ts"; +import { ERRORS, LOCEND, LOCSRCID, LOCSTA, PARENT, STATE, TOKENS } from "../syntax/constants.ts"; import { AstNodePropertyType, EnumAstNodeStatus } from "./types.ts"; /** @@ -46,7 +46,7 @@ export function getNodeProperty(node: AstNode, key: AstNodePropertyType): any { case "parent": return node[PARENT]; case "location": - return node[LOC]; + return node[LOCSRCID] == null && node[LOCSTA] == null && node[LOCEND] == null ? null : {srcId: node[LOCSRCID], sta: node[LOCSTA], end: node[LOCEND]} as SourceLocation; case "state": return node[STATE]; case "errors": @@ -105,7 +105,9 @@ export function setNodeProperty(node: AstNode, key: AstNodePropertyType, value: node[PARENT] = value; break; case "location": - node[LOC] = value; + node[LOCSRCID] = (value as SourceLocation).srcId; + node[LOCSTA] = (value as SourceLocation).sta; + node[LOCEND] = (value as SourceLocation).end; break; case "state": node[STATE] = value; diff --git a/src/lib/ast/transform/compute.ts b/src/lib/ast/transform/compute.ts index cbcd6a4f..2f25767e 100644 --- a/src/lib/ast/transform/compute.ts +++ b/src/lib/ast/transform/compute.ts @@ -32,6 +32,7 @@ export function compute(transformLists: Token[]): { let matrix: Matrix | null = identity(); let mat: Matrix; + let transforms: Token[]; const cumulative: Token[] = []; for (const transformList of splitTransformList(transformLists)) { @@ -42,7 +43,12 @@ export function compute(transformLists: Token[]): { } matrix = multiply(matrix, mat) as Matrix; - cumulative.push(...((minify(mat) as Token[]) ?? transformList)); + + transforms = (minify(mat) as Token[]) ?? transformList; + + for (let i = 0; i < transforms.length; i++) { + cumulative.push(transforms[i]); + } } const serialized: Token = serialize(matrix); @@ -62,11 +68,79 @@ export function compute(transformLists: Token[]): { } } - return { + const result = { matrix: serialize(toZero(matrix) as Matrix), cumulative, minified: minify(matrix) ?? [serialized], }; + + // valid identity matrix + if ( + (result.minified.length == 1 && + result.minified[0].typ == EnumToken.IdenTokenType && + (result.minified[0] as IdentToken).val == "none") || + (result.cumulative.length == 1 && + result.cumulative[0].typ == EnumToken.IdenTokenType && + (result.cumulative[0] as IdentToken).val == "none") || + (result.matrix?.typ == EnumToken.IdenTokenType && (result.matrix as IdentToken).val == "none") + ) { + // all transform function arguments must be 0 or scale(1) + for (const transform of transformLists) { + switch ((transform as FunctionToken).val) { + case "translate": + case "translateX": + case "translateY": + case "translateZ": + case "translate3d": + case "rotate": + case "rotateX": + case "rotateY": + case "rotateZ": + case "rotate3d": + case "skew": + case "skewX": + case "skewY": + for (const child of (transform as FunctionToken).chi) { + if (child.typ == EnumToken.WhitespaceTokenType || child.typ == EnumToken.CommaTokenType) { + continue; + } + + if ( + (child.typ != EnumToken.AngleTokenType && + child.typ != EnumToken.NumberTokenType && + child.typ != EnumToken.PercentageTokenType) || + getNumber(child as NumberToken) != 0 + ) { + return null; + } + } + + break; + + case "scale": + case "scaleX": + case "scaleY": + case "scaleZ": + case "scale3d": + for (const child of (transform as FunctionToken).chi) { + if (child.typ == EnumToken.WhitespaceTokenType || child.typ == EnumToken.CommaTokenType) { + continue; + } + + if ( + (child.typ != EnumToken.NumberTokenType && child.typ != EnumToken.PercentageTokenType) || + getNumber(child as NumberToken) != 1 + ) { + return null; + } + } + + break; + } + } + } + + return result; } export function computeMatrix(transformList: Token[], matrixVar: Matrix): Matrix | null { @@ -216,7 +290,7 @@ export function computeMatrix(transformList: Token[], matrixVar: Matrix): Matrix return null; } - matrixVar = scale3d(...(values as [number, number, number]), matrixVar); + matrixVar = scale3d(values[0], values[1], values[2], matrixVar); break; } diff --git a/src/lib/ast/transform/minify.ts b/src/lib/ast/transform/minify.ts index 48783725..8281f783 100644 --- a/src/lib/ast/transform/minify.ts +++ b/src/lib/ast/transform/minify.ts @@ -273,7 +273,7 @@ export function eqMatrix(a: FunctionToken | Matrix, b: Token[]): boolean { let mat: Matrix = identity(); let tmp: Matrix = identity(); - const data = (Array.isArray(a) ? a : parseMatrix(a)) as Matrix; + const data = (Array.isArray(a) || ArrayBuffer.isView(a) ? a : parseMatrix(a)) as Matrix; for (const transform of b) { tmp = computeMatrix([transform], identity()) as Matrix; @@ -303,7 +303,7 @@ export function eqMatrix(a: FunctionToken | Matrix, b: Token[]): boolean { export function minifyTransformFunctions(transform: FunctionToken): FunctionToken { const name: string = transform.val.toLowerCase(); - if ("skewx" == name) { + if ("skewX" == name) { transform.val = "skew"; return transform; } @@ -359,11 +359,11 @@ export function minifyTransformFunctions(transform: FunctionToken): FunctionToke const ignoredValue = name.startsWith("scale") ? 1 : 0; const t = new Set(["x", "y", "z"]); - let i: number = 3; + for (let i = 0; i < 3; i++) { + const axis = i == 0 ? "x" : i == 1 ? "y" : "z"; - while (i--) { if (values.length <= i || values[i].val == ignoredValue) { - t.delete(i == 0 ? "x" : i == 1 ? "y" : "z"); + t.delete(axis); } } diff --git a/src/lib/ast/transform/type.d.ts b/src/lib/ast/transform/type.d.ts index 661d6737..217f0a7a 100644 --- a/src/lib/ast/transform/type.d.ts +++ b/src/lib/ast/transform/type.d.ts @@ -1,10 +1,10 @@ export declare type Point = [number, number, number]; -export declare type Matrix = [ +export declare type Matrix = Float32Array< number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number -]; +>; export interface DecomposedMatrix3D { skew: [number, number, number]; diff --git a/src/lib/ast/transform/utils.ts b/src/lib/ast/transform/utils.ts index fcd9401c..764d5608 100644 --- a/src/lib/ast/transform/utils.ts +++ b/src/lib/ast/transform/utils.ts @@ -1,8 +1,10 @@ import { epsilon } from "../../syntax/constants.ts"; import type { DecomposedMatrix3D, Matrix, Point } from "./type.d.ts"; +const identityMatrix = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); + export function identity(): Matrix { - return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] as Matrix; + return identityMatrix.slice() as Matrix; } function normalize(point: Point): Point { const [x, y, z] = point; @@ -25,17 +27,32 @@ function dot( } export function multiply(matrixA: Matrix, matrixB: Matrix): Matrix { - let result: Matrix = new Array(16).fill(0) as Matrix; - - for (let i = 0; i < 4; i++) { - for (let j = 0; j < 4; j++) { - for (let k = 0; k < 4; k++) { - // Utiliser l'indexation linéaire pour accéder aux éléments - // Pour une matrice 4x4, l'index est (row * 4 + col) - result[j * 4 + i] += matrixA[k * 4 + i] * matrixB[j * 4 + k]; - } - } - } + const result = new Float32Array(16) as Matrix; + + result[0] = matrixA[0] * matrixB[0] + matrixA[4] * matrixB[1] + matrixA[8] * matrixB[2] + matrixA[12] * matrixB[3]; + result[1] = matrixA[1] * matrixB[0] + matrixA[5] * matrixB[1] + matrixA[9] * matrixB[2] + matrixA[13] * matrixB[3]; + result[2] = matrixA[2] * matrixB[0] + matrixA[6] * matrixB[1] + matrixA[10] * matrixB[2] + matrixA[14] * matrixB[3]; + result[3] = matrixA[3] * matrixB[0] + matrixA[7] * matrixB[1] + matrixA[11] * matrixB[2] + matrixA[15] * matrixB[3]; + result[4] = matrixA[0] * matrixB[4] + matrixA[4] * matrixB[5] + matrixA[8] * matrixB[6] + matrixA[12] * matrixB[7]; + result[5] = matrixA[1] * matrixB[4] + matrixA[5] * matrixB[5] + matrixA[9] * matrixB[6] + matrixA[13] * matrixB[7]; + result[6] = matrixA[2] * matrixB[4] + matrixA[6] * matrixB[5] + matrixA[10] * matrixB[6] + matrixA[14] * matrixB[7]; + result[7] = matrixA[3] * matrixB[4] + matrixA[7] * matrixB[5] + matrixA[11] * matrixB[6] + matrixA[15] * matrixB[7]; + result[8] = + matrixA[0] * matrixB[8] + matrixA[4] * matrixB[9] + matrixA[8] * matrixB[10] + matrixA[12] * matrixB[11]; + result[9] = + matrixA[1] * matrixB[8] + matrixA[5] * matrixB[9] + matrixA[9] * matrixB[10] + matrixA[13] * matrixB[11]; + result[10] = + matrixA[2] * matrixB[8] + matrixA[6] * matrixB[9] + matrixA[10] * matrixB[10] + matrixA[14] * matrixB[11]; + result[11] = + matrixA[3] * matrixB[8] + matrixA[7] * matrixB[9] + matrixA[11] * matrixB[10] + matrixA[15] * matrixB[11]; + result[12] = + matrixA[0] * matrixB[12] + matrixA[4] * matrixB[13] + matrixA[8] * matrixB[14] + matrixA[12] * matrixB[15]; + result[13] = + matrixA[1] * matrixB[12] + matrixA[5] * matrixB[13] + matrixA[9] * matrixB[14] + matrixA[13] * matrixB[15]; + result[14] = + matrixA[2] * matrixB[12] + matrixA[6] * matrixB[13] + matrixA[10] * matrixB[14] + matrixA[14] * matrixB[15]; + result[15] = + matrixA[3] * matrixB[12] + matrixA[7] * matrixB[13] + matrixA[11] * matrixB[14] + matrixA[15] * matrixB[15]; return result; } @@ -43,22 +60,34 @@ export function multiply(matrixA: Matrix, matrixB: Matrix): Matrix { function inverse(matrix: Matrix): Matrix | null { // Create augmented matrix [matrix | identity] let augmented: number[] = [ - ...matrix.slice(0, 4), + matrix[0], + matrix[1], + matrix[2], + matrix[3], 1, 0, 0, 0, - ...matrix.slice(4, 8), + matrix[4], + matrix[5], + matrix[6], + matrix[7], 0, 1, 0, 0, - ...matrix.slice(8, 12), + matrix[8], + matrix[9], + matrix[10], + matrix[11], 0, 0, 1, 0, - ...matrix.slice(12, 16), + matrix[12], + matrix[13], + matrix[14], + matrix[15], 0, 0, 0, @@ -191,13 +220,13 @@ export function decompose(original: Matrix): DecomposedMatrix3D | null { ]; // Compute scale - const scaleX = Math.hypot(...row0); + const scaleX = Math.hypot(row0[0], row0[1], row0[2]); const row0Norm = normalize(row0); const skewXY = dot(row0Norm, row1); const row1Proj = [row1[0] - skewXY * row0Norm[0], row1[1] - skewXY * row0Norm[1], row1[2] - skewXY * row0Norm[2]]; - const scaleY = Math.hypot(...(row1Proj as Point)); + const scaleY = Math.hypot(row1Proj[0], row1Proj[1], row1Proj[2]); const row1Norm = normalize(row1Proj as Point); const skewXZ = dot(row0Norm, row2); @@ -211,7 +240,7 @@ export function decompose(original: Matrix): DecomposedMatrix3D | null { const row2Norm = normalize(row2Proj as Point); const determinant: number = row0[0] * cross[0] + row0[1] * cross[1] + row0[2] * cross[2]; - const scaleZ = Math.hypot(...(row2Proj as Point)) * (determinant < 0 ? -1 : 1); + const scaleZ = Math.hypot(row2Proj[0], row2Proj[1], row2Proj[2]) * (determinant < 0 ? -1 : 1); // Build rotation matrix from orthonormalized vectors const r00 = row0Norm[0], diff --git a/src/lib/ast/walk.ts b/src/lib/ast/walk.ts index df5c7825..970fc7e7 100644 --- a/src/lib/ast/walk.ts +++ b/src/lib/ast/walk.ts @@ -458,6 +458,7 @@ export function* walkValues( (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn( value, map.get(value) ?? root, @@ -490,9 +491,13 @@ export function* walkValues( for (const o of op) { map.set(o as Token, map.get(value) ?? (root as FunctionToken | ParensToken)); - } - stack[reverse ? "push" : "unshift"](...op); + if (reverse) { + stack.unshift(o); + } else { + stack.push(o); + } + } } } } @@ -529,9 +534,13 @@ export function* walkValues( for (const child of sliced) { map.set(child, value); - } - stack[reverse ? "push" : "unshift"](...sliced); + if (reverse) { + stack.unshift(child); + } else { + stack.push(child); + } + } } else { const values: Token[] = []; @@ -566,7 +575,13 @@ export function* walkValues( } if (values.length > 0) { - stack[reverse ? "push" : "unshift"](...values); + for (const v of values) { + if (reverse) { + stack.unshift(v); + } else { + stack.push(v); + } + } } } } @@ -579,6 +594,7 @@ export function* walkValues( (typeof filter.type == "function" && filter.type(value)); if (isValid) { + // @ts-ignore option = filter.fn(value, map.get(value), WalkerEvent.Leave); // @ts-ignore @@ -587,9 +603,13 @@ export function* walkValues( for (const o of op) { map.set(o as Token, map.get(value) ?? (root as FunctionToken | ParensToken)); - } - stack[reverse ? "push" : "unshift"](...op); + if (reverse) { + stack.unshift(o); + } else { + stack.push(o); + } + } } } } diff --git a/src/lib/fs/resolve.ts b/src/lib/fs/resolve.ts index f863f743..160670c7 100644 --- a/src/lib/fs/resolve.ts +++ b/src/lib/fs/resolve.ts @@ -5,6 +5,8 @@ import { memoize } from "../parser/utils/cache.ts"; */ export const matchUrl: RegExp = /^(https?:)?\/\//; +const windowsPathnameRegexp = /^\/?[a-zA-Z]:/; + /** * return the directory name of a path * @param path @@ -93,6 +95,10 @@ export const normalize = memoize(function (path: string) { path = path.replace(/(\\)/g, "/"); } + if (windowsPathnameRegexp.test(path)) { + path = path.replace(windowsPathnameRegexp, ""); + } + for (; i < path.length; i++) { const chr: string = path.charAt(i); @@ -180,9 +186,16 @@ export const resolve = memoize(function ( currentDirectory = normalize(currentDirectory); } - const dir = cwd || currentDirectory; + let dir = cwd || currentDirectory; + + if (windowsPathnameRegexp.test(dir)) { + dir = dir.replace(windowsPathnameRegexp, ""); + } + const absolute = - dir == "" || url.startsWith("/") || url.match(/^[a-zA-Z]:/) ? resolvePath(url) : resolvePath(dir, url); + dir == "" || url.startsWith("/") || url.startsWith(dir) || windowsPathnameRegexp.test(url) + ? resolvePath(url) + : resolvePath(dir, url); return { absolute, diff --git a/src/lib/parser/arena.ts b/src/lib/parser/arena.ts new file mode 100644 index 00000000..1102e838 --- /dev/null +++ b/src/lib/parser/arena.ts @@ -0,0 +1,53 @@ +import { StringInterner } from "./utils/intern.ts"; + +class ArenaData { + private count: number = 0; + private nodes: Uint32Array; + /** + * node token properties data: example + * - Color(kind[ColorType], cal: ["rel" | "mix" | "col"]) + * - pointer to the first node token (parsed node selector, parsed prelude) + * + */ + private data: Uint32Array; + private source: Uint8Array; + + private nodeView: DataView; + private dataView: DataView; + + private strings: StringInterner = new StringInterner(); + + constructor(size: number = 1024) { + this.nodes = new Uint32Array(size); + this.data = new Uint32Array(size); + this.source = new Uint8Array(5); + + this.nodeView = new DataView(this.nodes.buffer); + this.dataView = new DataView(this.data.buffer); + this.strings = new StringInterner(); + } + + allocate(kind: number, node: number, parent: number, data: number, source: number) { + if (this.count === this.nodes.length) { + this.grow(); + } + this.nodes[this.count] = node; + this.data[this.count] = data; + this.source[this.count] = source; + return this.count++; + } + + private grow() { + const nodes = new Uint32Array(this.nodes.length * 2); + const data = new Uint32Array(this.data.length * 2); + + nodes.set(this.nodes); + data.set(this.data); + + this.nodes = nodes; + this.data = data; + + this.nodeView = new DataView(this.nodes.buffer); + this.dataView = new DataView(this.data.buffer); + } +} diff --git a/src/lib/parser/declaration/list.ts b/src/lib/parser/declaration/list.ts index db4e33d5..5e9dc0ae 100644 --- a/src/lib/parser/declaration/list.ts +++ b/src/lib/parser/declaration/list.ts @@ -21,7 +21,8 @@ import type { ValidationMatch } from "../../validation/types.d.ts"; import { createValidationContext, matchAllSyntaxes } from "../../validation/match.ts"; import type { ValidationToken } from "../../validation/parser/types.d.ts"; import { STATE } from "../../syntax/constants.ts"; -import { objectHash } from "../utils/hash.ts"; +import { objectHash, toSortedString } from "../utils/hash.ts"; +import { equalsIgnoreCase } from "../utils/text.ts"; const config: PropertiesConfig = getConfig(); @@ -29,6 +30,7 @@ export class PropertyList { protected options: PropertyListOptions = { removeDuplicateDeclarations: true, computeShorthand: true }; protected declarations: Map; + // ketsey = new Map; constructor(options: PropertyListOptions = {}) { this.options = options; this.declarations = new Map(); @@ -48,17 +50,14 @@ export class PropertyList { let result: ValidationMatch; for (const declaration of declarations) { - name = - declaration.typ != EnumToken.DeclarationNodeType - ? null - : (declaration as AstDeclaration).nam.toLowerCase(); + name = declaration.typ != EnumToken.DeclarationNodeType ? null : (declaration as AstDeclaration).nam; if ( (declaration as AstDeclaration)[STATE] == EnumAstNodeStatus.Invalid || (declaration as AstDeclaration)[STATE] == EnumAstNodeStatus.Unknown || (declaration as AstDeclaration)[STATE] == EnumAstNodeStatus.ValidationFailed || declaration.typ != EnumToken.DeclarationNodeType || - "composes" === name || + equalsIgnoreCase("composes", name as string) || (typeof this.options.removeDuplicateDeclarations === "string" && this.options.removeDuplicateDeclarations === name) || (Array.isArray(this.options.removeDuplicateDeclarations) @@ -93,7 +92,27 @@ export class PropertyList { // do not compute shorthand for invalid declarations if (declaration[STATE] !== EnumAstNodeStatus.Validated) { - this.declarations.set(declaration.nam, declaration); + // const key = objectHash(declaration); + // if (!this.ketsey.has(key)) { + // this.ketsey.set(key, [declaration.nam]); + + // console.error( + // `Adding declaration : ${(declaration).nam} with key : ${key}` + // ) + // } + + // else { + + // console.error( + // `Duplicate declaration found: ${(declaration).nam} with key : [ ${key} => ${this.ketsey.get(key)} ]` + // ) + + // console.error(JSON.stringify(toSortedString(declaration))) + + // this.ketsey.get(key).push(declaration.nam); + // } + + this.declarations.set(objectHash(declaration), declaration); return this; } @@ -234,7 +253,10 @@ export class PropertyList { if (values != declaration.val) { declaration.val.length = 0; - declaration.val.push(...values); + + for (const v of values) { + declaration.val.push(v); + } } } diff --git a/src/lib/parser/declaration/map.ts b/src/lib/parser/declaration/map.ts index c6d1a79e..0f324296 100644 --- a/src/lib/parser/declaration/map.ts +++ b/src/lib/parser/declaration/map.ts @@ -166,12 +166,17 @@ export class PropertyMap { } else { if (current == tokens[property].length) { tokens[property].push([]); - tokens[property][current].push(...defaults); + + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } else { - tokens[property][current].push( - { typ: EnumToken.WhitespaceTokenType }, - ...defaults, - ); + tokens[property][current].push({ + typ: EnumToken.WhitespaceTokenType, + }); + for (let i = 0; i < defaults.length; i++) { + tokens[property][current].push(defaults[i]); + } } } } @@ -194,7 +199,10 @@ export class PropertyMap { acc.push({ ...separator }); } - acc.push(...curr); + for (let i = 0; i < curr.length; i++) { + acc.push(curr[i]); + } + return acc; }, []), }); @@ -371,7 +379,9 @@ export class PropertyMap { const values: AstDeclaration[] = [...this.declarations.values()].reduce( (acc: AstDeclaration[], curr: AstDeclaration | PropertySet) => { if (curr instanceof PropertySet) { - acc.push(...curr); + for (const declaration of curr) { + acc.push(declaration); + } } else { acc.push(curr); } @@ -678,24 +688,24 @@ export class PropertyMap { acc[i].push({ typ: EnumToken.WhitespaceTokenType }); } - acc[i].push( - ...values.reduce((acc, curr: Token) => { - if (acc.length > 0) { - // @ts-ignore - acc.push({ - ...((props.separator && { - ...props.separator, - // @ts-ignore - typ: EnumToken[props.separator.typ], - }) ?? { typ: EnumToken.WhitespaceTokenType }), - }); - } - + for (const v of values.reduce((acc, curr: Token) => { + if (acc.length > 0) { // @ts-ignore - acc.push(curr); - return acc; - }, []), - ); + acc.push({ + ...((props.separator && { + ...props.separator, + // @ts-ignore + typ: EnumToken[props.separator.typ], + }) ?? { typ: EnumToken.WhitespaceTokenType }), + }); + } + + // @ts-ignore + acc.push(curr); + return acc; + }, [])) { + acc[i].push(v); + } } } @@ -724,7 +734,10 @@ export class PropertyMap { ); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } + return acc; }, []); @@ -812,13 +825,17 @@ export class PropertyMap { private matchTypes(declaration: AstDeclaration) { const patterns: string[] = this.pattern.slice(); - const values: Token[] = [...declaration.val]; + const values: Token[] = []; let i: number; let j: number; const map: Map = new Map(); + for (i = 0; i < declaration.val.length; i++) { + values.push(declaration.val[i]); + } + for (i = 0; i < patterns.length; i++) { for (j = 0; j < values.length; j++) { if (!map.has(patterns[i])) { diff --git a/src/lib/parser/declaration/set.ts b/src/lib/parser/declaration/set.ts index e47736c5..db7b1b22 100644 --- a/src/lib/parser/declaration/set.ts +++ b/src/lib/parser/declaration/set.ts @@ -9,7 +9,7 @@ import type { WhitespaceToken, } from "../../../@types/index.d.ts"; import { eq } from "../utils/eq.ts"; -import { EnumToken } from "../../ast/types.ts"; +import { EnumToken } from "../../ast/types.ts"; import { isLength } from "../../syntax/syntax.ts"; function dedup(values: Token[][]): Token[][] { @@ -241,7 +241,10 @@ export class PropertySet { acc.push({ ...this.config.separator, typ: EnumToken.LiteralTokenType }); } - acc.push(...curr); + for (const token of curr) { + acc.push(token); + } + return acc; }, [], diff --git a/src/lib/parser/linesmap.ts b/src/lib/parser/linesmap.ts index 219a10ca..0b81f6b5 100644 --- a/src/lib/parser/linesmap.ts +++ b/src/lib/parser/linesmap.ts @@ -26,13 +26,10 @@ export class LineMap { */ getOffsets(offset: number): [number, number] { const line: number = this.search(offset); - - // if (offset < 0 || line < 0) { - // return [1, 1]; - // } + const column: number = offset - this.lineStarts[line]; // [line, column] - return [line + 1, offset - this.lineStarts[line] + 1]; + return [line + 1, line == 0 ? column + 1 : column]; } /** diff --git a/src/lib/parser/parse.ts b/src/lib/parser/parse.ts index 2742b020..bc4d1375 100644 --- a/src/lib/parser/parse.ts +++ b/src/lib/parser/parse.ts @@ -5,7 +5,7 @@ import { EnumAstNodeStatus, EnumToken, ModuleCaseTransformEnum, ModuleScopeEnumO import { minify } from "../ast/minify.ts"; import { expand } from "../ast/expand.ts"; import { walk, WalkerEvent, walkValues } from "../ast/walk.ts"; -import { tokenize, tokenizeStream } from "./tokenize.ts"; +import { Tokenizer } from "./tokenize.ts"; import type { AstAtRule, AstComment, @@ -19,11 +19,13 @@ import type { AtRuleToken, AttrStartToken, ClassSelectorToken, + ColorToken, ComposesSelectorToken, CssVariableImportTokenType, CssVariableMapTokenType, CssVariableToken, DashedIdentToken, + DimensionToken, ErrorDescription, FunctionToken, GenericVisitorAstNodeHandlerMap, @@ -48,7 +50,18 @@ import type { VisitorNodeMap, WhitespaceToken, } from "../../@types/index.d.ts"; -import { ERRORS, LOC, pageMarginBoxType, PARENT, ROOT, STATE, TOKENS, tokensfuncDefMap } from "../syntax/constants.ts"; +import { + ERRORS, + LOCEND, + LOCSRCID, + LOCSTA, + pageMarginBoxType, + PARENT, + ROOT, + STATE, + TOKENS, + tokensfuncDefMap, +} from "../syntax/constants.ts"; import { hash, hashAlgorithms, syncHash } from "../parser/utils/hash.ts"; import { parseSelector } from "./utils/selector.ts"; import { parseDeclaration } from "./utils/declaration.ts"; @@ -491,7 +504,9 @@ function parseVisitors( .push(value.handler); } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { errors.push({ action: "ignore", message: `doParse: visitor.${key} is not a valid key name` }); @@ -513,8 +528,6 @@ function parseVisitors( .get(key as "Declaration" | "Rule" | "AtRule" | "KeyframesRule" | "KeyframesAtRule")! .push(value); } else if (typeof value == "object") { - // visitors.push(...Object.entries(value)); - if ("type" in value && "handler" in value && value.type in WalkerEvent) { if (value.type == WalkerEvent.Enter) { if ( @@ -624,10 +637,7 @@ function parseVisitors( * @throws Error * @private */ -export function doParseSync( - iter: Array | Iterable, - options: ParserSyncOptions = {}, -): ParseResult { +export function doParseSync(tokenizer: Tokenizer, options: ParserSyncOptions = {}): ParseResult { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -693,59 +703,91 @@ export function doParseSync( let tokens: Token[] = []; let context: AstRuleList = ast; - let item: TokenizeResult; + let item: Token; let node: AstAtRule | AstRule | AstKeyframesRule | AstKeyframesAtRule | AstDeclaration | AstComment | null; // @ts-ignore ignore error let parensMatch: number = 0; let curlyBracketMatch: number = 0; - let currentItemIndex: number; + // let currentItemIndex: number; + + ast[LOCSRCID] = options.source!.id; + ast[LOCSTA] = 0; + + // let tokenizer: Tokenizer; + + while (!tokenizer.done()) { + tokenizer.next(); + // item = (iter as Array)[currentItemIndex]; + + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + unit: tokenizer.unit, + } as DimensionToken; + } else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ as EnumToken, + nam: tokenizer.nam, + } as Token; + } else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ as EnumToken, + } as Token; + } else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + kin: tokenizer.kin, + } as ColorToken; + } else { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + } as Token; + } - // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source!.id, - }; + item[LOCSRCID] = tokenizer.srcId as number; + item[LOCSTA] = tokenizer.sta as number; + item[LOCEND] = tokenizer.end as number; - for (currentItemIndex = 0; currentItemIndex < (iter as Array).length; currentItemIndex++) { - item = (iter as Array)[currentItemIndex]; - stats.bytesIn = item.bytesIn; + stats.bytesIn = tokenizer.bytesIn as number; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source!.getSourceLocation(item.token[LOC]!.sta), + node: item, + location: options.source!.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; - } else if (item.token.typ === EnumToken.EndParensTokenType && parensMatch > 0) { + } else if (item.typ === EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === EnumToken.BlockStartTokenType) { + if (item.typ === EnumToken.BlockStartTokenType) { curlyBracketMatch++; - } else if (item.token.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + } else if (item.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if ( parensMatch === 0 && - (item.token.typ === EnumToken.SemiColonTokenType || - item.token.typ === EnumToken.BlockStartTokenType || - item.token.typ === EnumToken.EOFTokenType) + (item.typ === EnumToken.SemiColonTokenType || + item.typ === EnumToken.BlockStartTokenType || + item.typ === EnumToken.EOFTokenType) ) { node = parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); @@ -754,42 +796,70 @@ export function doParseSync( stack.push(node as AstAtRule | AstRule | AstKeyframesRule); context = node as AstRuleList; } - } else if (item.token.typ == EnumToken.BlockStartTokenType) { + } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock: number = 1; - tokens = [item.token]; - do { - item = (iter as Array)[++currentItemIndex]; + tokens.length = 0; + tokens.push(item); - if (item == null) { - break; + do { + tokenizer.next(); + + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + unit: tokenizer.unit, + } as DimensionToken; + } else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ as EnumToken, + nam: tokenizer.nam, + } as Token; + } else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ as EnumToken, + } as Token; + } else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + kin: tokenizer.kin, + } as ColorToken; + } else { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + } as Token; } - tokens.push(item.token); + item[LOCSRCID] = tokenizer.srcId as number; + item[LOCSTA] = tokenizer.sta as number; + item[LOCEND] = tokenizer.end as number; - if (item.token.typ === EnumToken.BlockStartTokenType) { + tokens.push(item); + + if (item.typ === EnumToken.BlockStartTokenType) { inBlock++; - } else if (item.token.typ === EnumToken.BlockEndTokenType) { + } else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source!.getSourceLocation(tokens[0][LOC]!.sta), + location: options.source!.getSourceLocation(tokens[0][LOCSTA]!), }); } } - tokens = []; - } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === EnumToken.BlockEndTokenType) { + tokens.length = 0; + } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC]!.end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop() as AstRuleList; context = (stack[stack.length - 1] ?? ast) as AstRuleList; @@ -803,7 +873,7 @@ export function doParseSync( context.chi!.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -856,12 +926,18 @@ export function doParseSync( case EnumToken.AtRuleNodeType: case EnumToken.KeyframesRuleNodeType: case EnumToken.KeyframesAtRuleNodeType: - subNodes.push( - ...(nodes[i] as AstRule | AstAtRule | AstKeyframesRule | AstKeyframesAtRule)[TOKENS]!, - ); + for (const token of (nodes[i] as AstRule | AstAtRule | AstKeyframesRule | AstKeyframesAtRule)[ + TOKENS + ]!) { + subNodes.push(token); + } + break; case EnumToken.DeclarationNodeType: - subNodes.push(...(nodes[i] as AstDeclaration).val); + for (const token of (nodes[i] as AstDeclaration).val) { + subNodes.push(token); + } + break; } } @@ -869,7 +945,9 @@ export function doParseSync( // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (const child of nodes[i].chi) { + subNodes.push(child); + } } if (subNodes.length > 0) { @@ -1064,7 +1142,7 @@ export function doParseSync( ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, } as ParseResult; @@ -1097,7 +1175,7 @@ export function doParseSync( filePath = filePath === "" - ? (options.src as string) + ? options.resolve!(options.src as string, options.cwd as string).relative : options.resolve!(filePath, options.dirname!(options.src as string), options.cwd).relative; if (typeof options.module == "number") { @@ -1149,7 +1227,7 @@ export function doParseSync( if (node.typ == EnumToken.CssVariableImportTokenType) { throw new Error( "css variable import not supported by parseSync() or transformSync(). use parse() or transform() instead.\nat " + - options.source!.getSourceLocation(node[LOC]!.sta).join(":"), + options.source!.getSourceLocation(node[LOCSTA]!).join(":"), ); } @@ -1311,7 +1389,7 @@ export function doParseSync( // composes: a b c from 'file.css'; else if (token.r.typ == EnumToken.String) { throw new Error( - `composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source!.getSourceLocation(node[LOC]!.sta).join(":")}`, + `composes from file is not supported using parseSync() or transformSync(). Use parse() or transform() instead.\nat ${options.source!.getSourceLocation(node[LOCSTA]!).join(":")}`, ); } @@ -1614,7 +1692,7 @@ export function doParseSync( if (moduleSettings.scoped! & ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { throw new Error( - `pure module: No id or class found in selector '${node.sel}' at '${options.source!.getOffsets(node[LOC]?.sta as number).join(":")}'`, + `pure module: No id or class found in selector '${node.sel}' at '${options.source!.getOffsets(node[LOCSTA] as number).join(":")}'`, ); } } @@ -1708,10 +1786,7 @@ export function doParseSync( * @throws Error * @private */ -export async function doParse( - iter: Array | Iterable | AsyncGenerator, - options: ParserOptions = {}, -): Promise { +export async function doParse(iter: Tokenizer | Promise, options: ParserOptions = {}): Promise { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -1784,70 +1859,97 @@ export async function doParse( const imports: AstAtRule[] = []; - let item: TokenizeResult; + let item: Token; let node: AstAtRule | AstRule | AstKeyframesRule | AstKeyframesAtRule | AstDeclaration | AstComment | null; // @ts-ignore ignore error let isAsync: boolean = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch: number = 0; let curlyBracketMatch: number = 0; + let tokenizer: Tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; - ast[LOC] = { - sta: 0, - end: 0, - srcId: options.source!.id, - }; + ast[LOCSRCID] = options.source!.id; + ast[LOCSTA] = 0; + ast[LOCEND] = 0; + + // if (Array.isArray(iter)) { + // // @ts-expect-error + // iter = iter[Symbol.iterator]() as Iterator; + // } + + while (!tokenizer.done()) { + tokenizer.next(); + + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + unit: tokenizer.unit, + } as DimensionToken; + } else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ as EnumToken, + nam: tokenizer.nam, + } as Token; + } else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ as EnumToken, + } as Token; + } else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + kin: tokenizer.kin, + } as ColorToken; + } else { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + } as Token; + } - if (Array.isArray(iter)) { - // @ts-expect-error - iter = iter[Symbol.iterator]() as Iterator; - } + item[LOCSRCID] = tokenizer.srcId as number; + item[LOCSTA] = tokenizer.sta as number; + item[LOCEND] = tokenizer.end as number; - while ( - (item = isAsync - ? // @ts-expect-error - ((await iter.next()).value as TokenizeResult) - : // @ts-expect-error - ((iter as Iterator).next().value as TokenizeResult)) - ) { - stats.bytesIn = item.bytesIn; + stats.bytesIn = tokenizer.bytesIn as number; stats.tokensCount++; - if (BadTokensTypes.includes(item.token.typ)) { - tokens.push(item.token); + if (BadTokensTypes.includes(item.typ)) { + tokens.push(item); errors.push({ action: "drop", message: "Bad token", syntax: null, - node: item.token, - location: options.source!.getSourceLocation(item.token[LOC]!.sta), + node: item, + location: options.source!.getSourceLocation(item[LOCSTA]), }); // bad token continue; } - if (item.token.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.token.typ)) { + if (item.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(item.typ)) { parensMatch++; - } else if (item.token.typ === EnumToken.EndParensTokenType && parensMatch > 0) { + } else if (item.typ === EnumToken.EndParensTokenType && parensMatch > 0) { parensMatch--; } - if (item.token.typ === EnumToken.BlockStartTokenType) { + if (item.typ === EnumToken.BlockStartTokenType) { curlyBracketMatch++; - } else if (item.token.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { + } else if (item.typ === EnumToken.BlockEndTokenType && curlyBracketMatch > 0) { curlyBracketMatch--; } - tokens.push(item.token); + tokens.push(item); if ( parensMatch === 0 && - (item.token.typ === EnumToken.SemiColonTokenType || - item.token.typ === EnumToken.BlockStartTokenType || - item.token.typ === EnumToken.EOFTokenType) + (item.typ === EnumToken.SemiColonTokenType || + item.typ === EnumToken.BlockStartTokenType || + item.typ === EnumToken.EOFTokenType) ) { node = parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); @@ -1858,46 +1960,69 @@ export async function doParse( } else if (node.typ == EnumToken.AtRuleNodeType && (node as AstAtRule).nam === "import") { imports.push(node); } - } else if (item.token.typ == EnumToken.BlockStartTokenType) { + } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock: number = 1; - tokens = [item.token]; + tokens.length = 0; + tokens.push(item); do { - item = isAsync - ? // @ts-expect-error - ((await iter.next()).value as TokenizeResult) - : // @ts-expect-error - ((iter as Iterator).next().value as TokenizeResult); - - if (item == null) { - break; + tokenizer.next(); + + if (tokenizer.unit != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + unit: tokenizer.unit, + } as DimensionToken; + } else if (tokenizer.nam != null) { + item = { + typ: tokenizer.typ as EnumToken, + nam: tokenizer.nam, + } as Token; + } else if (tokenizer.val === null) { + item = { + typ: tokenizer.typ as EnumToken, + } as Token; + } else if (tokenizer.kin != null) { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + kin: tokenizer.kin, + } as ColorToken; + } else { + item = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + } as Token; } - tokens.push(item.token); + item[LOCSRCID] = tokenizer.srcId as number; + item[LOCSTA] = tokenizer.sta as number; + item[LOCEND] = tokenizer.end as number; - if (item.token.typ === EnumToken.BlockStartTokenType) { + tokens.push(item); + + if (item.typ === EnumToken.BlockStartTokenType) { inBlock++; - } else if (item.token.typ === EnumToken.BlockEndTokenType) { + } else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", message: "invalid block", - location: options.source!.getSourceLocation(tokens[0][LOC]!.sta), + location: options.source!.getSourceLocation(tokens[0][LOCSTA]!), }); } } - tokens = []; - } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.token.typ === EnumToken.BlockEndTokenType) { + tokens.length = 0; + } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); - if (context[LOC] != null) { - context[LOC].end = item.token[LOC]!.end; - } + context[LOCEND] = item[LOCEND]; const previousNode = stack.pop() as AstRuleList; context = (stack[stack.length - 1] ?? ast) as AstRuleList; @@ -1911,7 +2036,7 @@ export async function doParse( context.chi!.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -1962,9 +2087,12 @@ export async function doParse( source, position: 0, currentPosition: 0, + time: 0, } as ParseInfo; const root: ParseResult = await doParse( - stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), + stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { minify: false, setParent: false, @@ -1980,7 +2108,9 @@ export async function doParse( node[PARENT]!.chi!.splice(node[PARENT]!.chi!.indexOf(node), 1, ...root.ast.chi); if (root.errors.length > 0) { - errors.push(...root.errors); + for (const error of root.errors) { + errors.push(error); + } } } catch (error) { // @ts-ignore ignore error @@ -2025,12 +2155,17 @@ export async function doParse( case EnumToken.AtRuleNodeType: case EnumToken.KeyframesRuleNodeType: case EnumToken.KeyframesAtRuleNodeType: - subNodes.push( - ...(nodes[i] as AstRule | AstAtRule | AstKeyframesRule | AstKeyframesAtRule)[TOKENS]!, - ); + for (const token of (nodes[i] as AstRule | AstAtRule | AstKeyframesRule | AstKeyframesAtRule)[ + TOKENS + ]!) { + subNodes.push(token); + } + break; case EnumToken.DeclarationNodeType: - subNodes.push(...(nodes[i] as AstDeclaration).val); + for (const token of (nodes[i] as AstDeclaration).val) { + subNodes.push(token); + } break; } } @@ -2038,7 +2173,10 @@ export async function doParse( // @ts-ignore if (nodes[i].chi != null) { // @ts-ignore - subNodes.push(...nodes[i].chi); + for (k = 0; k < nodes[i].chi.length; k++) { + // @ts-ignore + subNodes.push(nodes[i].chi[k]); + } } if (subNodes.length > 0) { @@ -2238,7 +2376,7 @@ export async function doParse( ...stats, parse: `${(endParseTime - startTime).toFixed(2)}ms`, minify: `${(endTime - endParseTime).toFixed(2)}ms`, - tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, + // tokenize: `${(options?.parseInfo?.time ?? 0).toFixed(2)}ms`, total: `${(endTime - startTime).toFixed(2)}ms`, }, } as ParseResult; @@ -2271,7 +2409,7 @@ export async function doParse( filePath = filePath === "" - ? (options.src as string) + ? options.resolve!(options.src as string, options.cwd as string).relative : options.resolve!(filePath, options.dirname!(options.src as string), options.cwd).relative; if (typeof options.module == "number") { @@ -2347,7 +2485,9 @@ export async function doParse( } as ParseInfo; const root: ParseResult = await doParse( - stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), + stream instanceof ReadableStream + ? new Tokenizer(parseInfo, stream).tokenizeStream() + : new Tokenizer(parseInfo), Object.assign({}, options, { source, minify: false, @@ -2356,7 +2496,7 @@ export async function doParse( }) as ParserOptions, ); - options.parseInfo!.time += parseInfo.time; + // options.parseInfo!.time += parseInfo.time; cssVariablesMap[(node as CssVariableImportTokenType).nam] = root.cssModuleVariables!; parent!.chi!.splice(parent!.chi!.indexOf(node), 1); @@ -2536,19 +2676,23 @@ export async function doParse( : result; const root: ParseResult = await doParse( stream instanceof ReadableStream - ? tokenizeStream(stream, { - offset: 0, - source: new SourceFile("", [], src.relative), - position: 0, - currentPosition: 0, - } as ParseInfo) - : tokenize({ + ? new Tokenizer( + { + offset: 0, + source: new SourceFile("", [], src.relative), + position: 0, + currentPosition: 0, + } as ParseInfo, + stream, + ).tokenizeStream() + : new Tokenizer({ stream, offset: 0, position: 0, - source: new SourceFile(stream, [], src.relative), + source: new SourceFile(stream as string, [], src.relative), currentPosition: 0, } as ParseInfo), + Object.assign({}, options, { minify: false, setParent: false, @@ -2943,7 +3087,7 @@ export async function doParse( if (moduleSettings.scoped! & ModuleScopeEnumOptions.Pure) { if (!hasIdOrClass) { throw new Error( - `pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOC]?.sta as number) ?? []).join(":")}'`, + `pure module: No id or class found in selector '${node.sel}' at '${(options.source?.getOffsets?.(node[LOCSTA] as number) ?? []).join(":")}'`, ); } } @@ -2996,33 +3140,6 @@ export async function doParse( (node as AstAtRule).val = renderTokens(node[TOKENS]!); } - // else { - // let isReplaced: boolean = false; - - // for (const { value, parent } of walkValues(node[TOKENS], node)) { - // if ( - // EnumToken.MediaQueryConditionTokenType == parent.typ && - // // @ts-expect-error - // value != (parent as MediaQueryConditionToken).l - // ) { - // if ( - // (value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && - // (value as IdentToken).val in importedCssVariables - // ) { - // isReplaced = true; - // (parent as MediaQueryConditionToken).r.splice( - // (parent as MediaQueryConditionToken).r.indexOf(value), - // 1, - // ...importedCssVariables[(value as IdentToken).val].val, - // ); - // } - // } - // } - - // if (isReplaced) { - // node.val = renderTokens(node[TOKENS]!); - // } - // } } } @@ -3075,7 +3192,6 @@ function parseNode( // check parenthesis are balanced let matchCount: number = 0; - let position: SourceLocation = tokens.at(-1)?.[LOC] as SourceLocation; for (let i = 0; i < tokens.length; i++) { const token: Token = tokens[i]; @@ -3102,7 +3218,9 @@ function parseNode( while (matchCount > 0) { tokens.push({ typ: EnumToken.EndParensTokenType, - [LOC]: { ...position }, + [LOCSRCID]: tokens[k]?.[LOCSRCID], + [LOCSTA]: tokens[k]?.[LOCSTA], + [LOCEND]: tokens[k]?.[LOCEND], }); matchCount--; } @@ -3115,7 +3233,7 @@ function parseNode( action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source!.getSourceLocation(tokens[i][LOC]!.sta), + location: options.source!.getSourceLocation(tokens[i][LOCSTA]!), }); tokens[i].typ = EnumToken.InvalidCommentTokenType; @@ -3147,7 +3265,7 @@ function parseNode( action: "drop", message: `CDOCOMM not allowed here ${JSON.stringify(tokens[i], null, 1)}`, node: tokens[i], - location: options.source!.getSourceLocation(tokens[i][LOC]!.sta), + location: options.source!.getSourceLocation(tokens[i][LOCSTA]!), }); tokens[i].typ = EnumToken.InvalidCommentTokenType; @@ -3247,7 +3365,7 @@ function parseNode( return node; } else { - const node = parseDeclaration(tokens, context as AstRule | AstAtRule, options, errors); + const node = parseDeclaration(tokens, context as AstRule | AstAtRule, options, errors) as AstDeclaration; node[PARENT] = context; node[ROOT] = context[ROOT]; @@ -3258,7 +3376,7 @@ function parseNode( message: " not allowed in ", action: "drop", node, - location: options.source!.getSourceLocation(node[LOC]!.sta), + location: options.source!.getSourceLocation(node[LOCSTA]!), }); } else if (options.lenient || node.typ === EnumToken.DeclarationNodeType) { context.chi!.push(node); @@ -3311,7 +3429,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: "unknown at-rule", }); @@ -3336,7 +3454,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); @@ -3358,8 +3476,8 @@ export function parseAtRule( errors.push({ action: "drop", node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), - message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.srcId}:${token[LOC]!.sta}:${token[LOC]!.sta}`, + location: options.source!.getSourceLocation(token[LOCSTA]!), + message: `unexpected token`, }); atRule[TOKENS] = parseTokens(stream); @@ -3383,7 +3501,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: parseAsBlock ? "at-rule block not supported" : "at-rule block is required", }); @@ -3412,7 +3530,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[0] ?? atRule, - location: options.source!.getSourceLocation((stream[0] ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((stream[0] ?? atRule)[LOCSTA]!), message: "expecting ", }); } else if (stream[1].typ !== EnumToken.StringTokenType) { @@ -3420,7 +3538,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source!.getSourceLocation((stream[1] ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((stream[1] ?? atRule)[LOCSTA]!), message: "expecting ", }); } @@ -3430,7 +3548,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[1] ?? atRule, - location: options.source!.getSourceLocation((stream[1] ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((stream[1] ?? atRule)[LOCSTA]!), message: "expecting double-quoted string", }); } @@ -3439,7 +3557,7 @@ export function parseAtRule( atRule[TOKENS] = stream; atRule[STATE] = EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { @@ -3455,7 +3573,7 @@ export function parseAtRule( atRule[TOKENS] = stream; atRule[STATE] = EnumAstNodeStatus.Validated; atRule[ERRORS] = []; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { @@ -3468,13 +3586,15 @@ export function parseAtRule( const result = parseAtRuleFontFeatureValues(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } atRule[TOKENS] = stream; atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; // @ts-expect-error return Object.assign(atRule, { @@ -3497,7 +3617,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: `unexpected at-rule ${atRule.nam}`, }); } @@ -3509,14 +3629,14 @@ export function parseAtRule( errors.push({ action: "drop", node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), - message: `unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.srcId}:${token[LOC]!.sta}:${token[LOC]!.sta}`, + location: options.source!.getSourceLocation(token[LOCSTA]!), + message: `unexpected token`, }); } } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = [errors[errors.length - 1]]; @@ -3533,10 +3653,12 @@ export function parseAtRule( const result = parseAtRuleContainerQueryList(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC] = { ...atRule[LOC], end: (stream.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; atRule[TOKENS] = stream; atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -3553,13 +3675,15 @@ export function parseAtRule( const result = matchAllSyntaxes(syntax, createValidationContext(tokens), options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (tokens.at(-1)! ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.ValidationFailed; atRule[ERRORS] = result.success ? [] : result.errors; @@ -3585,8 +3709,8 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), - message: `expected at ${atRule[LOC]!.srcId}:${atRule[LOC]!.sta!}:${atRule[LOC]!.sta!}`, + location: options.source!.getSourceLocation(atRule[LOCSTA]!), + message: `expected `, }); success = false; } @@ -3594,7 +3718,7 @@ export function parseAtRule( // @ts-expect-error options = { ...options, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: (tokens.at(-1)! ?? atRule)[LOC]!.end } as SourceLocation; + atRule[LOCEND] = (tokens.at(-1)! ?? atRule)[LOCEND]; atRule[TOKENS] = tokens; atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3615,7 +3739,9 @@ export function parseAtRule( ); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // else { // parseUrlToken(stream); @@ -3650,7 +3776,7 @@ export function parseAtRule( } } - atRule[LOC]!.end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = valid ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = valid ? [] : result.errors; @@ -3677,7 +3803,9 @@ export function parseAtRule( const result = matchAtRuleImportSyntax(atRule, stream, context, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } else { if ( stream[0]?.typ == EnumToken.UrlFunctionTokenType && @@ -3689,8 +3817,7 @@ export function parseAtRule( } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -3723,7 +3850,9 @@ export function parseAtRule( : matchAtRuleWhenElseSyntax(stream, atRule, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } let success: boolean = result.success; @@ -3767,7 +3896,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: "at-rule @when is required before @else block", }); } else if (definedAfterLastElse) { @@ -3775,7 +3904,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: "at-rule @else block is defined after last @else block", }); } @@ -3784,7 +3913,7 @@ export function parseAtRule( // @ts-expect-error options = { ...options, minify: false, convertColor: false }; - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end } as SourceLocation; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : [errors[errors.length - 1]].concat(result.errors); @@ -3802,10 +3931,12 @@ export function parseAtRule( const result = parseMediaqueryList(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } - atRule[LOC]!.end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.success ? [] : result.errors; @@ -3828,7 +3959,7 @@ export function parseAtRule( errors.push({ action: "drop", node: range[0] ?? atRule, - location: options.source!.getSourceLocation((range[0] ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((range[0] ?? atRule)[LOCSTA]!), message: "expected '(' at start of @scope block", }); success = false; @@ -3836,7 +3967,7 @@ export function parseAtRule( errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source!.getSourceLocation((range.at(-1) ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]!), message: "expected ')' at end of @scope block", }); success = false; @@ -3867,7 +3998,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[index], - location: options.source!.getSourceLocation(stream[index]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[index]?.[LOCSTA]!), message: "expected 'to' at end of @scope block", }); success = false; @@ -3881,7 +4012,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[index], - location: options.source!.getSourceLocation(stream[index]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[index]?.[LOCSTA]!), message: "expected 'to' at end of @scope block", }); success = false; @@ -3893,7 +4024,7 @@ export function parseAtRule( errors.push({ action: "drop", node: range.at(-1) ?? atRule, - location: options.source!.getSourceLocation((range.at(-1) ?? atRule)[LOC]!.sta), + location: options.source!.getSourceLocation((range.at(-1) ?? atRule)[LOCSTA]!), message: "expected ')' at end of @scope block", }); success = false; @@ -3916,8 +4047,7 @@ export function parseAtRule( } } - // @ts-expect-error - atRule[LOC].end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3932,7 +4062,7 @@ export function parseAtRule( case "page": { trimArray(stream); - atRule[LOC]!.end = stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -3964,7 +4094,7 @@ export function parseAtRule( errors.push({ action: "drop", node: atRule, - location: options.source!.getSourceLocation(atRule[LOC]!.sta), + location: options.source!.getSourceLocation(atRule[LOCSTA]!), message: "node is allowed only in @page rule", }); } else { @@ -3979,7 +4109,7 @@ export function parseAtRule( errors.push({ action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), message: "expected whitespace or comment", }); break; @@ -3987,7 +4117,7 @@ export function parseAtRule( } } - atRule[LOC] = { ...atRule[LOC], end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end } as SourceLocation; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); atRule[STATE] = success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; @@ -4013,7 +4143,9 @@ export function parseAtRule( stream.splice(index, 0, { typ: EnumToken.ColonTokenType, - [LOC]: { ...stream[index][LOC], end: stream[index]?.[LOC]?.end } as SourceLocation, + [LOCSRCID]: stream[index][LOCSRCID], + [LOCSTA]: stream[index][LOCSTA], + [LOCEND]: stream[index][LOCEND], }); isVarDeclaration = true; @@ -4042,15 +4174,16 @@ export function parseAtRule( atRule[ERRORS] = success ? [] : [errors[errors.length - 1]]; if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { typ: EnumToken.AtRuleNodeType, val: renderTokens(stream, options), - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end, - } as SourceLocation, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -4069,10 +4202,9 @@ export function parseAtRule( typ: EnumToken.CssVariableImportTokenType, nam: (nam as IdentToken).val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end, - } as SourceLocation, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Validated, [ERRORS]: [], @@ -4084,20 +4216,17 @@ export function parseAtRule( typ: EnumToken.CssVariableTokenType, nam: (nam as IdentToken).val, val: value, - [LOC]: { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end, - } as SourceLocation, + [LOCSRCID]: atRule[LOCSRCID], + [LOCSTA]: atRule[LOCSTA], + [LOCEND]: stream.at(-1)?.[LOCEND] ?? atRule[LOCEND], [TOKENS]: stream, [STATE]: EnumAstNodeStatus.Validated, [ERRORS]: [], } as CssVariableToken; } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end, - } as SourceLocation; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; + atRule[STATE] = EnumAstNodeStatus.Validated; atRule[ERRORS] = []; @@ -4122,13 +4251,17 @@ export function parseAtRule( result = matchGenericSyntax(stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } else { result = matchAtRuleSyntax(atRule, stream, options); if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } if (result.success) { @@ -4144,7 +4277,7 @@ export function parseAtRule( if (stream[i].typ === EnumToken.EndParensTokenType && stack.length > 0) { const index = stream.indexOf(stack[stack.length - 1]); - stream[index][LOC]!.end = stream[i][LOC]!.end; + stream[index][LOCEND] = stream[i][LOCEND]; Object.assign(stream[index], { typ: tokensfuncDefMap.get(stream[index].typ)!, chi: stream.splice(index + 1, i - index - 1), @@ -4152,16 +4285,13 @@ export function parseAtRule( i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } } - atRule[LOC] = { - ...atRule[LOC], - end: stream.at(-1)?.[LOC]?.end ?? atRule[LOC]!.end, - } as SourceLocation; + atRule[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; + atRule[TOKENS] = stream.slice(); atRule[STATE] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.errors; @@ -4190,7 +4320,7 @@ export function parseAtRule( export async function parseDeclarations(declaration: string): Promise> { const stream: string = `.x{${declaration}}`; return doParse( - tokenize({ + new Tokenizer({ stream, offset: 0, position: 0, @@ -4232,20 +4362,59 @@ export function parseString( options: { src?: string; parseColor?: boolean } | null = { parseColor: true }, errors?: ErrorDescription[], ): Token[] { - const parseInfo: ParseInfo = { + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + + const tokenizer: Tokenizer = new Tokenizer({ stream: src, + buffer: "", + src: options?.src ?? "", offset: 0, time: 0, - source: new SourceFile(src, [], ""), + source: new SourceFile(src, [], options?.src ?? ""), position: 0, currentPosition: 0, - }; - - const tokenResults: TokenizeResult[] = tokenize(parseInfo); + } as ParseInfo); const mapped: Token[] = []; + let token: Token; + + while (!tokenizer.done()) { + tokenizer.next(); + + if (tokenizer.unit != null) { + token = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + unit: tokenizer.unit, + } as DimensionToken; + } else if (tokenizer.val === null) { + token = { + typ: tokenizer.typ as EnumToken, + } as Token; + } else if (tokenizer.kin != null) { + token = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + kin: tokenizer.kin, + } as ColorToken; + } else { + token = { + typ: tokenizer.typ as EnumToken, + val: tokenizer.val, + } as Token; + } - for (const token of tokenResults) { - mapped.push(token.token); + token[LOCSRCID] = tokenizer!.source!.id; + token[LOCEND] = tokenizer.end as number; + token[LOCSTA] = tokenizer.sta as number; + + mapped.push(token); } const result: Token[] = parseTokens(mapped, options, errors); @@ -4306,7 +4475,7 @@ export function parseTokens( (tokens[i - 1].typ === EnumToken.ColonTokenType ? ":" : "::") + (tokens[i] as FunctionToken).val, }); - t[LOC]!.end = tokens[i][LOC]!.end; + t[LOCEND] = tokens[i][LOCEND]; tokens.splice(i--, 1); } } @@ -4331,7 +4500,7 @@ export function parseTokens( action: "drop", message: `Unbalanced token ')'`, node, - location: options.source!.getSourceLocation(node[LOC]!.sta), + location: options.source!.getSourceLocation(node[LOCSTA]!), }); // return []; @@ -4367,7 +4536,7 @@ export function parseTokens( action: "drop", message: `Unbalanced token ']'`, node, - location: options.source!.getSourceLocation(node[LOC]!.sta), + location: options.source!.getSourceLocation(node[LOCSTA]!), }); continue; } @@ -4375,7 +4544,7 @@ export function parseTokens( index = tokens.indexOf(stack.at(-1)!); const attr = stack.at(-1) as AttrStartToken; - attr[LOC]!.end = t[LOC]!.end; + attr[LOCEND] = t[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { @@ -4517,10 +4686,8 @@ export function parseTokens( action: "drop", message: `Unbalanced token. Expecting ${node.typ === EnumToken.AttrStartTokenType ? "']'" : ")"}'`, node, - location: options.source!.getSourceLocation(node[LOC]!.sta), + location: options.source!.getSourceLocation(node[LOCSTA]!), }); - - // return []; } return tokens; diff --git a/src/lib/parser/source.ts b/src/lib/parser/source.ts index a65ee98d..acfb2a18 100644 --- a/src/lib/parser/source.ts +++ b/src/lib/parser/source.ts @@ -28,7 +28,7 @@ export class SourceFile { /** * Source file content */ - private content: string; + content: string; /** * Constructor diff --git a/src/lib/parser/tokenize.ts b/src/lib/parser/tokenize.ts index e4a6e4dc..8c007075 100644 --- a/src/lib/parser/tokenize.ts +++ b/src/lib/parser/tokenize.ts @@ -1,27 +1,10 @@ -import type { - AngleToken, - ColorToken, - DimensionToken, - FlexToken, - FrequencyToken, - HashToken, - LengthToken, - NumberToken, - ParseInfo, - PercentageToken, - ResolutionToken, - TimeToken, - Token, - TokenizeResult, - UnclosedStringToken, -} from "../../@types/index.d.ts"; +import type { ParseInfo } from "../../@types/index.d.ts"; import { ColorType, EnumToken } from "../ast/types.ts"; import { colorsFunc, containerFunc, gridTemplateFunc, imageFunc, - LOC, mathFuncs, pseudoElements, supportFunc, @@ -33,110 +16,105 @@ import { wildCardFuncs, } from "../syntax/constants.ts"; import { + angleUnits, + dimensionUnits, + flexUnits, + frequencyUnits, isDigit, - isHash, - isHexColor, - isIdent, isIdentCodepoint, isIdentStart, + isLetter, isNewLine, isNonPrintable, - isNumber, - isPercentage, isWhiteSpace, - parseDimension, + resolutionUnits, + timeUnits, } from "../syntax/syntax.ts"; import { SourceFile } from "./source.ts"; -import { equalsIgnoreCase } from "./utils/text.ts"; - -export const SymbolsMapTokens: Record = { - "+": EnumToken.Plus, - "=": EnumToken.DelimTokenType, - "|": EnumToken.Pipe, - "||": EnumToken.ColumnCombinatorTokenType, - "|=": EnumToken.DashMatchTokenType, - "&": EnumToken.NestingSelectorTokenType, - "*": EnumToken.Star, - "*=": EnumToken.ContainMatchTokenType, - "~": EnumToken.Tilda, - "~=": EnumToken.IncludeMatchTokenType, - "^=": EnumToken.StartMatchTokenType, - "$=": EnumToken.EndMatchTokenType, - ",": EnumToken.Comma, - ":": EnumToken.ColonTokenType, - "::": EnumToken.DoubleColonTokenType, - ";": EnumToken.SemiColonTokenType, - "(": EnumToken.StartParensTokenType, - ")": EnumToken.EndParensTokenType, - "[": EnumToken.AttrStartTokenType, - "]": EnumToken.AttrEndTokenType, - "{": EnumToken.BlockStartTokenType, - "}": EnumToken.BlockEndTokenType, - "<=": EnumToken.LteTokenType, - ">": EnumToken.GtTokenType, - ">=": EnumToken.GteTokenType, - " ": EnumToken.Whitespace, - "\t": EnumToken.Whitespace, - "\r": EnumToken.Whitespace, - "\n": EnumToken.Whitespace, - "\f": EnumToken.Whitespace, - ...pseudoElements.reduce((acc, curr: string) => { - acc[curr] = EnumToken.PseudoElementTokenType; - return acc; - }, Object.create(null)), - ...containerFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.ContainerFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...urlFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.UrlFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...gridTemplateFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.GridTemplateFuncTokenDefType; - return acc; - }, Object.create(null)), - ...imageFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.ImageFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timelineFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.TimelineFunctionTokenDefType; - return acc; - }, Object.create(null)), - // ...generalEnclosedFunc.reduce((acc, curr: string) => { - // acc[curr + "("] = EnumToken.GeneralEnclosedFunctionTokenDefType; - // return acc; - // }, Object.create(null)), - ...supportFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.SupportsFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...timingFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.TimingFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...colorsFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.ColorFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...mathFuncs.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.MathFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...transformFunctions.reduce((acc, curr: string) => { - acc[curr.toLowerCase() + "("] = EnumToken.TransformFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...whenElseFunc.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.WhenElseFunctionTokenDefType; - return acc; - }, Object.create(null)), - ...wildCardFuncs.reduce((acc, curr: string) => { - acc[curr + "("] = EnumToken.WildCardFunctionTokenDefType; - return acc; - }, Object.create(null)), -}; + +const SymbolsMapTokens: Record = Object.create(null); + +// Regex for escape sequence decoding - compile once, reuse many times +const ESCAPE_SEQUENCE_REGEX = /\\([0-9a-fA-F]{1,6})(?:\s)?/g; + +function decodeEscapeSequences(value: string): string { + return value.replace(ESCAPE_SEQUENCE_REGEX, (_, sequence) => { + const codepoint = parseInt(sequence, 16); + + if ( + codepoint == 0 || + // leading surrogate + (0xd800 <= codepoint && codepoint <= 0xdbff) || + // trailing surrogate + (0xdc00 <= codepoint && codepoint <= 0xdfff) || + codepoint > 0x10ffff + ) { + return "\uFFFD"; + } + + return String.fromCodePoint(codepoint); + }); +} + +function assignTokenMap(entries: string[], tokenType: EnumToken, suffix: string = "", lowercase: boolean = false) { + for (const entry of entries) { + SymbolsMapTokens[(lowercase ? entry.toLowerCase() : entry) + suffix] = tokenType; + } +} + +SymbolsMapTokens[""] = EnumToken.DelimTokenType; +SymbolsMapTokens["+"] = EnumToken.Plus; +SymbolsMapTokens["="] = EnumToken.DelimTokenType; +SymbolsMapTokens["|"] = EnumToken.Pipe; +SymbolsMapTokens["||"] = EnumToken.ColumnCombinatorTokenType; +SymbolsMapTokens["|="] = EnumToken.DashMatchTokenType; +SymbolsMapTokens["&"] = EnumToken.NestingSelectorTokenType; +SymbolsMapTokens["*"] = EnumToken.Star; +SymbolsMapTokens["*="] = EnumToken.ContainMatchTokenType; +SymbolsMapTokens["~"] = EnumToken.Tilda; +SymbolsMapTokens["~="] = EnumToken.IncludeMatchTokenType; +SymbolsMapTokens["^="] = EnumToken.StartMatchTokenType; +SymbolsMapTokens["$="] = EnumToken.EndMatchTokenType; +SymbolsMapTokens[","] = EnumToken.Comma; +SymbolsMapTokens[":"] = EnumToken.ColonTokenType; +SymbolsMapTokens["::"] = EnumToken.DoubleColonTokenType; +SymbolsMapTokens[";"] = EnumToken.SemiColonTokenType; +SymbolsMapTokens["("] = EnumToken.StartParensTokenType; +SymbolsMapTokens[")"] = EnumToken.EndParensTokenType; +SymbolsMapTokens["["] = EnumToken.AttrStartTokenType; +SymbolsMapTokens["]"] = EnumToken.AttrEndTokenType; +SymbolsMapTokens["{"] = EnumToken.BlockStartTokenType; +SymbolsMapTokens["}"] = EnumToken.BlockEndTokenType; +SymbolsMapTokens["<="] = EnumToken.LteTokenType; +SymbolsMapTokens[">"] = EnumToken.GtTokenType; +SymbolsMapTokens[">="] = EnumToken.GteTokenType; +SymbolsMapTokens[" "] = EnumToken.Whitespace; +SymbolsMapTokens["\t"] = EnumToken.Whitespace; +SymbolsMapTokens["\r"] = EnumToken.Whitespace; +SymbolsMapTokens["\n"] = EnumToken.Whitespace; +SymbolsMapTokens["\f"] = EnumToken.Whitespace; + +assignTokenMap(flexUnits, EnumToken.FlexTokenType); +assignTokenMap(dimensionUnits, EnumToken.LengthTokenType); +assignTokenMap(resolutionUnits, EnumToken.ResolutionTokenType); +assignTokenMap(angleUnits, EnumToken.AngleTokenType); +assignTokenMap(timeUnits, EnumToken.TimeTokenType); +assignTokenMap(frequencyUnits, EnumToken.FrequencyTokenType); +assignTokenMap(pseudoElements, EnumToken.PseudoElementTokenType); +assignTokenMap(containerFunc, EnumToken.ContainerFunctionTokenDefType, "("); +assignTokenMap(urlFunc, EnumToken.UrlFunctionTokenDefType, "("); +assignTokenMap(gridTemplateFunc, EnumToken.GridTemplateFuncTokenDefType, "("); +assignTokenMap(imageFunc, EnumToken.ImageFunctionTokenDefType, "("); +assignTokenMap(timelineFunc, EnumToken.TimelineFunctionTokenDefType, "("); +assignTokenMap(supportFunc, EnumToken.SupportsFunctionTokenDefType, "("); +assignTokenMap(timingFunc, EnumToken.TimingFunctionTokenDefType, "("); +assignTokenMap(colorsFunc, EnumToken.ColorFunctionTokenDefType, "("); +assignTokenMap(mathFuncs, EnumToken.MathFunctionTokenDefType, "("); +assignTokenMap(transformFunctions, EnumToken.TransformFunctionTokenDefType, "(", true); +assignTokenMap(whenElseFunc, EnumToken.WhenElseFunctionTokenDefType, "("); +assignTokenMap(wildCardFuncs, EnumToken.WildCardFunctionTokenDefType, "("); + +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); // do not capture the value export const hintsEnum = new Set([ @@ -180,1044 +158,1920 @@ export const enum TokenMap { PLUS = 43, // '+', PLUS MINUS = 45, GREATERTHAN = 62, // '>', GREATER THAN + PERCENTAGE = 37, // '%', PERCENTAGE } -export function consumeString(parseInfo: ParseInfo): Array { - const quote: number = next(parseInfo).charCodeAt(0); - let charCode: number; - let decodeSegments: boolean = false; - - const result: Array = []; - while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { - if (charCode == TokenMap.REVERSE_SOLIDUS) { - if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { - next(parseInfo, 2); - continue; - } +function getSymbolHint(parseInfo: ParseInfo, start: number, end: number): EnumToken | null { + const len: number = end - start; + const keysLength = SymbolsMapTokensKeys.length; - const sequence: string = peek(parseInfo, 7); - let escapeSequence: string = ""; - let codepoint: number; - let i; + // Early exit for impossible lengths + if (len < 0) return null; - for (i = 1; i < sequence.length; i++) { - codepoint = sequence.charCodeAt(i); + for (let i = 0; i < keysLength; i++) { + const key = SymbolsMapTokensKeys[i]; + if (key.length !== len) continue; - if ( - codepoint == 0x20 || - (codepoint >= 0x61 && codepoint <= 0x66) || - (codepoint >= 0x41 && codepoint <= 0x46) || - (codepoint >= 0x30 && codepoint <= 0x39) - ) { - escapeSequence += sequence[i]; + // Match character by character + let match = true; - if (codepoint == 0x20) { - break; - } + for (let j = 0; j < len; j++) { + let ca = key.charCodeAt(j); + let cb = parseInfo.stream.charCodeAt(start + j); - continue; - } + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) ca += 32; + if (cb >= 65 && cb <= 90) cb += 32; + if (ca !== cb) { + match = false; break; } - - if (escapeSequence.trimEnd().length > 0) { - // const codepoint = parseInt(escapeSequence, 16); - - // TODO set decode flag ON - // if ( - // codepoint == 0 || - // // leading surrogate - // (0xd800 <= codepoint && codepoint <= 0xdbff) || - // // trailing surrogate - // (0xdc00 <= codepoint && codepoint <= 0xdfff) - // ) { - // buffer += String.fromCodePoint(0xfffd); - // } else { - // buffer += String.fromCodePoint(codepoint); - // } - - const length: number = - escapeSequence.length + - 1 + - (isWhiteSpace(parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0)) - ? 1 - : 0); - - decodeSegments = true; - - next(parseInfo, length); - - continue; - } - - next(parseInfo, 2); - continue; } - if (charCode == quote) { - next(parseInfo); - result.push( - yieldResult( - parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, - decodeSegments ? { decodeSegments } : null, - ), - ); - - return result; + if (match) { + return SymbolsMapTokens[key]; } + } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BadStringTokenType)); + return null; +} - return result; - } +function searchArray(array: string[], parseInfo: ParseInfo, start: number, end: number): string | null { + const len: number = end - start; - next(parseInfo); - } + // Early exit for impossible lengths + if (len < 0) return null; - // EOF - 'Unclosed-string' fixed - result.push(yieldResult(parseInfo, EnumToken.StringTokenType)); - return result; -} + // Use a simple linear search optimized with length pre-filtering + let i: number = array.length; -export function yieldResult( - parseInfo: ParseInfo, - hint?: EnumToken, - options?: { decodeSegments: boolean } | null, -): TokenizeResult { - let val: string = parseInfo.stream.slice( - parseInfo.position - parseInfo.offset, - parseInfo.currentPosition - parseInfo.offset, - ); - - let token: Token | null = null; - let dimension: - | DimensionToken - | LengthToken - | AngleToken - | FlexToken - | TimeToken - | ResolutionToken - | FrequencyToken - | null; - - if (options?.decodeSegments) { - val = val.replace(/\\([0-9a-fA-F]{1,6})(?:\s)?/g, (_, sequence) => { - const codepoint = parseInt(sequence, 16); + while (i--) { + if (array[i].length !== len) continue; - if ( - codepoint == 0 || - // leading surrogate - (0xd800 <= codepoint && codepoint <= 0xdbff) || - // trailing surrogate - (0xdc00 <= codepoint && codepoint <= 0xdfff) || - codepoint > 0x10ffff - ) { - return "\uFFFD"; - } + // Match character by character + let match = true; + const arrayItem = array[i]; - return String.fromCodePoint(codepoint); - }); - } + for (let j: number = 0; j < len; j++) { + let ca = arrayItem.charCodeAt(j); + let cb = parseInfo.stream.charCodeAt(start + j); - if (hint != null) { - let searchArray: string[] | null = null; + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) ca += 32; + if (cb >= 65 && cb <= 90) cb += 32; - switch (hint) { - case EnumToken.TransformFunctionTokenDefType: - searchArray = transformFunctions; - break; - case EnumToken.ColorFunctionTokenDefType: - searchArray = colorsFunc; - break; - case EnumToken.ContainerFunctionTokenDefType: - searchArray = containerFunc; - break; - case EnumToken.UrlFunctionTokenDefType: - searchArray = urlFunc; - break; - case EnumToken.GridTemplateFuncTokenDefType: - searchArray = gridTemplateFunc; - break; - case EnumToken.ImageFunctionTokenDefType: - searchArray = imageFunc; - break; - case EnumToken.TimelineFunctionTokenDefType: - searchArray = timelineFunc; - break; - // case EnumToken.GeneralEnclosedFunctionTokenDefType: - // searchArray = generalEnclosedFunc; - // break; - case EnumToken.SupportsFunctionTokenDefType: - searchArray = supportFunc; - break; - case EnumToken.TimingFunctionTokenDefType: - searchArray = timingFunc; - break; - case EnumToken.MathFunctionTokenDefType: - searchArray = mathFuncs; - break; - case EnumToken.WhenElseFunctionTokenDefType: - searchArray = whenElseFunc; - break; - case EnumToken.WildCardFunctionTokenDefType: - searchArray = wildCardFuncs; + if (ca != cb) { + match = false; break; + } } - if (searchArray != null) { - val = searchArray.find((v: string): boolean => equalsIgnoreCase(v, val)) as string; + if (match) { + return arrayItem; } + } - token = hintsEnum.has(hint) ? ({ typ: hint } as Token) : ({ typ: hint, val } as Token); - } else { - let slice: string = val.slice(1); - const chr: string = val.charAt(0); - - if (chr == "!" && equalsIgnoreCase("!important", val)) { - token = { - typ: EnumToken.ImportantTokenType, - } as Token; - } else if (chr == "@" && isIdent(slice)) { - token = { - typ: EnumToken.AtRuleTokenType, - nam: slice, - } as Token; - } else if (chr == "." && isIdent(slice)) { - token = { - typ: EnumToken.ClassSelectorTokenType, - val, - }; - } else if (chr == "#") { - if (isHexColor(val)) { - token = { - typ: EnumToken.ColorTokenType, - val: val, - kin: ColorType.HEX, - }; - } else if (isHash(val)) { - token = { - typ: EnumToken.HashTokenType, - val: val, + return null; +} + +/** + * tokenizer class + */ +export class Tokenizer { + /** + * token type + */ + typ: EnumToken | null = null; + /** + * token kind + */ + public kin: ColorType | null = null; + /** + * token name + */ + public nam: string | null = null; + /** + * token value + */ + public val: number | string | null = null; + /** + * token unit + */ + public unit: string | null = null; + /** + * source id + */ + public srcId: number | null = null; + /** + * token start + */ + public sta: number | null = null; + /** + * token end + */ + public end: number | null = null; + /** + * bytes in + */ + public bytesIn: number | null = null; + /** + * decode string + */ + public decodeString: boolean | null = null; + /** + * token slice + */ + public slice: number | null = null; + /** + * source file + */ + public source: SourceFile | null = null; + /** + * token hint + */ + private hint: EnumToken | null = null; + private state: EnumToken | null = null; + + constructor( + private parseInfo: ParseInfo, + private input: ReadableStream | null = null, + ) { + if (typeof this.parseInfo == "string") { + if (typeof parseInfo == "string") { + this.parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, }; } - } else if ("\"'".includes(chr)) { - token = { - typ: EnumToken.UnclosedStringTokenType, - val: val, - }; - } else if (isNumber(val)) { - token = - val[0] === "-" || val[0] === "+" - ? { - typ: EnumToken.NumberTokenType, - sign: val[0], - val: +val, - } - : { - typ: EnumToken.NumberTokenType, - val: +val, - }; - } else if (isPercentage(val)) { - token = { - typ: EnumToken.PercentageTokenType, - val: +val.slice(0, -1), - }; - } else if ((dimension = parseDimension(val))) { - token = dimension; - } else if (isIdent(val)) { - token = { - typ: val.startsWith("--") ? EnumToken.DashedIdenTokenType : EnumToken.IdenTokenType, - val, - } as Token; } } - if (token == null) { - token = { - typ: EnumToken.LiteralTokenType, - val, - }; - } - - // return token; - token[LOC] = { - srcId: parseInfo.source.id as number, - sta: parseInfo.position, - end: parseInfo.currentPosition, - }; - - parseInfo.position = parseInfo.currentPosition; - - return { token, bytesIn: parseInfo.currentPosition }; -} - -export function match(parseInfo: ParseInfo, input: string): boolean { - let position: number = parseInfo.currentPosition - parseInfo.offset; + /** + * + * @param parseInfo + * @returns + */ + consumeString(parseInfo: ParseInfo): this { + const quote: number = this.advance(parseInfo).charCodeAt(0); + let charCode: number; + let decodeSegments: boolean = false; + + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == TokenMap.REVERSE_SOLIDUS) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } - for (let i: number = 0; i < input.length; i++) { - if (parseInfo.stream[position + i] != input.charAt(i)) { - return false; - } - } + const sequence: string = this.peek(parseInfo, 7); + let escapeSequence: string = ""; + let codepoint: number; + let i; - return true; -} + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); -export function peek(parseInfo: ParseInfo, count: number = 1): string { - if (count == 1) { - return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); - } + if ( + codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39) + ) { + escapeSequence += sequence[i]; - const position = parseInfo.currentPosition - parseInfo.offset; - return parseInfo.stream.slice(position, position + count); -} + if (codepoint == 0x20) { + break; + } -export function next(parseInfo: ParseInfo, count: number = 1): string { - let position = parseInfo.currentPosition - parseInfo.offset; + continue; + } - let char: string = - count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); - let i: number = 0; - let codepoint: number; + break; + } - for (; i < char.length; i++) { - codepoint = char[i].charCodeAt(0); + if (escapeSequence.trimEnd().length > 0) { + const length: number = + escapeSequence.length + + 1 + + (isWhiteSpace( + parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0), + ) + ? 1 + : 0); + + decodeSegments = true; + this.advance(parseInfo, length); + continue; + } - if ( - codepoint == 0xa || // \n - codepoint == 0xb || // \v - codepoint == 0xc || // \f - codepoint == 0xd || // \r - codepoint == 0x2028 || // \u2028 - codepoint == 0x2029 // \u2029 - ) { - // \r\n - if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) { - // nope - } else { - parseInfo.source.lineStarts.lineStarts.push(position + i); + this.advance(parseInfo, 2); + continue; } - } - } - parseInfo.currentPosition += char.length; - return char; -} -function isIdentToken(parseInfo: ParseInfo, start?: number, end?: number): boolean { - let j: number = parseInfo.currentPosition - parseInfo.offset; - let i: number = parseInfo.position - parseInfo.offset; - - if (start != null) { - if (end == null) { - if (start < 0) { - j += start; - } else { - i += start; + if (charCode == quote) { + this.advance(parseInfo); + return this.makeToken( + parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, + decodeSegments ? { decodeSegments } : null, + // ), + ); } - } else { - if (end < 0) { - j += end; - } else { - j = parseInfo.position + end; + + if (isNewLine(charCode)) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } + + this.advance(parseInfo); } + + // EOF - 'Unclosed-string' fixed + return this.makeToken(parseInfo, EnumToken.StringTokenType); + // return result; } - j--; + /** + * + * @param parseInfo + * @returns + */ + consumeURLToken(parseInfo: ParseInfo): this { + const quote: number = this.advance(parseInfo).charCodeAt(0); + let charCode: number; + let decodeSegments: boolean = false; + + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == TokenMap.REVERSE_SOLIDUS) { + if (charCode == parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1)) { + this.advance(parseInfo, 2); + continue; + } - let codepoint: number = parseInfo.stream.charCodeAt(i) as number; + const sequence: string = this.peek(parseInfo, 7); + let escapeSequence: string = ""; + let codepoint: number; + let i; - // - - if (codepoint == 0x2d) { - let nextCodepoint: number; + for (i = 1; i < sequence.length; i++) { + codepoint = sequence.charCodeAt(i); - if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { - return false; - } + if ( + codepoint == 0x20 || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) || + (codepoint >= 0x30 && codepoint <= 0x39) + ) { + escapeSequence += sequence[i]; - if (isDigit(nextCodepoint)) { - return false; - } + if (codepoint == 0x20) { + break; + } - codepoint = nextCodepoint; - i++; - } + continue; + } - if (codepoint !== 0x2d && !isIdentStart(codepoint)) { - return false; - } + break; + } - if (codepoint == TokenMap.REVERSE_SOLIDUS) { - codepoint = parseInfo.stream.charCodeAt(i + 1) as number; + if (escapeSequence.trimEnd().length > 0) { + const length: number = + escapeSequence.length + + 1 + + (isWhiteSpace( + parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset)?.charCodeAt(0), + ) + ? 1 + : 0); - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - i += String.fromCodePoint(codepoint).length; + decodeSegments = true; - // if (i < j) { - // codepoint = name.charCodeAt(i) as number; + this.advance(parseInfo, length); - // if (!isIdentCodepoint(codepoint)) { - // return false; - // } - // } - } + continue; + } - while (i < j) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i) as number; + this.advance(parseInfo, 2); + continue; + } - if (codepoint == TokenMap.REVERSE_SOLIDUS) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i) as number; - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + if (charCode == quote) { + this.advance(parseInfo); - continue; - } + let k: number = 1; + let end: number = parseInfo.stream.length - parseInfo.offset; + let position: number = parseInfo.currentPosition - parseInfo.offset; - if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { - return false; - } - } + while (position + k < end) { + charCode = parseInfo.stream.charCodeAt(position); - return true; -} + // NaN != NaN + if (charCode != charCode) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } -function 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) == ":" - ? isIdentToken(parseInfo, 2, -1) - : isIdentToken(parseInfo, 1, -1))) || - parseInfo.stream.charAt(position + 1) == ":" - ? isIdentToken(parseInfo, 2) - : isIdentToken(parseInfo, 1); -} + if (isWhiteSpace(charCode)) { + this.advance(parseInfo, k); + k++; + continue; + } -function startsWith(parseInfo: ParseInfo, input: string): boolean { - let i: number = 0; - let j: number = input.length; + if (charCode != TokenMap.RIGHT_PARENTHESIS) { + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } + break; + } - while (i < j) { - if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { - return false; - } - i++; - } + // consume until the ')' + return this.makeToken( + parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, + decodeSegments ? { decodeSegments } : null, + ); + // return result; + } - return true; -} + if (isNewLine(charCode)) { + // bad string + this.advance(parseInfo); + + while ( + (charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode + ) { + if (charCode == TokenMap.REVERSE_SOLIDUS) { + this.advance(parseInfo, 2); + continue; + } -function isURLToken(parseInfo: ParseInfo): boolean { - let i: number = parseInfo.position - parseInfo.offset; - let c: number; + if (charCode == TokenMap.RIGHT_PARENTHESIS) { + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + } - while (++i < parseInfo.currentPosition) { - c = parseInfo.stream.charCodeAt(i) as number; + this.advance(parseInfo); + } - // single quote or double quote or start parenthesis or close parenthesis - if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { - return false; + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); + } + + this.advance(parseInfo); } - // valid escape - if (c == TokenMap.REVERSE_SOLIDUS) { - i++; + // EOF - bad url token + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + // return result; + } - if (i >= parseInfo.currentPosition) { - return false; + /** + * consume number, dimension, or percentage + * @param parseInfo + * @returns + */ + consumeNumericToken(parseInfo: ParseInfo): number { + let position: number = parseInfo.currentPosition - parseInfo.offset; + let offset: number = position; + let hasDigits: boolean = false; + let hasLetter: boolean = false; + let hasPercent: boolean = false; + + let codepoint: number = parseInfo.stream.charCodeAt(position) as number; + + this.slice = null; + this.hint = null; + + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } + + // consume digits + while (position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position) as number; + + if (isDigit(codepoint)) { + hasDigits = true; + position++; + continue; } - c = parseInfo.stream.charCodeAt(i) as number; + // '.' 'E' 'e' + if (codepoint == 0x2e || codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } - // c is not '\n' or '\r' or '\f' - if (c == 0x6e || c == 0x72 || c == 0x66) { - return false; + if ( + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + return !hasDigits ? 0 : position - offset; } - continue; - } + if (codepoint == TokenMap.PERCENTAGE) { + hasPercent = true; + break; + } - // is white space - if (c == 0x20 || c == 0x09) { - break; + if (isLetter(codepoint)) { + hasLetter = true; + break; + } + + return 0; } - } - return i == parseInfo.currentPosition; -} + if (!hasLetter && !hasPercent) { + // '.' + if (codepoint == 0x2e) { + codepoint = parseInfo.stream.charCodeAt(position) as number; -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -export function tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = true): Array { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } + if (codepoint != codepoint) { + return !hasDigits ? 0 : position - offset; + } - let charCode: number; - let nextCharCode: number; + if ( + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + return !hasDigits ? 0 : position - offset; + } - const startTime: number = performance.now(); - const result: TokenizeResult[] = []; - // allow 10 characters buffer for the streaming parser to avoid incomplete tokens - const endPosition: number = parseInfo.stream.length - 1; + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; + } - // NaN is not equal to NaN - while ((charCode = peek(parseInfo).charCodeAt(0)) == charCode) { - switch (charCode) { - case TokenMap.EQUALS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (codepoint == TokenMap.PERCENTAGE) { + hasPercent = true; + } else if (isLetter(codepoint)) { + hasLetter = true; + } else { + return 0; + } + } else { + position++; + hasDigits = true; } + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.DelimTokenType)); - break; + if (!hasLetter && !hasPercent) { + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position) as number; - // '+' or '-' - case TokenMap.PLUS: - case TokenMap.MINUS: - nextCharCode = peek(parseInfo).charCodeAt(0); + if (isDigit(codepoint)) { + position++; + continue; + } - // not a number - if (charCode === TokenMap.PLUS && !(nextCharCode >= 0x30 && nextCharCode <= 0x39)) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (!hasDigits) { + return 0; } - next(parseInfo); + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + position++; + break; + } - result.push( - yieldResult( - parseInfo, - SymbolsMapTokens[ - parseInfo.stream - .slice( - parseInfo.position - parseInfo.offset, - parseInfo.currentPosition - parseInfo.offset, - ) - .toLowerCase() - ], - ), - ); - break; - } + if ( + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + return position - offset; + } - next(parseInfo); + if (isLetter(codepoint)) { + hasLetter = true; + break; + } - break; + if (codepoint == TokenMap.PERCENTAGE) { + hasPercent = true; + break; + } - // '{' - case TokenMap.LEFT_BRACE: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + return 0; } - - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BlockStartTokenType)); - break; - // '}' - case TokenMap.RIGHT_BRACE: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // 'E' 'e' - 'em' + if ((codepoint == 0x45 || codepoint == 0x65) && hasDigits && !hasLetter && !hasPercent) { + if (isLetter(parseInfo.stream.charCodeAt(position) as number)) { + hasLetter = true; + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BlockEndTokenType)); - break; + if (!hasLetter && !hasPercent) { + // 'E' 'e' + if (codepoint == 0x45 || codepoint == 0x65) { + codepoint = parseInfo.stream.charCodeAt(position + 1) as number; - // '(' - case TokenMap.LEFT_PARENTHESIS: - if (parseInfo.position < parseInfo.currentPosition) { - if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && isPseudo(parseInfo)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.PseudoClassFunctionTokenDefType)); + // '+' '-' + if (codepoint == 0x2b || codepoint == 0x2d) { + position++; + } - break; - } else if (isIdentToken(parseInfo)) { - const hint: EnumToken = startsWith(parseInfo, "--") - ? EnumToken.CustomFunctionTokenDefType - : (SymbolsMapTokens[ - parseInfo.stream - .slice( - parseInfo.position - parseInfo.offset, - parseInfo.currentPosition - parseInfo.offset, - ) - .toLowerCase() + "(" - ] ?? EnumToken.FunctionTokenDefType); - - result.push(yieldResult(parseInfo, hint)); - next(parseInfo); - - // consume '(' - parseInfo.position = parseInfo.currentPosition; + codepoint = position = parseInfo.stream.charCodeAt(position + 1) as number; - if (hint === EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(peek(parseInfo).charCodeAt(0))) { - next(parseInfo); + if (!isDigit(codepoint)) { + if (!hasDigits) { + return 0; } + if (isLetter(codepoint)) { + hasLetter = true; + } else if (codepoint == TokenMap.PERCENTAGE) { + hasPercent = true; + } else { + return 0; + } + } + } - charCode = peek(parseInfo).charCodeAt(0); + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position) as number; - let values: Array | null = null; + // eof + if (codepoint != codepoint) { + break; + } - if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { - values = consumeString(parseInfo); - } else { - do { - next(parseInfo); - // value = peek(parseInfo); - charCode = peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && match(parseInfo, "/*") && - charCode !== TokenMap.RIGHT_PARENTHESIS && - parseInfo.currentPosition < endPosition - ); + if (isDigit(codepoint)) { + position++; + continue; + } + + if (!hasDigits) { + return 0; } - if (values != null) { - // NaN is not equal to NaN - if ((charCode = peek(parseInfo).charCodeAt(0)) != charCode) { - for (let i = 0; i < values.length; i++) { - values[i].token.typ = EnumToken.BadUrlTokenType; - } - } - - result.push(...values); - } else if (parseInfo.position < parseInfo.currentPosition) { - result.push( - yieldResult( - parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = peek(parseInfo).charCodeAt(0)) != charCode || !isURLToken(parseInfo) - ? EnumToken.BadUrlTokenType - : EnumToken.UrlTokenTokenType, - ), - ); + if ( + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + return position - offset; + } else if (isLetter(codepoint)) { + hasLetter = true; + break; + } else if (codepoint == TokenMap.PERCENTAGE) { + hasPercent = true; + break; + } else { + return 0; } } - break; + if (!hasLetter && !hasPercent) { + return position - offset; + } } } + } + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.StartParensTokenType)); - - break; - - // ')' - case TokenMap.RIGHT_PARENTHESIS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.EndParensTokenType)); - break; + if (!hasDigits) { + return 0; + } - // '[' - case TokenMap.LEFT_BRACKETS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + if (hasPercent) { + const slice = position; - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrStartTokenType)); - break; - // ']' - case TokenMap.RIGHT_BRACKETS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + codepoint = parseInfo.stream.charCodeAt(++position) as number; - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrEndTokenType)); - break; + if ( + codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + this.slice = slice; + this.hint = EnumToken.PercentageTokenType; + return position - offset; + } - case TokenMap.SEMICOLON: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + return 0; + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.SemiColonTokenType)); - break; + if (hasLetter) { + codepoint = parseInfo.stream.charCodeAt(position - 1) as number; - case TokenMap.COLON: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + // 'E' 'e' + const slice = codepoint == 0x45 || codepoint == 0x65 ? position - 1 : position; - next(parseInfo); + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(++position) as number; - if (peek(parseInfo).charCodeAt(0) == TokenMap.COLON) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.DoubleColonTokenType)); + if (!isLetter(codepoint)) { break; } + } - result.push(yieldResult(parseInfo, EnumToken.ColonTokenType)); - break; + if ( + codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.PLUS || + codepoint == TokenMap.SLASH || + codepoint == TokenMap.STAR || + codepoint == TokenMap.COMMA + ) { + this.slice = slice; + this.hint = getSymbolHint(parseInfo, slice, position) ?? EnumToken.DimensionTokenType; + return position - offset; + } - // \n \r \f \v \t space - case 0x9: - case 0x20: - case 0xa: - case 0xb: - case 0xc: - case 0xd: - case 0x2028: - case 0x2029: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + return 0; + } - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + return 0; + } - while ( - nextCharCode == 0x20 || - (nextCharCode >= 0x9 && nextCharCode <= 0xd) || - nextCharCode == 0x2028 || - nextCharCode == 0x2029 - ) { - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); - } + /** + * + * @param parseInfo + * @returns + */ + consumeIdentToken(parseInfo: ParseInfo): number { + let position: number = parseInfo.currentPosition - parseInfo.offset; + let offset: number = position; - result.push(yieldResult(parseInfo, EnumToken.WhitespaceTokenType)); + let codepoint: number = parseInfo.stream.charCodeAt(position); - break; + if (!isIdentStart(codepoint) && codepoint != TokenMap.MINUS) { + return 0; + } - case TokenMap.COMMA: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + if (codepoint == TokenMap.MINUS) { + position++; + codepoint = parseInfo.stream.charCodeAt(position); - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommaTokenType)); - break; + if (!isIdentStart(codepoint) && codepoint != TokenMap.MINUS) { + return 0; + } + } - case TokenMap.DOLLAR: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + while ((codepoint = parseInfo.stream.charCodeAt(position)) == codepoint) { + if (codepoint == TokenMap.REVERSE_SOLIDUS) { + // eof + if ((codepoint = parseInfo.stream.charCodeAt(position + 1)) != codepoint) { + // this.next(parseInfo, position); + return 0; } - if (match(parseInfo, "$=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.EndMatchTokenType)); - break; + // \n \r \f \v + if ( + codepoint == 0xa || + codepoint == 0xb || + codepoint == 0xc || + codepoint == 0xd || + codepoint == 0x2028 || + codepoint == 0x2029 + ) { + return 0; } - next(parseInfo); - break; + position += 2; + continue; + } - case TokenMap.TILDA: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (codepoint == 0x2d || isIdentCodepoint(codepoint)) { + position++; + } else { + switch (codepoint) { + case TokenMap.COLON: + case TokenMap.LEFT_BRACE: + case TokenMap.RIGHT_BRACE: + case TokenMap.LEFT_PARENTHESIS: + case TokenMap.RIGHT_PARENTHESIS: + case TokenMap.LEFT_BRACKETS: + case TokenMap.RIGHT_BRACKETS: + case TokenMap.SEMICOLON: + case TokenMap.EXCLAMATION: + case TokenMap.SLASH: + case TokenMap.HASH: + case TokenMap.STAR: + case TokenMap.EQUALS: + case TokenMap.TILDA: + case TokenMap.PIPE: + case TokenMap.CARET: + case TokenMap.DOLLAR: + case TokenMap.COMMA: + case TokenMap.GREATERTHAN: + case TokenMap.DOT: + case TokenMap.PLUS: + return position - offset; } - if (match(parseInfo, "~=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.IncludeMatchTokenType)); + if (codepoint != codepoint || isWhiteSpace(codepoint)) { + return position - offset; + } + + return 0; + } + } + + return position - offset; + } + + /** + * + * @param parseInfo + * @returns + */ + consumeColor(parseInfo: ParseInfo) { + let position: number = parseInfo.currentPosition - parseInfo.offset; + let offset: number = position; + + let codepoint: number = parseInfo.stream.charCodeAt(position); + + if (codepoint != TokenMap.HASH) { + return 0; + } + + position++; + + let count: number = 0; + + while (true) { + codepoint = parseInfo.stream.charCodeAt(position); + + // 'a-f0-9' 'A-F0-9' + if ( + (codepoint >= 0x30 && codepoint <= 0x39) || + (codepoint >= 0x61 && codepoint <= 0x66) || + (codepoint >= 0x41 && codepoint <= 0x46) + ) { + position++; + count++; + continue; + } + + break; + } + + if (count != 3 && count != 4 && count != 6 && count != 8) { + return 0; + } + + codepoint = parseInfo.stream.charCodeAt(position); + + if ( + codepoint != codepoint || + isWhiteSpace(codepoint) || + codepoint == TokenMap.RIGHT_PARENTHESIS || + codepoint == TokenMap.SEMICOLON || + codepoint == TokenMap.RIGHT_BRACE || + codepoint == TokenMap.COMMA + ) { + return position - offset; + } + + return 0; + } + + parseURLToken(parseInfo: ParseInfo, endPosition: number): this { + let charCode: number; + + // consume an + while (isWhiteSpace(this.peekCharCode(parseInfo))) { + this.advance(parseInfo); + } + + charCode = this.peekCharCode(parseInfo); + + if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { + return this.consumeURLToken(parseInfo); + } + + do { + this.advance(parseInfo); + charCode = this.peekCharCode(parseInfo); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== TokenMap.RIGHT_PARENTHESIS && + parseInfo.currentPosition < endPosition + ); + + // if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken( + parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType, + ); + // } + } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ + makeToken( + parseInfo: ParseInfo, + hint?: EnumToken | null, + options?: { decodeSegments?: boolean; slice?: number | null; sign?: "+" | "-" | null } | null, + ): this { + let val: string | null = null; + + this.typ = null; + this.nam = null; + this.val = null; + this.unit = null; + this.kin = null; + this.decodeString = null; + this.slice = null; + this.hint = null; + + if (options?.slice) { + this.slice = options.slice; + } + + if (options?.decodeSegments) { + this.decodeString = true; + } + + if (hint != null) { + let array: string[] | null = null; + let hasUnit: boolean = false; + + switch (hint) { + case EnumToken.TransformFunctionTokenDefType: + array = transformFunctions; + break; + case EnumToken.ColorFunctionTokenDefType: + array = colorsFunc; + break; + case EnumToken.ContainerFunctionTokenDefType: + array = containerFunc; + break; + case EnumToken.UrlFunctionTokenDefType: + array = urlFunc; + break; + case EnumToken.GridTemplateFuncTokenDefType: + array = gridTemplateFunc; + break; + case EnumToken.ImageFunctionTokenDefType: + array = imageFunc; + break; + case EnumToken.TimelineFunctionTokenDefType: + array = timelineFunc; + break; + // case EnumToken.GeneralEnclosedFunctionTokenDefType: + // searchArray = generalEnclosedFunc; + // break; + case EnumToken.SupportsFunctionTokenDefType: + array = supportFunc; break; + case EnumToken.TimingFunctionTokenDefType: + array = timingFunc; + break; + case EnumToken.MathFunctionTokenDefType: + array = mathFuncs; + break; + case EnumToken.WhenElseFunctionTokenDefType: + array = whenElseFunc; + break; + case EnumToken.WildCardFunctionTokenDefType: + array = wildCardFuncs; + break; + case EnumToken.FrequencyTokenType: + array = frequencyUnits; + hasUnit = true; + break; + case EnumToken.ResolutionTokenType: + array = resolutionUnits; + hasUnit = true; + break; + case EnumToken.LengthTokenType: + array = dimensionUnits; + hasUnit = true; + break; + case EnumToken.FlexTokenType: + array = flexUnits; + hasUnit = true; + break; + case EnumToken.AngleTokenType: + array = angleUnits; + hasUnit = true; + break; + case EnumToken.TimeTokenType: + array = timeUnits; + hasUnit = true; + break; + case EnumToken.DimensionTokenType: + hasUnit = true; + break; + } + + if (array != null) { + val = searchArray( + array, + parseInfo, + hasUnit ? (options?.slice as number) : parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset, + ) as string; + } else if (!hintsEnum.has(hint)) { + val = parseInfo.stream.slice( + (options?.slice as number) ?? parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset, + ); + } + + if (this.decodeString) { + val = decodeEscapeSequences(val as string); + } + + if (hintsEnum.has(hint)) { + this.typ = hint; + } else { + this.typ = hint; + + if (hasUnit || hint == EnumToken.PercentageTokenType || hint == EnumToken.DimensionTokenType) { + this.val = parseFloat( + parseInfo.stream.slice(parseInfo.position - parseInfo.offset, options?.slice as number), + ); + + if (hint != EnumToken.PercentageTokenType) { + this.unit = val; + } + } else if (hint == EnumToken.NumberTokenType) { + this.val = parseFloat(val as string); + } else if (hint == EnumToken.AtRuleTokenType) { + this.nam = val; + } else { + this.val = val; + + if (hint == EnumToken.ColorTokenType) { + this.kin = ColorType.HEX; + } } + } + } else { + if (this.equalsIgnoreCase(parseInfo, "!important")) { + this.typ = EnumToken.ImportantTokenType; + } + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Tilda)); + if (this.typ == null) { + val = parseInfo.stream.slice( + parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset, + ); - break; + if (options?.decodeSegments) { + val = decodeEscapeSequences(val); + this.decodeString = true; + } + + this.typ = EnumToken.LiteralTokenType; + this.val = val; + } + + this.srcId = parseInfo.source.id as number; + this.sta = parseInfo.position; + this.end = parseInfo.currentPosition; + this.bytesIn = parseInfo.currentPosition; + + parseInfo.position = parseInfo.currentPosition; + return this; + } + + /** + * + * @param parseInfo + * @param input + * @returns + */ + equalsIgnoreCase(parseInfo: ParseInfo, input: string): boolean { + let position: number = parseInfo.currentPosition - parseInfo.offset; + + let ca: number; + let cb: number; + + for (let i: number = 0; i < input.length; i++) { + ca = parseInfo.stream.charCodeAt(position + i); + cb = input.charCodeAt(i); + + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) ca += 32; + if (cb >= 65 && cb <= 90) cb += 32; + + if (ca != cb) { + return false; + } + } + + return true; + } + + /** + * + * @param parseInfo + * @param input + * @returns + */ + match(parseInfo: ParseInfo, input: string): boolean { + let position: number = parseInfo.currentPosition - parseInfo.offset; + + for (let i: number = 0; i < input.length; i++) { + if (parseInfo.stream[position + i] != input.charAt(i)) { + return false; + } + } + + return true; + } + + /** + * Get the current character code without creating a string + * @param parseInfo + * @returns charCode at current position + */ + peekCharCode(parseInfo: ParseInfo): number { + return parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + } - // case '^': - case TokenMap.CARET: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + /** + * + * @param parseInfo + * @param count + * @returns + */ + peek(parseInfo: ParseInfo, count: number = 1): string { + if (count == 1) { + return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); + } + + const position = parseInfo.currentPosition - parseInfo.offset; + return parseInfo.stream.slice(position, position + count); + } + + /** + * + * @param parseInfo + * @param count + * @returns + */ + advance(parseInfo: ParseInfo, count: number = 1): string { + let position = parseInfo.currentPosition - parseInfo.offset; + + let char: string = + count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); + let i: number = 0; + let codepoint: number; + const lineStarts = parseInfo.source.lineStarts.lineStarts; + + for (; i < char.length; i++) { + codepoint = char.charCodeAt(i); + + if ( + codepoint == 0xa || // \n + codepoint == 0xb || // \v + codepoint == 0xc || // \f + codepoint == 0xd || // \r + codepoint == 0x2028 || // \u2028 + codepoint == 0x2029 // \u2029 + ) { + // \r\n + if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) { + // nope + } else { + lineStarts.push(position + parseInfo.offset + i); } + } + } - if (match(parseInfo, "^=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.StartMatchTokenType)); - break; + parseInfo.currentPosition += char.length; + return char; + } + + /** + * + * @param parseInfo + * @param start + * @param end + * @returns + */ + isIdentToken(parseInfo: ParseInfo, start?: number, end?: number): boolean { + let j: number = parseInfo.currentPosition - parseInfo.offset; + let i: number = parseInfo.position - parseInfo.offset; + + if (start != null) { + if (end == null) { + if (start < 0) { + j += start; + } else { + i += start; } + } else { + if (end < 0) { + j += end; + } else { + j = parseInfo.position + end; + } + } + } - next(parseInfo); - break; + j--; + + let codepoint: number = parseInfo.stream.charCodeAt(i) as number; + + // - + if (codepoint == 0x2d) { + let nextCodepoint: number; - case TokenMap.STAR: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // NaN != NaN + if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { + return false; + } + + if (!isIdentStart(nextCodepoint) && nextCodepoint != 0x2d) { + return false; + } + + codepoint = nextCodepoint; + i++; + } + + if (codepoint !== 0x2d && !isIdentStart(codepoint)) { + return false; + } + + if (codepoint == TokenMap.REVERSE_SOLIDUS) { + codepoint = parseInfo.stream.charCodeAt(i + 1) as number; + + i += String.fromCodePoint(codepoint).length; + } + + while (i < j) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i) as number; + + if (codepoint == TokenMap.REVERSE_SOLIDUS) { + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + codepoint = parseInfo.stream.charCodeAt(i) as number; + i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; + + continue; + } + + if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { + return false; + } + } + + 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 + * @param input + * @returns + */ + startsWith(parseInfo: ParseInfo, input: string): boolean { + let i: number = 0; + let j: number = input.length; + + while (i < j) { + if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { + return false; + } + i++; + } + + return true; + } + + /** + * + * @param parseInfo + * @returns + */ + isURLToken(parseInfo: ParseInfo): boolean { + let i: number = parseInfo.position - parseInfo.offset; + let c: number; + + while (++i < parseInfo.currentPosition) { + c = parseInfo.stream.charCodeAt(i) as number; + + // single quote or double quote or start parenthesis or close parenthesis + if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { + return false; + } + + // valid escape + if (c == TokenMap.REVERSE_SOLIDUS) { + i++; + + if (i >= parseInfo.currentPosition) { + return false; } - if (match(parseInfo, "*=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ContainMatchTokenType)); - break; + c = parseInfo.stream.charCodeAt(i) as number; + + // c is not '\n' or '\r' or '\f' + if (c == 0x6e || c == 0x72 || c == 0x66) { + return false; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Star)); + continue; + } + // is white space + if (c == 0x20 || c == 0x09) { break; + } + } + + return i == parseInfo.currentPosition; + } + + done(): boolean { + return this.typ === EnumToken.EOF; + } - case TokenMap.AMPERSAND: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + next(/* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */): this { + const parseInfo: ParseInfo = this.parseInfo as ParseInfo; + + this.source = parseInfo.source; + + let charCode: number; + let nextCharCode: number; + + // const result: TokenizeResult[] = []; + // allow 10 characters buffer for the streaming parser to avoid incomplete tokens + const endPosition: number = parseInfo.stream.length - 1; // yieldEOFToken ? parseInfo.stream.length - 1 : parseInfo.stream.length - 10; + let tokensCount: number; + + // NaN is not equal to NaN + while ((charCode = this.peekCharCode(parseInfo)) == charCode) { + if (this.state === EnumToken.UrlFunctionTokenDefType) { + this.state = null; + return this.parseURLToken(parseInfo, endPosition); + continue; + } + + if (parseInfo.position == parseInfo.currentPosition) { + if ( + charCode == TokenMap.MINUS || + charCode == TokenMap.PLUS || + charCode == TokenMap.DOT || + 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: charCode == TokenMap.MINUS ? "-" : charCode == TokenMap.PLUS ? "+" : null, + }); + continue; + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.NestingSelectorTokenType)); + if (isIdentStart(charCode) || charCode == TokenMap.MINUS) { + tokensCount = this.consumeIdentToken(parseInfo); - break; + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + + charCode = this.peekCharCode(parseInfo); - case TokenMap.PIPE: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + // do not match function + if (TokenMap.LEFT_PARENTHESIS != charCode) { + return this.makeToken( + parseInfo, + this.startsWith(parseInfo, "--") + ? EnumToken.DashedIdenTokenType + : EnumToken.IdenTokenType, + ); + continue; + } + } } - // '||' - if (match(parseInfo, "||")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ColumnCombinatorTokenType)); - break; - } else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.DashMatchTokenType)); - break; + if (charCode == TokenMap.AT) { + this.advance(parseInfo); + + charCode = this.peekCharCode(parseInfo); + + // match at-rule + if (charCode == TokenMap.MINUS || isIdentStart(this.peekCharCode(parseInfo))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + + return this.makeToken(parseInfo, EnumToken.AtRuleTokenType); + continue; + } + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Pipe)); + if (charCode == TokenMap.HASH) { + tokensCount = this.consumeColor(parseInfo); - break; + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ColorTokenType); + continue; + } + + this.advance(parseInfo); - case TokenMap.EXCLAMATION: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + tokensCount = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.HashTokenType); + continue; + } } + } + // EOF + switch (charCode) { + case TokenMap.EQUALS: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.DelimTokenType); + break; + + // '+' or '-' + case TokenMap.PLUS: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); - if (match(parseInfo, "!important")) { - next(parseInfo, 10); - result.push(yieldResult(parseInfo, EnumToken.ImportantTokenType)); + 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: "+", + }); + break; + } + } + + return this.makeToken(parseInfo, EnumToken.Plus); break; - } - next(parseInfo); - break; + case TokenMap.MINUS: + if (parseInfo.position == parseInfo.currentPosition) { + nextCharCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); - case TokenMap.SLASH: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + // not a number + if (isWhiteSpace(nextCharCode)) { + this.advance(parseInfo); - if (!match(parseInfo, "/*")) { - next(parseInfo); - result.push( - yieldResult( - parseInfo, - SymbolsMapTokens[parseInfo.stream.slice(parseInfo.position, parseInfo.currentPosition)], - ), - ); + return this.makeToken(parseInfo, EnumToken.Sub); + break; + } + + 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); + continue; + } + } + } + + this.advance(parseInfo); break; - } - next(parseInfo, 2); + // '{' + case TokenMap.LEFT_BRACE: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockStartTokenType); + break; + // '}' + case TokenMap.RIGHT_BRACE: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == TokenMap.STAR) { - if (match(parseInfo, "/")) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommentTokenType)); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockEndTokenType); + break; + // '(' + case TokenMap.LEFT_PARENTHESIS: + if (parseInfo.position < parseInfo.currentPosition) { + if ( + parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo) + ) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); + + break; + } else if (this.isIdentToken(parseInfo)) { + const hint: EnumToken = this.startsWith(parseInfo, "--") + ? EnumToken.CustomFunctionTokenDefType + : (getSymbolHint( + parseInfo, + parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset + 1, + ) ?? EnumToken.FunctionTokenDefType); + + this.makeToken(parseInfo, hint); + this.advance(parseInfo); + + // consume '(' + parseInfo.position = parseInfo.currentPosition; + + if (hint === EnumToken.UrlFunctionTokenDefType) { + this.state = hint; + } + + return this; break; } } - // else { - // buffer += value; - // } - } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCommentTokenType)); - } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.StartParensTokenType); - break; + break; - case TokenMap.GREATERTHAN: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + // ')' + case TokenMap.RIGHT_PARENTHESIS: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.GteTokenType)); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.EndParensTokenType); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.GtTokenType)); + // '[' + case TokenMap.LEFT_BRACKETS: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrStartTokenType); + break; + // ']' + case TokenMap.RIGHT_BRACKETS: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - case TokenMap.LOWERTHAN: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrEndTokenType); + break; - if (match(parseInfo, "<=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.LteTokenType)); + case TokenMap.SEMICOLON: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.SemiColonTokenType); break; - } - next(parseInfo); + case TokenMap.COLON: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - if (match(parseInfo, "!--")) { - next(parseInfo, 3); + this.advance(parseInfo); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == TokenMap.MINUS && match(parseInfo, "->")) { - break; + if (this.peekCharCode(parseInfo) == TokenMap.COLON) { + this.advance(parseInfo); + + return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); + break; + } + + return this.makeToken(parseInfo, EnumToken.ColonTokenType); + break; + + // \n \r \f \v \t space + case 0x9: + case 0x20: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0x2028: + case 0x2029: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + + while ( + nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029 + ) { + this.advance(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + + return this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); + + break; + + case TokenMap.COMMA: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommaTokenType); + break; + + case TokenMap.DOLLAR: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "$=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.EndMatchTokenType); + break; + } + + this.advance(parseInfo); + break; + + case TokenMap.TILDA: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "~=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); + break; + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Tilda); + + break; + + // case '^': + case TokenMap.CARET: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "^=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.StartMatchTokenType); + break; + } + + this.advance(parseInfo); + break; + + case TokenMap.STAR: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "*=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); + break; + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Star); + + break; + + case TokenMap.AMPERSAND: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); + + break; + + case TokenMap.PIPE: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + // '||' + if (this.match(parseInfo, "||")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); + break; + } else if (this.match(parseInfo, "|=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.DashMatchTokenType); + break; + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Pipe); + + break; + + case TokenMap.EXCLAMATION: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "!important")) { + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, EnumToken.ImportantTokenType); + + break; + } + + this.advance(parseInfo); + break; + + case TokenMap.SLASH: + 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, + ), + ); + break; + } + + this.advance(parseInfo, 2); + + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == TokenMap.STAR) { + if (this.match(parseInfo, "/")) { + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommentTokenType); + + break; + } } } - if (parseInfo.currentPosition >= endPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCdoTokenType)); - } else { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.CDOCOMMTokenType)); + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo, EnumToken.BadCommentTokenType); } - } - break; + break; - case TokenMap.HASH: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + case TokenMap.GREATERTHAN: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - next(parseInfo); - break; + if (this.match(parseInfo, ">=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.GteTokenType); + break; + } + + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.GtTokenType); - case TokenMap.REVERSE_SOLIDUS: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { break; - } - next(parseInfo); + case TokenMap.LOWERTHAN: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - // EOF - if (!peek(parseInfo)) { - if (!yieldEOFToken) { + if (this.match(parseInfo, "<=")) { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.LteTokenType); break; } - // end of stream ignore \\ + this.advance(parseInfo); + + if (this.match(parseInfo, "!--")) { + this.advance(parseInfo, 3); + + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == TokenMap.MINUS && this.match(parseInfo, "->")) { + break; + } + } + + if (parseInfo.currentPosition >= endPosition) { + return this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + } else { + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); + } + } + + break; + + case TokenMap.HASH: if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + return this.makeToken(parseInfo); } + this.advance(parseInfo); break; - } - next(parseInfo); - break; + case TokenMap.REVERSE_SOLIDUS: + // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } - case TokenMap.SINGLE_QUOTE: - case TokenMap.DOUBLE_QUOTE: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + this.advance(parseInfo); - result.push(...consumeString(parseInfo)); - break; + // EOF + if (!this.peek(parseInfo)) { + // if (!yieldEOFToken) { + // break; + // } - case TokenMap.DOT: - const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); + // end of stream ignore \\ + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - next(parseInfo, 2); + break; + } + + this.advance(parseInfo); break; - } - next(parseInfo); - break; - default: - next(parseInfo); - break; - } + case TokenMap.SINGLE_QUOTE: + case TokenMap.DOUBLE_QUOTE: + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); + } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + return this.consumeString(parseInfo); + break; + + case TokenMap.DOT: + const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + + if (isIdentStart(codepoint) || codepoint == TokenMap.MINUS) { + this.advance(parseInfo); + let tokensCount: number = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); + break; + } + } + + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; + break; + } + + this.advance(parseInfo); + break; + default: + this.advance(parseInfo); + break; + } + + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - } - if (yieldEOFToken) { + // if (yieldEOFToken) { if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + return this.makeToken(parseInfo); } - result.push(yieldResult(parseInfo, EnumToken.EOFTokenType)); + return this.makeToken(parseInfo, EnumToken.EOFTokenType); + // } } - parseInfo.time += performance.now() - startTime; - return result; -} + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async tokenizeStream(): Promise { + const decoder = new TextDecoder("utf-8"); + const reader = this.input!.getReader(); -/** - * tokenize readable stream - * @param input - * @param parseInfo - */ -export async function* tokenizeStream( - input: ReadableStream, - parseInfo: ParseInfo, -): AsyncGenerator { - const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); + let parseInfo: ParseInfo = this.parseInfo as ParseInfo; - parseInfo.stream = ""; + parseInfo.stream = ""; - while (true) { - const { done, value } = await reader.read(); - const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; + while (true) { + const { done, value } = await reader.read(); + const stream = ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value; - if (!done) { - parseInfo.source.append(stream as string); - - parseInfo.stream = (parseInfo.stream.slice(parseInfo.position - parseInfo.offset) + stream) as string; - - parseInfo.offset = parseInfo.offset = parseInfo.position; - } else { - parseInfo.stream = ""; + if (!done) { + parseInfo.source.append(stream as string); + } else { + break; + } } - yield* tokenize(parseInfo, done); - - if (done) { - break; - } + parseInfo.stream = parseInfo.source.getContent(); + return this; // .next(); } } diff --git a/src/lib/parser/utils/at-rule-container.ts b/src/lib/parser/utils/at-rule-container.ts index 91a56293..11d89e0d 100644 --- a/src/lib/parser/utils/at-rule-container.ts +++ b/src/lib/parser/utils/at-rule-container.ts @@ -10,7 +10,7 @@ import type { Token, } from "../../../@types/index.d.ts"; import { EnumToken } from "../../ast/types.ts"; -import { LOC, mFGT, mFLT } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, mFGT, mFLT } from "../../syntax/constants.ts"; import { createValidationContext, matchAllSyntaxes, trimArray } from "../../validation/match.ts"; import { ValidationSyntaxGroupEnum } from "../../validation/parser/typedef.ts"; @@ -60,7 +60,9 @@ export function parseAtRuleContainerQueryList( ); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, @@ -87,20 +89,6 @@ export function parseAtRuleContainerQueryList( tokens.push(stream[i++]); } - // if (i >= stream.length) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: context, - // location: context[LOC], - // message: `expecting at ${context[LOC]?.src}:${context?.[LOC]?.sta.lin}:${context[LOC]?.sta.col}`, - // }, - // ], - // }; - // } - if (stream[i].typ === EnumToken.IdenTokenType) { tokens.push(stream[i++]); } @@ -120,7 +108,7 @@ export function parseAtRuleContainerQueryList( { action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i]?.[LOC]!.sta), // ?? context[LOC], + location: options.source!.getSourceLocation(stream[i]?.[LOCSTA]!), message: `expecting `, }, ], @@ -150,12 +138,10 @@ export function parseAtRuleContainerQueryList( action: "drop", node: stream[i], message: `expecting , or comma`, - location: options.source!.getSourceLocation(stream[i]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[i]?.[LOCSTA]!), }); break; } - - // expectAndOr = false; } if (stream[i].typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(stream[i].typ)) { @@ -194,150 +180,21 @@ export function parseAtRuleContainerQueryList( errors.push({ action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), message: ` is not allowed outside of parentheses`, }); break; } - // if (currentScope.has(val === "or" ? EnumToken.AndTokenType : EnumToken.OrTokenType)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `cannot mix and at the same level at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - currentScope.add(stream[i].typ); stack.push(stream[i]); } - // else if (scopes.length === 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unexpected at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - - // return { - // success, - // errors, - // }; - // } } break; case EnumToken.EndParensTokenType: - // feature - // if (mFLT.has(stack.at(-1)?.typ) || mFGT.has(stack.at(-1)?.typ)) { - // // | - // const index: number = tokens.indexOf(stack.at(-1)!); - // const prevToken: Token = stack[stack.length - 2]; - - // if (mFLT.has(prevToken?.typ) || mFGT.has(prevToken?.typ)) { - // if (stack[stack.length - 3]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `unmatched '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - - // if (!mFLT.has(stack.at(-1)?.typ) && mFLT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - - // break; - // } else if (!mFGT.has(stack.at(-1)?.typ) && mFGT.has(prevToken?.typ)) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // message: `expected at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - - // break; - // } - - // // - // // const index: number = tokens.indexOf(stack.at(-1)!); - // // | - // const index2: number = tokens.indexOf(prevToken); - // // '(' - // const index3: number = tokens.indexOf(stack.at(-3)!); - - // const left: Token[] = trimArray(tokens.slice(index3 + 1, index2)); - // const right: Token[] = trimArray(tokens.slice(index + 1, tokens.length - 1)); - // const names: Token[] = trimArray(tokens.slice(index2 + 1, index)); - - // if (!isStyleFeatureValue(left)) { - // success = false; - // errors.push({ - // action: "drop", - // node: left[0], - // message: `expected at ${left[0]?.[LOC]?.src}:${left[0]?.[LOC]?.sta.lin}:${left[0]?.[LOC]?.sta.col}`, - // }); - - // break; - // } - - // if (!isStyleFeatureValue(right)) { - // success = false; - // errors.push({ - // action: "drop", - // node: right[0], - // message: `expected at ${right[0]?.[LOC]?.src}:${right[0]?.[LOC]?.sta.lin}:${right[0]?.[LOC]?.sta.col}`, - // }); - - // break; - // } - - // if (!isStyleFeatureValue(names)) { - // success = false; - // errors.push({ - // action: "drop", - // node: names[0], - // message: `expected at ${names[0]?.[LOC]?.src}:${names[0]?.[LOC]?.sta.lin}:${names[0]?.[LOC]?.sta.col}`, - // }); - - // break; - // } - - // tokens.splice(index3 + 1, tokens.length - index3 - 2, { - // typ: EnumToken.ContainerStyleRangeTokenType, - // l: left, - // op: names, - // r: right, - // [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, - // } as ContainerStyleRangeToken); - - // // check or - - // stack.pop(); - // stack.pop(); - // } else if (stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `expected '(' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - // break; - // } - // } - if ( mFGT.has(stack.at(-1)?.typ) || mFLT.has(stack.at(-1)?.typ) || @@ -348,47 +205,12 @@ export function parseAtRuleContainerQueryList( stack[stack.length - 2] as FunctionToken ).val?.toLowerCase?.() as string; - // if ( - // stack[stack.length - 2]?.typ !== EnumToken.StartParensTokenType && - // !( - // stack[stack.length - 2]?.typ === EnumToken.ContainerFunctionTokenDefType && - // ("style" === funcName || "scroll-state" === funcName) - // ) - // ) { - // success = false; - // errors.push({ - // action: "drop", - // node: stream[i], - // location: stream[i]?.[LOC], - // message: `unmatched2 ')' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // }); - - // break; - // } - const index2: number = tokens.indexOf(stack.at(-1)!); const index3: number = tokens.indexOf(stack.at(-2)!); let names: Token[] = trimArray(tokens.slice(index3 + 1, index2)); let values: Token[] = trimArray(tokens.slice(index2 + 1, tokens.length - 1)); - // if ( - // stack.at(-1)?.typ !== EnumToken.ColonTokenType && - // stack.at(-1)?.typ !== EnumToken.DelimTokenType - // ) { - // const filteredNames = names.filter( - // (n) => - // n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, - // ); - - // if ( - // filteredNames.length !== 1 || - // (filteredNames[0].typ !== EnumToken.IdenTokenType && - // filteredNames[0].typ !== EnumToken.DashedIdenTokenType) - // ) { - // } - // } - tokens.splice( index3 + 1, tokens.length - index3 - 2, @@ -398,7 +220,9 @@ export function parseAtRuleContainerQueryList( l: names, op: stack.pop() as Token, r: values, - [LOC]: { ...names[0][LOC]!, end: values.at(-1)![LOC]!.end }, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)![LOCEND], } as MediaQueryConditionToken, ); @@ -412,7 +236,9 @@ export function parseAtRuleContainerQueryList( chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), }); - tokens[index][LOC] = { ...tokens[index][LOC]!, end: stream[i]![LOC]!.end }; + tokens[index][LOCSRCID] = tokens[index][LOCSRCID]; + tokens[index][LOCSTA] = tokens[index][LOCSTA]; + tokens[index][LOCEND] = stream[i]![LOCEND]; if ( (tokens[index] as FunctionToken).chi.every( @@ -424,7 +250,7 @@ export function parseAtRuleContainerQueryList( errors.push({ action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[i]?.[LOCSTA]!), message: `expecting '<${(tokens[index] as FunctionToken).val}-query>'`, }); break; @@ -440,7 +266,9 @@ export function parseAtRuleContainerQueryList( tokens[index] = { typ: EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - [LOC]: { ...tokens[index][LOC]!, end: stream[i]![LOC]!.end }, + [LOCSRCID]: tokens[index][LOCSRCID], + [LOCSTA]: tokens[index][LOCSTA], + [LOCEND]: stream[i]![LOCEND], } as ParensToken; if ( @@ -453,7 +281,7 @@ export function parseAtRuleContainerQueryList( errors.push({ action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[i]?.[LOCSTA]!), message: `expecting ''`, }); break; @@ -481,23 +309,12 @@ export function parseAtRuleContainerQueryList( errors.push({ action: "drop", node: tokens[k], - location: options.source!.getSourceLocation(tokens[k]?.[LOC]!.sta), + location: options.source!.getSourceLocation(tokens[k]?.[LOCSTA]!), message: `unexpected token 'not'`, }); break; } } - - // const index = tokens.indexOf(stack.at(-1)!); - // const slice = trimArray(tokens.slice(index + 1)); - // tokens[index] = { - // typ: EnumToken.MediaQueryUnaryFeatureTokenType, - // l: stack.pop()!, - // r: slice, - // [LOC]: { ...tokens[index][LOC]!, end: slice.at(-1)![LOC]!.end }, - // }; - - // tokens.length = index + 1; } if ( @@ -523,7 +340,9 @@ export function parseAtRuleContainerQueryList( op: stack.pop()!, l: left, r: right, - [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)![LOCEND], } as MediaQueryConditionToken; tokens.length = l + 1; @@ -532,14 +351,6 @@ export function parseAtRuleContainerQueryList( } break; - - // default: - // if (tokensfuncDefMap.has(stream[i]?.typ)) { - // stack.push(stream[i]); - // scopes.push((currentScope = new Set())); - // } - - // break; } if (!success) { @@ -547,15 +358,6 @@ export function parseAtRuleContainerQueryList( } } - // if (success && stack.length > 0) { - // success = false; - // errors.push({ - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${EnumToken[stack.at(-1)?.typ]}' at ${stack.at(-1)?.[LOC]?.src}:${stack.at(-1)?.[LOC]?.sta.lin}:${stack.at(-1)?.[LOC]?.sta.col}`, - // }); - // } - if (!success) { return { success, @@ -564,7 +366,10 @@ export function parseAtRuleContainerQueryList( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const token of trimArray(tokens)) { + stream.push(token); + } } } @@ -573,11 +378,9 @@ export function parseAtRuleContainerQueryList( ...parts .filter((p) => p.length > 0 && p[0].typ !== EnumToken.InvalidMediaQueryTokenType) .reduce((acc, b) => { - // if (acc.length > 0) { - // acc.push({ typ: EnumToken.CommaTokenType }); - // } - - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, []), diff --git a/src/lib/parser/utils/at-rule-generic.ts b/src/lib/parser/utils/at-rule-generic.ts index c8a126e2..8173c8d2 100644 --- a/src/lib/parser/utils/at-rule-generic.ts +++ b/src/lib/parser/utils/at-rule-generic.ts @@ -1,9 +1,12 @@ import type { ErrorDescription, IdentToken, ParserOptions, Token } from "../../../@types/index.d.ts"; import { EnumToken } from "../../ast/types.ts"; -import { LOC, tokensfuncDefMap } from "../../syntax/constants.ts"; +import { LOCSTA, tokensfuncDefMap } from "../../syntax/constants.ts"; import { equalsIgnoreCase } from "./text.ts"; -export function matchGenericSyntax(stream: Token[], options: ParserOptions): { +export function matchGenericSyntax( + stream: Token[], + options: ParserOptions, +): { success: boolean; errors: ErrorDescription[]; } { @@ -38,7 +41,7 @@ export function matchGenericSyntax(stream: Token[], options: ParserOptions): { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]!), }); success = false; break; @@ -56,7 +59,7 @@ export function matchGenericSyntax(stream: Token[], options: ParserOptions): { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]!), }); success = false; break; @@ -75,7 +78,7 @@ export function matchGenericSyntax(stream: Token[], options: ParserOptions): { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]!), }); success = false; break; @@ -94,7 +97,7 @@ export function matchGenericSyntax(stream: Token[], options: ParserOptions): { action: "drop", message: `unexpected token ${EnumToken[token.typ]}`, node: token, - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]!), }); success = false; break; @@ -118,8 +121,7 @@ export function matchGenericSyntax(stream: Token[], options: ParserOptions): { action: "drop", message: `unexpected token ${EnumToken[stack.at(-1)?.typ]}`, node: stack.at(-1), - // @ts-expect-error - location: options.source!.getSourceLocation(stack.at(-1)?.[LOC]!.sta), + location: options.source!.getSourceLocation(stack.at(-1)?.[LOCSTA]!), }); success = false; } diff --git a/src/lib/parser/utils/at-rule-import.ts b/src/lib/parser/utils/at-rule-import.ts index 93248493..08d12c43 100644 --- a/src/lib/parser/utils/at-rule-import.ts +++ b/src/lib/parser/utils/at-rule-import.ts @@ -15,7 +15,7 @@ import { getSyntaxRule } from "../../validation/config.ts"; import { trimArray } from "../../validation/match.ts"; import { ValidationSyntaxGroupEnum } from "../../validation/parser/typedef.ts"; import type { ValidationToken } from "../../validation/parser/types.d.ts"; -import { LOC, tokensfuncDefMap } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, tokensfuncDefMap } from "../../syntax/constants.ts"; import { isColor, parseColor } from "../../syntax/syntax.ts"; import { parseMediaqueryList } from "./at-rule-media.ts"; import { parseAtRuleSupportSyntax } from "./at-rule-support.ts"; @@ -66,12 +66,7 @@ export function matchAtRuleImportSyntax( const slice: Token[] = stream.slice(index + 1, k); - // @ts-expect-error - stream[0][LOC] = { - ...stream[0][LOC], - end: stream[1][LOC]!.end, - }; - + stream[0][LOCEND] = stream[1][LOCEND]; tokens.push( Object.assign({ typ: tokensfuncDefMap.get(stream[0].typ), @@ -89,7 +84,7 @@ export function matchAtRuleImportSyntax( message: "Expected string or url()", syntax: "@import", node: stream[0], - location: stream[0]?.[LOC], + location: options.source!.getSourceLocation(stream[0]?.[LOCSTA]!), } as ErrorDescription, ], }; @@ -128,7 +123,7 @@ export function matchAtRuleImportSyntax( message: `Expected `, syntax: "@import", node: stream[index], - location: options.source!.getSourceLocation(stream[index]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[index]?.[LOCSTA]!), } as ErrorDescription, ], }; @@ -157,7 +152,7 @@ export function matchAtRuleImportSyntax( message: `Expected `, syntax: "@import", node: stream[index], - location: options.source!.getSourceLocation(stream[index]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[index]?.[LOCSTA]!), } as ErrorDescription, ], }; @@ -227,10 +222,9 @@ export function matchAtRuleImportSyntax( typ: EnumToken.DeclarationNodeType, nam: (supports.chi[i] as IdentToken).val, val, - [LOC]: { - ...supports.chi[i][LOC], - end: (val.at(-1) ?? (supports.chi.at(-1) as Token))[LOC]?.end, - }, + [LOCSRCID]: supports.chi[i][LOCSRCID], + [LOCSTA]: supports.chi[i][LOCSTA], + [LOCEND]: supports.chi.at(-1)![LOCEND], } as AstDeclaration; supports.chi.splice(i + 1, j - i + 1 + val.length); @@ -263,7 +257,9 @@ export function matchAtRuleImportSyntax( options, ); if (!result.success && result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } return { success: false, @@ -276,10 +272,14 @@ export function matchAtRuleImportSyntax( const splice = stream.splice(index, stream.length - index); const sliced = parseMediaqueryList(splice, options); - tokens.push(...splice); + for (const sp of splice) { + tokens.push(sp); + } if (sliced.errors.length > 0) { - errors.push(...sliced.errors); + for (const error of sliced.errors) { + errors.push(error); + } } if (!sliced.success) { @@ -287,7 +287,10 @@ export function matchAtRuleImportSyntax( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, diff --git a/src/lib/parser/utils/at-rule-media.ts b/src/lib/parser/utils/at-rule-media.ts index 51d6da35..cfced660 100644 --- a/src/lib/parser/utils/at-rule-media.ts +++ b/src/lib/parser/utils/at-rule-media.ts @@ -12,7 +12,7 @@ import type { import { EnumToken } from "../../ast/types.ts"; import { evaluate } from "../../ast/math/expression.ts"; import { gcd } from "../../ast/math/math.ts"; -import { LOC, mediaTypes, mFGT, mFLT } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, mediaTypes, mFGT, mFLT } from "../../syntax/constants.ts"; import { createValidationContext, getMFInfo, isMFValue, matchAllSyntaxes, trimArray } from "../../validation/match.ts"; import { MediaFeatureType, ValidationSyntaxGroupEnum } from "../../validation/parser/typedef.ts"; @@ -92,7 +92,7 @@ export function parseMediaqueryList( action: "drop", message: `expecting ''`, node: stream[i], - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), }); } } else if (stream[i].typ !== EnumToken.StartParensTokenType) { @@ -101,7 +101,7 @@ export function parseMediaqueryList( action: "drop", message: `expecting '('`, node: stream[i], - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), }); } } @@ -123,7 +123,6 @@ export function parseMediaqueryList( valid = stream[i].typ !== EnumToken.CommaTokenType; } - expectAndOrComma = false; } @@ -134,8 +133,6 @@ export function parseMediaqueryList( } switch (stream[i].typ) { - - case EnumToken.ColonTokenType: case EnumToken.LtTokenType: case EnumToken.LteTokenType: @@ -160,7 +157,7 @@ export function parseMediaqueryList( action: "drop", node: stream[i], message: ` is not allowed outside of parentheses`, - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), }); break; @@ -172,7 +169,7 @@ export function parseMediaqueryList( action: "drop", node: stream[i], message: `cannot mix and at the same level`, - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]!), }); } @@ -187,7 +184,7 @@ export function parseMediaqueryList( if (tokensfuncDefMap.has(stack.at(-1)?.typ)) { const index: number = tokens.indexOf(stack.at(-1)!); - tokens[index][LOC] = { ...tokens[index][LOC]!, end: stream[i]![LOC]!.end }; + tokens[index][LOCEND] = stream[i]![LOCEND]; Object.assign(tokens[index], { typ: tokensfuncDefMap.get(stack.at(-1)?.typ), chi: trimArray(tokens.slice(index + 1, tokens.length - 1)), @@ -211,7 +208,10 @@ export function parseMediaqueryList( currentScope = scopes.at(-1)!; if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } + success = false; } @@ -225,7 +225,6 @@ export function parseMediaqueryList( const prevToken: Token = stack[stack.length - 2]; if (mFLT.has(prevToken?.typ) || mFGT.has(prevToken?.typ)) { - // const index: number = tokens.indexOf(stack.at(-1)!); // | const index2: number = tokens.indexOf(prevToken); @@ -241,7 +240,6 @@ export function parseMediaqueryList( n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, ); - const name: string = (filteredNames[0] as IdentToken | DashedIdentToken).val; const mfInfo = getMFInfo(name); @@ -260,8 +258,9 @@ export function parseMediaqueryList( const value = evaluate([val[l]]); if (value.length == 1) { - - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -272,10 +271,8 @@ export function parseMediaqueryList( // let isValidMFValue = isMFValue(name, left, true); - // isValidMFValue = isMFValue(name, right, true); - for (const val of [left, right]) { if (mfInfo?.type === MediaFeatureType.RatioType) { const filteredValues = val.filter( @@ -311,7 +308,9 @@ export function parseMediaqueryList( op1: prevToken, op2: stack.at(-1)!, r: right, - [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)![LOCEND], } as MediaRangeQueryToken); stack.pop(); @@ -321,13 +320,11 @@ export function parseMediaqueryList( if ( stack.length > 0 && - ( - mFGT.has(stack.at(-1)?.typ) || - mFLT.has(stack.at(-1)?.typ) || - stack.at(-1)?.typ === EnumToken.DelimTokenType || - stack.at(-1)?.typ === EnumToken.ColonTokenType) + (mFGT.has(stack.at(-1)?.typ) || + mFLT.has(stack.at(-1)?.typ) || + stack.at(-1)?.typ === EnumToken.DelimTokenType || + stack.at(-1)?.typ === EnumToken.ColonTokenType) ) { - const index2: number = tokens.indexOf(stack.at(-1)!); const index3: number = tokens.indexOf(stack.at(-2)!); @@ -335,14 +332,12 @@ export function parseMediaqueryList( let values: Token[] = trimArray(tokens.slice(index2 + 1, tokens.length - 1)); let swapped: boolean = false; - const filteredNames = (swapped ? values : names).filter( (n) => n.typ !== EnumToken.WhitespaceTokenType && n.typ !== EnumToken.CommentTokenType, ); const name: string = (filteredNames[0] as IdentToken | DashedIdentToken).val; - const mfInfo = getMFInfo(name); if (options.computeCalcExpression) { if ( @@ -360,8 +355,9 @@ export function parseMediaqueryList( const value = evaluate([val[l]]); if (value.length == 1) { - - value[0][LOC] = val[l][LOC]; + value[0][LOCSRCID] = val[l][LOCSRCID]; + value[0][LOCSTA] = val[l][LOCSTA]; + value[0][LOCEND] = val[l][LOCEND]; val[l] = value[0]; } } @@ -383,7 +379,7 @@ export function parseMediaqueryList( errors.push({ action: "drop", node: arr[0], - location: options.source!.getSourceLocation(arr[0]?.[LOC]!.sta), + location: options.source!.getSourceLocation(arr[0]?.[LOCSTA]!), message: `${mfValue.isValueAllowed === false ? "invalid " : "expected "}`, }); @@ -417,13 +413,15 @@ export function parseMediaqueryList( } } + // @ts-expect-error tokens.splice(index3 + 1, tokens.length - index3 - 2, { typ: EnumToken.MediaQueryConditionTokenType, l: names, op: stack.pop() as Token, r: values, - // @ts-expect-error - [LOC]: { ...names[0][LOC]!, end: values.at(-1)![LOC]!.end } as Location, + [LOCSRCID]: names[0][LOCSRCID], + [LOCSTA]: names[0][LOCSTA], + [LOCEND]: values.at(-1)![LOCEND], }); } @@ -432,7 +430,7 @@ export function parseMediaqueryList( errors.push({ action: "drop", node: stream[i], - location: options.source!.getSourceLocation(stream[i]?.[LOC]!.sta), + location: options.source!.getSourceLocation(stream[i]?.[LOCSTA]!), message: `unmatched ')'`, }); @@ -440,14 +438,14 @@ export function parseMediaqueryList( } { - const index: number = tokens.indexOf(stack.at(-1)!); tokens[index] = { typ: EnumToken.ParensTokenType, chi: tokens.slice(index + 1, tokens.length - 1), - // @ts-expect-error - [LOC]: { ...tokens[index][LOC]!, end: stream[i]![LOC]!.end } as Location, + [LOCSRCID]: tokens[index]![LOCSRCID], + [LOCSTA]: tokens[index]![LOCSTA], + [LOCEND]: stream[i]![LOCEND], }; tokens.length = index + 1; @@ -455,7 +453,6 @@ export function parseMediaqueryList( currentScope = scopes.at(-1)!; stack.pop(); - if ( stack.at(-1)?.typ === EnumToken.AndTokenType || stack.at(-1)?.typ === EnumToken.OrTokenType @@ -479,7 +476,9 @@ export function parseMediaqueryList( op: stack.pop()!, l: left, r: right, - [LOC]: { ...left[0][LOC]!, end: right.at(-1)![LOC]!.end }, + [LOCSRCID]: left[0][LOCSRCID], + [LOCSTA]: left[0][LOCSTA], + [LOCEND]: right.at(-1)![LOCEND], } as MediaQueryConditionToken; tokens.length = l + 1; @@ -501,7 +500,10 @@ export function parseMediaqueryList( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const t of trimArray(tokens)) { + stream.push(t); + } } } @@ -514,7 +516,10 @@ export function parseMediaqueryList( acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...b); + for (const t of b) { + acc.push(t); + } + return acc; }, []), ); diff --git a/src/lib/parser/utils/at-rule-page.ts b/src/lib/parser/utils/at-rule-page.ts index 7d59f879..b8ade16b 100644 --- a/src/lib/parser/utils/at-rule-page.ts +++ b/src/lib/parser/utils/at-rule-page.ts @@ -42,7 +42,10 @@ export function parseAtRulePage( } const result = matchAllSyntaxes(trimSyntaxArray(syntax), createValidationContext(stream), options); - errors.push(...result.errors); + + for (const error of result.errors) { + errors.push(error); + } return { success: result.success, errors }; } diff --git a/src/lib/parser/utils/at-rule-support.ts b/src/lib/parser/utils/at-rule-support.ts index a6663833..12cee750 100644 --- a/src/lib/parser/utils/at-rule-support.ts +++ b/src/lib/parser/utils/at-rule-support.ts @@ -11,7 +11,7 @@ import type { ParensToken, } from "../../../@types/index.d.ts"; import { EnumToken } from "../../ast/types.ts"; -import { LOC, pseudoElements } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, pseudoElements } from "../../syntax/constants.ts"; import { getParsedSyntax, getSyntaxConfig } from "../../validation/config.ts"; import { trimArray, matchAllSyntaxes, createValidationContext } from "../../validation/match.ts"; import { ValidationSyntaxGroupEnum } from "../../validation/parser/typedef.ts"; @@ -56,7 +56,7 @@ export function parseAtRuleSupportSyntax( val: ":" + val, }); - stream[i][LOC]!.end = stream[i + 1]![LOC]!.end; + stream[i][LOCEND] = stream[i + 1]![LOCEND]; stream.splice(i + 1, 1); continue; } @@ -73,7 +73,7 @@ export function parseAtRuleSupportSyntax( }); stack.push(stream[i]); - stream[i][LOC]!.end = stream[i + 1]![LOC]!.end; + stream[i][LOCEND] = stream[i + 1]![LOCEND]; stream.splice(i + 1, 1); continue; } @@ -137,7 +137,9 @@ export function parseAtRuleSupportSyntax( tokens[index] = { typ: EnumToken.ParensTokenType, chi: slice, - [LOC]: { ...stack.at(-1)![LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)![LOCSRCID], + [LOCSTA]: stack.at(-1)![LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], } as ParensToken; stack.pop(); @@ -153,7 +155,9 @@ export function parseAtRuleSupportSyntax( typ: tokensfuncDefMap.get(stack.at(-1)?.typ)!, val: (stack.at(-1) as FunctionToken)!.val, chi: trimArray(tokens.splice(index + 1, tokens.length - index - 2)), - [LOC]: { ...stack.at(-1)![LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)![LOCSRCID], + [LOCSTA]: stack.at(-1)![LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], } as FunctionToken; if (tokens[index].typ === EnumToken.PseudoClassFuncTokenType) { @@ -201,7 +205,9 @@ export function parseAtRuleSupportSyntax( typ: EnumToken.SupportsQueryUnaryConditionTokenType, l: stack.at(-1), r: trimArray(tokens.splice(index + 1, i - index - 1)), - [LOC]: { ...stack.at(-1)![LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)![LOCSRCID], + [LOCSTA]: stack.at(-1)![LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], } as SupportsQueryUnaryConditionToken; stack.pop(); @@ -223,7 +229,9 @@ export function parseAtRuleSupportSyntax( op: stack.at(-1)!, l: left, r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)![LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)![LOCSRCID], + [LOCSTA]: stack.at(-1)![LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], } as SupportsQueryConditionToken; tokens.length = index2 + 1; stack.pop(); @@ -248,7 +256,7 @@ export function parseAtRuleSupportSyntax( if ("and" === val || "or" === val) { if ("or" === val && scopes.length === 1) { const fileName = options.source!.getFileName() ?? ""; - const [line, column] = options.source!.getOffsets(stream[i]?.[LOC]?.sta!); + const [line, column] = options.source!.getOffsets(stream[i]?.[LOCSTA]!); return { success: false, errors: [ @@ -276,7 +284,11 @@ export function parseAtRuleSupportSyntax( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const token of trimArray(tokens)) { + + stream.push(token); + } return { success, errors }; } diff --git a/src/lib/parser/utils/at-rule-when-else.ts b/src/lib/parser/utils/at-rule-when-else.ts index 5205f371..edff047a 100644 --- a/src/lib/parser/utils/at-rule-when-else.ts +++ b/src/lib/parser/utils/at-rule-when-else.ts @@ -1,5 +1,4 @@ import type { - SourceLocation, AstAtRule, AtRuleToken, ErrorDescription, @@ -12,7 +11,7 @@ import type { } from "../../../@types/index.d.ts"; import { EnumToken } from "../../ast/types.ts"; import { trimArray } from "../../validation/match.ts"; -import { LOC, tokensfuncDefMap } from "../../syntax/constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA, tokensfuncDefMap } from "../../syntax/constants.ts"; import { parseMediaqueryList } from "./at-rule-media.ts"; import { parseAtRuleSupportSyntax } from "./at-rule-support.ts"; @@ -31,11 +30,9 @@ export function matchAtRuleWhenElseSyntax( const errors: ErrorDescription[] = []; // const scopes: Array> = [scope]; - for (; i < stream.length; i++) { tokens.push(stream[i]); - if (expectAndOr) { let k: number = i; while ( @@ -46,16 +43,13 @@ export function matchAtRuleWhenElseSyntax( k++; } - expectAndOr = false; } switch (stream[i].typ) { - case EnumToken.IdenTokenType: { const val = (stream[i] as IdentToken).val.toLowerCase(); - if ("and" === val || "or" === val) { Object.assign(stream[i], { @@ -95,7 +89,9 @@ export function matchAtRuleWhenElseSyntax( const tokenList = [ { typ: EnumToken.StartParensTokenType, - [LOC]: { ...stream[i][LOC], end:stream[j]?.[LOC]?.end }, + [LOCSRCID]: stream[i][LOCSRCID], + [LOCSTA]: stream[i][LOCSTA], + [LOCEND]: stream[j]?.[LOCEND], }, // @ts-expect-error ].concat(slice.slice(1)) as Token[]; @@ -120,16 +116,8 @@ export function matchAtRuleWhenElseSyntax( return result; } } - // else { - // errors.push({ - // action: "ignore", - // message: `unknown function '${funcName}' at ${stream[i]?.[LOC]?.src}:${stream[i]?.[LOC]?.sta.lin}:${stream[i]?.[LOC]?.sta.col}`, - // node: stream[i], - // location: stream[i][LOC], - // }); - // } - stream[i][LOC] = { ...stream[i][LOC], end: stream[j]?.[LOC]?.end } as SourceLocation; + stream[i][LOCEND] = stream[j]?.[LOCEND]; Object.assign(stream[i], { typ: tokensfuncDefMap.get(stream[i].typ)!, @@ -139,18 +127,6 @@ export function matchAtRuleWhenElseSyntax( : (tokenList[0] as ParensToken).chi, }); - // if (stack.at(-1)?.typ === EnumToken.NotTokenType || stack.at(-1)?.typ === EnumToken.OnlyTokenType) { - // const index: number = tokens.indexOf(stack.at(-1)!); - // tokens[index] = { - // typ: EnumToken.WhenElseUnaryConditionTokenType, - // l: stack.at(-1)!, - // r: trimArray(tokens.slice(index + 1)), - // [LOC]: { ...stack.at(-1)![LOC], end: { ...stream[i]?.[LOC]?.end } }, - // } as WhenElseUnaryConditionToken; - // tokens.length = index + 1; - // stack.pop(); - // } - if (stack.at(-1)?.typ === EnumToken.AndTokenType || stack.at(-1)?.typ === EnumToken.OrTokenType) { const index: number = tokens.indexOf(stack.at(-1)!); const index2: number = stack.length > 1 ? tokens.indexOf(stack.at(-2)!) + 1 : 0; @@ -160,7 +136,9 @@ export function matchAtRuleWhenElseSyntax( op: stack.at(-1)!, l: trimArray(tokens.slice(index2, index)), r: trimArray(tokens.slice(index + 1)), - [LOC]: { ...stack.at(-1)![LOC], end: stream[i]?.[LOC]?.end }, + [LOCSRCID]: stack.at(-1)![LOCSRCID], + [LOCSTA]: stack.at(-1)![LOCSTA], + [LOCEND]: stream[i]?.[LOCEND], } as WhenElseQueryConditionToken; tokens.length = index2 + 1; stack.pop(); @@ -173,32 +151,15 @@ export function matchAtRuleWhenElseSyntax( break; default: - // if (tokensfuncDefMap.has(stream[i].typ)) { - // stack.push(stream[i]); - // expectAndOr = true; - // } - break; } } - // if (stack.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // node: stack.at(-1), - // message: `unmatched token '${renderValue(stack.at(-1) as Token)}' at ${stack.at(-1)![LOC]!.src}:${ - // stack.at(-1)![LOC]!.sta.lin - // }:${stack.at(-1)![LOC]!.sta.col}`, - // }, - // ], - // }; - // } - stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } diff --git a/src/lib/parser/utils/at-rule.ts b/src/lib/parser/utils/at-rule.ts index e2162b59..b16d3133 100644 --- a/src/lib/parser/utils/at-rule.ts +++ b/src/lib/parser/utils/at-rule.ts @@ -24,26 +24,6 @@ export function matchAtRuleSyntax( trimArray(stream); if (syntax.length === 0) { - // const filtered = stream.filter( - // (token) => token.typ !== EnumToken.WhitespaceTokenType && token.typ !== EnumToken.CommentTokenType, - // ); - - // if (filtered.length > 0) { - // return { - // success: false, - // errors: [ - // { - // action: "drop", - // message: `unexpected token ${EnumToken[filtered[0].typ]} at ${filtered[0][LOC]!.src}:${ - // filtered[0][LOC]!.sta.lin - // }:${filtered[0][LOC]!.sta.col}`, - // node: filtered[0], - // location: filtered[0][LOC]!, - // }, - // ], - // }; - // } - return { success: true, errors: [] }; } diff --git a/src/lib/parser/utils/declaration-list.ts b/src/lib/parser/utils/declaration-list.ts index 767f73f2..9c0afaab 100644 --- a/src/lib/parser/utils/declaration-list.ts +++ b/src/lib/parser/utils/declaration-list.ts @@ -7,41 +7,46 @@ import { ValidationSyntaxGroupEnum } from "../../validation/parser/typedef.ts"; import type { ValidationToken } from "../../validation/parser/types.d.ts"; /** - * - * @param context - * @param stream - * @param options - * @param errors - * @returns + * + * @param context + * @param stream + * @param options + * @param errors + * @returns */ -export function parseDeclarationList(context: AstAtRule | AtRuleToken, stream: Token[], options: ParserOptions, errors: ErrorDescription[]): { +export function parseDeclarationList( + context: AstAtRule | AtRuleToken, + stream: Token[], + options: ParserOptions, + errors: ErrorDescription[], +): { success: boolean; errors: ErrorDescription[]; } { - const syntaxRules = getSyntaxRule(ValidationSyntaxGroupEnum.AtRules, "@page" ); + const syntaxRules = getSyntaxRule(ValidationSyntaxGroupEnum.AtRules, "@page"); const syntax: ValidationToken[] = syntaxRules?.getPreludeRules?.()?.slice?.(1) as ValidationToken[]; let validate: boolean = false; for (const token of stream) { - if (token.typ !== EnumToken.WhitespaceTokenType && token.typ !== EnumToken.CommentTokenType) { - validate = true; break; } } if (!validate) { - return { success: true, - errors - } + errors, + }; } - + const result = matchAllSyntaxes(trimSyntaxArray(syntax), createValidationContext(stream), options); - errors.push(...result.errors); + + for (const error of result.errors) { + errors.push(error); + } return { success: result.success, errors }; -} \ No newline at end of file +} diff --git a/src/lib/parser/utils/declaration.ts b/src/lib/parser/utils/declaration.ts index e30b807d..804c8b01 100644 --- a/src/lib/parser/utils/declaration.ts +++ b/src/lib/parser/utils/declaration.ts @@ -26,9 +26,11 @@ import { COLORS_NAMES, tokensMap, trimTokenSpace, - LOC, ERRORS, STATE, + LOCEND, + LOCSTA, + LOCSRCID, } from "../../syntax/constants.ts"; import { isColor, isWhiteSpace, parseColor, renamedStandardProperties } from "../../syntax/syntax.ts"; import { getSyntaxRule, getParsedSyntax, ValidationSyntaxRule } from "../../validation/config.ts"; @@ -41,7 +43,6 @@ import type { ValidationPropertyToken } from "../../validation/parser/types.d.ts import { equalsIgnoreCase } from "./text.ts"; import { buildExpression } from "../../ast/math/expression.ts"; import { splitTokenList } from "../../validation/utils/list.ts"; -import type { SourceLocation } from "../../../@types/ast.d.ts"; /** * @@ -95,6 +96,7 @@ export function parseDeclaration( options: ParserOptions, errors: ErrorDescription[], ): AstDeclaration | RawNodeToken { + // console.error(tokens); const name = tokens.shift() as IdentToken | DashedIdentToken; let i: number; let rules: ValidationSyntaxRule | null = null; @@ -125,18 +127,18 @@ export function parseDeclaration( (name.typ !== EnumToken.IdenTokenType && name.typ !== EnumToken.DashedIdenTokenType) || tokens[i]?.typ !== EnumToken.ColonTokenType ) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC]!.end, - } as SourceLocation; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND]; + } + name[STATE] = EnumAstNodeStatus.Unparsed; name[ERRORS] = [ { action: "drop", node: name, - location: name[LOC], + location: options.source!.getSourceLocation(name[LOCSTA]!), message: "invalid declaration", - }, + } as ErrorDescription, ]; return Object.assign({ @@ -171,46 +173,6 @@ export function parseDeclaration( rules.acceptAnyDeclaration && rules.acceptAnyRule ? getParsedSyntax(ValidationSyntaxGroupEnum.Declarations, name.val.toLowerCase()) : rules.getBlockRules(); - - // if (syntaxRules == null) { - // // check rule in nested context - // let pr = parent[PARENT] as AstNode | null; - - // while (pr != null && pr.typ !== EnumToken.RuleNodeType) { - // pr = pr[PARENT]; - // } - - // if (pr != null) { - // syntaxRules = getParsedSyntax( - // ValidationSyntaxGroupEnum.Declarations, - // name.val.toLowerCase(), - // ); - // } - - // if (syntaxRules == null) { - // errors.push({ - // action: "drop", - // message: "declaration not allowed in context", - // node: name, - // location: name[LOC], - // }); - - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1][LOC]!.end, - // } as Location; - - // name[STATE] = EnumAstNodeStatus.Disallowed; - // name[ERRORS] = [errors[errors.length - 1]]; - - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } - // } } } } else { @@ -253,13 +215,13 @@ export function parseDeclaration( action: "drop", message: "declaration value missing", node: name, - location: options.source!.getSourceLocation(name[LOC]!.sta), + location: options.source!.getSourceLocation(name[LOCSTA]!), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]!.end ?? name[LOC]!.end, - } as SourceLocation; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } + name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = [errors[errors.length - 1]]; @@ -297,7 +259,9 @@ export function parseDeclaration( } if (!doNotValidate && !result?.success && result!.errors!.length > 0) { - errors.push(...result!.errors); + for (index = 0; index < result!.errors!.length; index++) { + errors.push(result!.errors![index]); + } } } } @@ -321,7 +285,7 @@ export function parseDeclaration( // typ: EnumToken.FunctionTokenDefType, // }); - // token[LOC]!.end = tokens[i + 1][LOC]!.end; + // token[LOCEND] = tokens[i + 1][LOCEND]; // tokens.splice(i + 1, 1); // stack.push(token); @@ -371,29 +335,6 @@ export function parseDeclaration( break; case EnumToken.EndParensTokenType: - // if (stack.length == 0) { - // errors.push({ - // action: "drop", - // message: "unbalanced parentheses", - // node: token, - // location: token[LOC], - // }); - - // name[LOC] = { - // ...name[LOC], - // end: tokens[tokens.length - 1]?.[LOC]!.end ?? name[LOC]!.end, - // } as Location; - // name[STATE] = EnumAstNodeStatus.Invalid; - // name[ERRORS] = [errors[errors.length - 1]]; - - // // @ts-expect-error - // return Object.assign(name, { - // typ: EnumToken.DeclarationNodeType, - // nam: name.val, - // val: tokens, - // }) as AstDeclaration; - // } - if (stack.at(-1)?.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(stack.at(-1)?.typ)) { index = tokens.indexOf(stack.at(-1)!); @@ -487,9 +428,9 @@ export function parseDeclaration( // ((tokens[index] as FunctionToken).chi[m] as ClassSelectorToken).val, // }); - // (tokens[index] as FunctionToken).chi[l][LOC]!.end = ( + // (tokens[index] as FunctionToken).chi[l][LOCEND] = ( // tokens[index] as FunctionToken - // ).chi[m][LOC]!.end; + // ).chi[m][LOCEND]; // (tokens[index] as FunctionToken).chi.splice(m, 1); // } @@ -529,7 +470,7 @@ export function parseDeclaration( action: "drop", message: `invalid color`, node: tokens[index], - location: options.source!.getSourceLocation(tokens[index][LOC]!.sta), + location: options.source!.getSourceLocation(tokens[index][LOCSTA]!), }); } } @@ -586,13 +527,13 @@ export function parseDeclaration( action: "drop", message: "unbalanced token", node: stack[stack.length - 1], - location: options.source!.getSourceLocation(stack[stack.length - 1][LOC]!.sta), + location: options.source!.getSourceLocation(stack[stack.length - 1][LOCSTA]!), }); - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1][LOC]!.end, - } as SourceLocation; + if (tokens[tokens.length - 1][LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } + name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = result?.errors ?? []; @@ -635,10 +576,9 @@ export function parseDeclaration( } if (validate && syntaxRules == null && name.typ === EnumToken.IdenTokenType) { - name[LOC] = { - ...name[LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? name[LOC]!.end, - } as SourceLocation; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } name[STATE] = EnumAstNodeStatus.Unknown; name[ERRORS] = result?.errors ?? []; @@ -650,15 +590,6 @@ export function parseDeclaration( val: tokens, }) as AstDeclaration; - // if ((options.validation as ValidationLevel) & ValidationLevel.Declaration) { - // errors.push({ - // action: "drop", - // message: "unknown declaration", - // node: node, - // location: node[LOC], - // }); - // } - return node; } @@ -679,19 +610,17 @@ export function parseDeclaration( typ: EnumToken.ComposesSelectorNodeType, l: left, r: right?.[0] ?? null, - [LOC]: { - ...tokens[0][LOC], - sta: left[0]?.[LOC]?.sta, - end: index != -1 ? right![right!.length - 1]?.[LOC]?.end : left[left.length - 1][LOC]!.end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: index != -1 ? right![right!.length - 1]?.[LOCEND] : left[left.length - 1][LOCEND], } as ComposesSelectorToken, ]; } - name[LOC] = { - ...name[LOC], - end: (tokens[tokens.length - 1] ?? name)[LOC]!.end, - } as SourceLocation; + if (tokens[tokens.length - 1]?.[LOCEND] != null) { + name[LOCEND] = tokens[tokens.length - 1][LOCEND]; + } + name[STATE] = success ? result == null ? EnumAstNodeStatus.Unvalidated diff --git a/src/lib/parser/utils/hash.ts b/src/lib/parser/utils/hash.ts index fa658d56..04bf5d3c 100644 --- a/src/lib/parser/utils/hash.ts +++ b/src/lib/parser/utils/hash.ts @@ -37,7 +37,7 @@ export function hashId(input: string, length: number = 6): string { // Remaining characters for (let i = 1; i < length; i++) { - n = (n + chars.length + i) % FULL_ALPHABET.length; + n = (n + chars.length * i) % FULL_ALPHABET.length; chars.push(FULL_ALPHABET[n]); } @@ -49,7 +49,7 @@ export function hashId(input: string, length: number = 6): string { * @param input * @returns */ -function toSortedString(input: any): string { +export function toSortedString(input: any): string { if (input == null) { return "null"; } @@ -73,23 +73,30 @@ function toSortedString(input: any): string { * @returns */ export function objectHash(object: any): string { - return hashId(toSortedString(object)); + return hashCode(toSortedString(object)).toString(16); } /** * convert input to hex * @param input */ -function toHex(input: ArrayBuffer | string): string { +function toHex(input: ArrayBuffer | string, length?: number): string { let result = ""; if (input instanceof ArrayBuffer || ArrayBuffer.isView(input)) { for (const byte of Array.from(new Uint8Array(input as ArrayBuffer))) { result += byte.toString(16).padStart(2, "0"); + + if (length != null && result.length >= length) { + return result; + } } } else { for (const char of String(input)) { result += char.charCodeAt(0).toString(16).padStart(2, "0"); + if (length != null && result.length >= length) { + return result; + } } } diff --git a/src/lib/parser/utils/intern.ts b/src/lib/parser/utils/intern.ts new file mode 100644 index 00000000..20b2b457 --- /dev/null +++ b/src/lib/parser/utils/intern.ts @@ -0,0 +1,56 @@ + +export class StringInterner { + private readonly ids = new Map(); + private readonly strings: string[] = [""]; // 0 = invalid / empty + + /** + * Returns the ID for the string, interning it if necessary. + */ + intern(value: string): number { + const existing = this.ids.get(value); + + if (existing !== undefined) { + return existing; + } + + const id = this.strings.length; + + this.strings.push(value); + this.ids.set(value, id); + + return id; + } + + /** + * Returns the original string. + */ + resolve(id: number): string { + return this.strings[id]; + } + + /** + * Returns true if the string has already been interned. + */ + has(value: string): boolean { + return this.ids.has(value); + } + + /** + * Returns the ID without interning. + */ + lookup(value: string): number | undefined { + return this.ids.get(value); + } + + /** + * Number of unique strings. + */ + get size(): number { + return this.strings.length - 1; + } + + clear(): void { + this.ids.clear(); + this.strings.length = 1; + } +} \ No newline at end of file diff --git a/src/lib/parser/utils/selector.ts b/src/lib/parser/utils/selector.ts index 27ba815b..f3a5aaea 100644 --- a/src/lib/parser/utils/selector.ts +++ b/src/lib/parser/utils/selector.ts @@ -17,14 +17,15 @@ import type { PercentageToken, AtRuleToken, ColorToken, - AstNode, } from "../../../@types/index.d.ts"; import { EnumAstNodeStatus, EnumToken } from "../../ast/types.ts"; import { renderValue } from "../../renderer/render.ts"; import { combinators, ERRORS, - LOC, + LOCEND, + LOCSRCID, + LOCSTA, PARENT, pseudoElements, STATE, @@ -76,7 +77,9 @@ export function parseSelector( filtered[0] = { typ: EnumToken.PercentageTokenType, val: 0, - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } else if ( filtered[0].typ === EnumToken.PercentageTokenType && @@ -85,7 +88,9 @@ export function parseSelector( filtered[0] = { typ: EnumToken.IdenTokenType, val: "to", - [LOC]: filtered[0][LOC], + [LOCSRCID]: filtered[0][LOCSRCID], + [LOCSTA]: filtered[0][LOCSTA], + [LOCEND]: filtered[0][LOCEND], }; } @@ -102,7 +107,10 @@ export function parseSelector( acc.push({ typ: EnumToken.CommaTokenType }); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } + return acc; }, [] as Token[]), ); @@ -116,10 +124,9 @@ export function parseSelector( }, new Set()), ].join(), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1]?.[LOC]?.end ?? tokens[0]?.[LOC]?.end, - }, + [LOCSRCID]: tokens[0]?.[LOCSRCID], + [LOCSTA]: tokens[0]?.[LOCSTA], + [LOCEND]: tokens[tokens.length - 1]?.[LOCEND], [TOKENS]: tokens.length === 0 ? null : tokens, [STATE]: result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid, [ERRORS]: result.errors, @@ -182,7 +189,7 @@ export function parseSelector( val: ":" + (tokens[i + 1] as IdentToken).val, }); - tokens[i][LOC]!.end = tokens[i + 1]![LOC]!.end; + tokens[i][LOCEND] = tokens[i + 1]![LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -198,7 +205,7 @@ export function parseSelector( val, }); - tokens[i][LOC]!.end = tokens[i + 1]![LOC]!.end; + tokens[i][LOCEND] = tokens[i + 1]![LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -212,7 +219,7 @@ export function parseSelector( val: (pseudoElements.includes(val) ? "" : ":") + val, }); - tokens[i][LOC]!.end = tokens[i + 1]![LOC]!.end; + tokens[i][LOCEND] = tokens[i + 1]![LOCEND]; tokens.splice(i + 1, 1); continue; } @@ -227,20 +234,18 @@ export function parseSelector( val, }); - tokens[i][LOC]!.end = tokens[i + 1]![LOC]!.end; + tokens[i][LOCEND] = tokens[i + 1]![LOCEND]; tokens.splice(i + 1, 1); continue; } } if (tokens[i].typ == EnumToken.ColorTokenType) { - if (isHash((tokens[i] as ColorToken).val)) { Object.assign(tokens[i], { typ: EnumToken.HashTokenType, }); } else { - return { typ: EnumToken.RuleNodeType, sel: [ @@ -294,10 +299,9 @@ export function parseSelector( .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC]!.end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: EnumAstNodeStatus.Invalid, [ERRORS]: [ @@ -329,10 +333,9 @@ export function parseSelector( index = tokens.indexOf(stack.at(-1)!); // @ts-expect-error const { val, ...attr } = stack.at(-1) as AttrStartToken; - attr[LOC] = { - ...stack.at(-1)![LOC]!, - end: token[LOC]!.end, - }; + attr[LOCSRCID] = stack.at(-1)![LOCSRCID]; + attr[LOCSTA] = stack.at(-1)![LOCSTA]; + attr[LOCEND] = token[LOCEND]; tokens.splice(i, 1); Object.assign(attr, { @@ -356,7 +359,7 @@ export function parseSelector( if (stack.at(-1)?.typ == EnumToken.PseudoClassFunctionTokenDefType) { const func = stack.at(-1) as PseudoClassFunctionToken; index = tokens.indexOf(func); - (stack.at(-1) as AttrStartToken)[LOC]!.end = token[LOC]!.end; + (stack.at(-1) as AttrStartToken)[LOCEND] = token[LOCEND]; tokens.splice(i, 1); if (tokensfuncDefMap.has(func.typ)) { @@ -374,34 +377,101 @@ export function parseSelector( func.val == ":nth-of-type" || func.val == ":nth-last-of-type" ) { - const list: Token[] = []; let index: number; - for ( index = 0; index < func.chi.length; index++) { - - if (func.chi[index].typ == EnumToken.CommentTokenType || func.chi[index].typ == EnumToken.WhitespaceTokenType) { + for (index = 0; index < func.chi.length; index++) { + if ( + func.chi[index].typ == EnumToken.CommentTokenType || + func.chi[index].typ == EnumToken.WhitespaceTokenType + ) { continue; } - if (func.chi[index].typ == EnumToken.IdenTokenType && equalsIgnoreCase('of', (func.chi[index] as IdentToken).val)) { - + if ( + func.chi[index].typ == EnumToken.IdenTokenType && + equalsIgnoreCase("of", (func.chi[index] as IdentToken).val) + ) { index--; break; } - list.push(func.chi[index]); + list.push(func.chi[index]); + } + + if (list.length == 2) { + if (list[1].typ == EnumToken.NumberTokenType) { + if ((list[1] as NumberToken).val == 0) { + list.length = 1; + + if ( + list[0].typ == EnumToken.DimensionTokenType && + (list[0] as DimensionToken).val == -2 + ) { + (list[0] as DimensionToken).val = 2; + } + } else { + const sign = Math.sign((list[1] as NumberToken).val as number); + // @ts-ignore + (list[1] as NumberToken).val *= sign; + list.splice(1, 0, { + typ: EnumToken.LiteralTokenType, + val: sign > 0 ? "+" : "-", + } as LiteralToken); + } + } + + if ( + list.length == 3 && + list[2].typ == EnumToken.NumberTokenType && + list[0].typ == EnumToken.DimensionTokenType && + (((list[0] as DimensionToken).val as number) == 2 || + (list[0] as DimensionToken).val == -2) + ) { + if (1 == (list[2] as NumberToken).val) { + list.splice(0, 3, { + typ: EnumToken.IdenTokenType, + val: "odd", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + } as IdentToken); + } else if (0 == (list[2] as NumberToken).val) { + list.splice(0, 3, { + typ: EnumToken.IdenTokenType, + val: "even", + [LOCSRCID]: list[0][LOCSRCID], + [LOCSTA]: list[0][LOCSTA], + [LOCEND]: list[0][LOCEND], + } as IdentToken); + } + } + + func.chi.splice(0, index, ...list); + } + + if (list.length == 1) { + if ( + list[0].typ == EnumToken.IdenTokenType && + equalsIgnoreCase("-n", (list[0] as IdentToken).val) + ) { + (list[0] as IdentToken).val = "n"; + } } if (list.length == 3) { - - if (list[0].typ == EnumToken.IdenTokenType && ('n' == (list[0] as IdentToken).val || '-n' == (list[0] as IdentToken).val || '+n' == (list[0] as IdentToken).val)) { - + if ( + list[0].typ == EnumToken.IdenTokenType && + ("n" == (list[0] as IdentToken).val || + "-n" == (list[0] as IdentToken).val || + "+n" == (list[0] as IdentToken).val) + ) { if (list[1].typ == EnumToken.NextSiblingCombinatorTokenType) { - - if (list[2].typ == EnumToken.NumberTokenType && (0 == (list[2] as NumberToken).val)) { - - (list[0] as IdentToken).val = 'n'; + if ( + list[2].typ == EnumToken.NumberTokenType && + 0 == (list[2] as NumberToken).val + ) { + (list[0] as IdentToken).val = "n"; func.chi.splice(0, index, list[0]); break; } @@ -427,53 +497,6 @@ export function parseSelector( }); } } else { - // if (!/\d+$/.test((token as IdentToken | LiteralToken).val)) { - // let index = func.chi.indexOf(token); - // let i: number = index + 1; - // let sign: Token | null = null; - // let num: NumberToken | null = null; - - // for (; i < func.chi.length; i++) { - // if ( - // func.chi[i].typ == EnumToken.WhitespaceTokenType || - // func.chi[i].typ == EnumToken.CommentTokenType - // ) { - // continue; - // } - - // if (func.chi[i].typ == EnumToken.NumberTokenType) { - // num = func.chi[i] as NumberToken; - // break; - // } else { - // sign = func.chi[i] as Token; - // } - // } - - // if (num != null) { - // if (num.val === 0) { - // func.chi.splice(index + 1, i - index); - // if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - // break; - // } - - // if (sign == null) { - // func.chi.splice(index + 1, i - index - 1); - // if (Math.sign(num.val as number) === 1) { - // func.chi.splice(index + 1, 0, { - // typ: EnumToken.LiteralTokenType, - // val: "+", - // }); - // } - // } - // } else if ((token as IdentToken | LiteralToken).val == "-n") { - // (token as IdentToken).val = "n"; - // } - - // break; - // } - const matches = /^(([+-]?[0-9]*)?n)?([+-]?[0-9]+)?$/.exec( (token as IdentToken | LiteralToken).val, ); @@ -484,41 +507,6 @@ export function parseSelector( const a1 = matches[2] === "" ? 1 : matches[2] === "-" ? -1 : +matches[2]; const b1 = +matches[3]; - // if (a1 === 0) { - // if (b1 === 1) { - // let hasSelector: boolean = false; - // let i: number = func.chi.indexOf(token); - // let j: number = i + 1; - - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - - // if (hasSelector) { - // Object.assign(token, { - // typ: EnumToken.NumberTokenType, - // val: b1, - // }); - // } else { - // // :first-child - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - - // break; - // } else { - // Object.assign(token, { typ: EnumToken.NumberTokenType, val: b1 }); - // } - // } else if (b1 === 0) { Object.assign( token, @@ -534,17 +522,6 @@ export function parseSelector( }, ); } - // else if (Math.abs(a1) === 2) { - // if (b1 === 0) { - // Object.assign(token, { - // typ: EnumToken.DimensionTokenType, - // val: a1, - // unit: "n", - // }); - // } else if (Math.abs(b1) === 1) { - // Object.assign(token, { typ: EnumToken.IdenTokenType, val: "odd" }); - // } - // } } } } else if (token?.typ === EnumToken.DimensionTokenType) { @@ -571,40 +548,6 @@ export function parseSelector( } if (num != null) { - // if ((token as DimensionToken).val === 0) { - // if (num.val === 0) { - // func.chi.splice(0, i); - // } else if (num.val === 1) { - // let hasSelector: boolean = false; - // let j: number = i + 1; - - // for (; j < func.chi.length; j++) { - // if ( - // func.chi[j].typ == EnumToken.IdenTokenType && - // (func.chi[j] as IdentToken).val == "of" - // ) { - // hasSelector = true; - // break; - // } - // } - - // if (hasSelector) { - // func.chi.splice(0, i); - // } else { - // tokens[tokens.indexOf(func)] = { - // typ: EnumToken.PseudoClassTokenType, - // val: ":first-child", - // [LOC]: func[LOC], - // }; - // } - - // break; - // } else { - // func.chi.splice(0, i); - // } - - // break; - // } else if (num.val === 0) { func.chi.splice(index + 1, i - index); @@ -711,10 +654,9 @@ export function parseSelector( .keys(), ].join(","), chi: [], - [LOC]: { - ...tokens[0][LOC], - end: tokens[tokens.length - 1][LOC]!.end, - }, + [LOCSRCID]: tokens[0][LOCSRCID], + [LOCSTA]: tokens[0][LOCSTA], + [LOCEND]: tokens[tokens.length - 1][LOCEND], [TOKENS]: tokens, [STATE]: result.success && allowed diff --git a/src/lib/parser/utils/text.ts b/src/lib/parser/utils/text.ts index a22c07ef..910de221 100644 --- a/src/lib/parser/utils/text.ts +++ b/src/lib/parser/utils/text.ts @@ -8,9 +8,12 @@ export function camelize(value: string) { export function equalsIgnoreCase(a: string, b: string): boolean { if (a.length !== b.length) return false; + + let ca: number; + let cb: number; for (let i = 0; i < a.length; i++) { - let ca = a.charCodeAt(i); - let cb = b.charCodeAt(i); + ca = a.charCodeAt(i); + cb = b.charCodeAt(i); // Normalize A-Z to a-z if (ca >= 65 && ca <= 90) ca += 32; diff --git a/src/lib/renderer/render.ts b/src/lib/renderer/render.ts index 7e95e7cb..88f51b85 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -52,8 +52,18 @@ import { reduceHexValue } from "../syntax/color/hex.ts"; import { ColorType, EnumToken } from "../ast/types.ts"; import { expand } from "../ast/expand.ts"; import { SourceMap } from "./sourcemap/sourcemap.ts"; -import { colorPrecision, LOC, PARENT, pseudoElements, tokensfuncSet, urlTokenMatcher } from "../syntax/constants.ts"; import { + anglePrecision, + colorPrecision, + LOCSRCID, + LOCSTA, + PARENT, + pseudoElements, + tokensfuncSet, + urlTokenMatcher, +} from "../syntax/constants.ts"; +import { + isWhiteSpace, minifyNumber, parseColor, reduceColorStops, @@ -228,7 +238,7 @@ export function doRender( sourcemap.addSourceContent(source.id, source.getFileName(), source.getContent()); } - sourcemap.add(...(sourcemaps!.maps! as Array<[number, number, number, number, number]>)); + sourcemap.add(sourcemaps!.maps!); result.map = sourcemap; if (options.sourcemap === "inline") { @@ -264,44 +274,31 @@ function updateSourceMap( ) { let offset: number = 0; - while (true) { - if (str.charAt(offset) == options.newLine) { - offset += options.newLine.length; - continue; - } - - if (str.charAt(offset) == options.indent) { - offset += options.indent.length; - continue; - } - - break; + // eat leanding whitespace + while (offset < str.length && isWhiteSpace(str.charCodeAt(offset))) { + offset++; } if (offset > 0) { - move(sourceLocation, linesMap, str.slice(0, offset)); + move(sourceLocation, linesMap, str, 0, offset + 1); } - if ( - node[LOC] != null && - [ - EnumToken.RuleNodeType, - EnumToken.AtRuleNodeType, - EnumToken.KeyframesRuleNodeType, - EnumToken.KeyframesAtRuleNodeType, - ].includes(node.typ) - ) { - const source = options.sourcesMap!.get((node[LOC] as SourceLocation)!.srcId) as SourceFile; + if (node[LOCSTA] != null) { + const source = options.sourcesMap!.get(node[LOCSRCID]!) as SourceFile; const inputSourceMap = source.getInputSourceMap(); - const offsets: [number, number] = source.getOffsets(node[LOC].sta) as [number, number]; + const offsets: [number, number] = source.getOffsets(node[LOCSTA]) as [number, number]; const [newLine, newColumn] = linesMap.getOffsets(sourceLocation.end); let records: Array<[string | null, number, number, string | null]> | null = null; - let srcId: number = (node[LOC] as SourceLocation)!.srcId; + let srcId: number = node[LOCSRCID]!; let sourceFileName: string | null = (source.getFileName() as string) || null; - let sourceContent: string | null = (source.getContent() as string) || null; + let sourceContent: string | null; // = (source.getContent() as string) || null; if (inputSourceMap != null && (records = inputSourceMap.find(offsets[0], offsets[1])) != null) { + let newId: number | null = null; + for (const record of records) { + newId = null; + // @ts-ignore sourceFileName = (record[0] as string) || null; // @ts-ignore @@ -329,35 +326,56 @@ function updateSourceMap( sourceFileName = cache[sourceFileName] as string; } + for (const [id, file] of options.sourcesMap!.entries()) { + if (file.getFileName() === sourceFileName) { + newId = id; + break; + } + + if (sourceFileName == null && file.getContent() === sourceContent) { + newId = id; + break; + } + } + + if (newId == null) { + const source = new SourceFile(sourceContent as string, [], sourceFileName); + + options.sourcesMap!.set(source.id, source); + newId = source.id; + } + + srcId = newId as number; + if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } else { - if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { - if (cache[sourceFileName] == null) { - const absolute = options.resolve!(dirname(options.output as string), options.cwd as string) - .absolute as string; - const absoluteSourceFileName = options.resolve!(sourceFileName, options.cwd as string) - .absolute as string; - - cache[sourceFileName] = options.resolve!(absoluteSourceFileName, absolute).relative as string; - } + // if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { + // if (cache[sourceFileName] == null) { + // const absolute = options.resolve!(dirname(options.output as string), options.cwd as string) + // .absolute as string; + // const absoluteSourceFileName = options.resolve!(sourceFileName, options.cwd as string) + // .absolute as string; - sourceFileName = cache[sourceFileName] as string; - } + // cache[sourceFileName] = options.resolve!(absoluteSourceFileName, absolute).relative as string; + // } + + // sourceFileName = cache[sourceFileName] as string; + // } if (!sourcemaps.sources.includes(srcId)) { sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** @@ -366,12 +384,13 @@ function updateSourceMap( * @param linesMap * @param str */ -export function move(sourceLocation: SourceLocation, linesMap: LinesMap, str: string) { - let i: number = 0; +export function move(sourceLocation: SourceLocation, linesMap: LinesMap, str: string, start?: number, end?: number) { + let i: number = start ?? 0; + let j: number = end ?? str.length; let codepoint: number; let char: string; - for (; i < str.length; i++) { + for (; i < j; i++) { char = str.charAt(i); codepoint = char.charCodeAt(0); sourceLocation.end += char.length; @@ -561,8 +580,6 @@ function renderAstNode( children += str; if (sourcemaps != null && str !== "") { - move(sourceLocation, linesMap!, str); - if (node.typ == EnumToken.DeclarationNodeType && recordDeclarationSourceMap) { // if declaration is child of at-rule, then record it // .rule { @@ -570,19 +587,10 @@ function renderAstNode( // color: red; // } // } - const source = options.sourcesMap!.get(node[LOC]!.srcId) as SourceFile; - - if (!sourcemaps.sources.includes(node[LOC]!.srcId as number)) { - sourcemaps.sources.push(node[LOC]!.srcId as number); - } - - sourcemaps.maps.push([ - ...linesMap!.getOffsets( - sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - ), - node[LOC]!.srcId, - ...source!.getOffsets(node![LOC]!.sta), - ]); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap!, str); + } else { + move(sourceLocation, linesMap!, str); } } } @@ -1004,7 +1012,9 @@ export function renderValue( } if (slice[i]?.typ === EnumToken.ColorTokenType) { - slice.push(...reduceColorStops(slice.splice(i, slice.length - i))); + for (const token of reduceColorStops(slice.splice(i, slice.length - i))) { + slice.push(token); + } } } @@ -1242,7 +1252,9 @@ export function renderValue( const result: Token[] = []; if (form.length > 0) { - result.push(...form); + for (const token of form) { + result.push(token); + } } if (size.length > 0) { @@ -1250,7 +1262,9 @@ export function renderValue( result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...size); + for (const token of size) { + result.push(token); + } } if (positions.length > 0) { @@ -1261,25 +1275,36 @@ export function renderValue( result.push( { typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, - ...positions, ); + + for (const token of positions) { + result.push(token); + } } if (colorSpaceDef.length > 0) { if (result.length > 0) { result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + + for (const token of colorSpaceDef) { + result.push(token); + } } if (result.length > 0) { result.push({ typ: EnumToken.CommaTokenType }); } - result.push(...reduceColorStops(slice.slice(i))); + for (const token of reduceColorStops(slice.slice(i))) { + result.push(token); + } slice.length = 0; - slice.push(...result); + + for (const token of result) { + slice.push(token); + } } break; @@ -1435,13 +1460,19 @@ export function renderValue( angles.push( { typ: EnumToken.IdenTokenType, val: "at" }, { typ: EnumToken.WhitespaceTokenType }, - ...positions, ); + + for (const position of positions) { + angles.push(position); + } } } if (angles.length > 0) { - result.push(...angles, { typ: EnumToken.CommaTokenType }); + for (const angle of angles) { + result.push(angle); + } + result.push({ typ: EnumToken.CommaTokenType }); } if (colorSpaceDef.length > 0) { @@ -1450,15 +1481,23 @@ export function renderValue( result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...colorSpaceDef); + for (const token of colorSpaceDef) { + result.push(token); + } } result.push({ typ: EnumToken.CommaTokenType }); } - result.push(...reduceConicColorStops(slice.slice(i))); + for (const token of reduceConicColorStops(slice.slice(i))) { + result.push(token); + } + slice.length = 0; - slice.push(...result); + + for (let j = 0; j < result.length; j++) { + slice.push(result[j]); + } } break; } @@ -1647,16 +1686,18 @@ export function renderValue( let v: string; let value: string = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { + for (const u of ["deg", "turn", "rad", "grad"]) { if ((token as AngleToken).unit == u) { continue; } switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); + case "deg": + v = minifyNumber( + toPrecisionAngle(angle * 360, anglePrecision, false).toFixed(anglePrecision), + ); - if (v.length + 4 < value.length) { + if (v.length + 3 < value.length) { val = v; unit = u; value = v + u; @@ -1664,10 +1705,10 @@ export function renderValue( break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); + case "turn": + v = minifyNumber(toPrecisionAngle(angle, anglePrecision, false).toFixed(anglePrecision)); - if (v.length + 3 < value.length) { + if (v.length + 4 < value.length) { val = v; unit = u; value = v + u; @@ -1676,7 +1717,9 @@ export function renderValue( break; case "rad": - v = minifyNumber(toPrecisionAngle(angle * (2 * Math.PI), colorPrecision, false)); + v = minifyNumber( + toPrecisionAngle(angle * (2 * Math.PI), anglePrecision, false).toFixed(anglePrecision), + ); if (v.length + 3 < value.length) { val = v; @@ -1687,7 +1730,9 @@ export function renderValue( break; case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); + v = minifyNumber( + toPrecisionAngle(angle * 400, anglePrecision, false).toFixed(anglePrecision), + ); if (v.length + 4 < value.length) { val = v; diff --git a/src/lib/renderer/sourcemap/sourcemap.ts b/src/lib/renderer/sourcemap/sourcemap.ts index fc57cecf..bd773151 100644 --- a/src/lib/renderer/sourcemap/sourcemap.ts +++ b/src/lib/renderer/sourcemap/sourcemap.ts @@ -135,35 +135,14 @@ export class SourceMap { this.sourcesContent[this.sourcesContent.length] = content || null; } - /** - * Add sourcemap - * @param newLine - * @param newColumn - * @param srcId - * @param ln - * @param col - */ - add(newLine: number, newColumn: number, srcId: number, ln: number, col: number): void; - /** * Add multiple sourcemaps * @param maps * @throws */ - add(...maps: Array<[newLine: number, newColumn: number, srcId: number, ln: number, col: number]>): void; - - /** - * Add all location - * @param maps - * @throws - */ - add(...maps: Array<[number, number, number, number, number]> | [number, number, number, number, number]): void { + add(maps: Array<[newLine: number, newColumn: number, srcId: number, ln: number, col: number]>): void { let srcIndex: number; - if (typeof maps[0] === "number") { - maps = [maps as [number, number, number, number, number]]; - } - for (let [newLine, newColumn, srcId, ln, col] of maps as Array<[number, number, number, number, number]>) { const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; diff --git a/src/lib/syntax/color/a98rgb.ts b/src/lib/syntax/color/a98rgb.ts index 41cff8bc..0d6d226d 100644 --- a/src/lib/syntax/color/a98rgb.ts +++ b/src/lib/syntax/color/a98rgb.ts @@ -3,13 +3,27 @@ import { multiplyMatrices } from "./utils/matrix.ts"; import { srgb2xyz } from "./xyz.ts"; export function a98rgb2srgbvalues(r: number, g: number, b: number, a: number | null = null): number[] { - // @ts-ignore - return xyz2srgb(...la98rgb2xyz(...a98rgb2la98(r, g, b, a))); + let values = a98rgb2la98(r, g, b); + + values = la98rgb2xyz(values[0], values[1], values[2]); + values = xyz2srgb(values[0], values[1], values[2]); + + if (a != null && a < 1) { + values.push(a); + } + + return values; } export function srgb2a98values(r: number, g: number, b: number, a: number | null = null): number[] { - // @ts-ignore - return la98rgb2a98rgb(...xyz2la98rgb(...srgb2xyz(r, g, b, a))); + let values = srgb2xyz(r, g, b); + values = xyz2la98rgb(values[0], values[1], values[2]); + values = la98rgb2a98rgb(values[0], values[1], values[2]); + + if (a != null && a < 1) { + values.push(a); + } + return values; } // a98-rgb functions diff --git a/src/lib/syntax/color/cmyk.ts b/src/lib/syntax/color/cmyk.ts index 3c8b41ea..d8239950 100644 --- a/src/lib/syntax/color/cmyk.ts +++ b/src/lib/syntax/color/cmyk.ts @@ -12,25 +12,23 @@ import { import { hsl2srgbvalues } from "./rgb.ts"; export function rgb2cmykToken(token: ColorToken): ColorToken | null { - const components: number[] | null = rgb2srgbvalues(token); + let components: number[] | null = rgb2srgbvalues(token); if (components == null || components.length < 3) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } export function hsl2cmykToken(token: ColorToken): ColorToken | null { - const values: number[] | null = hsl2srgbvalues(token); + let values: number[] | null = hsl2srgbvalues(token); if (values == null) { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } export function hwb2cmykToken(token: ColorToken): ColorToken | null { @@ -40,8 +38,7 @@ export function hwb2cmykToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } export function lab2cmykToken(token: ColorToken): ColorToken | null { @@ -51,8 +48,7 @@ export function lab2cmykToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } export function lch2cmykToken(token: ColorToken): ColorToken | null { @@ -62,8 +58,7 @@ export function lch2cmykToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } export function oklab2cmyk(token: ColorToken): ColorToken | null { @@ -73,8 +68,7 @@ export function oklab2cmyk(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } export function oklch2cmykToken(token: ColorToken): ColorToken | null { @@ -84,8 +78,7 @@ export function oklch2cmykToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...components)); + return cmyktoken(srgb2cmykvalues(components[0], components[1], components[2], components[3])); } export function color2cmykToken(token: ColorToken): ColorToken | null { @@ -95,8 +88,7 @@ export function color2cmykToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return cmyktoken(srgb2cmykvalues(...values)); + return cmyktoken(srgb2cmykvalues(values[0], values[1], values[2], values[3])); } export function srgb2cmykvalues(r: number, g: number, b: number, a: number | null = null): number[] { diff --git a/src/lib/syntax/color/color-mix.ts b/src/lib/syntax/color/color-mix.ts index db2a91e4..6d3d4dc9 100644 --- a/src/lib/syntax/color/color-mix.ts +++ b/src/lib/syntax/color/color-mix.ts @@ -7,7 +7,7 @@ import { srgb2rgb } from "./rgb.ts"; import { srgb2hslvalues } from "./hsl.ts"; import { srgb2hwb } from "./hwb.ts"; import { srgb2labvalues } from "./lab.ts"; -import { srgb2lp3values, srgb2p3values } from "./p3.ts"; +import { srgb2lp3values, srgb2p3values } from "./p3.ts"; import { getColorComponents } from "./utils/components.ts"; import { srgb2oklch } from "./oklch.ts"; import { srgb2oklab } from "./oklab.ts"; @@ -17,6 +17,7 @@ import { XYZ_D65_to_D50, xyzd502lch } from "./xyzd50.ts"; import { srgb2rec2020values } from "./rec2020.ts"; import { isPolarColorspace, isRectangularOrthogonalColorspace } from "../syntax.ts"; import { equalsIgnoreCase } from "../../parser/utils/text.ts"; +import { srgb2a98values } from "./a98rgb.ts"; function interpolateHue(interpolationMethod: string, h1: number, h2: number): number[] { switch (interpolationMethod) { @@ -147,78 +148,72 @@ export function colorMix(...args: Token[]): ColorToken | null { break; case "display-p3": - // @ts-ignore - values = srgb2p3values(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2p3values(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = srgb2lp3values(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2lp3values(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = srgb2a98values(...values); + values = srgb2a98values(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = srgb2prophotorgbvalues(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2prophotorgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = srgb2lsrgbvalues(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2lsrgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = srgb2rec2020values(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2rec2020values(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = srgb2xyz_d65(...values); + (values[0], values[1], values[2], values[3]); + values = srgb2xyz_d65(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = XYZ_D65_to_D50(...srgb2xyz_d65(...values)); + 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": - // @ts-ignore - values = srgb2rgb(...values); + for (let j = 0; j < values.length; j++) { + values[j] = j == 3 ? values[j] : srgb2rgb(values[j]); + } break; case "hsl": - // @ts-ignore - values = srgb2hslvalues(...values); + values = srgb2hslvalues(values[0], values[1], values[2], values[3]); break; case "hwb": - // @ts-ignore - values = srgb2hwb(...values); + values = srgb2hwb(values[0], values[1], values[2], values[3]); break; case "lab": - // @ts-ignore - values = srgb2labvalues(...values); + values = srgb2labvalues(values[0], values[1], values[2], values[3]); break; case "lch": - // @ts-ignore - values = srgb2lch(...values); + values = srgb2lch(values[0], values[1], values[2], values[3]); break; case "oklab": - // @ts-ignore - values = srgb2oklab(...values); + values = srgb2oklab(values[0], values[1], values[2], values[3]); break; case "oklch": - // @ts-ignore - values = srgb2oklch(...values); + values = srgb2oklch(values[0], values[1], values[2], values[3]); break; default: @@ -428,11 +423,10 @@ export function colorMix(...args: Token[]): ColorToken | null { case "xyz-d65": case "xyz-d50": if (colorSpace == "xyz-d50") { - // @ts-ignore - values = xyzd502lch(...values) as number[]; + values = xyzd502lch(values[0], values[1], values[2], values[3]) as number[]; } else { - // @ts-ignore - values = xyz2lchvalues(...values) as number[]; + (values[0], values[1], values[2], values[3]); + values = xyz2lchvalues(values[0], values[1], values[2], values[3]) as number[]; } // @ts-ignore @@ -455,7 +449,6 @@ export function colorMix(...args: Token[]): ColorToken | null { case "display-p3": case "display-p3-linear": case "prophoto-rgb": - // @ts-ignore return { typ: EnumToken.ColorTokenType, diff --git a/src/lib/syntax/color/color.ts b/src/lib/syntax/color/color.ts index d2f2dc18..3976aa54 100644 --- a/src/lib/syntax/color/color.ts +++ b/src/lib/syntax/color/color.ts @@ -132,8 +132,8 @@ import { rgb2cmykToken, } from "./cmyk.ts"; import { a98rgb2srgbvalues, srgb2a98values } from "./a98rgb.ts"; -import { epsilon, LOC } from "../constants.ts"; -import { colorFuncColorSpace, colorPrecision, anglePrecision } from "../constants.ts"; +import { LOCEND, LOCSRCID, LOCSTA } from "../constants.ts"; +import { colorFuncColorSpace } from "../constants.ts"; import { trimArray } from "../../validation/match.ts"; import { alpha } from "./alpha.ts"; import { equalsIgnoreCase } from "../../parser/utils/text.ts"; @@ -168,8 +168,9 @@ export function convertColor(token: ColorToken, to: ColorType): ColorToken | nul args.splice(args.length - 2, 1); } - // @ts-expect-error - token = alpha(...trimArray(args.slice(1))); + let values = trimArray(args.slice(1)); + + token = alpha(values[0] as ColorToken, values[1] as Token) as ColorToken; if (token == null) { return null; @@ -226,11 +227,17 @@ export function convertColor(token: ColorToken, to: ColorType): ColorToken | nul let { cal, ...tk } = { ...token, - chi: [...((token as ColorToken).val == "color" ? [chi[offset]] : []), ...Object.values(components)], + chi: (token as ColorToken).val == "color" ? [chi[offset]] : [], kin: ColorType[token.val.toUpperCase().replaceAll("-", "_") as keyof typeof ColorType], }; - tk[LOC] = token[LOC]; + for (const t of Object.values(components)) { + tk.chi.push(t); + } + + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk as ColorToken; } } @@ -697,52 +704,38 @@ export function color2colorToken(token: ColorToken, to: ColorType): ColorToken | return values2colortoken(values, to); } -function srgb2srgbcolorspace(val: number[], to: ColorType): number[] { - const values: number[] = []; - +function srgb2srgbcolorspace(val: number[], to: ColorType): number[] | null { switch (to) { case ColorType.SRGB: - values.push(...val); - break; + return val; + case ColorType.SRGB_LINEAR: - // @ts-ignore - values.push(...srgb2lsrgbvalues(...val)); - break; + return srgb2lsrgbvalues(val[0], val[1], val[2], val[3]); + case ColorType.DISPLAY_P3: - // @ts-ignore - values.push(...srgb2p3values(...val)); - break; + return srgb2p3values(val[0], val[1], val[2], val[3]); + case ColorType.DISPLAY_P3_LINEAR: - // @ts-ignore - values.push(...srgb2lp3values(...val)); - break; + return srgb2lp3values(val[0], val[1], val[2], val[3]); + case ColorType.PROPHOTO_RGB: - // @ts-ignore - values.push(...srgb2prophotorgbvalues(...val)); - break; + return srgb2prophotorgbvalues(val[0], val[1], val[2], val[3]); + case ColorType.A98_RGB: - // @ts-ignore - values.push(...srgb2a98values(...val)); - break; + return srgb2a98values(val[0], val[1], val[2], val[3]); case ColorType.REC2020: - // @ts-ignore - values.push(...srgb2rec2020values(...val)); - break; + return srgb2rec2020values(val[0], val[1], val[2], val[3]); case ColorType.XYZ: case ColorType.XYZ_D65: - // @ts-ignore - values.push(...srgb2xyz(...val)); - break; + return srgb2xyz(val[0], val[1], val[2], val[3]); case ColorType.XYZ_D50: - // @ts-ignore - values.push(...srgb2xyz_d65(...val)); - break; + return srgb2xyz_d65(val[0], val[1], val[2], val[3]); } - return values; + return null; } export function minmax(value: number, min: number, max: number): number { @@ -763,37 +756,29 @@ export function color2srgbvalues(token: ColorToken): number[] | null { switch (colorSpace.val) { case "display-p3": - // @ts-ignore - values = p32srgbvalues(...values); + values = p32srgbvalues(values[0], values[1], values[2], values[3]); break; case "display-p3-linear": - // @ts-ignore - values = lp32srgbvalues(...values); + values = lp32srgbvalues(values[0], values[1], values[2], values[3]); break; case "srgb-linear": - // @ts-ignore - values = lsrgb2srgbvalues(...values); + values = lsrgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "prophoto-rgb": - // @ts-ignore - values = prophotorgb2srgbvalues(...values); + values = prophotorgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "a98-rgb": - // @ts-ignore - values = a98rgb2srgbvalues(...values); + values = a98rgb2srgbvalues(values[0], values[1], values[2], values[3]); break; case "rec2020": - // @ts-ignore - values = rec20202srgb(...values); + values = rec20202srgb(values[0], values[1], values[2], values[3]); break; case "xyz": case "xyz-d65": - // @ts-ignore - values = xyz2srgb(...values); + values = xyz2srgb(values[0], values[1], values[2], values[3]); break; case "xyz-d50": - // @ts-ignore - values = xyzd502srgb(...values); + values = xyzd502srgb(values[0], values[1], values[2], values[3]); break; } @@ -804,9 +789,14 @@ export function color2srgbvalues(token: ColorToken): number[] | null { return values; } -function values2colortoken(values: number[], to: ColorType): ColorToken { +function values2colortoken(values: number[], to: ColorType): ColorToken | null { + // @ts-expect-error values = srgb2srgbcolorspace(values, to); + if (values == null) { + return null; + } + const chi: Token[] = [ { typ: EnumToken.NumberTokenType, val: values[0] }, { typ: EnumToken.NumberTokenType, val: values[1] }, diff --git a/src/lib/syntax/color/hsl.ts b/src/lib/syntax/color/hsl.ts index 20006e4f..ccf6d6c4 100644 --- a/src/lib/syntax/color/hsl.ts +++ b/src/lib/syntax/color/hsl.ts @@ -7,8 +7,13 @@ import { hex2srgbvalues, hslvalues, oklab2srgbvalues, oklch2srgbvalues } from ". import { ColorType, EnumToken } from "../../ast/types.ts"; export function hex2HslToken(token: ColorToken): ColorToken | null { - // @ts-ignore - return hslToken(srgb2hslvalues(...hex2srgbvalues(token))); + let values = hex2srgbvalues(token); + + if (values == null) { + return null; + } + + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } export function rgb2HslToken(token: ColorToken): ColorToken | null { @@ -88,8 +93,7 @@ export function color2HslToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return hslToken(srgb2hslvalues(...values)); + return hslToken(srgb2hslvalues(values[0], values[1], values[2], values[3])); } function hslToken(values: number[]): ColorToken { @@ -155,8 +159,7 @@ export function rgb2hslvalues(token: ColorToken): number[] | null { values.push(a); } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } // https://gist.github.com/defims/0ca2ef8832833186ed396a2f8a204117#file-annotated-js @@ -182,16 +185,17 @@ export function hsv2hsl(h: number, s: number, v: number, a?: number): number[] { return result; } -export function cmyk2hslvalues(token: ColorToken): number[] { +export function cmyk2hslvalues(token: ColorToken): number[] | null { const values = cmyk2rgbvalues(token); - // @ts-ignore - return values == null ? null : rgbvalues2hslvalues(...values); + return values == null ? null : rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } export function hwb2hslvalues(token: ColorToken): [number, number, number, number] { - // @ts-ignore - return hsv2hsl(...hwb2hsv(...Object.values(hslvalues(token)))); + const hsla = hslvalues(token) as { h: number; s: number; l: number; a: number }; + const hwba = hwb2hsv(hsla.h, hsla.s, hsla.l, hsla.a) as [number, number, number, number]; + + return hsv2hsl(hwba[0], hwba[1], hwba[2], hwba[3]) as [number, number, number, number]; } export function lab2hslvalues(token: ColorToken): number[] | null { @@ -201,8 +205,7 @@ export function lab2hslvalues(token: ColorToken): number[] | null { return null; } - // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } export function lch2hslvalues(token: ColorToken): number[] | null { @@ -213,19 +216,19 @@ export function lch2hslvalues(token: ColorToken): number[] | null { } // @ts-ignore - return rgbvalues2hslvalues(...values); + return rgbvalues2hslvalues(values[0], values[1], values[2], values[3]); } export function oklab2hslvalues(token: ColorToken): number[] | null { const t: number[] | null = oklab2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } export function oklch2hslvalues(token: ColorToken): number[] | null { const t: number[] | null = oklch2srgbvalues(token); // @ts-ignore - return t == null ? null : srgb2hslvalues(...t); + return t == null ? null : srgb2hslvalues(t[0], t[1], t[2], t[3]); } export function rgbvalues2hslvalues(r: number, g: number, b: number, a: number | null = null): number[] { diff --git a/src/lib/syntax/color/hwb.ts b/src/lib/syntax/color/hwb.ts index ec23739e..71ceff96 100644 --- a/src/lib/syntax/color/hwb.ts +++ b/src/lib/syntax/color/hwb.ts @@ -106,7 +106,7 @@ export function hwbToken(values: number[]): ColorToken { { typ: EnumToken.LiteralTokenType, val: "/" }, { typ: EnumToken.PercentageTokenType, - val: values[3] * 100 + val: values[3] * 100, }, ); } @@ -120,38 +120,38 @@ export function hwbToken(values: number[]): ColorToken { } export function rgb2hwbvalues(token: ColorToken): number[] { + const values = getColorComponents(token)!.map((t: Token, index: number): number => { + if (index == 3) { + return getNumber(t); + } + + return getNumber(t) / 255; + }) as [number, number, number, number]; + // @ts-ignore - return srgb2hwb( - ...(getColorComponents(token)!.map((t: Token, index: number): number => { - if (index == 3) { - return getNumber(t); - } - - return getNumber(t) / 255; - }) as [number, number, number, number]), - ); + return srgb2hwb(values[0], values[1], values[2], values[3]); } -export function cmyk2hwbvalues(token: ColorToken): number[] { - // @ts-ignore - return srgb2hwb(...cmyk2srgbvalues(token)); +export function cmyk2hwbvalues(token: ColorToken): number[] | null { + const values = cmyk2srgbvalues(token); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } export function hsl2hwbvalues(token: ColorToken): number[] { - // @ts-ignore - return hslvalues2hwbvalues( - ...(getColorComponents(token)!.map((t: Token, index: number) => { - if (index == 3 && t.typ == EnumToken.IdenTokenType && (t as IdentToken).val == "none") { - return 1; - } + const values = getColorComponents(token)!.map((t: Token, index: number) => { + if (index == 3 && t.typ == EnumToken.IdenTokenType && (t as IdentToken).val == "none") { + return 1; + } - if (index == 0) { - return getAngle(t); - } + if (index == 0) { + return getAngle(t); + } - return getNumber(t); - }) as [number, number, number, number]), - ); + return getNumber(t); + }) as [number, number, number, number]; + + // @ts-ignore + return hslvalues2hwbvalues(values[0], values[1], values[2], values[3]); } export function lab2hwbvalues(token: ColorToken): number[] | null { @@ -160,8 +160,7 @@ export function lab2hwbvalues(token: ColorToken): number[] | null { if (values == null) { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } export function lch2hwbvalues(token: ColorToken): number[] | null { @@ -171,8 +170,7 @@ export function lch2hwbvalues(token: ColorToken): number[] | null { return null; } - // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } export function oklab2hwbvalues(token: ColorToken): number[] | null { @@ -183,13 +181,13 @@ export function oklab2hwbvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } export function oklch2hwbvalues(token: ColorToken): number[] { const values: number[] | null = oklch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2hwb(...values); + return values == null ? null : srgb2hwb(values[0], values[1], values[2], values[3]); } function rgb2hue(r: number, g: number, b: number, fallback: number = 0) { @@ -227,7 +225,7 @@ export function color2hwbvalues(token: ColorToken): number[] | null { return null; } // @ts-ignore - return srgb2hwb(...values); + return srgb2hwb(values[0], values[1], values[2], values[3]); } export function srgb2hwb(r: number, g: number, b: number, a: number | null = null, fallback: number = 0): number[] { @@ -260,6 +258,7 @@ export function hsv2hwb(h: number, s: number, v: number, a: number | null = null } export function hslvalues2hwbvalues(h: number, s: number, l: number, a: number | null = null): number[] { + let values = hsl2hsv(h, s, l); // @ts-ignore - return hsv2hwb(...hsl2hsv(h, s, l, a)); + return hsv2hwb(values[0], values[1], values[2], a); } diff --git a/src/lib/syntax/color/lab.ts b/src/lib/syntax/color/lab.ts index 03fd0ca1..eb4e100c 100644 --- a/src/lib/syntax/color/lab.ts +++ b/src/lib/syntax/color/lab.ts @@ -132,23 +132,23 @@ function labToken(values: number[]): ColorToken | null { // for a and b: -100% = -125, 100% = 125 export function hex2labvalues(token: ColorToken): number[] | null { - const values: number[] | null = hex2srgbvalues(token); + let values: number[] | null = hex2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } export function rgb2labvalues(token: ColorToken): number[] | null { const values: number[] | null = rgb2srgb(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } export function cmyk2labvalues(token: ColorToken) { const values: number[] | null = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2labvalues(...values); + return values == null ? null : srgb2labvalues(values[0], values[1], values[2], values[3]); } export function hsl2labvalues(token: ColorToken): number[] | null { @@ -159,7 +159,7 @@ export function hsl2labvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } export function hwb2labvalues(token: ColorToken): number[] | null { @@ -170,25 +170,27 @@ export function hwb2labvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } export function lch2labvalues(token: ColorToken): number[] | null { const values: number[] | null = getLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } export function oklab2labvalues(token: ColorToken): number[] | null { - const values: number[] | null = getOKLABComponents(token); + let values: number[] | null = getOKLABComponents(token); if (values == null) { return null; } - // @ts-ignore - return xyz2lab(...XYZ_D65_to_D50(...OKLab_to_XYZ(...values))); + values = OKLab_to_XYZ(values[0], values[1], values[2], values[3]); + values = XYZ_D65_to_D50(values[0], values[1], values[2], values[3]); + + return xyz2lab(values[0], values[1], values[2], values[3]); } export function oklch2labvalues(token: ColorToken): number[] | null { @@ -199,7 +201,7 @@ export function oklch2labvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2labvalues(...values); + return srgb2labvalues(values[0], values[1], values[2], values[3]); } export function color2labvalues(token: ColorToken): number[] | null { @@ -209,13 +211,12 @@ export function color2labvalues(token: ColorToken): number[] | null { return null; } - // @ts-ignore - return srgb2labvalues(...val); + return srgb2labvalues(val[0], val[1], val[2], val[3]); } export function srgb2labvalues(r: number, g: number, b: number, a: number | null): number[] { - // @ts-ignore */ - const result: number[] = xyz2lab(...srgb2xyz_d65(r, g, b)); + let result: number[] = srgb2xyz_d65(r, g, b); + result = xyz2lab(result[0], result[1], result[2]); // Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors // and approximated computations in sRGB <-> CIELab. @@ -326,10 +327,10 @@ export function getLABComponents(token: ColorToken): number[] | null { export function Lab_to_sRGB(l: number, a: number, b: number): number[] { const xyz_d50: number[] = Lab_to_XYZ(l, a, b); // @ts-ignore - const xyz_d65: number[] = XYZ_D50_to_D65(...xyz_d50); + const xyz_d65: number[] = XYZ_D50_to_D65(xyz_d50[0], xyz_d50[1], xyz_d50[2]); // @ts-ignore - return xyz2srgb(...xyz_d65); + return xyz2srgb(xyz_d65[0], xyz_d65[1], xyz_d65[2]); } // from https://www.w3.org/TR/css-color-4/#color-conversion-code diff --git a/src/lib/syntax/color/lch.ts b/src/lib/syntax/color/lch.ts index 9eab5a80..9b3aae6a 100644 --- a/src/lib/syntax/color/lch.ts +++ b/src/lib/syntax/color/lch.ts @@ -136,49 +136,49 @@ export function hex2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = hex2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function rgb2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = rgb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function hsl2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = hsl2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function hwb2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = hwb2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function lab2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = getLABComponents(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function srgb2lch(r: number, g: number, blue: number, alpha: number | null): number[] { - // @ts-ignore - return labvalues2lchvalues(...srgb2labvalues(r, g, blue, alpha)); + let values = srgb2labvalues(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function oklab2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = oklab2labvalues(token); // @ts-ignore - return values == null ? null : labvalues2lchvalues(...values); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function cmyk2lchvalues(token: ColorToken): number[] | null { const values: number[] | null = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2lch(...values); + return values == null ? null : srgb2lch(values[0], values[1], values[2], values[3]); } export function oklch2lchvalues(token: ColorToken): number[] | null { @@ -189,7 +189,7 @@ export function oklch2lchvalues(token: ColorToken): number[] | null { } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function color2lchvalues(token: ColorToken): number[] | null { @@ -200,7 +200,7 @@ export function color2lchvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2lch(...values); + return srgb2lch(values[0], values[1], values[2], values[3]); } export function labvalues2lchvalues(l: number, a: number, b: number, alpha: number | null = null): number[] { @@ -219,8 +219,8 @@ export function labvalues2lchvalues(l: number, a: number, b: number, alpha: numb } export function xyz2lchvalues(x: number, y: number, z: number, alpha?: number): number[] { - // @ts-ignore( - const lch = labvalues2lchvalues(...xyz2lab(x, y, z)); + const values = xyz2lab(x, y, z); + const lch = labvalues2lchvalues(values[0], values[1], values[2]); return alpha == null || alpha == 1 ? lch : lch.concat(alpha); } diff --git a/src/lib/syntax/color/oklab.ts b/src/lib/syntax/color/oklab.ts index a6ea64e6..116bc05d 100644 --- a/src/lib/syntax/color/oklab.ts +++ b/src/lib/syntax/color/oklab.ts @@ -140,7 +140,7 @@ export function hex2oklabvalues(token: ColorToken): number[] | null { } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } export function rgb2oklabvalues(token: ColorToken) { @@ -150,8 +150,7 @@ export function rgb2oklabvalues(token: ColorToken) { return null; } - // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } export function hsl2oklabvalues(token: ColorToken) { @@ -161,18 +160,18 @@ export function hsl2oklabvalues(token: ColorToken) { return null; } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } -export function hwb2oklabvalues(token: ColorToken): number[] { - // @ts-ignore - return srgb2oklab(...hwb2srgbvalues(token)); +export function hwb2oklabvalues(token: ColorToken): number[] | null { + const values = hwb2srgbvalues(token); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } export function cmyk2oklabvalues(token: ColorToken) { const values = cmyk2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } export function lab2oklabvalues(token: ColorToken) { @@ -183,26 +182,26 @@ export function lab2oklabvalues(token: ColorToken) { } // @ts-ignore - return srgb2oklab(...values); + return srgb2oklab(values[0], values[1], values[2], values[3]); } export function lch2oklabvalues(token: ColorToken): number[] | null { const values = lch2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } export function oklch2oklabvalues(token: ColorToken): number[] | null { const values: number[] | null = getOKLCHComponents(token); // @ts-ignore - return values == null ? null : lchvalues2labvalues(...values); + return values == null ? null : lchvalues2labvalues(values[0], values[1], values[2], values[3]); } function color2oklabvalues(token: ColorToken): number[] | null { const values = color2srgbvalues(token); // @ts-ignore - return values == null ? null : srgb2oklab(...values); + return values == null ? null : srgb2oklab(values[0], values[1], values[2], values[3]); } export function srgb2oklab(r: number, g: number, blue: number, alpha: number | null): number[] { diff --git a/src/lib/syntax/color/oklch.ts b/src/lib/syntax/color/oklch.ts index 0048cce3..33b988d0 100644 --- a/src/lib/syntax/color/oklch.ts +++ b/src/lib/syntax/color/oklch.ts @@ -16,9 +16,9 @@ import { import { cmyk2srgbvalues } from "./srgb.ts"; export function hex2oklchToken(token: ColorToken): ColorToken | null { - const values: number[] = hex2oklchvalues(token); + const values: number[] | null = hex2oklchvalues(token); - return oklchToken(values); + return values == null ? null : oklchToken(values); } export function rgb2oklchToken(token: ColorToken): ColorToken | null { @@ -98,8 +98,7 @@ export function color2oklchToken(token: ColorToken): ColorToken | null { return null; } - // @ts-ignore - return oklchToken(srgb2oklch(...values)); + return oklchToken(srgb2oklch(values[0], values[1], values[2], values[3])); } function oklchToken(values: number[]): ColorToken | null { @@ -129,9 +128,9 @@ function oklchToken(values: number[]): ColorToken | null { }; } -export function hex2oklchvalues(token: ColorToken): number[] { - // @ts-ignore - return labvalues2lchvalues(...hex2oklabvalues(token)); +export function hex2oklchvalues(token: ColorToken): number[] | null { + const values = hex2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function rgb2oklchvalues(token: ColorToken): number[] | null { @@ -141,25 +140,23 @@ export function rgb2oklchvalues(token: ColorToken): number[] | null { return null; } - // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } -export function hsl2oklchvalues(token: ColorToken): number[] { - // @ts-ignore - return labvalues2lchvalues(...hsl2oklabvalues(token)); +export function hsl2oklchvalues(token: ColorToken): number[] | null { + const values = hsl2oklabvalues(token); + return values == null ? null : labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function hwb2oklchvalues(token: ColorToken): number[] { - // @ts-ignore - return labvalues2lchvalues(...hwb2oklabvalues(token)); + const values = hwb2oklabvalues(token) as number[]; + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } -export function cmyk2oklchvalues(token: ColorToken): number[] { +export function cmyk2oklchvalues(token: ColorToken): number[] | null { const values = cmyk2srgbvalues(token); - // @ts-ignore - return values == null ? null : srgb2oklch(...values); + return values == null ? null : srgb2oklch(values[0], values[1], values[2], values[3]); } export function lab2oklchvalues(token: ColorToken): number[] | null { @@ -170,7 +167,7 @@ export function lab2oklchvalues(token: ColorToken): number[] | null { } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function lch2oklchvalues(token: ColorToken): number[] | null { @@ -181,7 +178,7 @@ export function lch2oklchvalues(token: ColorToken): number[] | null { } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function oklab2oklchvalues(token: ColorToken): number[] | null { @@ -192,12 +189,12 @@ export function oklab2oklchvalues(token: ColorToken): number[] | null { } // @ts-ignore - return labvalues2lchvalues(...values); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function srgb2oklch(r: number, g: number, blue: number, alpha: number | null): number[] { - // @ts-ignore - return labvalues2lchvalues(...srgb2oklab(r, g, blue, alpha)); + const values = srgb2oklab(r, g, blue, alpha); + return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } export function getOKLCHComponents(token: ColorToken): number[] | null { diff --git a/src/lib/syntax/color/p3.ts b/src/lib/syntax/color/p3.ts index 8dcb52b3..ac62a71f 100644 --- a/src/lib/syntax/color/p3.ts +++ b/src/lib/syntax/color/p3.ts @@ -3,23 +3,37 @@ import { multiplyMatrices } from "./utils/matrix.ts"; import { srgb2xyz } from "./xyz.ts"; export function p32srgbvalues(r: number, g: number, b: number, alpha?: number) { + let values = p32lp3(r, g, b); + values = lp32xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lp32xyz(...p32lp3(r, g, b, alpha))); + return xyz2srgb(values[0], values[1], values[2], alpha); } export function srgb2p3values(r: number, g: number, b: number, alpha?: number) { - // @ts-ignore - return lp32p3(...xyz2lp3(...srgb2xyz(r, g, b, alpha))); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + values = lp32p3(values[0], values[1], values[2]); + + if (alpha != null && alpha < 1) { + values.push(alpha); + } + + return values; } export function srgb2lp3values(r: number, g: number, b: number, alpha?: number) { - // @ts-ignore - return xyz2lp3(...srgb2xyz(r, g, b, alpha)); + let values = srgb2xyz(r, g, b); + values = xyz2lp3(values[0], values[1], values[2]); + if (alpha != null && alpha < 1) { + values.push(alpha); + } + return values; } export function lp32srgbvalues(r: number, g: number, b: number, alpha?: number) { + let values = lp32xyz(r, g, b); // @ts-ignore - return xyz2srgb(...lp32xyz(r, g, b, alpha)); + return xyz2srgb(values[0], values[1], values[2], alpha); } export function p32lp3(r: number, g: number, b: number, alpha?: number) { diff --git a/src/lib/syntax/color/prophotorgb.ts b/src/lib/syntax/color/prophotorgb.ts index 0fd63627..433261cc 100644 --- a/src/lib/syntax/color/prophotorgb.ts +++ b/src/lib/syntax/color/prophotorgb.ts @@ -1,70 +1,72 @@ -import {XYZ_D65_to_D50, xyzd502srgb} from "./xyzd50.ts"; -import {srgb2xyz} from "./xyz.ts"; +import { XYZ_D65_to_D50, xyzd502srgb } from "./xyzd50.ts"; +import { srgb2xyz } from "./xyz.ts"; export function prophotorgb2srgbvalues(r: number, g: number, b: number, a: number | null = null): number[] { - + let values = prophotorgb2xyz50(r, g, b); // @ts-ignore - return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); + return xyzd502srgb(values[0], values[1], values[2], a); } export function srgb2prophotorgbvalues(r: number, g: number, b: number, a?: number): number[] { + let values = srgb2xyz(r, g, b); + values = XYZ_D65_to_D50(values[0], values[1], values[2]); + values = xyz50_to_prophotorgb(values[0], values[1], values[2]); - // @ts-ignore - return xyz50_to_prophotorgb(...XYZ_D65_to_D50(...srgb2xyz(r, g, b, a))); + if (a != null && a < 1) { + values.push(a); + } + + return values; } function prophotorgb2lin_ProPhoto(r: number, g: number, b: number, a: number | null = null): number[] { - - return [r, g, b].map(v => { - let abs = Math.abs(v); - if (abs >= 16 / 512) { - return Math.sign(v) * Math.pow(abs, 1.8); - } - return v / 16; - }).concat(a == null || a == 1 ? [] : [a]); + return [r, g, b] + .map((v) => { + let abs = Math.abs(v); + if (abs >= 16 / 512) { + return Math.sign(v) * Math.pow(abs, 1.8); + } + return v / 16; + }) + .concat(a == null || a == 1 ? [] : [a]); } function prophotorgb2xyz50(r: number, g: number, b: number, a: number | null = null): number[] { - [r, g, b, a] = prophotorgb2lin_ProPhoto(r, g, b, a); const xyz = [ - - 0.7977666449006423 * r + - 0.1351812974005331 * g + - 0.0313477341283922 * b, - 0.2880748288194013 * r + - 0.7118352342418731 * g + - 0.0000899369387256 * b, - 0.8251046025104602 * b + 0.7977666449006423 * r + 0.1351812974005331 * g + 0.0313477341283922 * b, + 0.2880748288194013 * r + 0.7118352342418731 * g + 0.0000899369387256 * b, + 0.8251046025104602 * b, ]; return xyz.concat(a == null || a == 1 ? [] : [a]); } function xyz50_to_prophotorgb(x: number, y: number, z: number, a?: number): number[] { - // @ts-ignore - return gam_prophotorgb(...[ + return gam_prophotorgb( + x * 1.3457868816471585 - y * 0.2555720873797946 - 0.0511018649755453 * z, - x * 1.3457868816471585 - - y * 0.2555720873797946 - - 0.0511018649755453 * z, + x * -0.5446307051249019 + y * 1.5082477428451466 + 0.0205274474364214 * z, + 1.2119675456389452 * z, + a == 1 ? null : a, + ); +} - x * -0.5446307051249019 + - y * 1.5082477428451466 + - 0.0205274474364214 * z, - 1.2119675456389452 * z - ].concat(a == null || a == 1 ? [] : [a])); +function gam_prophotorgbvalue(v: number) { + let abs = Math.abs(v); + if (abs >= 1 / 512) { + return Math.sign(v) * Math.pow(abs, 1 / 1.8); + } + return 16 * v; } -function gam_prophotorgb(r: number, g: number, b: number, a?: number): number[] { +function gam_prophotorgb(r: number, g: number, b: number, a?: number | null): number[] { + const values = [gam_prophotorgbvalue(r), gam_prophotorgbvalue(g), gam_prophotorgbvalue(b)]; - return [r, g, b].map(v => { - let abs = Math.abs(v); - if (abs >= 1 / 512) { - return Math.sign(v) * Math.pow(abs, 1 / 1.8); - } - return 16 * v; - }).concat(a == null || a == 1 ? [] : [a]); -} \ No newline at end of file + if (a != null && a < 1) { + values.push(a); + } + return values; +} diff --git a/src/lib/syntax/color/rec2020.ts b/src/lib/syntax/color/rec2020.ts index e582a046..b9fbc314 100644 --- a/src/lib/syntax/color/rec2020.ts +++ b/src/lib/syntax/color/rec2020.ts @@ -3,13 +3,17 @@ import { multiplyMatrices } from "./utils/matrix.ts"; import { srgb2xyz } from "./xyz.ts"; export function rec20202srgb(r: number, g: number, b: number, a?: number): number[] { + let values = rec20202lrec2020(r, g, b); + values = lrec20202xyz(values[0], values[1], values[2]); // @ts-ignore - return xyz2srgb(...lrec20202xyz(...rec20202lrec2020(r, g, b)), a); + return xyz2srgb(values[0], values[1], values[2], a); } export function srgb2rec2020values(r: number, g: number, b: number, a?: number): number[] { + let values = srgb2xyz(r, g, b); + values = xyz2lrec2020(values[0], values[1], values[2]); // @ts-ignore - return lrec20202rec2020(...xyz2lrec2020(...srgb2xyz(r, g, b)), a); + return lrec20202rec2020(values[0], values[1], values[2], a); } function rec20202lrec2020(r: number, g: number, b: number, a?: number): number[] { // convert an array of rec2020 RGB values in the range 0.0 - 1.0 diff --git a/src/lib/syntax/color/relative-color.ts b/src/lib/syntax/color/relative-color.ts index 6ea62229..f09b38d7 100644 --- a/src/lib/syntax/color/relative-color.ts +++ b/src/lib/syntax/color/relative-color.ts @@ -13,7 +13,7 @@ import { convertColor, getNumber } from "./color.ts"; import { ColorType, EnumToken } from "../../ast/types.ts"; import { walkValues } from "../../ast/walk.ts"; import { evaluate, evaluateFunc } from "../../ast/math/expression.ts"; -import { colorFuncColorSpace, colorRange, colorsFunc, LOC, mathFuncs } from "../constants.ts"; +import { colorFuncColorSpace, colorRange, colorsFunc, LOC, LOCEND, LOCSRCID, LOCSTA, mathFuncs } from "../constants.ts"; import { equalsIgnoreCase } from "../../parser/utils/text.ts"; import { getColorComponents } from "./utils/components.ts"; @@ -80,7 +80,9 @@ export function parseRelativeColorComponents( let val: string = ""; if (components != null) { - allComponents.push(...components); + for (const component of components) { + allComponents.push(component); + } } // ensure all components are valid for the color space @@ -167,19 +169,25 @@ export function parseRelativeColorComponents( ? { typ: EnumToken.NumberTokenType, val: 1, - [LOC]: b[LOC], + [LOCSRCID]: b[LOCSRCID], + [LOCSTA]: b[LOCSTA], + [LOCEND]: b[LOCEND], } : alpha.typ == EnumToken.IdenTokenType && (alpha as IdentToken).val == "none" ? { typ: EnumToken.NumberTokenType, val: 0, - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha.typ == EnumToken.PercentageTokenType ? { typ: EnumToken.NumberTokenType, val: getNumber(alpha), - [LOC]: alpha[LOC], + [LOCSRCID]: alpha[LOCSRCID], + [LOCSTA]: alpha[LOCSTA], + [LOCEND]: alpha[LOCEND], } : alpha, }; @@ -194,13 +202,17 @@ export function parseRelativeColorComponents( ? { typ: EnumToken.NumberTokenType, val: 1, - [LOC]: bExp[LOC], + [LOCSRCID]: bExp[LOCSRCID], + [LOCSTA]: bExp[LOCSTA], + [LOCEND]: bExp[LOCEND], } : aExp.typ == EnumToken.IdenTokenType && (aExp as IdentToken).val == "none" ? { typ: EnumToken.NumberTokenType, val: 0, - [LOC]: aExp[LOC], + [LOCSRCID]: aExp[LOCSRCID], + [LOCSTA]: aExp[LOCSTA], + [LOCEND]: aExp[LOCEND], } : aExp, ), @@ -239,7 +251,9 @@ function getValue(t: Token, converted?: ColorToken, component?: string): Token { return { typ: EnumToken.NumberTokenType, val: value, - [LOC]: t[LOC], + [LOCSRCID]: t[LOCSRCID], + [LOCSTA]: t[LOCSTA], + [LOCEND]: t[LOCEND], }; } @@ -293,8 +307,10 @@ function computeComponentValue( ({ typ: EnumToken.NumberTokenType, // @ts-ignore - val: "" + Math[(value as IdentToken).val.toUpperCase()], - [LOC]: value[LOC], + val: Math[(value as IdentToken).val.toUpperCase()] as number, + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], // @ts-ignore } as Token), ); diff --git a/src/lib/syntax/color/rgb.ts b/src/lib/syntax/color/rgb.ts index 07782fd1..c0db582f 100644 --- a/src/lib/syntax/color/rgb.ts +++ b/src/lib/syntax/color/rgb.ts @@ -15,7 +15,6 @@ import { ColorType, EnumToken } from "../../ast/types.ts"; import { COLORS_NAMES } from "../constants.ts"; export function srgb2rgb(value: number): number { - return minmax(Math.round(value * 255), 0, 255); } diff --git a/src/lib/syntax/color/srgb.ts b/src/lib/syntax/color/srgb.ts index a5ae0c7b..6a862cc7 100644 --- a/src/lib/syntax/color/srgb.ts +++ b/src/lib/syntax/color/srgb.ts @@ -114,8 +114,9 @@ export function hex2srgbvalues(token: ColorToken): number[] { // xyz d65 input export function xyz2srgb(x: number, y: number, z: number, alpha: number | null = null): number[] { + let values = XYZ_to_lin_sRGB(x, y, z); // @ts-ignore - return lsrgb2srgbvalues(...XYZ_to_lin_sRGB(x, y, z, alpha)); + return lsrgb2srgbvalues(values[0], values[1], values[2], alpha); } export function hwb2srgbvalues(token: ColorToken): number[] | null { @@ -216,8 +217,8 @@ export function oklch2srgbvalues(token: ColorToken): number[] | null { return null; } - // @ts-ignore - const rgb: number[] = OKLab_to_sRGB(...lchvalues2labvalues(l, c, h)); + const values = lchvalues2labvalues(l, c, h); + const rgb: number[] = OKLab_to_sRGB(values[0], values[1], values[2]); if (alpha != 1) { rgb.push(alpha); @@ -344,7 +345,7 @@ export function lch2srgbvalues(token: ColorToken): number[] | null { } // @ts-ignore - const [l, a, b, alpha] = lchvalues2labvalues(...components); + const [l, a, b, alpha] = lchvalues2labvalues(components[0], components[1], components[2], components[3]); if (l == null || a == null || b == null) { return null; diff --git a/src/lib/syntax/color/utils/distance.ts b/src/lib/syntax/color/utils/distance.ts index 55a4438f..c3514dd6 100644 --- a/src/lib/syntax/color/utils/distance.ts +++ b/src/lib/syntax/color/utils/distance.ts @@ -35,7 +35,7 @@ export function okLabDistance(color1: ColorToken, color2: ColorToken): number | diff.push((okLab1[3] ?? 1) - (okLab2[3] ?? 1)); } - return toPrecisionValue(Math.hypot(...diff)); + return toPrecisionValue(Math.hypot(diff[0], diff[1], diff[2], diff[3] ?? 0)); } /** diff --git a/src/lib/syntax/color/utils/matrix.ts b/src/lib/syntax/color/utils/matrix.ts index 5361a2c3..24fd0479 100644 --- a/src/lib/syntax/color/utils/matrix.ts +++ b/src/lib/syntax/color/utils/matrix.ts @@ -1,4 +1,3 @@ - // from https://www.w3.org/TR/css-color-4/multiply-matrices.js /** * Simple matrix (and vector) multiplication @@ -20,17 +19,20 @@ export function multiplyMatrices(A: number[] | number[][], B: number[] | number[ } let p: number = (B)[0].length; - let B_cols: number[][] = (B)[0].map((_: number, i: number) => (B).map((x: number[]) => x[i])); // transpose B + let B_cols: number[][] = (B)[0].map((_: number, i: number) => + (B).map((x: number[]) => x[i]), + ); // transpose B // @ts-expect-error - let product: number[] = (A as number[][]).map((row: number[]) => B_cols.map((col: number[]): number => { - - // if (!Array.isArray(row)) { + let product: number[] = (A as number[][]).map((row: number[]) => + B_cols.map((col: number[]): number => { + // if (!Array.isArray(row)) { - // return col.reduce((a: number, c: number) => a + c * row, 0); - // } + // return col.reduce((a: number, c: number) => a + c * row, 0); + // } - return row.reduce((a: number, c: number, i: number) => a + c * (col[i] || 0), 0) as number; - })) as number[]; + return row.reduce((a: number, c: number, i: number) => a + c * (col[i] || 0), 0) as number; + }), + ) as number[]; // if (m === 1) { @@ -38,7 +40,6 @@ export function multiplyMatrices(A: number[] | number[][], B: number[] | number[ // } if (p === 1) { - // @ts-expect-error return product.map((x: number[]) => x[0]); // Avoid [[a], [b], [c], ...]] } diff --git a/src/lib/syntax/color/xyz.ts b/src/lib/syntax/color/xyz.ts index 4861de4c..acd24e7e 100644 --- a/src/lib/syntax/color/xyz.ts +++ b/src/lib/syntax/color/xyz.ts @@ -60,8 +60,8 @@ export function srgb2xyz(r: number, g: number, b: number, alpha?: number): numbe // xyz d50 export function srgb2xyz_d65(r: number, g: number, b: number, alpha?: number): number[] { // xyx d65 - // @ts-ignore - let rgb: number[] = XYZ_D65_to_D50(...srgb2xyz(r, g, b)); + let values = srgb2xyz(r, g, b); + let rgb: number[] = XYZ_D65_to_D50(values[0], values[1], values[2]); if (alpha != null && alpha != 1) { rgb.push(alpha); diff --git a/src/lib/syntax/color/xyzd50.ts b/src/lib/syntax/color/xyzd50.ts index 64ba808f..b921b2aa 100644 --- a/src/lib/syntax/color/xyzd50.ts +++ b/src/lib/syntax/color/xyzd50.ts @@ -25,8 +25,8 @@ export function srgb2xyzd50values(r: number, g: number, b: number, alpha: number /* */ export function xyzd502lch(x: number, y: number, z: number, alpha?: number): number[] { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + const values = XYZ_D50_to_D65(x, y, z); + const [l, a, b] = xyz2lab(values[0], values[1], values[2]); // L in range [0,100]. For use in CSS, add a percent return labvalues2lchvalues(l, a, b, alpha); diff --git a/src/lib/syntax/constants.ts b/src/lib/syntax/constants.ts index 4922119f..9d53c8e5 100644 --- a/src/lib/syntax/constants.ts +++ b/src/lib/syntax/constants.ts @@ -1,6 +1,15 @@ import { EnumToken } from "../ast/types.ts"; import { config } from "../validation/json.ts"; +/** + * Location source id + */ +export const LOCSRCID = Symbol.for("locSrcId"); +export const LOCSTA = Symbol.for("locSta"); +export const LOCEND = Symbol.for("locEnd"); +/** + * Used by the validation parser + */ export const LOC = Symbol.for("loc"); export const RAW = Symbol.for("raw"); export const STATE = Symbol.for("state"); @@ -56,7 +65,7 @@ export const colorPrecision = 6; /** * Angle precision */ -export const anglePrecision = 0.001; +export const anglePrecision = 3; /** * Color range definitions @@ -116,6 +125,7 @@ export const mathFuncs = [ "acos", "atan", "atan2", + "tan", "pow", "sqrt", "hypot", diff --git a/src/lib/syntax/syntax.ts b/src/lib/syntax/syntax.ts index 8d73f86b..1e1fccce 100644 --- a/src/lib/syntax/syntax.ts +++ b/src/lib/syntax/syntax.ts @@ -26,16 +26,15 @@ import { splitTokenList } from "../validation/utils/list.ts"; import { getColorSpace } from "./color/utils/colorspace.ts"; import { getColorComponents } from "./color/utils/components.ts"; import { - colorsFunc, - systemColors, - deprecatedSystemColors, - nonStandardColors, - COLORS_NAMES, - colorFuncColorSpace, - LOC, anglePrecision, + colorFuncColorSpace, colorPrecision, + COLORS_NAMES, + colorsFunc, + deprecatedSystemColors, epsilon, + nonStandardColors, + systemColors, } from "./constants.ts"; import { getSyntaxConfig } from "../validation/config.ts"; @@ -44,7 +43,12 @@ import { getSyntaxConfig } from "../validation/config.ts"; // '\\' const REVERSE_SOLIDUS = 0x5c; -export const dimensionUnits: Set = new Set([ +export const flexUnits: Array = ["fr"]; +export const frequencyUnits: Array = ["hz", "khz"]; +export const timeUnits: Array = ["ms", "s"]; +export const angleUnits: Array = ["rad", "turn", "deg", "grad"]; +export const resolutionUnits: Array = ["dpi", "dpcm", "dppx", "x"]; +export const dimensionUnits: Array = [ "q", "cap", "ch", @@ -88,7 +92,7 @@ export const dimensionUnits: Set = new Set([ "vmax", "vmin", "vw", -]); +]; // https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions // https://developer.mozilla.org/en-US/docs/Web/CSS/Mozilla_Extensions @@ -524,23 +528,23 @@ export const mozExtensions = new Set([ export const renamedStandardProperties = new Map([["color-adjust", "print-color-adjust"]]); export function isLength(dimension: DimensionToken): boolean { - return "unit" in dimension && dimensionUnits.has(dimension.unit.toLowerCase()); + return "unit" in dimension && dimensionUnits.includes(dimension.unit.toLowerCase()); } export function isResolution(dimension: DimensionToken): boolean { - return "unit" in dimension && ["dpi", "dpcm", "dppx", "x"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && resolutionUnits.includes(dimension.unit.toLowerCase()); } export function isAngle(dimension: DimensionToken): boolean { - return "unit" in dimension && ["rad", "turn", "deg", "grad"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && angleUnits.includes(dimension.unit.toLowerCase()); } export function isTime(dimension: DimensionToken): boolean { - return "unit" in dimension && ["ms", "s"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && timeUnits.includes(dimension.unit.toLowerCase()); } export function isFrequency(dimension: DimensionToken): boolean { - return "unit" in dimension && ["hz", "khz"].includes(dimension.unit.toLowerCase()); + return "unit" in dimension && frequencyUnits.includes(dimension.unit.toLowerCase()); } /** @@ -601,7 +605,10 @@ export function reduceColorStops(stops: Token[]) { ); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } + parts.splice(i--, 1); updated = true; continue; @@ -630,7 +637,10 @@ export function reduceColorStops(stops: Token[]) { if (stops.length > 0) { stops.push({ typ: EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + + for (let m = 0; m < parts[j].length; m++) { + stops.push(parts[j][m]); + } } } @@ -755,7 +765,10 @@ export function reduceConicColorStops(stops: Token[]): Token[] { ); } - parts[i - 1].push(...parts[i].slice(1)); + for (let m = 1; m < parts[i].length; m++) { + parts[i - 1].push(parts[i][m]); + } + parts.splice(i--, 1); updated = true; continue; @@ -783,7 +796,10 @@ export function reduceConicColorStops(stops: Token[]): Token[] { if (stops.length > 0) { stops.push({ typ: EnumToken.CommaTokenType }); } - stops.push(...parts[j]); + + for (const token of parts[j]) { + stops.push(token); + } } } @@ -1187,7 +1203,11 @@ export function isColor(token: Token, errors?: ErrorDescription[]): boolean { ) ) { // @ts-ignore - keywords.push("alpha", ...(token as ColorToken).val.slice(-3).split("")); + keywords.push("alpha"); + + for (const keyword of (token as ColorToken).val.slice(-3).split("")) { + keywords.push(keyword); + } } // @ts-ignore @@ -1584,9 +1604,9 @@ export function parseDimension( // @ts-ignore dimension.typ = EnumToken.ResolutionTokenType; - if (dimension.unit == "dppx") { - dimension.unit = "x"; - } + // if (dimension.unit == "dppx") { + // dimension.unit = "x"; + // } } else if (isFrequency(dimension)) { // @ts-ignore dimension.typ = EnumToken.FrequencyTokenType; @@ -1765,7 +1785,7 @@ export function toPrecisionValue(value: number | string, precision: number = col export function toPrecisionAngle( angle: number, - precision: number = colorPrecision, + precision: number = anglePrecision, correctValue: boolean = true, ): number { angle = toPrecisionValue(angle, precision); @@ -1774,10 +1794,6 @@ export function toPrecisionAngle( angle %= 360; } - if (Math.abs(angle) < anglePrecision) { - angle = 0; - } - if (correctValue && angle < 0) { angle += 360; } diff --git a/src/lib/validation/config.json b/src/lib/validation/config.json index 1f669254..e921ec66 100644 --- a/src/lib/validation/config.json +++ b/src/lib/validation/config.json @@ -1815,6 +1815,9 @@ "text-emphasis-style": { "syntax": "none | [ [ filled | open ] || [ dot | circle | double-circle | triangle | sesame ] ] | " }, + "text-fit": { + "syntax": "[ none | grow | shrink ] [consistent | per-line | per-line-all]? ?" + }, "text-indent": { "syntax": " && hanging? && each-line?" }, diff --git a/src/lib/validation/match.ts b/src/lib/validation/match.ts index 9bf8fe58..8f285544 100644 --- a/src/lib/validation/match.ts +++ b/src/lib/validation/match.ts @@ -36,9 +36,8 @@ import type { import { MediaFeatureType, ValidationSyntaxGroupEnum, ValidationTokenEnum } from "./parser/typedef.ts"; import type { ValidationContext, ValidationMatch } from "./types.d.ts"; import type { ValidationConfiguration, ValidationMediaFeature } from "../../@types/validation.d.ts"; -import { funcLike, LOC, mFGT, mFLT, tokensfuncDefMap, tokensfuncSet } from "../syntax/constants.ts"; +import { funcLike, LOCSTA, mFGT, mFLT, tokensfuncDefMap, tokensfuncSet } from "../syntax/constants.ts"; import { isColor } from "../syntax/syntax.ts"; -// import { isDeclarationValue } from "../parser/utils/declaration.ts"; import { renderSyntax } from "./parser/parse.ts"; import { equalsIgnoreCase } from "../parser/utils/text.ts"; import { cloneNode } from "../ast/clone.ts"; @@ -52,11 +51,13 @@ const allValues = config.declarations.all!.syntax.split(/[\s|]+/g) as string[]; /** * @type {Array.} */ -export const funcTypes: EnumToken[] = [ - ...tokensfuncDefMap.values(), +export const funcTypes: EnumToken[] = Array.from(tokensfuncDefMap.values()); + +funcTypes.push( + EnumToken.FunctionTokenType, EnumToken.PseudoClassFuncTokenType, -]; +); /** * trim leading and trailing whitespace @@ -488,7 +489,7 @@ export function matchSelectorSyntax( message: `Unexpected token ${EnumToken[stream[i].typ]}`, node: stream[i], // @ts-expect-error - location: options.source!.getSourceLocation(stream[i][LOC]!.sta), + location: options.source!.getSourceLocation(stream[i][LOCSTA]), }, ], }; @@ -543,7 +544,9 @@ export function matchSelectorSyntax( success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } } @@ -565,7 +568,7 @@ export function matchSelectorSyntax( message: `Nesting selector is not allowed`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -605,7 +608,7 @@ export function matchSelectorSyntax( message: `Unexpected combinator ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -670,7 +673,7 @@ export function matchSelectorSyntax( message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -738,7 +741,7 @@ export function matchSelectorSyntax( message: `Unexpected token ${EnumToken[slice[0].typ]}`, node: slice[0], // @ts-expect-error - location: options.source!.getSourceLocation(slice[0][LOC]!.sta), + location: options.source!.getSourceLocation(slice[0][LOCSTA]), }, ], }; @@ -752,8 +755,8 @@ export function matchSelectorSyntax( // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOC]!.sta.lin}:${ - // slice[0][LOC]!.sta.col + // message: `Unexpected token ${EnumToken[slice[0].typ]} at ${slice[0][LOC]!.src}:${slice[0][LOCSTA].lin}:${ + // slice[0][LOCSTA].col // }`, // node: slice[0], // location: slice[0][LOC], @@ -796,8 +799,8 @@ export function matchSelectorSyntax( // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -831,8 +834,8 @@ export function matchSelectorSyntax( // errors: [ // { // action: "drop", - // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOC]!.sta.lin}:${ - // token[LOC]!.sta.col + // message: `Unexpected token ${EnumToken[token.typ]} at ${token[LOC]!.src}:${token[LOCSTA].lin}:${ + // token[LOCSTA].col // }`, // node: token, // location: token[LOC], @@ -863,7 +866,7 @@ export function matchSelectorSyntax( message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -909,7 +912,9 @@ export function matchSelectorSyntax( success = false; if (result.errors.length > 0) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } } @@ -925,7 +930,7 @@ export function matchSelectorSyntax( message: `Unexpected token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -950,7 +955,7 @@ export function matchSelectorSyntax( message: `Unsupported selector token ${EnumToken[token.typ]}`, node: token, // @ts-expect-error - location: options.source!.getSourceLocation(token[LOC]!.sta), + location: options.source!.getSourceLocation(token[LOCSTA]), }, ], }; @@ -980,14 +985,17 @@ export function matchSelectorSyntax( message: `Unmatched token ${EnumToken[stack.at(-1)!.typ]}`, node: stack.at(-1)! as Token, // @ts-expect-error - location: options.source!.getSourceLocation(stack.at(-1)![LOC]!.sta), + location: options.source!.getSourceLocation(stack.at(-1)![LOCSTA]), }, ], }; } stream.length = 0; - stream.push(...tokens); + + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } @@ -1042,7 +1050,7 @@ export function matchAllSyntaxes( node: result.token, syntax: result.syntaxToken, location: options.source!.getSourceLocation( - (result.token?.[LOC]! ?? context.tokens.at(-1)?.[LOC]).sta, + (result.token?.[LOCSTA] ?? context.tokens.at(-1)?.[LOCSTA])!, ), }, ] @@ -1168,7 +1176,7 @@ export function matchOccurenceSyntax( action: "drop", message: "could not match syntax", node: context.peek(), - // location: options.source!.getSourceLocation(context.peek()?.[LOC]!.sta), + // location: options.source!.getSourceLocation(context.peek()?.[LOCSTA]), }, ], syntaxToken: null, @@ -1871,7 +1879,6 @@ function matchSyntax( }; case ValidationTokenEnum.FunctionDefinition: - if ( equalsIgnoreCase( (token as FunctionToken).val, diff --git a/src/node.ts b/src/node.ts index 26d58168..5d90790e 100644 --- a/src/node.ts +++ b/src/node.ts @@ -21,7 +21,7 @@ import { lstat, readFile } from "node:fs/promises"; import { doParse, doParseSync } from "./lib/parser/parse.ts"; import { doRender } from "./lib/renderer/render.ts"; import { ModuleScopeEnumOptions } from "./lib/ast/types.ts"; -import { tokenize, tokenizeStream } from "./lib/parser/tokenize.ts"; +import { Tokenizer } from "./lib/parser/tokenize.ts"; import { dirname, matchUrl, resolve } from "./lib/fs/resolve.ts"; import { ResponseType } from "./types.ts"; import { resolve as resolvePath } from "node:path"; @@ -105,6 +105,10 @@ export async function load( return response.arrayBuffer(); } + if (responseType == ResponseType.JSON) { + return response.json(); + } + return responseType == ResponseType.ReadableStream ? (response.body as ReadableStream>) : response.text(); @@ -116,8 +120,10 @@ export async function load( const stats = await lstat(resolved.absolute); if (stats.isFile()) { - if (responseType == ResponseType.Text) { - return readFile(resolved.absolute, "utf-8"); + if (responseType == ResponseType.Text || responseType == ResponseType.JSON) { + return readFile(resolved.absolute, "utf-8").then((buffer) => + responseType == ResponseType.JSON ? JSON.parse(buffer) : buffer, + ); } if (responseType == ResponseType.ArrayBuffer) { @@ -131,9 +137,7 @@ export async function load( }), ) as ReadableStream; } - } catch (error) { - console.warn(error); - } + } catch (error) {} throw new Error(`File not found: '${resolved.absolute || url}'`); } @@ -316,8 +320,10 @@ export function parseSync( currentPosition: 0, } as ParseInfo; - const result = doParseSync(tokenize(options.parseInfo), options) as ParseResult; - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options) as ParseResult; + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** @@ -631,6 +637,7 @@ export async function parse( "", (options as ParseInputFileOptions).asStream ?? false, ), + // @ts-expect-error ).then((stream: string | ReadableStream) => parse(stream, { src: file, ...options })); } else { stream = input; @@ -668,9 +675,15 @@ export async function parse( } as ParseInfo; return doParse( - stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), + stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options, - ).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + ).then((result) => + options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options), + ); } /** @@ -883,6 +896,7 @@ export async function transform( "", (options as ParseInputFileOptions).asStream ?? false, ), + // @ts-expect-error ).then((stream: string | ReadableStream) => transform(stream, { src: file, ...options })); } else { stream = input; diff --git a/src/types.ts b/src/types.ts index 05bbcbce..111ce795 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,7 +2,6 @@ * response type */ export enum ResponseType { - /** * return text */ @@ -14,5 +13,9 @@ export enum ResponseType { /** * return an arraybuffer */ - ArrayBuffer -} \ No newline at end of file + ArrayBuffer, + /** + * return a json object + */ + JSON, +} diff --git a/src/utils/sync.ts b/src/utils/sync.ts index ac006a31..f3957bbc 100644 --- a/src/utils/sync.ts +++ b/src/utils/sync.ts @@ -1,6 +1,14 @@ -import type { AstComment, AstNode, ParseResult, ParserOptions, ParserSyncOptions } from "../@types/index.d.ts"; -import { AstNodePropertyType, EnumToken } from "../lib/ast/types.ts"; -import { ERRORS, LOC, PARENT, STATE, TOKENS } from "../lib/syntax/constants.ts"; +import type { + AstComment, + LoadResult, + ParseResult, + ParserOptions, + ParserSyncOptions, + SourceMapObject, +} from "../@types/index.d.ts"; +import { EnumToken } from "../lib/ast/types.ts"; +import { dirname } from "../lib/fs/resolve.ts"; +import { ResponseType } from "../types.ts"; /** * parse result. process input sourcemap @@ -21,7 +29,30 @@ export function parseResult(result: ParseResult, options: ParserOptions): ParseR token?.typ == EnumToken.CommentTokenType && (token as AstComment).val.startsWith("/*# sourceMappingURL=") ) { - options!.source!.setInputSourceMap((token as AstComment).val.slice(21, -2).trim()); + let data: string = (token as AstComment).val.slice(21, -2).trim(); + + if (data.endsWith(".map")) { + if (options.load == null) { + data = ""; + } else { + + options + .load( + options.resolve!(data, dirname(options.src as string)).absolute, + ".", + ResponseType.JSON, + ) + .catch((error) => console.error({ error })) + .then((res) => { + if (res != null) { + // @ts-expect-error + options!.source!.setInputSourceMap(res as SourceMapObject); + } + }); + } + } else { + options!.source!.setInputSourceMap(data); + } } } } diff --git a/src/web.ts b/src/web.ts index 7a238d93..b74204ac 100644 --- a/src/web.ts +++ b/src/web.ts @@ -18,7 +18,7 @@ import type { import { doParse, doParseSync } from "./lib/parser/parse.ts"; import { doRender } from "./lib/renderer/render.ts"; import { ModuleScopeEnumOptions } from "./lib/ast/types.ts"; -import { tokenize, tokenizeStream } from "./lib/parser/tokenize.ts"; +import { Tokenizer } from "./lib/parser/tokenize.ts"; import { dirname, matchUrl, resolve } from "./lib/fs/resolve.ts"; import { ResponseType } from "./types.ts"; import { SourceFile } from "./lib/parser/source.ts"; @@ -110,6 +110,10 @@ export async function load( return response.arrayBuffer(); } + if (responseType == ResponseType.JSON) { + return response.json(); + } + return responseType == ResponseType.ReadableStream ? response.body : response.text(); }) as Promise>>; } @@ -335,8 +339,10 @@ export function parseSync( currentPosition: 0, } as ParseInfo; - const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** @@ -594,6 +600,7 @@ export async function parse( "", (options as ParseInputFileOptions).asStream ?? false, ), + // @ts-expect-error ).then((stream: string | ReadableStream) => parse(stream, { src: (options as ParseInputFileOptions).file, ...options }), ); @@ -635,9 +642,15 @@ export async function parse( } as ParseInfo; return doParse( - stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), + stream instanceof ReadableStream + ? new Tokenizer(options.parseInfo, stream).tokenizeStream() + : new Tokenizer(options.parseInfo), options, - ).then((result) => (!options.module && !options.inputSourceMap ? result : parseResult(result, options))); + ).then((result) => + options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options), + ); } /** @@ -801,6 +814,7 @@ export async function transform( "", (options as ParseInputFileOptions).asStream ?? false, ), + // @ts-expect-error ).then((stream: string | ReadableStream) => transform(stream, { src: (options as ParseInputFileOptions).file, ...options }), ); diff --git a/test/specs/code/angle.js b/test/specs/code/angle.js index c2e49977..cd4eebc6 100644 --- a/test/specs/code/angle.js +++ b/test/specs/code/angle.js @@ -5,15 +5,15 @@ export function run(describe, expect, it, transform) { it('angle #1', function () { return transform(` -.transform { transform: rotate(0.75turn, 2.356194rad, 100grad); }`).then(result => expect(result.code).equals(`.transform{transform:rotate(270deg,.375turn,90deg)}`)); +.transform { transform: rotate(0.75turn, 2.356194rad, 100grad); }`).then(result => expect(result.code).equals(`.transform{transform:rotate(270deg,135deg,90deg)}`)); }); it('angle #2', function () { return transform(` -.transform { background: conic-gradient(black 0.75turn, green 2.356194rad, blue 100grad); }`).then(result => expect(result.code).equals(`.transform{background:conic-gradient(#000 270deg,green .375turn,blue 90deg)}`)); +.transform { background: conic-gradient(black 0.75turn, green 2.356194rad, blue 100grad); }`).then(result => expect(result.code).equals(`.transform{background:conic-gradient(#000 270deg,green 150grad,blue 90deg)}`)); }); it('angle #3', function () { return transform(` -.transform { background: conic-gradient(black 0.75turn, black 2.356194rad, blue 100grad); }`).then(result => expect(result.code).equals(`.transform{background:conic-gradient(#000 270deg .375turn,blue 90deg)}`)); +.transform { background: conic-gradient(black 0.75turn, black 2.356194rad, blue 100grad); }`).then(result => expect(result.code).equals(`.transform{background:conic-gradient(#000 270deg 135deg,blue 90deg)}`)); }); }); } \ No newline at end of file diff --git a/test/specs/code/calc.js b/test/specs/code/calc.js index 09a65e62..23562f73 100644 --- a/test/specs/code/calc.js +++ b/test/specs/code/calc.js @@ -1,39 +1,36 @@ - - export function run(describe, expect, it, transform, parse, render) { - - describe('calc expression', function () { - - it('calc() #1', function () { - + describe("calc expression", function () { + it("calc() #1", function () { return transform(` .foo { width: calc(100px * 2); height: calc(((75.37% - 63.5px) - 900px) + (2 * 100px)); } -`).then(result => expect(result.code).equals(`.foo{width:200px;height:calc(75.37% - 763.5px)}`)); +`).then((result) => expect(result.code).equals(`.foo{width:200px;height:calc(75.37% - 763.5px)}`)); }); - it('calc() #2', function () { - + it("calc() #2", function () { return transform(`.foo { height: calc(200% / 6 + 2%/3); width: calc(3.5rem + calc(var(--bs-border-width) * 2)); } -`).then(result => expect(result.code).equals(`.foo{height:34%;width:calc(3.5rem + var(--bs-border-width)*2)}`)); +`).then((result) => expect(result.code).equals(`.foo{height:34%;width:calc(3.5rem + var(--bs-border-width)*2)}`)); }); - it('calc() #3', function () { - + it("calc() #3", function () { return transform(`.foo { bottom:calc(-1*(var(--bs-popover-arrow-height)) - var(--bs-popover-border-width)) } -`).then(result => expect(result.code).equals(`.foo{bottom:calc(-1*var(--bs-popover-arrow-height) - var(--bs-popover-border-width))}`)); +`).then((result) => + expect(result.code).equals( + `.foo{bottom:calc(-1*var(--bs-popover-arrow-height) - var(--bs-popover-border-width))}`, + ), + ); }); - it('calc() #4', function () { - - return transform(` + it("calc() #4", function () { + return transform( + ` :root { --preferred-width: 20px; @@ -41,12 +38,14 @@ export function run(describe, expect, it, transform, parse, render) { .foo-bar { width: calc(var(--preferred-width) + 5px); } -`, {inlineCssVariables: true}).then(result => expect(result.code).equals(`.foo-bar{width:25px}`)); +`, + { inlineCssVariables: true }, + ).then((result) => expect(result.code).equals(`.foo-bar{width:25px}`)); }); - it('calc() #5', function () { - - return transform(` + it("calc() #5", function () { + return transform( + ` :root { --preferred-width: 20px; @@ -55,11 +54,12 @@ export function run(describe, expect, it, transform, parse, render) { width: calc((var(--preferred-width) + 1px) / 3 + 5px); height: calc(100% / 4); } -`, {inlineCssVariables: true}).then(result => expect(result.code).equals(`.foo-bar{width:12px;height:25%}`)); +`, + { inlineCssVariables: true }, + ).then((result) => expect(result.code).equals(`.foo-bar{width:12px;height:25%}`)); }); - it('calc() #6', function () { - + it("calc() #6", function () { return transform(` :root { @@ -69,113 +69,106 @@ export function run(describe, expect, it, transform, parse, render) { width: calc((var(--preferred-width) + 1px) / 3 + 5px); height: calc(100% / 4); } -`).then(result => expect(result.code).equals(`:root{--preferred-width:20px}.foo-bar{width:calc((var(--preferred-width) + 1px)/3 + 5px);height:25%}`)); +`).then((result) => + expect(result.code).equals( + `:root{--preferred-width:20px}.foo-bar{width:calc((var(--preferred-width) + 1px)/3 + 5px);height:25%}`, + ), + ); }); - it('calc() #7', function () { - + it("calc() #7", function () { return transform(` .foo { height: calc(100px * 2/ 15 + 2px/3); } -`).then(result => expect(result.code).equals(`.foo{height:14px}`)); +`).then((result) => expect(result.code).equals(`.foo{height:14px}`)); }); - it('calc() #8', function () { - + it("calc() #8", function () { return transform(` .foo { height: calc(100px * 2/ 15 - 5% - 1px/3); } -`).then(result => expect(result.code).equals(`.foo{height:calc(13px - 5%)}`)); +`).then((result) => expect(result.code).equals(`.foo{height:calc(13px - 5%)}`)); }); - it('calc() #9', function () { - + it("calc() #9", function () { return transform(` .foo { height: calc(100px * 2/ 15); } -`).then(result => expect(result.code).equals(`.foo{height:calc(40px/3)}`)); +`).then((result) => expect(result.code).equals(`.foo{height:calc(40px/3)}`)); }); - it('calc() #10', function () { - + it("calc() #10", function () { return transform(` .foo { width: calc(2px * 50%); height: calc(80% * 50%); } -`).then(result => expect(result.code).equals(`.foo{width:1px;height:40%}`)); +`).then((result) => expect(result.code).equals(`.foo{width:1px;height:40%}`)); }); - it('calc() #11', function () { - + it("calc() #11", function () { return transform(` a { width: calc(100px * sin(pi / 4)) -`).then(result => expect(result.code).equals(`a{width:70.710678px}`)); +`).then((result) => expect(result.code).equals(`a{width:70.710678px}`)); }); - it('mod() #12', function () { - + it("mod() #12", function () { return transform(` .foo{ margin: mod(29vmin, 6vmin); } -`).then(result => expect(result.code).equals(`.foo{margin:5vmin}`)); +`).then((result) => expect(result.code).equals(`.foo{margin:5vmin}`)); }); - it('round() #13', function () { - + it("round() #13", function () { return transform(` .foo{ margin: round(up, calc(100px * sin(pi / 4)), 5.5px); } -`).then(result => expect(result.code).equals(`.foo{margin:71.5px}`)); +`).then((result) => expect(result.code).equals(`.foo{margin:71.5px}`)); }); - it('round() #14', function () { - + it("round() #14", function () { return transform(` .foo{ margin: round(down, calc(100px * sin(pi / 4)), 5.5px); } -`).then(result => expect(result.code).equals(`.foo{margin:66px}`)); +`).then((result) => expect(result.code).equals(`.foo{margin:66px}`)); }); - it('round() #15', function () { - + it("round() #15", function () { return transform(` .foo{ margin: round(nearest, calc(100px * sin(pi / 4)), 5.5px); } -`).then(result => expect(result.code).equals(`.foo{margin:71.5px}`)); +`).then((result) => expect(result.code).equals(`.foo{margin:71.5px}`)); }); - it('round() #16', function () { - + it("round() #16", function () { return transform(` .foo{ margin: round(to-zero, calc(100px * sin(pi / 4)), 5.5px); } -`).then(result => expect(result.code).equals(`.foo{margin:66px}`)); +`).then((result) => expect(result.code).equals(`.foo{margin:66px}`)); }); - it('min()/max() #17', function () { - + it("min()/max() #17", function () { return transform(` .foo{ @@ -183,34 +176,32 @@ width: calc(100px * sin(pi / 4)) height: min(calc(100px * sin(pi / 4)), 5.5px); width: max(calc(100px * sin(pi / 2)), 5.5px); } -`).then(result => expect(result.code).equals(`.foo{height:5.5px;width:100px}`)); +`).then((result) => expect(result.code).equals(`.foo{height:5.5px;width:100px}`)); }); - it('rem() #18', function () { - + it("rem() #18", function () { return transform(` .foo{ scale: rem(10 * 2, 1.7); } -`).then(result => expect(result.code).equals(`.foo{scale:1.3}`)); +`).then((result) => expect(result.code).equals(`.foo{scale:1.3}`)); }); - it('pow() #19', function () { - + it("pow() #19", function () { return transform(` .foo{ width: calc(10px * pow(5, 3)); } -`).then(result => expect(result.code).equals(`.foo{width:1250px}`)); +`).then((result) => expect(result.code).equals(`.foo{width:1250px}`)); }); - it('pow() #20', function () { - - return transform(` + it("pow() #20", function () { + return transform( + ` :root { --size-0: 100px; @@ -234,7 +225,10 @@ scale: rem(10 * 2, 1.7); height: var(--size-3); } -`, {inlineCssVariables: true, removeComments: false, beautify: true}).then(result => expect(result.code).equals(`:root { +`, + { inlineCssVariables: true, removeComments: false, beautify: true }, + ).then((result) => + expect(result.code).equals(`:root { /* --size-0: 100px */ /* --size-1: hypot(var(--size-0)) */ /* --size-2: hypot(var(--size-0),var(--size-0)) */ @@ -245,17 +239,17 @@ scale: rem(10 * 2, 1.7); height: 100px } .two { - width: 141px; - height: 141px + width: 141.421356px; + height: 141.421356px } .three { width: 250px; height: 250px -}`)); +}`), + ); }); - it('pow() #21', function () { - + it("pow() #21", function () { return parse(` a { @@ -264,176 +258,210 @@ a { line-height: calc(pi); transform: rotate(atan2(e, 30)); } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { - -moz-transform: rotate(atan2(1rem,-.5rem)); - line-height: calc(pi); - transform: rotate(atan2(e,30)) -}`)); +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { + -moz-transform: rotate(.324turn); + line-height: 3.141593; + transform: rotate(.09rad) +}`), + ); }); - it('log() #22', function () { - + it("log() #22", function () { return parse(` a { width: calc(100px * log(8, 2)); + transform: rotate( tan(45deg)) } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { - width: 300px -}`)); +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { + width: 300px; + transform: rotate(1rad) +}`), + ); }); - it('log() #23', function () { - + it("log() #23", function () { return parse(` a { width: calc(100px * log(625, 5)); } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { width: 400px -}`)); +}`), + ); }); - it('log() #24', function () { - + it("log() #24", function () { return parse(` a { width: calc(100px * log(625, 5)); } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { width: 400px -}`)); +}`), + ); }); - it('exp() #25', function () { - + it("exp() #25", function () { return parse(` a { width: calc(100px * exp(-1));} } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { width: 36.787944px -}`)); +}`), + ); }); - it('abs() #26', function () { - + it("abs() #26", function () { return parse(` a { width: calc(2px *abs(-1);} } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { -}`)); +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { +}`), + ); }); - it('sign() #27', function () { - + it("sign() #27", function () { return parse(` a { width: calc(-2px *sign(-1);} } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { -}`)); +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { +}`), + ); }); - it('calc() #28', function () { - - return transform(` + it("calc() #28", function () { + return transform( + ` :root { --preferred-width: 20px; } .foo-bar { width: calc(calc(var(--preferred-width) + 2px) / 3 + 5/2px); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: calc(59px/6) -}`)); +}`), + ); }); - it('calc() #29', function () { - - return transform(` + it("calc() #29", function () { + return transform( + ` :root { --preferred-width: 20px; } .foo-bar { width: calc(calc(var(--preferred-width) + 2px) / 3 + 5/2px - 5/6px); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: 9px -}`)); +}`), + ); }); - it('calc() #30', function () { - - return transform(` + it("calc() #30", function () { + return transform( + ` :root { --preferred-width: 20px; } .foo-bar { width: calc(calc(var(--preferred-width) + 2px) / (10/3px)); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: 6.6px -}`)); +}`), + ); }); - it('max() #31', function () { - - return transform(` + it("max() #31", function () { + return transform( + ` :root { --preferred-width: 20px; } .foo-bar { width: max(calc(calc(var(--preferred-width) + 2px) / (10/3px)), 200px); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: 200px -}`)); +}`), + ); }); - it('max() #32', function () { - - return transform(` + it("max() #32", function () { + return transform( + ` :root { --preferred-width: 20px; } .foo-bar { width: max(calc(calc(var(--preferred-width) + 2px) / (10/3px)), 200px); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: 200px -}`)); +}`), + ); }); - it('max() #33', function () { - - return transform(` + it("max() #33", function () { + return transform( + ` :root { --preferred-width: 670px; } .foo-bar { width: max(calc(calc(var(--preferred-width) + 2px) / (10/3px)), 200px); -`, {inlineCssVariables: true, beautify: true}).then(result => expect(result.code).equals(`.foo-bar { +`, + { inlineCssVariables: true, beautify: true }, + ).then((result) => + expect(result.code).equals(`.foo-bar { width: 201.6px -}`)); +}`), + ); }); - it('pow() #34', function () { - - return transform(` + it("pow() #34", function () { + return transform( + ` :root { --size-0: 100px; @@ -457,7 +485,10 @@ width: calc(-2px *sign(-1);} height: var(--size-3); } -`, {inlineCssVariables: true, removeComments: false, beautify: true}).then(result => expect(result.code).equals(`:root { +`, + { inlineCssVariables: true, removeComments: false, beautify: true }, + ).then((result) => + expect(result.code).equals(`:root { /* --size-0: 100px */ /* --size-1: hypot(var(--size-0)) */ /* --size-2: hypot(var(--size-0),var(--size-0)) */ @@ -468,58 +499,71 @@ width: calc(-2px *sign(-1);} height: 100px } .two { - width: 141px; - height: 141px + width: 141.421356px; + height: 141.421356px } .three { width: 250px; height: 250px -}`)); +}`), + ); }); - - - it('abs() #35', function () { - + it("abs() #35", function () { return parse(` a { width: calc(2px *abs(-1));} } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { width: 2px -}`)); +}`), + ); }); - - it('translate() #36', function () { - + it("translate() #36", function () { return parse(` a { transform: translate(0, -50px); } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { transform: translateY(-50px) -}`)); +}`), + ); }); - - it('hypth() #37', function () { - + it("hypth() #37", function () { return parse(` :root { --size-0: 100px; --size-1: hypot(var(--size-0)); -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`:root { +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`:root { --size-0: 100px; --size-1: hypot(var(--size-0)) -}`)); +}`), + ); }); - }); -} \ No newline at end of file + it("hypth() #38", function () { + return parse(` + +a { +transform: rotate(360deg); + + +`).then((result) => + expect(render(result.ast, { beautify: true }).code).equals(`a { + transform: rotate(1turn) +}`), + ); + }); + }); +} diff --git a/test/specs/code/color-rec2020.js b/test/specs/code/color-rec2020.js index 95b5b9c0..005c24db 100644 --- a/test/specs/code/color-rec2020.js +++ b/test/specs/code/color-rec2020.js @@ -222,7 +222,7 @@ export function run(describe, expect, it, transform, parse, render) { }); it('display-p3 to rec2020 #7', function () { - return transform(`.hsl { color: color(display-p3 0.644980276448 0.191199800941 0.165770885403 / 0.501960784314); }`, { + return transform(`.hsl { color: color(display-p3 0.644980276448 0.191199800941 0.165770885403 / 0.5); }`, { beautify: true, convertColor: ColorType.SRGB_LINEAR }).then(result => expect(isOkLabClose(result.ast.chi[0].chi[0].val[0], { diff --git a/test/specs/code/modules.js b/test/specs/code/modules.js index 68a05349..2d32c524 100644 --- a/test/specs/code/modules.js +++ b/test/specs/code/modules.js @@ -38,15 +38,15 @@ export function run( }, ).then((result) => { expect(result.mapping).deep.equals({ - goal: "goal_r7bhp", - "bg-indigo": "bg-indigo_gy28g", - "indigo-white": "indigo-white_wims0 bg-indigo_gy28g title_qw06e", - title: "title_qw06e", + goal: "goal_r6ajz", + "bg-indigo": "bg-indigo_gx1aq", + "indigo-white": "indigo-white_whlua bg-indigo_gx1aq title_qvz8o", + title: "title_qvz8o", }); - expect(result.code).equals(`.goal_r7bhp .bg-indigo_gy28g { + expect(result.code).equals(`.goal_r6ajz .bg-indigo_gx1aq { background: indigo } -.indigo-white_wims0 { +.indigo-white_whlua { color: #fff }`); }); @@ -70,15 +70,15 @@ export function run( }, ).then((result) => { expect(result.mapping).deep.equals({ - "--accent-color": "--accent-color_yosy6", - button: "button_oims0", + "--accent-color": "--accent-color_ynr0g", + button: "button_ohlua", }); expect(result.code).equals(`:root { - --accent-color_yosy6: hotpink + --accent-color_ynr0g: hotpink } -.button_oims0 { - background: var(--accent-color_yosy6) +.button_ohlua { + background: var(--accent-color_ynr0g) }`); }); }); @@ -102,15 +102,15 @@ export function run( }, ).then((result) => { expect(result.mapping).deep.equals({ - goal: "goal_r7bhp", - "bg-indigo": "bg-indigo_gy28g", - "indigo-white": "indigo-white_wims0 bg-indigo_gy28g title block ruler", + goal: "goal_r6ajz", + "bg-indigo": "bg-indigo_gx1aq", + "indigo-white": "indigo-white_whlua bg-indigo_gx1aq title block ruler", }); - expect(result.code).equals(`.goal_r7bhp .bg-indigo_gy28g { + expect(result.code).equals(`.goal_r6ajz .bg-indigo_gx1aq { background: indigo } -.indigo-white_wims0 { +.indigo-white_whlua { color: #fff }`); }); @@ -136,16 +136,16 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - goal: "goal_r7bhp", - "bg-indigo": "bg-indigo_gy28g", + goal: "goal_r6ajz", + "bg-indigo": "bg-indigo_gx1aq", "indigo-white": - "indigo-white_wims0 bg-indigo_gy28g button_egkqy_mixins cell_s04ai_mixins title_seiow_mixins", + "indigo-white_whlua bg-indigo_gx1aq button_efjs8_mixins cell_sz3cs_mixins title_sdhq6_mixins", }); - expect(result.code).equals(`.goal_r7bhp .bg-indigo_gy28g { + expect(result.code).equals(`.goal_r6ajz .bg-indigo_gx1aq { background: indigo } -.indigo-white_wims0 { +.indigo-white_whlua { color: #fff }`); }); @@ -187,27 +187,27 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - "--progress": "--progress_rlpv3", - bar: "bar_dnrx5", - progressAnimation: "progressAnimation_nrv19", + "--progress": "--progress_rkoxd", + bar: "bar_dmqzf", + progressAnimation: "progressAnimation_nqu3j", }); - expect(result.code).equals(`@property --progress_rlpv3 { + expect(result.code).equals(`@property --progress_rkoxd { syntax: ""; inherits: false; initial-value: 25% } -.bar_dnrx5 { +.bar_dmqzf { display: inline-block; - --progress_rlpv3: 25%; + --progress_rkoxd: 25%; width: 100%; height: 5px; - background: linear-gradient(90deg,#00d230 var(--progress_rlpv3),#000 var(--progress_rlpv3)); - animation: progressAnimation_nrv19 2.5s infinite + background: linear-gradient(90deg,#00d230 var(--progress_rkoxd),#000 var(--progress_rkoxd)); + animation: progressAnimation_nqu3j 2.5s infinite } -@keyframes progressAnimation_nrv19 { +@keyframes progressAnimation_nqu3j { to { - --progress_rlpv3: 100% + --progress_rkoxd: 100% } }`); }); @@ -263,9 +263,9 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - sun: "sun_ckou2", - rise: "rise_jtx3b", - bounce: "bounce_gw06e", + sun: "sun_cjnwc", + rise: "rise_jsw5l", + bounce: "bounce_gvz8o", }); expect(result.code).equals(`:root { @@ -274,14 +274,14 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; display: flex; justify-content: center } -.sun_ckou2 { +.sun_cjnwc { background-color: #ff0; border-radius: 50%; height: 100vh; aspect-ratio: 1 / 1; - animation: 4s linear infinite alternate rise_jtx3b,4s linear 0s infinite alternate bounce_gw06e + animation: 4s linear infinite alternate rise_jsw5l,4s linear 0s infinite alternate bounce_gvz8o } -@keyframes rise_jtx3b { +@keyframes rise_jsw5l { 0% { transform: translateY(110vh) } @@ -289,7 +289,7 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; transform: none } } -@keyframes bounce_gw06e { +@keyframes bounce_gvz8o { 0% { transform: translateX(-50vw) } @@ -323,17 +323,17 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - className: "className_vjnt1", - subClass: "subClass_sgkqy", + className: "className_vimvb", + subClass: "subClass_sfjs8", }); - expect(result.code).equals(`.className_vjnt1 { + expect(result.code).equals(`.className_vimvb { background: red } -.className_vjnt1,.className_vjnt1 .subClass_sgkqy { +.className_vimvb,.className_vimvb .subClass_sfjs8 { color: green } -.className_vjnt1 .subClass_sgkqy .global-class-name { +.className_vimvb .subClass_sfjs8 .global-class-name { color: blue }`); }); @@ -358,15 +358,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - className: "className_vjnt1", - subClass: "subClass_sgkqy className_vjnt1", + className: "className_vimvb", + subClass: "subClass_sfjs8 className_vimvb", }); - expect(result.code).equals(`.className_vjnt1 { + expect(result.code).equals(`.className_vimvb { background: red; color: #ff0 } -.subClass_sgkqy { +.subClass_sfjs8 { background: blue }`); }); @@ -391,15 +391,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - "class-name": "class-name_vjnt1", - "sub-class": "sub-class_sgkqy class-name_vjnt1", + "class-name": "class-name_vimvb", + "sub-class": "sub-class_sfjs8 class-name_vimvb", }); - expect(result.code).equals(`.class-name_vjnt1 { + expect(result.code).equals(`.class-name_vimvb { background: red; color: #ff0 } -.sub-class_sgkqy { +.sub-class_sfjs8 { background: blue }`); }); @@ -424,15 +424,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - "class-name": "className_vjnt1", - "sub-class": "subClass_sgkqy className_vjnt1", + "class-name": "className_vimvb", + "sub-class": "subClass_sfjs8 className_vimvb", }); - expect(result.code).equals(`.className_vjnt1 { + expect(result.code).equals(`.className_vimvb { background: red; color: #ff0 } -.subClass_sgkqy { +.subClass_sfjs8 { background: blue }`); }); @@ -457,15 +457,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - className: "className_agkqy", - subClass: "subClass_nfjpx className_agkqy", + className: "className_afjs8", + subClass: "subClass_neir7 className_afjs8", }); - expect(result.code).equals(`.className_agkqy { + expect(result.code).equals(`.className_afjs8 { background: red; color: #ff0 } -.subClass_nfjpx { +.subClass_neir7 { background: blue }`); }); @@ -490,15 +490,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - className: "class-name_agkqy", - subClass: "sub-class_nfjpx class-name_agkqy", + className: "class-name_afjs8", + subClass: "sub-class_neir7 class-name_afjs8", }); - expect(result.code).equals(`.class-name_agkqy { + expect(result.code).equals(`.class-name_afjs8 { background: red; color: #ff0 } -.sub-class_nfjpx { +.sub-class_neir7 { background: blue }`); }); @@ -523,15 +523,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - className: "className_vjnt1", - subClass: "subClass_sgkqy className_vjnt1", + className: "className_vimvb", + subClass: "subClass_sfjs8 className_vimvb", }); - expect(result.code).equals(`.className_vjnt1 { + expect(result.code).equals(`.className_vimvb { background: red; color: #ff0 } -.subClass_sgkqy { +.subClass_sfjs8 { background: blue }`); }); @@ -556,15 +556,15 @@ composes: button cell title from "${url.pathname.replace(root.pathname, "")}"; }, ).then((result) => { expect(result.mapping).deep.equals({ - "class-name": "class-name_agkqy", - "sub-class": "sub-class_nfjpx class-name_agkqy", + "class-name": "class-name_afjs8", + "sub-class": "sub-class_neir7 class-name_afjs8", }); - expect(result.code).equals(`.class-name_agkqy { + expect(result.code).equals(`.class-name_afjs8 { background: red; color: #ff0 } -.sub-class_nfjpx { +.sub-class_neir7 { background: blue }`); }); @@ -657,32 +657,32 @@ a span { ).then((result) => { expect(result.importMapping).deep.equals({ "./test/css-modules/mixins.css": { - title: "title_seiow_mixins", - cell: "cell_s04ai_mixins", - button: "button_egkqy_mixins", + title: "title_sdhq6_mixins", + cell: "cell_sz3cs_mixins", + button: "button_efjs8_mixins", }, }); expect(result.mapping).deep.equals({ - goal: "goal_r7bhp", - "bg-indigo": "bg-indigo_gy28g", + goal: "goal_r6ajz", + "bg-indigo": "bg-indigo_gx1aq", "indigo-white": - "indigo-white_wims0 title block ruler bg-indigo_gy28g button_egkqy_mixins cell_s04ai_mixins title_seiow_mixins", + "indigo-white_whlua title block ruler bg-indigo_gx1aq button_efjs8_mixins cell_sz3cs_mixins title_sdhq6_mixins", }); expect(result.code).equals(`:import("./test/css-modules/mixins.css") { - button_egkqy_mixins: button; - cell_s04ai_mixins: cell; - title_seiow_mixins: title; + button_efjs8_mixins: button; + cell_sz3cs_mixins: cell; + title_sdhq6_mixins: title; } :export { - goal: goal_r7bhp; - bg-indigo: bg-indigo_gy28g; - indigo-white: indigo-white_wims0 title block ruler bg-indigo_gy28g button_egkqy_mixins cell_s04ai_mixins title_seiow_mixins; + goal: goal_r6ajz; + bg-indigo: bg-indigo_gx1aq; + indigo-white: indigo-white_whlua title block ruler bg-indigo_gx1aq button_efjs8_mixins cell_sz3cs_mixins title_sdhq6_mixins; } -.goal_r7bhp .bg-indigo_gy28g { +.goal_r6ajz .bg-indigo_gx1aq { background: indigo } -.indigo-white_wims0 { +.indigo-white_whlua { color: #fff }`); }); @@ -769,15 +769,15 @@ a span { }, ).then((result) => { expect(result.code).equals(`:export { - button: button_oims0; - green: green_znrx5; + button: button_ohlua; + green: green_zmqzf; } -.button_oims0 { +.button_ohlua { color: light-dark(#0c77f8,#ff0020); display: inline-block } @supports (border-color:green) and (color:color(from green srgb r g b/.5)) { - .green_znrx5 .button_oims0 { + .green_zmqzf .button_ohlua { color: #aaf201 } }`); @@ -965,15 +965,15 @@ a span { ); expect(result.mapping).deep.equals({ - goal: "goal_r7bhp", - "bg-indigo": "bg-indigo_gy28g", - "indigo-white": "indigo-white_wims0 bg-indigo_gy28g title_qw06e", - title: "title_qw06e", + goal: "goal_r6ajz", + "bg-indigo": "bg-indigo_gx1aq", + "indigo-white": "indigo-white_whlua bg-indigo_gx1aq title_qvz8o", + title: "title_qvz8o", }); - expect(result.code).equals(`.goal_r7bhp .bg-indigo_gy28g { + expect(result.code).equals(`.goal_r6ajz .bg-indigo_gx1aq { background: indigo } -.indigo-white_wims0 { +.indigo-white_whlua { color: #fff }`); }); @@ -1008,5 +1008,179 @@ a span { `Unsupported hash algorithm: 'sha1'. Not supported by parseSync() or transformSync(). Use parse() or transform().`, ); }); + + it("module pattern #26", function () { + const file = new URL(dirname(import.meta.url) + "/../../css-modules/button.css"); + + return transform({ + file: file.pathname, + beautify: true, + module: { + pattern: "[local]-name-[name]-folder-[folder]-ext-[ext]-path-[path]-hash-[hash:base64:5]", + }, + }).then((result) => { + expect(result.code) + .equals(`.button-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YnV0d { + background-color: #007bff; + color: #fff; + padding: 10px 20px; + border: 0; + cursor: pointer; + border-radius: 4px +} +.button-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YnV0d:hover { + background-color: #0056b3 +} +@property --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ { + syntax: ""; + inherits: false; + initial-value: 25% +} +.bar-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YmFyO { + display: inline-block; + --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ: 25%; + width: 100%; + height: 5px; + background: linear-gradient(90deg,#00d230 var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ),#000 var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ)); + animation: progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ 2.5s infinite +} +@keyframes progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ { + to { + --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ: 100% + } +} +.body-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-Ym9ke { + background: #6e28d9; + padding: 0 24px; + color: #fff; + margin: 0; + height: 100vh; + justify-content: center; + align-items: center +} +.animation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YW5pb { + display: block; + width: var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ); + animation: progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ infinite alternate 3s; + background: red +}`); + }); + }); + + it("module pattern #27", function () { + const file = new URL(dirname(import.meta.url) + "/../../css-modules/button.css"); + + const result = transformSync({ + src: file.pathname, + input: `/* Button.module.css file */ + +.button { + background-color: #007bff; + color: #ffffff; + padding: 10px 20px; + border: none; + cursor: pointer; + border-radius: 4px; +} + +.button:hover { + background-color: #0056b3; +} + +@property --progress { + syntax: ""; + inherits: false; + initial-value: 25%; +} + +.bar { + display: inline-block; + --progress: 25%; + width: 100%; + height: 5px; + background: linear-gradient( + to right, + #00d230 var(--progress), + black var(--progress) + ); + animation: progressAnimation 2.5s ease infinite; +} + +@keyframes progressAnimation { + to { + --progress: 100%; + } +} + +.body { + background: #6e28d9; + padding: 0 24px; + color: white; /* Change my color to yellow */ + margin: 0; + height: 100vh; + justify-content: center; + align-items: center; + +} + +.animation { + display: block; + width: var(--progress); + animation: progressAnimation infinite alternate 3s; + background: red; +} +`, + beautify: true, + module: { + pattern: "[local]-name-[name]-folder-[folder]-ext-[ext]-path-[path]-hash-[hash:base64:5]", + }, + }); + + expect(result.code) + .equals(`.button-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YnV0d { + background-color: #007bff; + color: #fff; + padding: 10px 20px; + border: 0; + cursor: pointer; + border-radius: 4px +} +.button-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YnV0d:hover { + background-color: #0056b3 +} +@property --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ { + syntax: ""; + inherits: false; + initial-value: 25% +} +.bar-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YmFyO { + display: inline-block; + --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ: 25%; + width: 100%; + height: 5px; + background: linear-gradient(90deg,#00d230 var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ),#000 var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ)); + animation: progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ 2.5s infinite +} +@keyframes progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ { + to { + --progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ: 100% + } +} +.body-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-Ym9ke { + background: #6e28d9; + padding: 0 24px; + color: #fff; + margin: 0; + height: 100vh; + justify-content: center; + align-items: center +} +.animation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-YW5pb { + display: block; + width: var(--progress-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ); + animation: progressAnimation-name-button-folder-css-modules-ext-css-path-test_css-modules_button_css-hash-cHJvZ infinite alternate 3s; + background: red +}`); + }); }); } diff --git a/test/specs/code/sourcemaps.js b/test/specs/code/sourcemaps.js index 7a4f3038..356d1192 100644 --- a/test/specs/code/sourcemaps.js +++ b/test/specs/code/sourcemaps.js @@ -48,7 +48,7 @@ button { return transform(options).then(async (result) => { // result.map.computePositions(); let positions = result.map.find(40, 2); - expect(positions?.length == 1 && positions[0].slice(0, 3)).deep.equals([null, 6, 2]); + expect(positions?.length == 1 && positions[0].slice(0, 3)).deep.equals([null, 6, 1]); }); }); @@ -63,46 +63,11 @@ button { // result2.map.computePositions(); let positions = result2.map.find(1, 254); - expect(positions?.[0]?.slice?.(0, 3)).deep.equals([null, 19, 2]); - - positions = result2.map.find(1, 255); - expect(positions).equals(null); + expect(positions?.[0]?.slice?.(0, 3)).deep.equals(["files/css/nested.css", 1, 207]); positions = result2.map.find(100, 255); expect(positions).equals(null); }); }); - - it("input sourcemap minified #3", async () => { - return transform({ ...options, sourcemap: true }).then(async (result) => { - const result2 = transformSync({ - input: result.code, - nestingRules: false, - sourcemap: "inline", - inputSourceMap: result.map.toJSON(), - output: "test/sourcemap.html", - }); - - // result2.map.computePositions(); - const positions = result2.map.find(1, 254); - expect(positions?.[0]?.slice?.(0, 3)).deep.equals([null, 19, 2]); - }); - }); - - it("input sourcemap minified #3", async () => { - return transform({ ...options, sourcemap: true }).then(async (result) => { - const result2 = transformSync({ - input: result.code, - nestingRules: false, - sourcemap: "inline", - inputSourceMap: `data:application/json;charset=utf-8;${encodeURIComponent(JSON.stringify(result.map.toJSON()))}`, - output: "test/sourcemap.html", - }); - - // result2.map.computePositions(); - const positions = result2.map.find(1, 254); - expect(positions?.[0]?.slice?.(0, 3)).deep.equals([null, 19, 2]); - }); - }); }); } diff --git a/test/specs/code/walk.js b/test/specs/code/walk.js index 5d3d0dd4..77bd8014 100644 --- a/test/specs/code/walk.js +++ b/test/specs/code/walk.js @@ -48,11 +48,13 @@ export function run(describe, expect, it, transform, parse, render, dirname, rea ]; return parse(css, { minify: false }).then((r) => { + + let i = 0; for (const s of walk(r.ast)) { - expect(s.node.typ).equals(values.shift()); + expect(s.node.typ).equals(values[i++]); } - expect(values.length).equals(0); + expect(values.length).equals(i); }); }); diff --git a/typedoc.config.js b/typedoc.config.js index 43cb0480..75cd0791 100644 --- a/typedoc.config.js +++ b/typedoc.config.js @@ -9,7 +9,7 @@ export default { Benchmark: "https://tbela99.github.io/css-parser/benchmark/index.html", Docs: "https://tbela99.github.io/css-parser/docs/", Playground: "https://tbela99.github.io/css-parser/playground/", - "llm.txt": "https://tbela99.github.io/css-parser/llms.txt", + "llms.txt": "https://tbela99.github.io/css-parser/llms.txt", GitHub: "https://github.com/tbela99/css-parser", }, highlightLanguages: ["ts", "css", "javascript", "json", 'html', 'shell'],