From de11344822f1dc27d65dc23714f0d803d3afe219 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Thu, 20 Aug 2026 15:22:09 -0400 Subject: [PATCH 01/11] add string intern and arena --- src/lib/ast/node.ts | 118 +++++++++++++++++++++++++++++++++ src/lib/parser/arena.ts | 60 +++++++++++++++++ src/lib/parser/utils/intern.ts | 56 ++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 src/lib/ast/node.ts create mode 100644 src/lib/parser/arena.ts create mode 100644 src/lib/parser/utils/intern.ts diff --git a/src/lib/ast/node.ts b/src/lib/ast/node.ts new file mode 100644 index 00000000..c34b7bdf --- /dev/null +++ b/src/lib/ast/node.ts @@ -0,0 +1,118 @@ +import type { AstNode, SourceLocation } from "../../@types/ast.d.ts"; +import type { ErrorDescription, Token } from "../../@types/index.d.ts"; +import { ERRORS, LOC, PARENT, STATE, TOKENS } from "../syntax/constants.ts"; +import { AstNodePropertyType, EnumAstNodeStatus } from "./types.ts"; + +/** + * + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: "location", value: SourceLocation): void; +/** + * + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: "state", value: EnumAstNodeStatus): void; +/** + * + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: "errors", value: ErrorDescription[]): void; +/** + * + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: "tokens", value: Token[]): void; +/** + * + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: "parent", value: AstNode | Token): void; + +/** + * set node property + * @param node + * @param property + * @param value + */ +export function setNodeProperty(node: AstNode, property: AstNodePropertyType, value: any): void { + switch (property) { + case "location": + node[LOC] = value; + break; + case "state": + node[STATE] = value; + break; + case "errors": + node[ERRORS] = value; + break; + case "tokens": + node[TOKENS] = value; + break; + case "parent": + node[PARENT] = value; + break; + } +} + +/** + * + * @param node + * @param property + */ +export function getNodeProperty(node: AstNode, property: "location"): SourceLocation | null; +/** + * + * @param node + * @param property + */ +export function getNodeProperty(node: AstNode, property: "state"): EnumAstNodeStatus | null; +/** + * + * @param node + * @param property + */ +export function getNodeProperty(node: AstNode, property: "errors"): ErrorDescription[] | null; +/** + * + * @param node + * @param property + */ +export function getNodeProperty(node: AstNode, property: "tokens"): Token[] | null; +/** + * + * @param node + * @param property + */ +export function getNodeProperty(node: AstNode, property: "parent"): AstNode | Token | null; + +/** + * get node property + * @param node + * @param property + * @returns + */ +export function getNodeProperty(node: AstNode, property: AstNodePropertyType): any { + switch (property) { + case "location": + return node[LOC]; + case "state": + return node[STATE]; + case "errors": + return node[ERRORS]; + case "tokens": + return node[TOKENS]; + case "parent": + return node[PARENT]; + } +} diff --git a/src/lib/parser/arena.ts b/src/lib/parser/arena.ts new file mode 100644 index 00000000..14b6c1fc --- /dev/null +++ b/src/lib/parser/arena.ts @@ -0,0 +1,60 @@ +class ArenaData { + private count: number = 0; + private kind: Uint8Array; + private nodes: Uint32Array; + private parents: Uint32Array; + private data: Uint32Array; + private children: Uint32Array; + private childrenLen: Uint32Array; + private args: Uint32Array; + private argsLen: Uint8Array; + private spans: Uint32Array; + private source: Uint8Array; + + constructor(size: number = 1024) { + this.kind = new Uint8Array(size); + this.nodes = new Uint32Array(size); + this.parents = new Uint32Array(size); + this.data = new Uint32Array(size); + this.source = new Uint8Array(size); + this.children = new Uint32Array(size); + this.childrenLen = new Uint32Array(size); + this.args = new Uint32Array(size); + this.argsLen = new Uint8Array(size); + this.spans = new Uint32Array(size); + } + + private grow() { + const kind = new Uint8Array(this.kind.length * 2); + kind.set(this.kind); + const nodes = new Uint32Array(this.nodes.length * 2); + nodes.set(this.nodes); + const parents = new Uint32Array(this.parents.length * 2); + parents.set(this.parents); + const data = new Uint32Array(this.data.length * 2); + data.set(this.data); + const source = new Uint8Array(this.source.length * 2); + source.set(this.source); + const children = new Uint32Array(this.children.length * 2); + children.set(this.children); + const childrenLen = new Uint32Array(this.childrenLen.length * 2); + childrenLen.set(this.childrenLen); + const args = new Uint32Array(this.args.length * 2); + args.set(this.args); + const argsLen = new Uint8Array(this.argsLen.length * 2); + argsLen.set(this.argsLen); + const spans = new Uint32Array(this.spans.length * 2); + spans.set(this.spans); + + this.kind = kind; + this.nodes = nodes; + this.parents = parents; + this.data = data; + this.source = source; + this.children = children; + this.childrenLen = childrenLen; + this.args = args; + this.argsLen = argsLen; + this.spans = spans; + } +} 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 From 041086c524e6c4033a9b992c290ea9c318dfd8a1 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Fri, 21 Aug 2026 16:51:48 -0400 Subject: [PATCH 02/11] use Float32Array instead of generic array --- dist/index-umd-web.js | 46 ++++++++++++++------- dist/index.cjs | 46 ++++++++++++++------- dist/lib/ast/transform/compute.js | 2 +- dist/lib/ast/transform/minify.js | 10 ++--- dist/lib/ast/transform/perspective.js | 2 +- dist/lib/ast/transform/rotate.js | 2 +- dist/lib/ast/transform/scale.js | 2 +- dist/lib/ast/transform/skew.js | 2 +- dist/lib/ast/transform/translate.js | 2 +- dist/lib/ast/transform/utils.js | 38 ++++++++++++------ src/lib/ast/transform/minify.ts | 8 ++-- src/lib/ast/transform/type.d.ts | 4 +- src/lib/ast/transform/utils.ts | 41 +++++++++++++------ src/lib/parser/arena.ts | 57 +++++---------------------- 14 files changed, 145 insertions(+), 117 deletions(-) diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 08381ca2..6f54131d 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -19795,8 +19795,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,16 +19811,31 @@ 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) { @@ -20472,7 +20488,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) { @@ -20534,10 +20550,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") { diff --git a/dist/index.cjs b/dist/index.cjs index fceaa1b3..4ed63c7a 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -19798,8 +19798,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,16 +19814,31 @@ 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) { @@ -20475,7 +20491,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) { @@ -20537,10 +20553,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/compute.js b/dist/lib/ast/transform/compute.js index 409a15c7..4401951d 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'; diff --git a/dist/lib/ast/transform/minify.js b/dist/lib/ast/transform/minify.js index bb83a9e6..6a35f512 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) { @@ -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..453e3056 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,16 +16,31 @@ 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) { diff --git a/src/lib/ast/transform/minify.ts b/src/lib/ast/transform/minify.ts index 48783725..41b7e0aa 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; @@ -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..479c6612 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; } diff --git a/src/lib/parser/arena.ts b/src/lib/parser/arena.ts index dd4989f9..4ea81862 100644 --- a/src/lib/parser/arena.ts +++ b/src/lib/parser/arena.ts @@ -2,80 +2,43 @@ import { StringInterner } from "./utils/intern.ts"; class ArenaData { private count: number = 0; - private kind: Uint8Array; private nodes: Uint32Array; /** - * node token data + * 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 args: Uint32Array; - private argsLen: Uint8Array; - private spans: Uint32Array; private source: Uint8Array; private strings: StringInterner = new StringInterner(); constructor(size: number = 1024) { - this.kind = new Uint8Array(size); this.nodes = new Uint32Array(size); - this.parents = new Uint32Array(size); this.data = new Uint32Array(size); - this.source = new Uint8Array(size); - this.children = new Uint32Array(size); - this.childrenLen = new Uint32Array(size); - this.args = new Uint32Array(size); - this.argsLen = new Uint8Array(size); - this.spans = new Uint32Array(size); + this.source = new Uint8Array(5); + this.strings = new StringInterner(); } - allocate(kind: number, node: number, parent: number, data: number, source: number, children: number, childrenLen: number, args: number, argsLen: number, spans: number) { - if (this.count === this.kind.length) { + allocate(kind: number, node: number, parent: number, data: number, source: number) { + if (this.count === this.nodes.length) { this.grow(); } - this.kind[this.count] = kind; this.nodes[this.count] = node; - this.parents[this.count] = parent; this.data[this.count] = data; this.source[this.count] = source; - this.children[this.count] = children; - this.childrenLen[this.count] = childrenLen; - this.args[this.count] = args; - this.argsLen[this.count] = argsLen; - this.spans[this.count] = spans; return this.count++; } private grow() { - const kind = new Uint8Array(this.kind.length * 2); - kind.set(this.kind); const nodes = new Uint32Array(this.nodes.length * 2); - nodes.set(this.nodes); - const parents = new Uint32Array(this.parents.length * 2); - parents.set(this.parents); const data = new Uint32Array(this.data.length * 2); + + nodes.set(this.nodes); data.set(this.data); - const source = new Uint8Array(this.source.length * 2); - source.set(this.source); - const children = new Uint32Array(this.children.length * 2); - children.set(this.children); - const childrenLen = new Uint32Array(this.childrenLen.length * 2); - childrenLen.set(this.childrenLen); - const args = new Uint32Array(this.args.length * 2); - args.set(this.args); - const argsLen = new Uint8Array(this.argsLen.length * 2); - argsLen.set(this.argsLen); - const spans = new Uint32Array(this.spans.length * 2); - spans.set(this.spans); - this.kind = kind; this.nodes = nodes; - this.parents = parents; this.data = data; - this.source = source; - this.children = children; - this.childrenLen = childrenLen; - this.args = args; - this.argsLen = argsLen; - this.spans = spans; } } From cbc80cf43187b65853d119dab4714601a1ca95b5 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Thu, 27 Aug 2026 09:32:52 -0400 Subject: [PATCH 03/11] remove buffer variable to reduce allocations --- CHANGELOG.md | 2 + README.md | 14 +- dist/index-umd-web.js | 9542 +++++++++++--------- dist/index.cjs | 9538 ++++++++++--------- dist/index.d.ts | 31 +- dist/lib/ast/features/calc.js | 72 +- dist/lib/ast/features/if.js | 10 +- dist/lib/ast/math/expression.js | 204 +- dist/lib/ast/minify.js | 9 +- dist/lib/ast/node.js | 8 +- dist/lib/ast/walk.js | 2 + dist/lib/parser/declaration/list.js | 22 +- dist/lib/parser/linesmap.js | 6 +- dist/lib/parser/parse.js | 505 +- dist/lib/parser/tokenize.js | 2085 +++-- dist/lib/parser/utils/at-rule-container.js | 212 +- dist/lib/parser/utils/at-rule-generic.js | 13 +- dist/lib/parser/utils/at-rule-import.js | 14 +- dist/lib/parser/utils/at-rule-media.js | 43 +- dist/lib/parser/utils/at-rule-support.js | 24 +- dist/lib/parser/utils/at-rule-when-else.js | 45 +- dist/lib/parser/utils/at-rule.js | 18 - dist/lib/parser/utils/declaration.js | 121 +- dist/lib/parser/utils/hash.js | 8 +- dist/lib/parser/utils/selector.js | 229 +- dist/lib/parser/utils/text.js | 6 +- dist/lib/renderer/render.js | 113 +- dist/lib/syntax/color/color.js | 6 +- dist/lib/syntax/color/relative-color.js | 32 +- dist/lib/syntax/constants.js | 12 +- dist/lib/syntax/syntax.js | 112 +- dist/lib/validation/config.json.js | 3 + dist/lib/validation/match.js | 36 +- dist/node.js | 4 +- dist/web.js | 8 +- files/usage.md | 28 +- src/@types/ast.d.ts | 19 +- src/@types/walker.d.ts | 3 +- src/lib/ast/features/calc.ts | 181 +- src/lib/ast/features/if.ts | 11 +- src/lib/ast/math/expression.ts | 211 +- src/lib/ast/minify.ts | 9 +- src/lib/ast/node.ts | 8 +- src/lib/ast/walk.ts | 2 + src/lib/parser/arena.ts | 11 +- src/lib/parser/declaration/list.ts | 33 +- src/lib/parser/linesmap.ts | 7 +- src/lib/parser/parse.ts | 533 +- src/lib/parser/source.ts | 2 +- src/lib/parser/tokenize.ts | 2583 ++++-- src/lib/parser/utils/at-rule-container.ts | 242 +- src/lib/parser/utils/at-rule-generic.ts | 18 +- src/lib/parser/utils/at-rule-import.ts | 22 +- src/lib/parser/utils/at-rule-media.ts | 66 +- src/lib/parser/utils/at-rule-support.ts | 24 +- src/lib/parser/utils/at-rule-when-else.ts | 58 +- src/lib/parser/utils/at-rule.ts | 20 - src/lib/parser/utils/declaration.ts | 145 +- src/lib/parser/utils/hash.ts | 15 +- src/lib/parser/utils/selector.ts | 275 +- src/lib/parser/utils/text.ts | 7 +- src/lib/renderer/render.ts | 137 +- src/lib/syntax/color/color.ts | 6 +- src/lib/syntax/color/relative-color.ts | 32 +- src/lib/syntax/constants.ts | 10 + src/lib/syntax/syntax.ts | 60 +- src/lib/validation/config.json | 3 + src/lib/validation/match.ts | 38 +- src/node.ts | 4 +- src/utils/sync.ts | 5 +- src/web.ts | 10 +- test/specs/code/calc.js | 18 +- test/specs/code/color-rec2020.js | 2 +- test/specs/code/modules.js | 190 +- test/specs/code/sourcemaps.js | 39 +- test/specs/code/walk.js | 6 +- 76 files changed, 15403 insertions(+), 12799 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf61c73f..bcf0140b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +- [x] added `tan()` function. + # 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 6f54131d..b8d8997e 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"); @@ -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; @@ -9652,6 +9667,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* () { @@ -9750,6 +9766,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), exports.WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { @@ -9928,7 +9945,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 +9967,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 +9994,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 +10033,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 +10073,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 +10116,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 +10147,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 +10212,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 +10228,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 +10277,9 @@ { ...v1[0], val: Math.pow(val1, val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10150,8 +10288,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 +10301,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 +10340,9 @@ { ...values[0], val: Math.log(val1) / Math.log(val2), - [LOC]: token[LOC], + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], }, ]; } @@ -10232,7 +10378,7 @@ : 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 +10396,12 @@ result.push(token); } else { - result.push(...inlineExpression$1(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression$1(token.r)); + result.push(...inlineExpression$1(token.l), { + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, ...inlineExpression$1(token.r)); } } else { @@ -10313,7 +10464,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 +10508,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--; } @@ -10456,19 +10615,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 +10646,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 +10687,9 @@ return { typ: exports.EnumToken.NumberTokenType, val: value, - [LOC]: t[LOC], + [LOCSRCID]: t[LOCSRCID], + [LOCSTA]: t[LOCSTA], + [LOCEND]: t[LOCEND], }; } return t; @@ -10561,8 +10732,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 }); } @@ -10941,7 +11114,7 @@ [LOC]: pos, }; } - if (isPseudo$1(token)) { + if (isPseudo(token)) { return { typ: ValidationTokenEnum.PseudoClassToken, val: token, @@ -12058,7 +12231,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]), }, ], }; @@ -12112,7 +12285,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 +12319,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 +12363,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 +12414,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 +12426,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 +12465,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 +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], @@ -12355,7 +12528,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]), }, ], }; @@ -12398,7 +12571,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 +12593,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,7 +12619,7 @@ 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]), }, ], }; @@ -12493,7 +12666,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 +12761,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, @@ -14374,7 +14547,9 @@ chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], kin: exports.ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } @@ -15043,7 +15218,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 +15267,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 +15404,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 @@ -15861,7 +16041,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 +16049,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 +16089,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 +16103,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)); } @@ -19280,7 +19375,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 +19406,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 +19486,7 @@ class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; + // ketsey = new Map; constructor(options = {}) { this.options = options; this.declarations = new Map(); @@ -19410,12 +19506,12 @@ name = declaration.typ != exports.EnumToken.DeclarationNodeType ? null - : declaration.nam.toLowerCase(); + : 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 +19539,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; @@ -19668,57 +19778,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 +19833,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 +19849,9 @@ typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; } @@ -21272,7 +21344,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"; @@ -21297,7 +21371,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 @@ -21381,3336 +21457,2279 @@ 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; + 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); } - else { - const should_negate = value & 1; - value >>>= 1; - if (should_negate) { - result.push(value === 0 ? -2147483648 : -value); + 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; } - else { - result.push(value); + 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); + } + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } + } + } + 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); } - // reset - value = shift = 0; } } - 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; + 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; } - 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)); + 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; } - else { - sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); + if (result != null) { + replacement = result; } } - 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)) { - continue; - } - this.map.set(index, decodedMappings[index]); - } - this.computePositions(); + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); } - } - /** - * add source - * @param id - * @param fileName - * @param content - * @returns - */ - addSourceContent(id, fileName, content) { - if (this.sourcesMap.includes(id)) { - return; + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } } - 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]; - } - for (let [newLine, newColumn, srcId, ln, col] of maps) { - const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; - if (this.keys.has(key)) { - continue; - } - 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; + 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.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 { - mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); + else if (hasUpdates) { + tokens.length = 0; + tokens.push(...[...sections.values()].reduce((acc, t) => { + if (acc.length > 0) { + acc.push({ + typ: exports.EnumToken.CommaTokenType, + }); } - } - return { - version: this.version, - sources: this.sources.slice(), - sourcesContent: this.sourcesContent?.slice(), - mappings: mappings.join(";"), - }; + acc.push(...t); + 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); + 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; + } + 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; } - 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; + while (previous?.typ === exports.EnumToken.CommentNodeType) { + // @ts-ignore + previous = ast.chi[--nodeIndex]; } - 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); + node = ast.chi[i]; + if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { 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; - } - } - else { - if (end < 0) { - j += end; - } - else { - j = parseInfo.position + end; - } - } - } - 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; - } - 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; - } - /** - * 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)); - } - 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)); + 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; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - 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 + previous.chi.push(...node.chi); + // @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; + 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; + } } - 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) { + // @ts-ignore + previous.chi.push(...node.chi); + 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)) { + // @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); + } + } + } + } + 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(","); + } + 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; } /** - * 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; - } + } + } + 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 === "") { + wrapper.chi.push(...previous.chi); + if (nSel == "&" || nSel === "") { + wrapper.chi.push(...node.chi); + } + 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; } - 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)), ""); + prefixes1.add(matches[1]); + if (prefixes1.size > 1) { + break; } } - 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); - } + } + 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; + } + prefixes2.add(matches[1]); + if (prefixes2.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); - 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); - } - } - } - } - 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 + 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); + } + 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; + } + } + } + } + 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 (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; + } + } + } + return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; + } + /** + * Reduce rule selector * @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; + 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; + } + 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(); + } + } + 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); + } + 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; } - // @ts-ignore - return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; } - return true; } + /** - * Optimize selector - * @param selector + * expand css nesting ast nodes + * @param ast * * @private */ - function optimizeSelector(selector) { - const map = new Set(); - selector = selector - .reduce((acc, curr) => { - // @ts-ignore - if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { + 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; + } // @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); + result.chi.push(...children); + } + 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; } - 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; + if (hasRule) { + node = expand(node); + for (const child of node.chi) { + child[PARENT] = result; + } + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); + } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - if (!match) { - break; + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } - optimized.push(item); } - while (optimized.length > 0) { - const last = optimized.at(-1); - if (last == " " || combinators.includes(last)) { - optimized.pop(); - continue; - } - 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); - } - } - 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 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 { - 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; + 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)); } - if (reducible) { - const chr = curr[0].charAt(0); + 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 - reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); + result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); + ast.chi.splice(i--, 1); } - acc.push(hasCompound ? ["&"].concat(curr) : curr); - return acc; - }, []), - reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), - }; + } + } + // @ts-ignore + return ast.chi.length > 0 ? [ast].concat(result) : result; } /** - * Split selector string - * @param buffer - * - * @internal + * replace compound selector + * @param input + * @param replace */ - 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(" "); + 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; } - // 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); - } - 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; + const rule = splitRule(replace); + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: rule.length > 1 ? ":is(" + replace + ")" : replace, + }); } } - if (str !== "") { - result.at(-1).push(str); + 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("&", ""); + } } - return result; + 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; } /** - * Reduce selector - * @param acc - * @param curr - * - * @private + * @param {string} str */ - 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; + 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; } - 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 { + const should_negate = value & 1; + value >>>= 1; + if (should_negate) { + result.push(value === 0 ? -2147483648 : -value); } - else if (token == ")") ; - else if (token == ",") { - if (!canReduce) { - canReduce = curr[index + 1] == "&"; - } - acc.push([]); + else { + result.push(value); } - 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; - }, []); + // reset + value = shift = 0; } } - 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; + return result; } /** - * Match selectors - * @param selector1 - * @param selector2 * - * @private + * @param value + * @returns */ - 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]; - } - } - } + function encode(value) { + if (typeof value === 'number') { + return encode_integer(value); } - 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 result = ''; + for (let i = 0; i < value.length; i += 1) { + result += encode_integer(value[i]); } - for (; i < j; i++) { - k = 0; - token = selector1[0][i]; - for (; k < selector1.length; k++) { - if (selector1[k][i] != token) { - matching = false; - 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; } - if (matching) { - l = 0; - for (; l < selector2.length; l++) { - if (selector2[l][i] != token) { - matching = false; - 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)); } } + sourcemaps = JSON.parse(sourcemaps); } - if (!matching) { - break; - } - if (token.endsWith("(")) { - matchFunction++; + 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(); } - match.at(-1).push(token); } - // invalid function - if (matchFunction != 0 || inAttr != 0) { - return null; + /** + * 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; } - 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(); + /** + * Add all location + * @param maps + * @throws + */ + 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)) { continue; } - 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; } } - 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 = [...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); - } + /** + * 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 []; + } + generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; + result = [generatedCodeColumn]; + if (segment.length <= 1) { + return result; + } + 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); } - 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 === "") { - wrapper.chi.push(...previous.chi); - if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); + /** + * retrieve original sources, lines and columns + * @param line generated line + * @param column generated column + */ + find(line, column) { + if (this.reverseMap.size == 0) { + this.computePositions(); } - else { - wrapper.chi.push(node); + if (!this.reverseMap.has(--line)) { + return null; } - } - 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; - } - prefixes1.add(matches[1]); - if (prefixes1.size > 1) { - break; - } - } + column--; + const result = []; + for (const record of this.reverseMap.get(line)) { + if (record.length == 0 || record[0] < column) { + continue; } - if (prefixes1.size > 1) { + if (record[0] > column) { break; } + result.push([ + this.sources?.[record[1]] ?? null, + record[2] + 1, + record[3] + 1, + this.sourcesContent?.[record[1]] ?? null, + ]); } - 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; - } - } + 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()))}`; + } + /** + * Convert to JSON object + */ + toJSON() { + const mappings = []; + let i = 0; + for (; i <= this.line; i++) { + if (!this.map.has(i)) { + mappings.push(""); } - if (prefixes2.size > 1) { - break; + else { + mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); } } - if (prefixes1.size != prefixes2.size) { - return null; + return { + version: this.version, + sources: this.sources.slice(), + sourcesContent: this.sourcesContent?.slice(), + mappings: mappings.join(";"), + }; + } + } + + /** + * Compute line and column of the offset + */ + class LineMap { + /** + * line starts + */ + lineStarts; + /** + * Constructor + * @param lines + */ + constructor(lines = []) { + if (lines.length === 0) { + lines.push(0); } - for (const prefix of prefixes1) { - if (!prefixes2.has(prefix)) { - return null; + this.lineStarts = lines; + } + /** + * 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; + } + else if (this.lineStarts[mid] > offset) { + end = mid - 1; } } + return result; } - 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); + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts; } - if (css2 != null) { - options.cache.set(node2, css2); + /** + * add line start + */ + addLineStart(lineStart) { + this.lineStarts.push(lineStart); } - if (raw1 != null) { - node1[RAW] = raw1; + } + + /** + * match url + */ + const matchUrl = /^(https?:)?\/\//; + /** + * return the directory name of a path + * @param path + * + * @private + */ + function dirname(path) { + if (path === "") { + return ""; } - if (raw2 != null) { - node2[RAW] = raw2; + if (path.startsWith("data:")) { + return path; } - const intersect = []; - while (i--) { - if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; + let i = 0; + let parts = [""]; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + parts.push(""); } - 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; - } - } - } - } - 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 (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; - } + else { + parts[parts.length - 1] += chr; } } - return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; + parts.pop(); + return parts.join("/"); } /** - * Reduce rule selector - * @param node - * + * split path + * @param result * @private */ - 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; + function splitPath(result) { + if (result.length == 0) { + return { parts: [], i: 0 }; } - 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(); - } + const parts = result == "/" ? [] : [""]; + let i = 0; + for (; i < result.length; i++) { + const chr = result.charAt(i); + if (chr == "/") { + parts.push(""); } - 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); - } - 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; + // 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 }; } - /** - * expand css nesting ast nodes - * @param ast - * + * Nomalize 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; + const normalize = memoize(function (path) { + let parts = []; + let i = 0; + if (path.includes("\\")) { + path = path.replace(/(\\)/g, "/"); } - 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; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + if (parts.length == 0 || parts[parts.length - 1] !== "") { + parts.push(""); } - // @ts-ignore - result.chi.push(...children); } - 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 { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); - } + else if (chr == "?" || chr == "#") { + break; } else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + if (parts.length == 0) { + parts.push(""); + } + parts[parts.length - 1] += chr; } } - 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]; + 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; + } } - 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); - } - } - } - // @ts-ignore - return ast.chi.length > 0 ? [ast].concat(result) : result; - } + return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); + }); /** - * replace compound selector - * @param input - * @param replace + * diff path + * @param path1 + * @param path2 + * @private */ - 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, - }); + 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(); } - } - 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("&", ""); + else { + parts.unshift(".."); } } - 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?:)?\/\//; + return parts.join("/"); + }); /** - * return the directory name of a path - * @param path + * resolve path + * @param url url or path to resolve + * @param currentDirectory directory used to resolve the path + * @param cwd current working directory * * @private */ - function dirname(path) { - if (path === "") { - return ""; + const resolve = memoize(function (url, currentDirectory, cwd) { + if (matchUrl.test(url)) { + return { + absolute: url, + relative: url, + }; } - if (path.startsWith("data:")) { - return path; + cwd ??= ""; + currentDirectory ??= ""; + url = normalize(url); + if (cwd !== "") { + cwd = normalize(cwd); } - let i = 0; - let parts = [""]; - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - parts.push(""); - } - else { - parts[parts.length - 1] += chr; - } + if (currentDirectory !== "") { + currentDirectory = normalize(currentDirectory); } - parts.pop(); - return parts.join("/"); - } + 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), + }; + }); /** - * 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, "/"); - } - 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; - } - } - 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 { - parts.unshift(".."); - } - } - 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, - }; - } - cwd ??= ""; - currentDirectory ??= ""; - url = normalize(url); - if (cwd !== "") { - cwd = normalize(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); - return { - absolute, - relative: dir === "" ? absolute : diff(absolute, dir), - }; - }); - /** - * - * @param parts - * @returns + * + * @param parts + * @returns * @private */ function resolvePath(...parts) { @@ -24741,6 +23760,119 @@ return result || (isAbsolute ? "/" : "."); } + /** + * Source file ID + */ + let sourceId = 0; + /** + * Source file helper class + */ + 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); + } + /** + * return input source map + * @returns + */ + getInputSourceMap() { + return this.inputSourceMap; + } + } + /** * render ast * @param data @@ -24867,43 +23999,34 @@ */ 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]; + // console.error({record}); + 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) @@ -24916,6 +24039,22 @@ } 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); } @@ -24923,23 +24062,24 @@ } } 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]); } + // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -24947,11 +24087,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; @@ -25075,7 +24216,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 { @@ -25083,15 +24223,23 @@ // 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), - ]); + // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; + // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { + // sourcemaps.sources.push(node[LOCSTA] as number); + // } + // sourcemaps.maps.push([ + // ...linesMap!.getOffsets( + // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, + // ), + // node[LOCSTA], + // ...source!.getOffsets(node![LOCSTA]), + // ]); + // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } @@ -25595,483 +24743,2085 @@ } result.push(...size); } - 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); + 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); + } + if (colorSpaceDef.length > 0) { + if (result.length > 0) { + result.push({ typ: exports.EnumToken.WhitespaceTokenType }); + } + result.push(...colorSpaceDef); + } + if (result.length > 0) { + result.push({ typ: exports.EnumToken.CommaTokenType }); + } + result.push(...reduceColorStops(slice.slice(i))); + slice.length = 0; + slice.push(...result); + } + break; + case "conic-gradient": + case "repeating-conic-gradient": + { + let i = 0; + const angles = []; + const positions = []; + const colorSpaceDef = []; + // while ( + // i < slice.length && + // (slice[i].typ === EnumToken.WhitespaceTokenType || + // slice[i].typ === EnumToken.CommentTokenType) + // ) { + // i++; + // } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase(slice[i].val, "from")) { + angles.push(slice[i++]); + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + angles.push(slice[i++]); + } + if ((slice[i]?.typ === exports.EnumToken.NumberTokenType || + slice[i]?.typ === exports.EnumToken.AngleTokenType) && + 0 === toDegrees(slice[i]).val) { + angles.length = 0; + i++; + } + else if (slice[i]?.typ !== exports.EnumToken.CommaTokenType && + slice[i].typ != exports.EnumToken.IdenTokenType) { + angles.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase(slice[i].val, "at")) { + i++; + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + let position1 = ""; + let position2 = ""; + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + !equalsIgnoreCase("in", slice[i].val)) { + position1 = slice[i].val; + positions.push(slice[i++]); + } + else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || + slice[i]?.typ === exports.EnumToken.NumberTokenType) { + position1 = slice[i].val + "%"; + positions.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + positions.push(slice[i++]); + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + !equalsIgnoreCase("in", slice[i].val)) { + position2 = slice[i].val; + positions.push(slice[i++]); + } + else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || + slice[i]?.typ === exports.EnumToken.NumberTokenType) { + position2 = slice[i].val + "%"; + positions.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + if (position1.length > 0) { + reducegradientBackgroundPosition(positions, `${position1} ${position2}`.trim()); + } + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase("in", slice[i].val)) { + while (i < slice.length && slice[i].typ !== exports.EnumToken.CommaTokenType) { + colorSpaceDef.push(slice[i++]); + } + } + if (slice[i]?.typ === exports.EnumToken.CommaTokenType) { + i++; + } + const result = []; + if (positions.length > 0) { + if (positions.length > 0) { + if (angles.length > 0) { + angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); + } + angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + } + } + if (angles.length > 0) { + result.push(...angles, { 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); + } + result.push({ typ: exports.EnumToken.CommaTokenType }); + } + result.push(...reduceConicColorStops(slice.slice(i))); + slice.length = 0; + slice.push(...result); + } + break; + } + return token.val + "(" + slice.reduce(reducer, "") + ")"; + } + case exports.EnumToken.TimingFunctionTokenType: + case exports.EnumToken.PseudoClassFuncTokenType: + case exports.EnumToken.WhenElseFunctionTokenType: + case exports.EnumToken.TimelineFunctionTokenType: + case exports.EnumToken.GridTemplateFuncTokenType: + case exports.EnumToken.SupportsFunctionTokenType: + case exports.EnumToken.ContainerFunctionTokenType: + case exports.EnumToken.TransformFunctionTokenType: + case exports.EnumToken.GeneralEnclosedFunctionTokenType: + case exports.EnumToken.CustomFunctionTokenType: + case exports.EnumToken.WildCardFunctionTokenType: + if (token.typ == exports.EnumToken.MathFunctionTokenType && + token.chi.length == 1 && + ![exports.EnumToken.BinaryExpressionTokenType, exports.EnumToken.FractionTokenType, exports.EnumToken.IdenTokenType].includes(token.chi[0].typ) && + // @ts-ignore + token.chi[0].val + ?.typ != exports.EnumToken.FractionTokenType) { + return (token.val + + "(" + + token.chi.reduce((acc, curr) => acc + + renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + + ")"); + } + return ( + /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + + "(" + + token.chi.reduce(reducer, "") + + ")"); + // case EnumToken.MatchExpressionTokenType: + // return ( + // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + + // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + + // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + + // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") + // ); + // case EnumToken.NameSpaceAttributeTokenType: + // return ( + // ((token as NameSpaceAttributeToken).l == null + // ? "" + // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + + // "|" + + // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) + // ); + // case EnumToken.ComposesSelectorNodeType: + // return ( + // (token as ComposesSelectorToken).l.reduce( + // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), + // "", + // ) + + // ((token as ComposesSelectorToken).r == null + // ? "" + // : " from " + + // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) + // ); + case exports.EnumToken.BlockStartTokenType: + return "{"; + case exports.EnumToken.BlockEndTokenType: + return "}"; + case exports.EnumToken.StartParensTokenType: + return "("; + case exports.EnumToken.DelimTokenType: + case exports.EnumToken.EqualMatchTokenType: + return "="; + case exports.EnumToken.IncludeMatchTokenType: + return "~="; + case exports.EnumToken.DashMatchTokenType: + return "|="; + case exports.EnumToken.StartMatchTokenType: + return "^="; + case exports.EnumToken.EndMatchTokenType: + return "$="; + case exports.EnumToken.ContainMatchTokenType: + return "*="; + case exports.EnumToken.LtTokenType: + return "<"; + case exports.EnumToken.LteTokenType: + return "<="; + case exports.EnumToken.Tilda: + case exports.EnumToken.SubsequentSiblingCombinatorTokenType: + return "~"; + case exports.EnumToken.Plus: + case exports.EnumToken.NextSiblingCombinatorTokenType: + return "+"; + case exports.EnumToken.GtTokenType: + case exports.EnumToken.ChildCombinatorTokenType: + return ">"; + case exports.EnumToken.GteTokenType: + return ">="; + case exports.EnumToken.ColumnCombinatorTokenType: + return "||"; + case exports.EnumToken.EndParensTokenType: + return ")"; + case exports.EnumToken.AttrStartTokenType: + return "["; + case exports.EnumToken.AttrEndTokenType: + return "]"; + case exports.EnumToken.DescendantCombinatorTokenType: + case exports.EnumToken.WhitespaceTokenType: + return " "; + case exports.EnumToken.ColonTokenType: + return ":"; + case exports.EnumToken.DoubleColonTokenType: + return "::"; + case exports.EnumToken.SemiColonTokenType: + return ";"; + case exports.EnumToken.CommaTokenType: + return ","; + case exports.EnumToken.ImportantTokenType: + return "!important"; + case exports.EnumToken.Pipe: + return "|"; + case exports.EnumToken.AttrTokenType: + case exports.EnumToken.IdenListTokenType: + return "[" + token.chi.reduce(reducer, "") + "]"; + case exports.EnumToken.TimeTokenType: + case exports.EnumToken.AngleTokenType: + case exports.EnumToken.LengthTokenType: + case exports.EnumToken.DimensionTokenType: + case exports.EnumToken.FrequencyTokenType: + case exports.EnumToken.ResolutionTokenType: + let val = token.val.typ == exports.EnumToken.FractionTokenType + ? renderValue(token.val, options, cache) + : minifyNumber(token.val); + let unit = token.unit; + if (token.typ == exports.EnumToken.AngleTokenType && !val.includes("/")) { + const angle = getAngle(token); + let v; + let value = val + unit; + for (const u of ["turn", "deg", "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; + } + break; + case "deg": + v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + 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; + } + break; + case "grad": + v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); + 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 = { + "+": 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, + ...flexUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.FlexTokenType; + return acc; + }, Object.create(null)), + ...dimensionUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.LengthTokenType; + return acc; + }, Object.create(null)), + ...resolutionUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.ResolutionTokenType; + return acc; + }, Object.create(null)), + ...angleUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.AngleTokenType; + return acc; + }, Object.create(null)), + ...timeUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.TimeTokenType; + return acc; + }, Object.create(null)), + ...frequencyUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.FrequencyTokenType; + return acc; + }, Object.create(null)), + ...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, + ]); + const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); + 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) { + let i = SymbolsMapTokensKeys.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = len == SymbolsMapTokensKeys[i].length; + if (!match) { + continue; + } + for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { + index = start + j; + if (index > end) { + match = false; + break; + } + ca = SymbolsMapTokensKeys[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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) { + continue; + } + return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; + } + return null; + } + function searchArray(array, parseInfo, start, end) { + let i = array.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = true; + for (j = 0; j < array[i].length; j++) { + if (len != array[i].length) { + match = false; + break; + } + index = start + j; + if (index > end) { + match = false; + break; + } + ca = array[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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 array[i]; + } + } + return null; + } + class Tokenizer { + typ = null; + kin = null; + nam = null; + val = null; + unit = null; + srcId = null; + sta = null; + end = null; + bytesIn = null; + decodeString = null; + slice = null; + source = null; + hint = null; + *consumeString(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(parseInfo); + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + } + if (isNewLine(charCode)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); + } + // EOF - 'Unclosed-string' fixed + yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + // return result; + } + *consumeURLToken(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(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.next(parseInfo, k); + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + if (isWhiteSpace(charCode)) { + this.next(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.next(parseInfo, k); + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + break; + } + // consume until the ')' + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.next(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.next(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + this.next(parseInfo); + } + yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); + } + // EOF - bad url token + yield 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; + } + if (isLetter(codepoint)) { + hasLetter = true; } - if (colorSpaceDef.length > 0) { - if (result.length > 0) { - result.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - result.push(...colorSpaceDef); + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; } - if (result.length > 0) { - result.push({ typ: exports.EnumToken.CommaTokenType }); + else { + return 0; } - result.push(...reduceColorStops(slice.slice(i))); - slice.length = 0; - slice.push(...result); } - break; - case "conic-gradient": - case "repeating-conic-gradient": - { - let i = 0; - const angles = []; - const positions = []; - const colorSpaceDef = []; - // while ( - // i < slice.length && - // (slice[i].typ === EnumToken.WhitespaceTokenType || - // slice[i].typ === EnumToken.CommentTokenType) - // ) { - // i++; - // } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase(slice[i].val, "from")) { - angles.push(slice[i++]); - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - angles.push(slice[i++]); - } - if ((slice[i]?.typ === exports.EnumToken.NumberTokenType || - slice[i]?.typ === exports.EnumToken.AngleTokenType) && - 0 === toDegrees(slice[i]).val) { - angles.length = 0; - i++; - } - else if (slice[i]?.typ !== exports.EnumToken.CommaTokenType && - slice[i].typ != exports.EnumToken.IdenTokenType) { - angles.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase(slice[i].val, "at")) { - i++; - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - let position1 = ""; - let position2 = ""; - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - !equalsIgnoreCase("in", slice[i].val)) { - position1 = slice[i].val; - positions.push(slice[i++]); - } - else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || - slice[i]?.typ === exports.EnumToken.NumberTokenType) { - position1 = slice[i].val + "%"; - positions.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - positions.push(slice[i++]); - } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - !equalsIgnoreCase("in", slice[i].val)) { - position2 = slice[i].val; - positions.push(slice[i++]); - } - else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || - slice[i]?.typ === exports.EnumToken.NumberTokenType) { - position2 = slice[i].val + "%"; - positions.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - if (position1.length > 0) { - reducegradientBackgroundPosition(positions, `${position1} ${position2}`.trim()); - } + } + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + // eof + if (codepoint != codepoint) { + break; } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; + if (isDigit(codepoint)) { + position++; + continue; } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase("in", slice[i].val)) { - while (i < slice.length && slice[i].typ !== exports.EnumToken.CommaTokenType) { - colorSpaceDef.push(slice[i++]); - } + if (!hasDigits) { + return 0; } - if (slice[i]?.typ === exports.EnumToken.CommaTokenType) { - i++; + 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; } - const result = []; - if (positions.length > 0) { - if (positions.length > 0) { - if (angles.length > 0) { - angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); - } + else if (isLetter(codepoint)) { + hasLetter = true; + break; } - if (angles.length > 0) { - result.push(...angles, { typ: exports.EnumToken.CommaTokenType }); + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; } - if (colorSpaceDef.length > 0) { - if (colorSpaceDef.length > 0) { - if (result.length > 0) { - result.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - result.push(...colorSpaceDef); - } - result.push({ typ: exports.EnumToken.CommaTokenType }); + else { + return 0; } - result.push(...reduceConicColorStops(slice.slice(i))); - slice.length = 0; - slice.push(...result); } - break; + 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; + } + 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; + } + 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; + } + 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 = 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 (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; + } } - return token.val + "(" + slice.reduce(reducer, "") + ")"; } - case exports.EnumToken.TimingFunctionTokenType: - case exports.EnumToken.PseudoClassFuncTokenType: - case exports.EnumToken.WhenElseFunctionTokenType: - case exports.EnumToken.TimelineFunctionTokenType: - case exports.EnumToken.GridTemplateFuncTokenType: - case exports.EnumToken.SupportsFunctionTokenType: - case exports.EnumToken.ContainerFunctionTokenType: - case exports.EnumToken.TransformFunctionTokenType: - case exports.EnumToken.GeneralEnclosedFunctionTokenType: - case exports.EnumToken.CustomFunctionTokenType: - case exports.EnumToken.WildCardFunctionTokenType: - if (token.typ == exports.EnumToken.MathFunctionTokenType && - token.chi.length == 1 && - ![exports.EnumToken.BinaryExpressionTokenType, exports.EnumToken.FractionTokenType, exports.EnumToken.IdenTokenType].includes(token.chi[0].typ) && - // @ts-ignore - token.chi[0].val - ?.typ != exports.EnumToken.FractionTokenType) { - return (token.val + - "(" + - token.chi.reduce((acc, curr) => acc + - renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + - ")"); + } + 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 = 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); + }); + this.decodeString = true; } - return ( - /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + - "(" + - token.chi.reduce(reducer, "") + - ")"); - // case EnumToken.MatchExpressionTokenType: - // return ( - // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + - // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") - // ); - // case EnumToken.NameSpaceAttributeTokenType: - // return ( - // ((token as NameSpaceAttributeToken).l == null - // ? "" - // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + - // "|" + - // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) - // ); - // case EnumToken.ComposesSelectorNodeType: - // return ( - // (token as ComposesSelectorToken).l.reduce( - // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), - // "", - // ) + - // ((token as ComposesSelectorToken).r == null - // ? "" - // : " from " + - // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) - // ); - case exports.EnumToken.BlockStartTokenType: - return "{"; - case exports.EnumToken.BlockEndTokenType: - return "}"; - case exports.EnumToken.StartParensTokenType: - return "("; - case exports.EnumToken.DelimTokenType: - case exports.EnumToken.EqualMatchTokenType: - return "="; - case exports.EnumToken.IncludeMatchTokenType: - return "~="; - case exports.EnumToken.DashMatchTokenType: - return "|="; - case exports.EnumToken.StartMatchTokenType: - return "^="; - case exports.EnumToken.EndMatchTokenType: - return "$="; - case exports.EnumToken.ContainMatchTokenType: - return "*="; - case exports.EnumToken.LtTokenType: - return "<"; - case exports.EnumToken.LteTokenType: - return "<="; - case exports.EnumToken.Tilda: - case exports.EnumToken.SubsequentSiblingCombinatorTokenType: - return "~"; - case exports.EnumToken.Plus: - case exports.EnumToken.NextSiblingCombinatorTokenType: - return "+"; - case exports.EnumToken.GtTokenType: - case exports.EnumToken.ChildCombinatorTokenType: - return ">"; - case exports.EnumToken.GteTokenType: - return ">="; - case exports.EnumToken.ColumnCombinatorTokenType: - return "||"; - case exports.EnumToken.EndParensTokenType: - return ")"; - case exports.EnumToken.AttrStartTokenType: - return "["; - case exports.EnumToken.AttrEndTokenType: - return "]"; - case exports.EnumToken.DescendantCombinatorTokenType: - case exports.EnumToken.WhitespaceTokenType: - return " "; - case exports.EnumToken.ColonTokenType: - return ":"; - case exports.EnumToken.DoubleColonTokenType: - return "::"; - case exports.EnumToken.SemiColonTokenType: - return ";"; - case exports.EnumToken.CommaTokenType: - return ","; - case exports.EnumToken.ImportantTokenType: - return "!important"; - case exports.EnumToken.Pipe: - return "|"; - case exports.EnumToken.AttrTokenType: - case exports.EnumToken.IdenListTokenType: - return "[" + token.chi.reduce(reducer, "") + "]"; - case exports.EnumToken.TimeTokenType: - case exports.EnumToken.AngleTokenType: - case exports.EnumToken.LengthTokenType: - case exports.EnumToken.DimensionTokenType: - case exports.EnumToken.FrequencyTokenType: - case exports.EnumToken.ResolutionTokenType: - let val = token.val.typ == exports.EnumToken.FractionTokenType - ? renderValue(token.val, options, cache) - : minifyNumber(token.val); - let unit = token.unit; - if (token.typ == exports.EnumToken.AngleTokenType && !val.includes("/")) { - const angle = getAngle(token); - let v; - let value = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { - if (token.unit == u) { + 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; + } + 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; + } + 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; + } + 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); + } + 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 + parseInfo.offset + i); + } + } + } + parseInfo.currentPosition += char.length; + return char; + } + 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; + } + 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); + } + 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; + } + 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; + } + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + *tokenize(parseInfo, yieldEOFToken = true) { + if (typeof parseInfo == "string") { + parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + slice: this.slice, + sign: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + continue; + } + } + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + charCode = this.peek(parseInfo).charCodeAt(0); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? exports.EnumToken.DashedIdenTokenType + : exports.EnumToken.IdenTokenType); + continue; + } + } + } + if (charCode == 64 /* TokenMap.AT */) { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); + continue; + } + } + } + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); + continue; + } + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.HashTokenType); continue; } - switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; - } + } + } + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); + break; + // '+' or '-' + case 43 /* TokenMap.PLUS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + if (isDigit(charCode)) { + tokensCount = this.consumeNumericToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + slice: this.slice, + sign: "+", + }); + break; + } + } + yield this.makeToken(parseInfo, exports.EnumToken.Plus); + break; + 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.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Sub); break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + } + if (charCode == 45 /* TokenMap.MINUS */ && + (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); + continue; } + } + } + this.next(parseInfo); + break; + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); + break; + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); + break; + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); 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 (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); + yield this.makeToken(parseInfo, hint); + this.next(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === exports.EnumToken.UrlFunctionTokenDefType) { + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.next(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + yield* this.consumeURLToken(parseInfo); + } + else { + do { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || + !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + } + } } break; - case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + } + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); + break; + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); + break; + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); + break; + // ']' + case 93 /* TokenMap.RIGHT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); + break; + case 59 /* TokenMap.SEMICOLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); + break; + case 58 /* TokenMap.COLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); + break; + } + yield this.makeToken(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) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.next(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + yield this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); + break; + case 44 /* TokenMap.COMMA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); + break; + case 36 /* TokenMap.DOLLAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "$=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); + break; + } + this.next(parseInfo); + break; + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Tilda); + break; + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); + break; + } + this.next(parseInfo); + break; + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Star); + break; + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); + break; + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); + break; + } + else if (this.match(parseInfo, "|=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Pipe); + break; + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.next(parseInfo, 10); + yield this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); + break; + } + this.next(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (!this.match(parseInfo, "/*")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); + break; + } + this.next(parseInfo, 2); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); + break; } - 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"; + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); } - 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), "")); + break; + case 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.GteTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.GtTokenType); + break; + case 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "<=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.LteTokenType); + break; + } + this.next(parseInfo); + if (this.match(parseInfo, "!--")) { + this.next(parseInfo, 3); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + yield this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + } + else { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + } + } + break; + case 35 /* TokenMap.HASH */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + break; + case 92 /* TokenMap.REVERSE_SOLIDUS */: + if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + break; + } + this.next(parseInfo); + // EOF + if (!this.peek(parseInfo)) { + if (!yieldEOFToken) { + break; + } + // end of stream ignore \\ + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + break; + } + this.next(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + yield* this.consumeString(parseInfo); + break; + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset + 1) + .charCodeAt(0); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.next(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); + break; + } + } + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + this.next(parseInfo, 2); + break; + } + this.next(parseInfo); + break; + default: + this.next(parseInfo); + break; + } + if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + break; + } + } + if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + yield this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); } - 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 ""; + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async *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); + } + yield* this.tokenize(parseInfo, done); + if (done) { + break; + } + } + parseInfo.stream = parseInfo.source.getContent(); + yield* this.tokenize(parseInfo); + } } /** - * Remove whitespace tokens that are not needed - * @param values - * - * @internal + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken */ - 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; + function tokenize(parseInfo, yieldEOFToken = true) { + return new Tokenizer().tokenize(parseInfo, yieldEOFToken); + } + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + function tokenizeStream(input, parseInfo) { + return new Tokenizer().tokenizeStream(input, parseInfo); } /** @@ -26091,7 +26841,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 && @@ -26099,7 +26851,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); @@ -26122,10 +26876,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, @@ -26175,7 +26928,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; } @@ -26187,7 +26940,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; } @@ -26199,7 +26952,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; } @@ -26211,7 +26964,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; } @@ -26266,10 +27019,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]: [ @@ -26297,10 +27049,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, @@ -26318,7 +27069,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 @@ -26335,20 +27086,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; } @@ -26368,83 +27176,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 ? { @@ -26457,17 +27192,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" }); - // } - // } } } } @@ -26486,36 +27210,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) { @@ -26604,10 +27298,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 @@ -26659,6 +27352,7 @@ * @param errors */ function parseDeclaration(tokens, parent, options, errors) { + // console.error(tokens); const name = tokens.shift(); let i; let rules = null; @@ -26679,16 +27373,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", }, ]; @@ -26718,39 +27411,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; - // } - // } } } } @@ -26788,12 +27448,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 @@ -26843,7 +27502,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); // } @@ -26881,26 +27540,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); @@ -26973,9 +27612,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; @@ -27005,7 +27644,7 @@ action: "drop", message: `invalid color`, node: tokens[index], - location: options.source.getSourceLocation(tokens[index][LOC].sta), + location: options.source.getSourceLocation(tokens[index][LOCSTA]), }); } } @@ -27057,12 +27696,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 @@ -27095,10 +27733,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 @@ -27107,14 +27744,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)) { @@ -27132,18 +27761,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 @@ -27213,7 +27839,7 @@ action: "drop", message: `expecting ''`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27223,7 +27849,7 @@ action: "drop", message: `expecting '('`, node: stream[i], - location: options.source.getSourceLocation(stream[i][LOC].sta), + location: options.source.getSourceLocation(stream[i][LOCSTA]), }); } } @@ -27265,7 +27891,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; } @@ -27275,7 +27901,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); @@ -27286,7 +27912,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)), @@ -27329,7 +27955,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]; } } @@ -27364,7 +27992,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(); @@ -27392,7 +28022,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]; } } @@ -27408,7 +28040,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; @@ -27429,13 +28061,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) { @@ -27443,7 +28077,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; @@ -27453,8 +28087,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(); @@ -27476,7 +28111,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; @@ -27545,7 +28182,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; } @@ -27558,7 +28195,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; } @@ -27608,7 +28245,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(); @@ -27622,7 +28261,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 @@ -27653,7 +28294,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(); } @@ -27668,7 +28311,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(); @@ -27689,7 +28334,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: [ @@ -27749,11 +28394,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), @@ -27769,7 +28410,7 @@ message: "Expected string or url()", syntax: "@import", node: stream[0], - location: stream[0]?.[LOC], + location: options.source.getSourceLocation(stream[0]?.[LOCSTA]), }, ], }; @@ -27799,7 +28440,7 @@ message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27826,7 +28467,7 @@ message: `Expected `, syntax: "@import", node: stream[index], - location: options.source.getSourceLocation(stream[index]?.[LOC].sta), + location: options.source.getSourceLocation(stream[index]?.[LOCSTA]), }, ], }; @@ -27949,7 +28590,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)); @@ -27972,32 +28615,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; @@ -28006,7 +28630,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(); @@ -28017,20 +28643,6 @@ 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)); return { success, errors }; @@ -28080,19 +28692,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++]); } @@ -28108,7 +28707,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 `, }, ], @@ -28133,11 +28732,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())); @@ -28171,174 +28769,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 } @@ -28348,13 +28806,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; @@ -28369,14 +28829,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; @@ -28398,21 +28860,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) { @@ -28430,31 +28883,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, @@ -28469,9 +28910,6 @@ 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); return acc; }, [])); @@ -28486,24 +28924,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); @@ -28544,7 +28964,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 +28979,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 +28995,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; @@ -28591,7 +29011,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; @@ -28611,8 +29031,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; } @@ -29094,46 +29513,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; + while ((tokenizer = iter.next().value) != null) { + // 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; + // console.error(item); + 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) { @@ -29141,19 +29592,53 @@ context = node; } } - else if (item.token.typ == exports.EnumToken.BlockStartTokenType) { + else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item.token]; + tokens = [item]; do { - item = iter[++currentItemIndex]; - if (item == null) { + tokenizer = iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + 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; + 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); @@ -29161,17 +29646,15 @@ 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 === 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 && @@ -29395,7 +29878,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`, }, }; @@ -29469,7 +29952,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) { @@ -29588,7 +30071,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) { @@ -29822,7 +30305,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 = ""; @@ -29959,52 +30442,83 @@ let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer; // 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 = isAsync + ? (await iter.next()).value + : iter.next().value)) { + 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) { @@ -30015,23 +30529,55 @@ 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 = [item]; do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { + tokenizer = isAsync + ? (await iter.next()).value + : iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + 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; + 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); @@ -30039,17 +30585,15 @@ 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 === 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 && @@ -30097,6 +30641,7 @@ source, position: 0, currentPosition: 0, + time: 0, }; const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream, parseInfo) : tokenize(parseInfo), Object.assign({}, options, { minify: false, @@ -30322,7 +30867,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`, }, }; @@ -30418,7 +30963,7 @@ 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; @@ -30858,7 +31403,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 = ""; @@ -30895,31 +31440,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) { @@ -30951,7 +31471,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)) { @@ -30972,7 +31491,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--; } @@ -30984,7 +31505,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; @@ -31007,7 +31528,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; @@ -31088,7 +31609,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) { @@ -31127,7 +31648,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); @@ -31148,7 +31669,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); @@ -31166,8 +31687,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; @@ -31187,7 +31708,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); @@ -31210,7 +31731,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 ", }); } @@ -31219,7 +31740,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 ", }); } @@ -31228,7 +31749,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", }); } @@ -31236,7 +31757,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, @@ -31249,7 +31770,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, @@ -31264,7 +31785,7 @@ 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, @@ -31283,7 +31804,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}`, }); } @@ -31294,13 +31815,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]]; @@ -31316,7 +31837,7 @@ if (result.errors.length > 0) { errors.push(...result.errors); } - 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; @@ -31335,7 +31856,7 @@ } // @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; @@ -31355,14 +31876,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]]; @@ -31405,7 +31926,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; @@ -31433,8 +31954,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; @@ -31495,7 +32015,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", }); } @@ -31504,14 +32024,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); @@ -31528,7 +32048,7 @@ if (result.errors.length > 0) { errors.push(...result.errors); } - 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; @@ -31548,7 +32068,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; @@ -31557,7 +32077,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; @@ -31583,7 +32103,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; @@ -31596,7 +32116,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; @@ -31609,7 +32129,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; @@ -31628,8 +32148,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]]; @@ -31642,7 +32161,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]]; @@ -31673,7 +32192,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", }); } @@ -31686,14 +32205,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]]; @@ -31715,7 +32234,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; @@ -31741,10 +32262,9 @@ 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, @@ -31759,10 +32279,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]: [], @@ -31773,19 +32292,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 @@ -31823,7 +32338,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), @@ -31836,10 +32351,7 @@ } } } - 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; @@ -31898,18 +32410,48 @@ * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { - stream: src, - offset: 0, - time: 0, - source: new SourceFile(src, [], ""), - position: 0, - currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const iter = tokenize(src); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + let tokenizer; + while ((tokenizer = iter.next().value)) { + 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 @@ -31955,7 +32497,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); } } @@ -31974,7 +32516,7 @@ action: "drop", message: `Unbalanced token ')'`, node, - location: options.source.getSourceLocation(node[LOC].sta), + location: options.source.getSourceLocation(node[LOCSTA]), }); // return []; continue; @@ -32002,13 +32544,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, @@ -32124,7 +32666,7 @@ 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 []; } @@ -32210,7 +32752,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": @@ -32232,7 +32774,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; @@ -32410,7 +32954,9 @@ currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -32543,7 +33089,9 @@ 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 ? tokenizeStream(stream, options.parseInfo) : tokenize(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 4ed63c7a..5b910a13 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"); @@ -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; @@ -9655,6 +9670,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* () { @@ -9753,6 +9769,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), exports.WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { @@ -9931,7 +9948,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 +9970,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 +9997,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 +10036,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 +10076,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 +10119,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 +10150,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 +10215,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 +10231,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 +10280,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 +10291,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 +10304,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 +10343,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 +10381,7 @@ 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 +10399,12 @@ function inlineExpression$1(token) { result.push(token); } else { - result.push(...inlineExpression$1(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression$1(token.r)); + result.push(...inlineExpression$1(token.l), { + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, ...inlineExpression$1(token.r)); } } else { @@ -10316,7 +10467,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 +10511,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--; } @@ -10459,19 +10618,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 +10649,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 +10690,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 +10735,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 }); } @@ -10944,7 +11117,7 @@ function getTokenType(token, position, currentPosition) { [LOC]: pos, }; } - if (isPseudo$1(token)) { + if (isPseudo(token)) { return { typ: ValidationTokenEnum.PseudoClassToken, val: token, @@ -12061,7 +12234,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]), }, ], }; @@ -12115,7 +12288,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 +12322,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 +12366,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 +12417,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 +12429,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 +12468,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 +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], @@ -12358,7 +12531,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]), }, ], }; @@ -12401,7 +12574,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 +12596,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,7 +12622,7 @@ 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]), }, ], }; @@ -12496,7 +12669,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 +12764,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, @@ -14377,7 +14550,9 @@ function convertColor(token, to) { chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], kin: exports.ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } @@ -15046,7 +15221,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 +15270,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 +15407,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 @@ -15864,7 +16044,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 +16052,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 +16092,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 +16106,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)); } @@ -19283,7 +19378,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 +19409,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 +19489,7 @@ const config = getConfig(); class PropertyList { options = { removeDuplicateDeclarations: true, computeShorthand: true }; declarations; + // ketsey = new Map; constructor(options = {}) { this.options = options; this.declarations = new Map(); @@ -19413,12 +19509,12 @@ class PropertyList { name = declaration.typ != exports.EnumToken.DeclarationNodeType ? null - : declaration.nam.toLowerCase(); + : 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 +19542,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; @@ -19671,57 +19781,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 +19836,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 +19852,9 @@ class ComputeCalcExpressionFeature { typ: exports.EnumToken.MathFunctionTokenType, val: "calc", chi: values, - [LOC]: value[LOC], + [LOCSRCID]: value[LOCSRCID], + [LOCSTA]: value[LOCSTA], + [LOCEND]: value[LOCEND], }); break; } @@ -21275,7 +21347,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"; @@ -21300,7 +21374,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 @@ -21384,3336 +21460,2279 @@ 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; +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); } - else { - const should_negate = value & 1; - value >>>= 1; - if (should_negate) { - result.push(value === 0 ? -2147483648 : -value); + 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; } - else { - result.push(value); + 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); + } + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } + } + } + 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); } - // reset - value = shift = 0; } } - 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; + 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; } - 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)); + 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; } - else { - sourcemaps = decodeURIComponent(sourcemaps.slice(offset)); + const result = feature.run(replacement, options2, + // @ts-ignore + parent[PARENT] ?? ast, context, exports.FeatureWalkMode.Post); + if (result != null) { + replacement = result; } } - 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)) { - continue; - } - this.map.set(index, decodedMappings[index]); - } - this.computePositions(); + if (replacement != null && + (!Array.isArray(replacement) || replacement.length > 0) && + replacement != parent && + parent[PARENT] != null) { + // @ts-ignore + replaceNodeOrValue(parent[PARENT], parent, replacement); } - } - /** - * add source - * @param id - * @param fileName - * @param content - * @returns - */ - addSourceContent(id, fileName, content) { - if (this.sourcesMap.includes(id)) { - return; + // @ts-ignore + if (replacement.chi != null) { + // @ts-ignore + for (const node of replacement.chi) { + node[PARENT] = replacement; + parents.add(node); + } } - 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]; - } - for (let [newLine, newColumn, srcId, ln, col] of maps) { - const key = `${srcId}:${ln}:${col}:${newLine}:${newColumn}`; - if (this.keys.has(key)) { - continue; - } - 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; + 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.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 { - mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); + else if (hasUpdates) { + tokens.length = 0; + tokens.push(...[...sections.values()].reduce((acc, t) => { + if (acc.length > 0) { + acc.push({ + typ: exports.EnumToken.CommaTokenType, + }); } - } - return { - version: this.version, - sources: this.sources.slice(), - sourcesContent: this.sourcesContent?.slice(), - mappings: mappings.join(";"), - }; + acc.push(...t); + 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); + 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; + } + 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; } - 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; + while (previous?.typ === exports.EnumToken.CommentNodeType) { + // @ts-ignore + previous = ast.chi[--nodeIndex]; } - 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); + node = ast.chi[i]; + if (node.typ === exports.EnumToken.AtRuleNodeType && node.nam === "font-face") { 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; - } - } - else { - if (end < 0) { - j += end; - } - else { - j = parseInfo.position + end; - } - } - } - 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; - } - 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; -} -/** - * 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)); - } - 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)); + 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; } - next(parseInfo); - result.push(yieldResult(parseInfo, exports.EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - 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 + previous.chi.push(...node.chi); + // @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; + 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; + } } - 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) { + // @ts-ignore + previous.chi.push(...node.chi); + 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)) { + // @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); + } + } + } + } + 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(","); + } + 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; } /** - * 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; - } + } + } + 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 === "") { + wrapper.chi.push(...previous.chi); + if (nSel == "&" || nSel === "") { + wrapper.chi.push(...node.chi); + } + 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; } - 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)), ""); + prefixes1.add(matches[1]); + if (prefixes1.size > 1) { + break; } } - 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); - } + } + 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; + } + prefixes2.add(matches[1]); + if (prefixes2.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); - 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); - } - } - } - } - 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 + 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); + } + 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; + } + } + } + } + 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 (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; + } + } + } + return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; +} +/** + * Reduce rule selector * @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; +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; + } + 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(); + } + } + 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); + } + 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; } - // @ts-ignore - return node.chi[i].typ == exports.EnumToken.DeclarationNodeType; } - return true; } + /** - * Optimize selector - * @param selector + * expand css nesting ast nodes + * @param ast * * @private */ -function optimizeSelector(selector) { - const map = new Set(); - selector = selector - .reduce((acc, curr) => { - // @ts-ignore - if (curr.length > 0 && curr.at(-1).startsWith(":is(")) { +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; + } // @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); + result.chi.push(...children); + } + 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; } - 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; + if (hasRule) { + node = expand(node); + for (const child of node.chi) { + child[PARENT] = result; + } + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); + } + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } } - if (!match) { - break; + else { + node[PARENT] = result; + // @ts-ignore + result.chi.push(node); } - optimized.push(item); } - while (optimized.length > 0) { - const last = optimized.at(-1); - if (last == " " || combinators.includes(last)) { - optimized.pop(); - continue; - } - 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); - } - } - 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 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 { - 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; + 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)); } - if (reducible) { - const chr = curr[0].charAt(0); + 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 - reducible = chr == "." || chr == ":" || isIdentStart(chr.charCodeAt(0)); + result.push(...(astAtRule.chi.length > 0 ? [astAtRule].concat(values) : values)); + ast.chi.splice(i--, 1); } - acc.push(hasCompound ? ["&"].concat(curr) : curr); - return acc; - }, []), - reducible: selector.every((selector) => ![">", "+", "~", "&"].includes(selector[0])), - }; + } + } + // @ts-ignore + return ast.chi.length > 0 ? [ast].concat(result) : result; } /** - * Split selector string - * @param buffer - * - * @internal + * replace compound selector + * @param input + * @param replace */ -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(" "); +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; } - // 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); - } - 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; + const rule = splitRule(replace); + Object.assign(t.value, { + typ: exports.EnumToken.LiteralTokenType, + val: rule.length > 1 ? ":is(" + replace + ")" : replace, + }); } } - if (str !== "") { - result.at(-1).push(str); + 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("&", ""); + } } - return result; + 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; } /** - * Reduce selector - * @param acc - * @param curr - * - * @private + * @param {string} str */ -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; +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; } - 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 { + const should_negate = value & 1; + value >>>= 1; + if (should_negate) { + result.push(value === 0 ? -2147483648 : -value); } - else if (token == ")") ; - else if (token == ",") { - if (!canReduce) { - canReduce = curr[index + 1] == "&"; - } - acc.push([]); + else { + result.push(value); } - 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; - }, []); + // reset + value = shift = 0; } } - 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; + return result; } /** - * Match selectors - * @param selector1 - * @param selector2 * - * @private + * @param value + * @returns */ -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]; - } - } - } +function encode(value) { + if (typeof value === 'number') { + return encode_integer(value); } - 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 result = ''; + for (let i = 0; i < value.length; i += 1) { + result += encode_integer(value[i]); } - for (; i < j; i++) { - k = 0; - token = selector1[0][i]; - for (; k < selector1.length; k++) { - if (selector1[k][i] != token) { - matching = false; - 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; } - if (matching) { - l = 0; - for (; l < selector2.length; l++) { - if (selector2[l][i] != token) { - matching = false; - 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)); } } + sourcemaps = JSON.parse(sourcemaps); } - if (!matching) { - break; - } - if (token.endsWith("(")) { - matchFunction++; + 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(); } - match.at(-1).push(token); } - // invalid function - if (matchFunction != 0 || inAttr != 0) { - return null; + /** + * 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; } - 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(); + /** + * Add all location + * @param maps + * @throws + */ + 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)) { continue; } - 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; } } - 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 = [...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); - } + /** + * 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 []; + } + generatedCodeColumn = index == 0 ? segment[0] : segment[0] + array[0][0]; + result = [generatedCodeColumn]; + if (segment.length <= 1) { + return result; + } + 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); } - 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 === "") { - wrapper.chi.push(...previous.chi); - if (nSel == "&" || nSel === "") { - wrapper.chi.push(...node.chi); + /** + * retrieve original sources, lines and columns + * @param line generated line + * @param column generated column + */ + find(line, column) { + if (this.reverseMap.size == 0) { + this.computePositions(); } - else { - wrapper.chi.push(node); + if (!this.reverseMap.has(--line)) { + return null; } - } - 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; - } - prefixes1.add(matches[1]); - if (prefixes1.size > 1) { - break; - } - } + column--; + const result = []; + for (const record of this.reverseMap.get(line)) { + if (record.length == 0 || record[0] < column) { + continue; } - if (prefixes1.size > 1) { + if (record[0] > column) { break; } + result.push([ + this.sources?.[record[1]] ?? null, + record[2] + 1, + record[3] + 1, + this.sourcesContent?.[record[1]] ?? null, + ]); } - 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; - } - } + 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()))}`; + } + /** + * Convert to JSON object + */ + toJSON() { + const mappings = []; + let i = 0; + for (; i <= this.line; i++) { + if (!this.map.has(i)) { + mappings.push(""); } - if (prefixes2.size > 1) { - break; + else { + mappings.push(this.map.get(i).reduce((acc, curr) => acc + (acc === "" ? "" : ",") + encode(curr), "")); } } - if (prefixes1.size != prefixes2.size) { - return null; + return { + version: this.version, + sources: this.sources.slice(), + sourcesContent: this.sourcesContent?.slice(), + mappings: mappings.join(";"), + }; + } +} + +/** + * Compute line and column of the offset + */ +class LineMap { + /** + * line starts + */ + lineStarts; + /** + * Constructor + * @param lines + */ + constructor(lines = []) { + if (lines.length === 0) { + lines.push(0); } - for (const prefix of prefixes1) { - if (!prefixes2.has(prefix)) { - return null; + this.lineStarts = lines; + } + /** + * 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; + } + else if (this.lineStarts[mid] > offset) { + end = mid - 1; } } + return result; } - 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); + /** + * get line starts + * @returns + */ + getLineStarts() { + return this.lineStarts; } - if (css2 != null) { - options.cache.set(node2, css2); + /** + * add line start + */ + addLineStart(lineStart) { + this.lineStarts.push(lineStart); } - if (raw1 != null) { - node1[RAW] = raw1; +} + +/** + * match url + */ +const matchUrl = /^(https?:)?\/\//; +/** + * return the directory name of a path + * @param path + * + * @private + */ +function dirname(path) { + if (path === "") { + return ""; } - if (raw2 != null) { - node2[RAW] = raw2; + if (path.startsWith("data:")) { + return path; } - const intersect = []; - while (i--) { - if (node1.chi[i].typ == exports.EnumToken.CommentNodeType) { - continue; + let i = 0; + let parts = [""]; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + parts.push(""); } - 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; - } - } - } - } - 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 (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; - } + else { + parts[parts.length - 1] += chr; } } - return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 }; + parts.pop(); + return parts.join("/"); } /** - * Reduce rule selector - * @param node - * + * split path + * @param result * @private */ -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; +function splitPath(result) { + if (result.length == 0) { + return { parts: [], i: 0 }; } - 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(); - } + const parts = result == "/" ? [] : [""]; + let i = 0; + for (; i < result.length; i++) { + const chr = result.charAt(i); + if (chr == "/") { + parts.push(""); } - 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); - } - 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; + // 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 }; } - /** - * expand css nesting ast nodes - * @param ast - * + * Nomalize 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; +const normalize = memoize(function (path) { + let parts = []; + let i = 0; + if (path.includes("\\")) { + path = path.replace(/(\\)/g, "/"); } - 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; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == "/") { + if (parts.length == 0 || parts[parts.length - 1] !== "") { + parts.push(""); } - // @ts-ignore - result.chi.push(...children); } - 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 { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); - } + else if (chr == "?" || chr == "#") { + break; } else { - node[PARENT] = result; - // @ts-ignore - result.chi.push(node); + if (parts.length == 0) { + parts.push(""); + } + parts[parts.length - 1] += chr; } } - 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]; + 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; + } } - 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); - } - } - } - // @ts-ignore - return ast.chi.length > 0 ? [ast].concat(result) : result; -} + return (path.charAt(0) == "/" ? "/" : "") + parts.join("/"); +}); /** - * replace compound selector - * @param input - * @param replace + * diff path + * @param path1 + * @param path2 + * @private */ -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, - }); +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(); } - } - 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("&", ""); + else { + parts.unshift(".."); } } - 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?:)?\/\//; + return parts.join("/"); +}); /** - * return the directory name of a path - * @param path + * resolve path + * @param url url or path to resolve + * @param currentDirectory directory used to resolve the path + * @param cwd current working directory * * @private */ -function dirname(path) { - if (path === "") { - return ""; +const resolve = memoize(function (url, currentDirectory, cwd) { + if (matchUrl.test(url)) { + return { + absolute: url, + relative: url, + }; } - if (path.startsWith("data:")) { - return path; + cwd ??= ""; + currentDirectory ??= ""; + url = normalize(url); + if (cwd !== "") { + cwd = normalize(cwd); } - let i = 0; - let parts = [""]; - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == "/") { - parts.push(""); - } - else { - parts[parts.length - 1] += chr; - } + if (currentDirectory !== "") { + currentDirectory = normalize(currentDirectory); } - parts.pop(); - return parts.join("/"); -} + 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), + }; +}); /** - * 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, "/"); - } - 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; - } - } - 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 { - parts.unshift(".."); - } - } - 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, - }; - } - cwd ??= ""; - currentDirectory ??= ""; - url = normalize(url); - if (cwd !== "") { - cwd = normalize(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); - return { - absolute, - relative: dir === "" ? absolute : diff(absolute, dir), - }; -}); -/** - * - * @param parts - * @returns + * + * @param parts + * @returns * @private */ function resolvePath(...parts) { @@ -24744,6 +23763,119 @@ function resolvePath(...parts) { return result || (isAbsolute ? "/" : "."); } +/** + * Source file ID + */ +let sourceId = 0; +/** + * Source file helper class + */ +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); + } + /** + * return input source map + * @returns + */ + getInputSourceMap() { + return this.inputSourceMap; + } +} + /** * render ast * @param data @@ -24870,43 +24002,34 @@ 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]; + // console.error({record}); + 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) @@ -24919,6 +24042,22 @@ 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); } @@ -24926,23 +24065,24 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } } 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]); } + // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -24950,11 +24090,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; @@ -25078,7 +24219,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 { @@ -25086,15 +24226,23 @@ 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), - ]); + // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; + // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { + // sourcemaps.sources.push(node[LOCSTA] as number); + // } + // sourcemaps.maps.push([ + // ...linesMap!.getOffsets( + // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, + // ), + // node[LOCSTA], + // ...source!.getOffsets(node![LOCSTA]), + // ]); + // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } @@ -25598,483 +24746,2085 @@ function renderValue(token, options = {}, cache = Object.create(null), reducer, } result.push(...size); } - 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); + 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); + } + if (colorSpaceDef.length > 0) { + if (result.length > 0) { + result.push({ typ: exports.EnumToken.WhitespaceTokenType }); + } + result.push(...colorSpaceDef); + } + if (result.length > 0) { + result.push({ typ: exports.EnumToken.CommaTokenType }); + } + result.push(...reduceColorStops(slice.slice(i))); + slice.length = 0; + slice.push(...result); + } + break; + case "conic-gradient": + case "repeating-conic-gradient": + { + let i = 0; + const angles = []; + const positions = []; + const colorSpaceDef = []; + // while ( + // i < slice.length && + // (slice[i].typ === EnumToken.WhitespaceTokenType || + // slice[i].typ === EnumToken.CommentTokenType) + // ) { + // i++; + // } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase(slice[i].val, "from")) { + angles.push(slice[i++]); + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + angles.push(slice[i++]); + } + if ((slice[i]?.typ === exports.EnumToken.NumberTokenType || + slice[i]?.typ === exports.EnumToken.AngleTokenType) && + 0 === toDegrees(slice[i]).val) { + angles.length = 0; + i++; + } + else if (slice[i]?.typ !== exports.EnumToken.CommaTokenType && + slice[i].typ != exports.EnumToken.IdenTokenType) { + angles.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase(slice[i].val, "at")) { + i++; + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + let position1 = ""; + let position2 = ""; + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + !equalsIgnoreCase("in", slice[i].val)) { + position1 = slice[i].val; + positions.push(slice[i++]); + } + else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || + slice[i]?.typ === exports.EnumToken.NumberTokenType) { + position1 = slice[i].val + "%"; + positions.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + positions.push(slice[i++]); + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + !equalsIgnoreCase("in", slice[i].val)) { + position2 = slice[i].val; + positions.push(slice[i++]); + } + else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || + slice[i]?.typ === exports.EnumToken.NumberTokenType) { + position2 = slice[i].val + "%"; + positions.push(slice[i++]); + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + if (position1.length > 0) { + reducegradientBackgroundPosition(positions, `${position1} ${position2}`.trim()); + } + } + while (i < slice.length && + (slice[i].typ === exports.EnumToken.WhitespaceTokenType || + slice[i].typ === exports.EnumToken.CommentTokenType)) { + i++; + } + if (slice[i]?.typ === exports.EnumToken.IdenTokenType && + equalsIgnoreCase("in", slice[i].val)) { + while (i < slice.length && slice[i].typ !== exports.EnumToken.CommaTokenType) { + colorSpaceDef.push(slice[i++]); + } + } + if (slice[i]?.typ === exports.EnumToken.CommaTokenType) { + i++; + } + const result = []; + if (positions.length > 0) { + if (positions.length > 0) { + if (angles.length > 0) { + angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); + } + angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); + } + } + if (angles.length > 0) { + result.push(...angles, { 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); + } + result.push({ typ: exports.EnumToken.CommaTokenType }); + } + result.push(...reduceConicColorStops(slice.slice(i))); + slice.length = 0; + slice.push(...result); + } + break; + } + return token.val + "(" + slice.reduce(reducer, "") + ")"; + } + case exports.EnumToken.TimingFunctionTokenType: + case exports.EnumToken.PseudoClassFuncTokenType: + case exports.EnumToken.WhenElseFunctionTokenType: + case exports.EnumToken.TimelineFunctionTokenType: + case exports.EnumToken.GridTemplateFuncTokenType: + case exports.EnumToken.SupportsFunctionTokenType: + case exports.EnumToken.ContainerFunctionTokenType: + case exports.EnumToken.TransformFunctionTokenType: + case exports.EnumToken.GeneralEnclosedFunctionTokenType: + case exports.EnumToken.CustomFunctionTokenType: + case exports.EnumToken.WildCardFunctionTokenType: + if (token.typ == exports.EnumToken.MathFunctionTokenType && + token.chi.length == 1 && + ![exports.EnumToken.BinaryExpressionTokenType, exports.EnumToken.FractionTokenType, exports.EnumToken.IdenTokenType].includes(token.chi[0].typ) && + // @ts-ignore + token.chi[0].val + ?.typ != exports.EnumToken.FractionTokenType) { + return (token.val + + "(" + + token.chi.reduce((acc, curr) => acc + + renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + + ")"); + } + return ( + /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + + "(" + + token.chi.reduce(reducer, "") + + ")"); + // case EnumToken.MatchExpressionTokenType: + // return ( + // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + + // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + + // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + + // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") + // ); + // case EnumToken.NameSpaceAttributeTokenType: + // return ( + // ((token as NameSpaceAttributeToken).l == null + // ? "" + // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + + // "|" + + // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) + // ); + // case EnumToken.ComposesSelectorNodeType: + // return ( + // (token as ComposesSelectorToken).l.reduce( + // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), + // "", + // ) + + // ((token as ComposesSelectorToken).r == null + // ? "" + // : " from " + + // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) + // ); + case exports.EnumToken.BlockStartTokenType: + return "{"; + case exports.EnumToken.BlockEndTokenType: + return "}"; + case exports.EnumToken.StartParensTokenType: + return "("; + case exports.EnumToken.DelimTokenType: + case exports.EnumToken.EqualMatchTokenType: + return "="; + case exports.EnumToken.IncludeMatchTokenType: + return "~="; + case exports.EnumToken.DashMatchTokenType: + return "|="; + case exports.EnumToken.StartMatchTokenType: + return "^="; + case exports.EnumToken.EndMatchTokenType: + return "$="; + case exports.EnumToken.ContainMatchTokenType: + return "*="; + case exports.EnumToken.LtTokenType: + return "<"; + case exports.EnumToken.LteTokenType: + return "<="; + case exports.EnumToken.Tilda: + case exports.EnumToken.SubsequentSiblingCombinatorTokenType: + return "~"; + case exports.EnumToken.Plus: + case exports.EnumToken.NextSiblingCombinatorTokenType: + return "+"; + case exports.EnumToken.GtTokenType: + case exports.EnumToken.ChildCombinatorTokenType: + return ">"; + case exports.EnumToken.GteTokenType: + return ">="; + case exports.EnumToken.ColumnCombinatorTokenType: + return "||"; + case exports.EnumToken.EndParensTokenType: + return ")"; + case exports.EnumToken.AttrStartTokenType: + return "["; + case exports.EnumToken.AttrEndTokenType: + return "]"; + case exports.EnumToken.DescendantCombinatorTokenType: + case exports.EnumToken.WhitespaceTokenType: + return " "; + case exports.EnumToken.ColonTokenType: + return ":"; + case exports.EnumToken.DoubleColonTokenType: + return "::"; + case exports.EnumToken.SemiColonTokenType: + return ";"; + case exports.EnumToken.CommaTokenType: + return ","; + case exports.EnumToken.ImportantTokenType: + return "!important"; + case exports.EnumToken.Pipe: + return "|"; + case exports.EnumToken.AttrTokenType: + case exports.EnumToken.IdenListTokenType: + return "[" + token.chi.reduce(reducer, "") + "]"; + case exports.EnumToken.TimeTokenType: + case exports.EnumToken.AngleTokenType: + case exports.EnumToken.LengthTokenType: + case exports.EnumToken.DimensionTokenType: + case exports.EnumToken.FrequencyTokenType: + case exports.EnumToken.ResolutionTokenType: + let val = token.val.typ == exports.EnumToken.FractionTokenType + ? renderValue(token.val, options, cache) + : minifyNumber(token.val); + let unit = token.unit; + if (token.typ == exports.EnumToken.AngleTokenType && !val.includes("/")) { + const angle = getAngle(token); + let v; + let value = val + unit; + for (const u of ["turn", "deg", "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; + } + break; + case "deg": + v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); + if (v.length + 3 < value.length) { + val = v; + unit = u; + value = v + u; + } + 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; + } + break; + case "grad": + v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); + 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 = { + "+": 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, + ...flexUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.FlexTokenType; + return acc; + }, Object.create(null)), + ...dimensionUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.LengthTokenType; + return acc; + }, Object.create(null)), + ...resolutionUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.ResolutionTokenType; + return acc; + }, Object.create(null)), + ...angleUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.AngleTokenType; + return acc; + }, Object.create(null)), + ...timeUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.TimeTokenType; + return acc; + }, Object.create(null)), + ...frequencyUnits.reduce((acc, curr) => { + acc[curr] = exports.EnumToken.FrequencyTokenType; + return acc; + }, Object.create(null)), + ...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, +]); +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); +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) { + let i = SymbolsMapTokensKeys.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = len == SymbolsMapTokensKeys[i].length; + if (!match) { + continue; + } + for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { + index = start + j; + if (index > end) { + match = false; + break; + } + ca = SymbolsMapTokensKeys[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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) { + continue; + } + return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; + } + return null; +} +function searchArray(array, parseInfo, start, end) { + let i = array.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = true; + for (j = 0; j < array[i].length; j++) { + if (len != array[i].length) { + match = false; + break; + } + index = start + j; + if (index > end) { + match = false; + break; + } + ca = array[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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 array[i]; + } + } + return null; +} +class Tokenizer { + typ = null; + kin = null; + nam = null; + val = null; + unit = null; + srcId = null; + sta = null; + end = null; + bytesIn = null; + decodeString = null; + slice = null; + source = null; + hint = null; + *consumeString(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(parseInfo); + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + } + if (isNewLine(charCode)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); + } + // EOF - 'Unclosed-string' fixed + yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + // return result; + } + *consumeURLToken(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(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.next(parseInfo, k); + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + if (isWhiteSpace(charCode)) { + this.next(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.next(parseInfo, k); + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + break; + } + // consume until the ')' + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.next(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.next(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return; + } + this.next(parseInfo); + } + yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); + } + // EOF - bad url token + yield 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; + } + if (isLetter(codepoint)) { + hasLetter = true; } - if (colorSpaceDef.length > 0) { - if (result.length > 0) { - result.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - result.push(...colorSpaceDef); + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; } - if (result.length > 0) { - result.push({ typ: exports.EnumToken.CommaTokenType }); + else { + return 0; } - result.push(...reduceColorStops(slice.slice(i))); - slice.length = 0; - slice.push(...result); } - break; - case "conic-gradient": - case "repeating-conic-gradient": - { - let i = 0; - const angles = []; - const positions = []; - const colorSpaceDef = []; - // while ( - // i < slice.length && - // (slice[i].typ === EnumToken.WhitespaceTokenType || - // slice[i].typ === EnumToken.CommentTokenType) - // ) { - // i++; - // } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase(slice[i].val, "from")) { - angles.push(slice[i++]); - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - angles.push(slice[i++]); - } - if ((slice[i]?.typ === exports.EnumToken.NumberTokenType || - slice[i]?.typ === exports.EnumToken.AngleTokenType) && - 0 === toDegrees(slice[i]).val) { - angles.length = 0; - i++; - } - else if (slice[i]?.typ !== exports.EnumToken.CommaTokenType && - slice[i].typ != exports.EnumToken.IdenTokenType) { - angles.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase(slice[i].val, "at")) { - i++; - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - let position1 = ""; - let position2 = ""; - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - !equalsIgnoreCase("in", slice[i].val)) { - position1 = slice[i].val; - positions.push(slice[i++]); - } - else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || - slice[i]?.typ === exports.EnumToken.NumberTokenType) { - position1 = slice[i].val + "%"; - positions.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - positions.push(slice[i++]); - } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - !equalsIgnoreCase("in", slice[i].val)) { - position2 = slice[i].val; - positions.push(slice[i++]); - } - else if (slice[i]?.typ === exports.EnumToken.PercentageTokenType || - slice[i]?.typ === exports.EnumToken.NumberTokenType) { - position2 = slice[i].val + "%"; - positions.push(slice[i++]); - } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; - } - if (position1.length > 0) { - reducegradientBackgroundPosition(positions, `${position1} ${position2}`.trim()); - } + } + if (!hasLetter && !hasPercent) { + while (++position < parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(position); + // eof + if (codepoint != codepoint) { + break; } - while (i < slice.length && - (slice[i].typ === exports.EnumToken.WhitespaceTokenType || - slice[i].typ === exports.EnumToken.CommentTokenType)) { - i++; + if (isDigit(codepoint)) { + position++; + continue; } - if (slice[i]?.typ === exports.EnumToken.IdenTokenType && - equalsIgnoreCase("in", slice[i].val)) { - while (i < slice.length && slice[i].typ !== exports.EnumToken.CommaTokenType) { - colorSpaceDef.push(slice[i++]); - } + if (!hasDigits) { + return 0; } - if (slice[i]?.typ === exports.EnumToken.CommaTokenType) { - i++; + 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; } - const result = []; - if (positions.length > 0) { - if (positions.length > 0) { - if (angles.length > 0) { - angles.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - angles.push({ typ: exports.EnumToken.IdenTokenType, val: "at" }, { typ: exports.EnumToken.WhitespaceTokenType }, ...positions); - } + else if (isLetter(codepoint)) { + hasLetter = true; + break; } - if (angles.length > 0) { - result.push(...angles, { typ: exports.EnumToken.CommaTokenType }); + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + break; } - if (colorSpaceDef.length > 0) { - if (colorSpaceDef.length > 0) { - if (result.length > 0) { - result.push({ typ: exports.EnumToken.WhitespaceTokenType }); - } - result.push(...colorSpaceDef); - } - result.push({ typ: exports.EnumToken.CommaTokenType }); + else { + return 0; } - result.push(...reduceConicColorStops(slice.slice(i))); - slice.length = 0; - slice.push(...result); } - break; + 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; + } + 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; + } + 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; + } + 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 = 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 (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; + } } - return token.val + "(" + slice.reduce(reducer, "") + ")"; } - case exports.EnumToken.TimingFunctionTokenType: - case exports.EnumToken.PseudoClassFuncTokenType: - case exports.EnumToken.WhenElseFunctionTokenType: - case exports.EnumToken.TimelineFunctionTokenType: - case exports.EnumToken.GridTemplateFuncTokenType: - case exports.EnumToken.SupportsFunctionTokenType: - case exports.EnumToken.ContainerFunctionTokenType: - case exports.EnumToken.TransformFunctionTokenType: - case exports.EnumToken.GeneralEnclosedFunctionTokenType: - case exports.EnumToken.CustomFunctionTokenType: - case exports.EnumToken.WildCardFunctionTokenType: - if (token.typ == exports.EnumToken.MathFunctionTokenType && - token.chi.length == 1 && - ![exports.EnumToken.BinaryExpressionTokenType, exports.EnumToken.FractionTokenType, exports.EnumToken.IdenTokenType].includes(token.chi[0].typ) && - // @ts-ignore - token.chi[0].val - ?.typ != exports.EnumToken.FractionTokenType) { - return (token.val + - "(" + - token.chi.reduce((acc, curr) => acc + - renderValue(curr, token.typ == exports.EnumToken.FunctionTokenType ? { minify: false } : options, cache, reducer), "") + - ")"); + } + 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 = 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); + }); + this.decodeString = true; } - return ( - /* options.minify && 'Pseudo-class-func' == token.typ && token.val.slice(0, 2) == '::' ? token.val.slice(1) :*/ (token.val ?? "") + - "(" + - token.chi.reduce(reducer, "") + - ")"); - // case EnumToken.MatchExpressionTokenType: - // return ( - // renderValue((token as MatchExpressionToken).l as Token, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).op, options, cache, reducer, errors) + - // renderValue((token as MatchExpressionToken).r, options, cache, reducer, errors) + - // ((token as MatchExpressionToken).attr ? " " + (token as MatchExpressionToken).attr : "") - // ); - // case EnumToken.NameSpaceAttributeTokenType: - // return ( - // ((token as NameSpaceAttributeToken).l == null - // ? "" - // : renderValue((token as NameSpaceAttributeToken).l as Token, options, cache, reducer, errors)) + - // "|" + - // renderValue((token as NameSpaceAttributeToken).r, options, cache, reducer, errors) - // ); - // case EnumToken.ComposesSelectorNodeType: - // return ( - // (token as ComposesSelectorToken).l.reduce( - // (acc: string, curr: Token) => acc + renderValue(curr, options, cache), - // "", - // ) + - // ((token as ComposesSelectorToken).r == null - // ? "" - // : " from " + - // renderValue((token as ComposesSelectorToken).r as Token, options, cache, reducer, errors)) - // ); - case exports.EnumToken.BlockStartTokenType: - return "{"; - case exports.EnumToken.BlockEndTokenType: - return "}"; - case exports.EnumToken.StartParensTokenType: - return "("; - case exports.EnumToken.DelimTokenType: - case exports.EnumToken.EqualMatchTokenType: - return "="; - case exports.EnumToken.IncludeMatchTokenType: - return "~="; - case exports.EnumToken.DashMatchTokenType: - return "|="; - case exports.EnumToken.StartMatchTokenType: - return "^="; - case exports.EnumToken.EndMatchTokenType: - return "$="; - case exports.EnumToken.ContainMatchTokenType: - return "*="; - case exports.EnumToken.LtTokenType: - return "<"; - case exports.EnumToken.LteTokenType: - return "<="; - case exports.EnumToken.Tilda: - case exports.EnumToken.SubsequentSiblingCombinatorTokenType: - return "~"; - case exports.EnumToken.Plus: - case exports.EnumToken.NextSiblingCombinatorTokenType: - return "+"; - case exports.EnumToken.GtTokenType: - case exports.EnumToken.ChildCombinatorTokenType: - return ">"; - case exports.EnumToken.GteTokenType: - return ">="; - case exports.EnumToken.ColumnCombinatorTokenType: - return "||"; - case exports.EnumToken.EndParensTokenType: - return ")"; - case exports.EnumToken.AttrStartTokenType: - return "["; - case exports.EnumToken.AttrEndTokenType: - return "]"; - case exports.EnumToken.DescendantCombinatorTokenType: - case exports.EnumToken.WhitespaceTokenType: - return " "; - case exports.EnumToken.ColonTokenType: - return ":"; - case exports.EnumToken.DoubleColonTokenType: - return "::"; - case exports.EnumToken.SemiColonTokenType: - return ";"; - case exports.EnumToken.CommaTokenType: - return ","; - case exports.EnumToken.ImportantTokenType: - return "!important"; - case exports.EnumToken.Pipe: - return "|"; - case exports.EnumToken.AttrTokenType: - case exports.EnumToken.IdenListTokenType: - return "[" + token.chi.reduce(reducer, "") + "]"; - case exports.EnumToken.TimeTokenType: - case exports.EnumToken.AngleTokenType: - case exports.EnumToken.LengthTokenType: - case exports.EnumToken.DimensionTokenType: - case exports.EnumToken.FrequencyTokenType: - case exports.EnumToken.ResolutionTokenType: - let val = token.val.typ == exports.EnumToken.FractionTokenType - ? renderValue(token.val, options, cache) - : minifyNumber(token.val); - let unit = token.unit; - if (token.typ == exports.EnumToken.AngleTokenType && !val.includes("/")) { - const angle = getAngle(token); - let v; - let value = val + unit; - for (const u of ["turn", "deg", "rad", "grad"]) { - if (token.unit == u) { + 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; + } + 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; + } + 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; + } + 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); + } + 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 + parseInfo.offset + i); + } + } + } + parseInfo.currentPosition += char.length; + return char; + } + 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; + } + 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); + } + 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; + } + 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; + } + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + *tokenize(parseInfo, yieldEOFToken = true) { + if (typeof parseInfo == "string") { + parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + slice: this.slice, + sign: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + continue; + } + } + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + charCode = this.peek(parseInfo).charCodeAt(0); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? exports.EnumToken.DashedIdenTokenType + : exports.EnumToken.IdenTokenType); + continue; + } + } + } + if (charCode == 64 /* TokenMap.AT */) { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); + continue; + } + } + } + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); + continue; + } + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.HashTokenType); continue; } - switch (u) { - case "turn": - v = minifyNumber(toPrecisionAngle(angle, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; - } + } + } + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); + break; + // '+' or '-' + case 43 /* TokenMap.PLUS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + if (isDigit(charCode)) { + tokensCount = this.consumeNumericToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + slice: this.slice, + sign: "+", + }); + break; + } + } + yield this.makeToken(parseInfo, exports.EnumToken.Plus); + break; + 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.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Sub); break; - case "deg": - v = minifyNumber(toPrecisionAngle(angle * 360, colorPrecision, false)); - if (v.length + 3 < value.length) { - val = v; - unit = u; - value = v + u; + } + if (charCode == 45 /* TokenMap.MINUS */ && + (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); + continue; } + } + } + this.next(parseInfo); + break; + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); + break; + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); + break; + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); 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 (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); + yield this.makeToken(parseInfo, hint); + this.next(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === exports.EnumToken.UrlFunctionTokenDefType) { + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.next(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + yield* this.consumeURLToken(parseInfo); + } + else { + do { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || + !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + } + } } break; - case "grad": - v = minifyNumber(toPrecisionAngle(angle * 400, colorPrecision, false)); - if (v.length + 4 < value.length) { - val = v; - unit = u; - value = v + u; + } + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); + break; + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); + break; + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); + break; + // ']' + case 93 /* TokenMap.RIGHT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); + break; + case 59 /* TokenMap.SEMICOLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); + break; + case 58 /* TokenMap.COLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); + break; + } + yield this.makeToken(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) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.next(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + yield this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); + break; + case 44 /* TokenMap.COMMA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); + break; + case 36 /* TokenMap.DOLLAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "$=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); + break; + } + this.next(parseInfo); + break; + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Tilda); + break; + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); + break; + } + this.next(parseInfo); + break; + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Star); + break; + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); + break; + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); + break; + } + else if (this.match(parseInfo, "|=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.Pipe); + break; + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.next(parseInfo, 10); + yield this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); + break; + } + this.next(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (!this.match(parseInfo, "/*")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); + break; + } + this.next(parseInfo, 2); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); + break; } - 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"; + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); } - 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), "")); + break; + case 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.GteTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, exports.EnumToken.GtTokenType); + break; + case 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "<=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.LteTokenType); + break; + } + this.next(parseInfo); + if (this.match(parseInfo, "!--")) { + this.next(parseInfo, 3); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + yield this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + } + else { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + } + } + break; + case 35 /* TokenMap.HASH */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + break; + case 92 /* TokenMap.REVERSE_SOLIDUS */: + if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + break; + } + this.next(parseInfo); + // EOF + if (!this.peek(parseInfo)) { + if (!yieldEOFToken) { + break; + } + // end of stream ignore \\ + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + break; + } + this.next(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + yield* this.consumeString(parseInfo); + break; + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset + 1) + .charCodeAt(0); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.next(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); + break; + } + } + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + this.next(parseInfo, 2); + break; + } + this.next(parseInfo); + break; + default: + this.next(parseInfo); + break; + } + if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + break; + } + } + if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + yield this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); } - 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 ""; + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async *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); + } + yield* this.tokenize(parseInfo, done); + if (done) { + break; + } + } + parseInfo.stream = parseInfo.source.getContent(); + yield* this.tokenize(parseInfo); + } } /** - * Remove whitespace tokens that are not needed - * @param values - * - * @internal + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken */ -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; +function tokenize(parseInfo, yieldEOFToken = true) { + return new Tokenizer().tokenize(parseInfo, yieldEOFToken); +} +/** + * tokenize readable stream + * @param input + * @param parseInfo + */ +function tokenizeStream(input, parseInfo) { + return new Tokenizer().tokenizeStream(input, parseInfo); } /** @@ -26094,7 +26844,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 && @@ -26102,7 +26854,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); @@ -26125,10 +26879,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, @@ -26178,7 +26931,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; } @@ -26190,7 +26943,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; } @@ -26202,7 +26955,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; } @@ -26214,7 +26967,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; } @@ -26269,10 +27022,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]: [ @@ -26300,10 +27052,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, @@ -26321,7 +27072,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 @@ -26338,20 +27089,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; } @@ -26371,83 +27179,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 ? { @@ -26460,17 +27195,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" }); - // } - // } } } } @@ -26489,36 +27213,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) { @@ -26607,10 +27301,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 @@ -26662,6 +27355,7 @@ function parseGridTemplate(template) { * @param errors */ function parseDeclaration(tokens, parent, options, errors) { + // console.error(tokens); const name = tokens.shift(); let i; let rules = null; @@ -26682,16 +27376,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", }, ]; @@ -26721,39 +27414,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; - // } - // } } } } @@ -26791,12 +27451,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 @@ -26846,7 +27505,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); // } @@ -26884,26 +27543,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); @@ -26976,9 +27615,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; @@ -27008,7 +27647,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]), }); } } @@ -27060,12 +27699,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 @@ -27098,10 +27736,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 @@ -27110,14 +27747,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)) { @@ -27135,18 +27764,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 @@ -27216,7 +27842,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]), }); } } @@ -27226,7 +27852,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]), }); } } @@ -27268,7 +27894,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; } @@ -27278,7 +27904,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); @@ -27289,7 +27915,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)), @@ -27332,7 +27958,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]; } } @@ -27367,7 +27995,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(); @@ -27395,7 +28025,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]; } } @@ -27411,7 +28043,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; @@ -27432,13 +28064,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) { @@ -27446,7 +28080,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; @@ -27456,8 +28090,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(); @@ -27479,7 +28114,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; @@ -27548,7 +28185,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; } @@ -27561,7 +28198,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; } @@ -27611,7 +28248,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(); @@ -27625,7 +28264,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 @@ -27656,7 +28297,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(); } @@ -27671,7 +28314,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(); @@ -27692,7 +28337,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: [ @@ -27752,11 +28397,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), @@ -27772,7 +28413,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]), }, ], }; @@ -27802,7 +28443,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]), }, ], }; @@ -27829,7 +28470,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]), }, ], }; @@ -27952,7 +28593,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)); @@ -27975,32 +28618,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; @@ -28009,7 +28633,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(); @@ -28020,20 +28646,6 @@ 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)); return { success, errors }; @@ -28083,19 +28695,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++]); } @@ -28111,7 +28710,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 `, }, ], @@ -28136,11 +28735,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())); @@ -28174,174 +28772,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 } @@ -28351,13 +28809,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; @@ -28372,14 +28832,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; @@ -28401,21 +28863,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) { @@ -28433,31 +28886,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, @@ -28472,9 +28913,6 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { 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); return acc; }, [])); @@ -28489,24 +28927,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); @@ -28547,7 +28967,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 +28982,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 +28998,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; @@ -28594,7 +29014,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; @@ -28614,8 +29034,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; } @@ -29097,46 +29516,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; + while ((tokenizer = iter.next().value) != null) { + // 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; + // console.error(item); + 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) { @@ -29144,19 +29595,53 @@ 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 = [item]; do { - item = iter[++currentItemIndex]; - if (item == null) { + tokenizer = iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + 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; + 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); @@ -29164,17 +29649,15 @@ function doParseSync(iter, options = {}) { 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 === 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 && @@ -29398,7 +29881,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`, }, }; @@ -29472,7 +29955,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) { @@ -29591,7 +30074,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) { @@ -29825,7 +30308,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 = ""; @@ -29962,52 +30445,83 @@ async function doParse(iter, options = {}) { let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer; // 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 = isAsync + ? (await iter.next()).value + : iter.next().value)) { + 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) { @@ -30018,23 +30532,55 @@ 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 = [item]; do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { + tokenizer = isAsync + ? (await iter.next()).value + : iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === exports.EnumToken.BlockStartTokenType) { + 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; + 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); @@ -30042,17 +30588,15 @@ async function doParse(iter, options = {}) { 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 === 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 && @@ -30100,6 +30644,7 @@ 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, { minify: false, @@ -30325,7 +30870,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`, }, }; @@ -30421,7 +30966,7 @@ async function doParse(iter, options = {}) { 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; @@ -30861,7 +31406,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 = ""; @@ -30898,31 +31443,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) { @@ -30954,7 +31474,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)) { @@ -30975,7 +31494,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--; } @@ -30987,7 +31508,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; @@ -31010,7 +31531,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; @@ -31091,7 +31612,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) { @@ -31130,7 +31651,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); @@ -31151,7 +31672,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); @@ -31169,8 +31690,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; @@ -31190,7 +31711,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); @@ -31213,7 +31734,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 ", }); } @@ -31222,7 +31743,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 ", }); } @@ -31231,7 +31752,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", }); } @@ -31239,7 +31760,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, @@ -31252,7 +31773,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, @@ -31267,7 +31788,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { 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, @@ -31286,7 +31807,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}`, }); } @@ -31297,13 +31818,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]]; @@ -31319,7 +31840,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { if (result.errors.length > 0) { errors.push(...result.errors); } - 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; @@ -31338,7 +31859,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } // @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; @@ -31358,14 +31879,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]]; @@ -31408,7 +31929,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; @@ -31436,8 +31957,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; @@ -31498,7 +32018,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", }); } @@ -31507,14 +32027,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); @@ -31531,7 +32051,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { if (result.errors.length > 0) { errors.push(...result.errors); } - 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; @@ -31551,7 +32071,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; @@ -31560,7 +32080,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; @@ -31586,7 +32106,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; @@ -31599,7 +32119,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; @@ -31612,7 +32132,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; @@ -31631,8 +32151,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]]; @@ -31645,7 +32164,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]]; @@ -31676,7 +32195,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", }); } @@ -31689,14 +32208,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]]; @@ -31718,7 +32237,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; @@ -31744,10 +32265,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { 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, @@ -31762,10 +32282,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]: [], @@ -31776,19 +32295,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 @@ -31826,7 +32341,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), @@ -31839,10 +32354,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } } } - 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; @@ -31901,18 +32413,48 @@ async function parseDeclarations(declaration) { * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { - stream: src, - offset: 0, - time: 0, - source: new SourceFile(src, [], ""), - position: 0, - currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const iter = tokenize(src); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + let tokenizer; + while ((tokenizer = iter.next().value)) { + 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 @@ -31958,7 +32500,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); } } @@ -31977,7 +32519,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; @@ -32005,13 +32547,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, @@ -32127,7 +32669,7 @@ 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 []; } @@ -32213,7 +32755,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": @@ -32235,7 +32777,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; @@ -32413,7 +32957,7 @@ function parseSync(...args) { currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); } /** * Transform CSS @@ -32570,7 +33114,7 @@ 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 ? tokenizeStream(stream, options.parseInfo) : tokenize(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..886d91f1 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; @@ -2668,11 +2677,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 @@ -4072,7 +4092,7 @@ declare class SourceFile { /** * Source file content */ - private content; + content: string; /** * Constructor * @param content @@ -4908,7 +4928,6 @@ interface BorderRadius { * node walker options */ export declare interface WalkerOptions { - /** * walk in reverse */ @@ -4953,7 +4972,7 @@ export declare type WalkerValueFilter = ( 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 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/math/expression.js b/dist/lib/ast/math/expression.js index 793bf50e..0317e6a8 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'; @@ -58,7 +58,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 +80,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 +107,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 +146,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 +186,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 +229,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 +260,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 +325,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 +341,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 +390,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 +401,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 +414,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 +453,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 +491,7 @@ 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 +509,12 @@ function inlineExpression(token) { result.push(token); } else { - result.push(...inlineExpression(token.l), { typ: token.op, [LOC]: token[LOC] }, ...inlineExpression(token.r)); + result.push(...inlineExpression(token.l), { + typ: token.op, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, ...inlineExpression(token.r)); } } else { @@ -443,7 +577,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 +621,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..2124e9bd 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], }, ], }; @@ -1144,7 +1145,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") { 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/walk.js b/dist/lib/ast/walk.js index 007b0984..337ac363 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* () { @@ -357,6 +358,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), WalkerEvent.Leave); // @ts-ignore if (option != null && ("typ" in option || Array.isArray(option))) { diff --git a/dist/lib/parser/declaration/list.js b/dist/lib/parser/declaration/list.js index e693bd67..4181137f 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(); @@ -32,12 +34,12 @@ class PropertyList { name = declaration.typ != EnumToken.DeclarationNodeType ? null - : declaration.nam.toLowerCase(); + : 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 +67,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; 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..cc1909bf 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -6,7 +6,7 @@ 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 { 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'; @@ -501,46 +501,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; + while ((tokenizer = iter.next().value) != null) { + // 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; + // console.error(item); + 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,19 +580,53 @@ 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 = [item]; do { - item = iter[++currentItemIndex]; - if (item == null) { + tokenizer = iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === EnumToken.BlockStartTokenType) { + 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; + 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); @@ -568,17 +634,15 @@ function doParseSync(iter, options = {}) { 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) { + 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 && @@ -802,7 +866,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`, }, }; @@ -876,7 +940,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 +1059,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 +1293,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 = ""; @@ -1366,52 +1430,83 @@ async function doParse(iter, options = {}) { let isAsync = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch = 0; let curlyBracketMatch = 0; + let tokenizer; // 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 = isAsync + ? (await iter.next()).value + : iter.next().value)) { + 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,23 +1517,55 @@ 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 = [item]; do { - item = isAsync - ? // @ts-expect-error - (await iter.next()).value - : // @ts-expect-error - iter.next().value; - if (item == null) { + tokenizer = isAsync + ? (await iter.next()).value + : iter.next().value; + if (tokenizer == null) { break; } - tokens.push(item.token); - if (item.token.typ === EnumToken.BlockStartTokenType) { + 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; + 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); @@ -1446,17 +1573,15 @@ async function doParse(iter, options = {}) { 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) { + 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 && @@ -1504,6 +1629,7 @@ 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, { minify: false, @@ -1729,7 +1855,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`, }, }; @@ -1825,7 +1951,7 @@ async function doParse(iter, options = {}) { 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; @@ -2265,7 +2391,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 +2428,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 +2459,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 +2479,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 +2493,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 +2516,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 +2597,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 +2636,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 +2657,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 +2675,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 +2696,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 +2719,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 +2728,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 +2737,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 +2745,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 +2758,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, @@ -2671,7 +2773,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { 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 +2792,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 +2803,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]]; @@ -2723,7 +2825,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { if (result.errors.length > 0) { errors.push(...result.errors); } - 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; @@ -2742,7 +2844,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } // @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 +2864,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]]; @@ -2812,7 +2914,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; @@ -2840,8 +2942,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; @@ -2902,7 +3003,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 +3012,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); @@ -2935,7 +3036,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { if (result.errors.length > 0) { errors.push(...result.errors); } - 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 +3056,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 +3065,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 +3091,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 +3104,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 +3117,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 +3136,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 +3149,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 +3180,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 +3193,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 +3222,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; @@ -3148,10 +3250,9 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { 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 +3267,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 +3280,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 @@ -3230,7 +3326,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), @@ -3243,10 +3339,7 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { } } } - 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; @@ -3305,18 +3398,48 @@ async function parseDeclarations(declaration) { * ``` */ function parseString(src, options = { parseColor: true }, errors) { - const parseInfo = { - stream: src, - offset: 0, - time: 0, - source: new SourceFile(src, [], ""), - position: 0, - currentPosition: 0, - }; - const tokenResults = tokenize(parseInfo); + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + const iter = tokenize(src); const mapped = []; - for (const token of tokenResults) { - mapped.push(token.token); + let token; + let tokenizer; + while ((tokenizer = iter.next().value)) { + 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 +3485,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 +3504,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 +3532,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,7 +3654,7 @@ 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 []; } diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index efd932cb..871a4ae1 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -1,8 +1,7 @@ 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, @@ -35,6 +34,30 @@ const SymbolsMapTokens = { "\r": EnumToken.Whitespace, "\n": EnumToken.Whitespace, "\f": EnumToken.Whitespace, + ...flexUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.FlexTokenType; + return acc; + }, Object.create(null)), + ...dimensionUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.LengthTokenType; + return acc; + }, Object.create(null)), + ...resolutionUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.ResolutionTokenType; + return acc; + }, Object.create(null)), + ...angleUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.AngleTokenType; + return acc; + }, Object.create(null)), + ...timeUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.TimeTokenType; + return acc; + }, Object.create(null)), + ...frequencyUnits.reduce((acc, curr) => { + acc[curr] = EnumToken.FrequencyTokenType; + return acc; + }, Object.create(null)), ...pseudoElements.reduce((acc, curr) => { acc[curr] = EnumToken.PseudoElementTokenType; return acc; @@ -104,6 +127,7 @@ const hintsEnum = new Set([ EnumToken.ColonTokenType, EnumToken.EOFTokenType, ]); +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); var TokenMap; (function (TokenMap) { TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; @@ -134,818 +158,1451 @@ 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) { + let i = SymbolsMapTokensKeys.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = len == SymbolsMapTokensKeys[i].length; + if (!match) { + continue; + } + for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { + index = start + j; + if (index > end) { + 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; + ca = SymbolsMapTokensKeys[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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; } - next(parseInfo, 2); - continue; } - if (charCode == quote) { - next(parseInfo); - result.push(yieldResult(parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null)); - return result; - } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BadStringTokenType)); - return result; + if (!match) { + continue; } - next(parseInfo); + return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } - // 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; +function searchArray(array, parseInfo, start, end) { + let i = array.length; + let j; + let ca; + let cb; + let match; + let index; + const len = end - start; + while (i--) { + match = true; + for (j = 0; j < array[i].length; j++) { + if (len != array[i].length) { + match = false; 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; + } + index = start + j; + if (index > end) { + match = false; break; - case EnumToken.WildCardFunctionTokenDefType: - searchArray = wildCardFuncs; + } + ca = array[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); + // 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)); + if (match) { + return array[i]; } - 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, - }; + return null; +} +class Tokenizer { + typ = null; + kin = null; + nam = null; + val = null; + unit = null; + srcId = null; + sta = null; + end = null; + bytesIn = null; + decodeString = null; + slice = null; + source = null; + hint = null; + *consumeString(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(parseInfo); + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + } + if (isNewLine(charCode)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); } - else if (chr == "@" && isIdent(slice)) { - token = { - typ: EnumToken.AtRuleTokenType, - nam: slice, - }; + // EOF - 'Unclosed-string' fixed + yield this.makeToken(parseInfo, EnumToken.StringTokenType); + // return result; + } + *consumeURLToken(parseInfo) { + const quote = this.next(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.next(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.next(parseInfo, length); + continue; + } + this.next(parseInfo, 2); + continue; + } + if (charCode == quote) { + this.next(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.next(parseInfo, k); + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } + if (isWhiteSpace(charCode)) { + this.next(parseInfo, k); + k++; + continue; + } + if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { + this.next(parseInfo, k); + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } + break; + } + // consume until the ')' + yield this.makeToken(parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); + return; + // return result; + } + if (isNewLine(charCode)) { + // bad string + this.next(parseInfo); + while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { + if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { + this.next(parseInfo, 2); + continue; + } + if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } + this.next(parseInfo); + } + yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); + return; + } + this.next(parseInfo); } - else if (chr == "." && isIdent(slice)) { - token = { - typ: EnumToken.ClassSelectorTokenType, - val, - }; + // EOF - bad url token + yield this.makeToken(parseInfo, 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++; } - 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, - }; + // 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; } - 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), - }; + 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; + } + if (isLetter(codepoint)) { + hasLetter = true; + } + else if (codepoint == 37 /* TokenMap.PERCENTAGE */) { + hasPercent = true; + } + else { + return 0; + } + } + } + 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; + } + } + } + } } - else if ((dimension = parseDimension(val))) { - token = dimension; + if (!hasDigits) { + return 0; } - else if (isIdent(val)) { - token = { - typ: val.startsWith("--") ? EnumToken.DashedIdenTokenType : EnumToken.IdenTokenType, - val, - }; + 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 (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; + 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) ?? EnumToken.DimensionTokenType; + return position - offset; + } + return 0; } + return 0; } - 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) ; + 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 { - parseInfo.source.lineStarts.lineStarts.push(position + i); + 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; } - 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; + 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; + } + 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; + 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 : 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 = 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 (hintsEnum.has(hint)) { + this.typ = hint; } else { - i += start; + 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; + } + } + else if (hint == EnumToken.NumberTokenType) { + this.val = parseFloat(val); + } + else if (hint == EnumToken.AtRuleTokenType) { + this.nam = val; + } + else { + this.val = val; + if (hint == EnumToken.ColorTokenType) { + this.kin = ColorType.HEX; + } + } } } else { - if (end < 0) { - j += end; + if (this.equalsIgnoreCase(parseInfo, "!important")) { + this.typ = EnumToken.ImportantTokenType; } - else { - j = parseInfo.position + end; + } + if (this.typ == null) { + val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); + 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); + }); + 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; } - j--; - let codepoint = parseInfo.stream.charCodeAt(i); - // - - if (codepoint == 0x2d) { - let nextCodepoint; - if ((nextCodepoint = parseInfo.stream.charCodeAt(i + 1)) != nextCodepoint) { - return false; + 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; + } } - if (isDigit(nextCodepoint)) { - return false; + return true; + } + 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; + } } - codepoint = nextCodepoint; - i++; + return true; } - if (codepoint !== 0x2d && !isIdentStart(codepoint)) { - return false; + 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); } - 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; - // } - // } + 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 + parseInfo.offset + i); + } + } + } + parseInfo.currentPosition += char.length; + return char; } - while (i < j) { - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - codepoint = parseInfo.stream.charCodeAt(i); + 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); - i += codepoint < 0x80 ? 1 : String.fromCodePoint(codepoint).length; - continue; - } - if (codepoint !== 0x2d && !isIdentCodepoint(codepoint)) { - return false; + 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; } - 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++; + 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); } - 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) { + 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; + } + isURLToken(parseInfo) { + let i = parseInfo.position - parseInfo.offset; + let c; + while (++i < parseInfo.currentPosition) { c = parseInfo.stream.charCodeAt(i); - // c is not '\n' or '\r' or '\f' - if (c == 0x6e || c == 0x72 || c == 0x66) { + // single quote or double quote or start parenthesis or close parenthesis + if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { return false; } - continue; - } - // is white space - if (c == 0x20 || c == 0x09) { - break; + // 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; } - 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)); - 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)); + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + *tokenize(parseInfo, yieldEOFToken = true) { + if (typeof parseInfo == "string") { + parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + slice: this.slice, + sign: charCode == 45 /* TokenMap.MINUS */ ? "-" : charCode == 43 /* TokenMap.PLUS */ ? "+" : null, + }); + continue; } - 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)); + if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + charCode = this.peek(parseInfo).charCodeAt(0); + // do not match function + if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { + yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + ? EnumToken.DashedIdenTokenType + : EnumToken.IdenTokenType); + continue; + } + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BlockStartTokenType)); - break; - // '}' - case 125 /* TokenMap.RIGHT_BRACE */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (charCode == 64 /* TokenMap.AT */) { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + // match at-rule + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.AtRuleTokenType); + continue; + } + } } - 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)); - break; + if (charCode == 35 /* TokenMap.HASH */) { + tokensCount = this.consumeColor(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.ColorTokenType); + continue; } - 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); - } - 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); + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.HashTokenType); + continue; + } + } + } + // EOF + switch (charCode) { + case 61 /* TokenMap.EQUALS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.DelimTokenType); + break; + // '+' or '-' + case 43 /* TokenMap.PLUS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + if (isDigit(charCode)) { + tokensCount = this.consumeNumericToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + slice: this.slice, + sign: "+", + }); + break; + } + } + yield this.makeToken(parseInfo, EnumToken.Plus); + break; + 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.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Sub); + break; + } + if (charCode == 45 /* TokenMap.MINUS */ && + (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { + this.next(parseInfo); + tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.IdenTokenType); + continue; } - 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; + } + } + this.next(parseInfo); + break; + // '{' + case 123 /* TokenMap.LEFT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BlockStartTokenType); + break; + // '}' + case 125 /* TokenMap.RIGHT_BRACE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BlockEndTokenType); + break; + // '(' + case 40 /* TokenMap.LEFT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + if (parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); + break; + } + 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); + yield this.makeToken(parseInfo, hint); + this.next(parseInfo); + // consume '(' + parseInfo.position = parseInfo.currentPosition; + if (hint === EnumToken.UrlFunctionTokenDefType) { + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.next(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + yield* this.consumeURLToken(parseInfo); + } + else { + do { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && + parseInfo.currentPosition < endPosition); + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || + !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType); } } - 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)); } + break; } + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.StartParensTokenType); + break; + // ')' + case 41 /* TokenMap.RIGHT_PARENTHESIS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.EndParensTokenType); + break; + // '[' + case 91 /* TokenMap.LEFT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.AttrStartTokenType); + break; + // ']' + case 93 /* TokenMap.RIGHT_BRACKETS */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.AttrEndTokenType); + break; + case 59 /* TokenMap.SEMICOLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.SemiColonTokenType); + break; + case 58 /* TokenMap.COLON */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); break; } - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.StartParensTokenType)); - break; - // ')' - case 41 /* TokenMap.RIGHT_PARENTHESIS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.EndParensTokenType)); - break; - // '[' - case 91 /* TokenMap.LEFT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrStartTokenType)); - break; - // ']' - case 93 /* TokenMap.RIGHT_BRACKETS */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrEndTokenType)); - break; - case 59 /* TokenMap.SEMICOLON */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, 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, EnumToken.DoubleColonTokenType)); + yield this.makeToken(parseInfo, EnumToken.ColonTokenType); 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); + // \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) { + yield this.makeToken(parseInfo); + } + this.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)); + while (nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029) { + this.next(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + yield this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); 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 44 /* TokenMap.COMMA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.CommaTokenType); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, 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, EnumToken.StartMatchTokenType)); + case 36 /* TokenMap.DOLLAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "$=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.EndMatchTokenType); + break; + } + this.next(parseInfo); 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, EnumToken.ContainMatchTokenType)); + case 126 /* TokenMap.TILDA */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "~=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Tilda); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Star)); - break; - case 38 /* TokenMap.AMPERSAND */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - next(parseInfo); - result.push(yieldResult(parseInfo, 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, EnumToken.ColumnCombinatorTokenType)); + // case '^': + case 94 /* TokenMap.CARET */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "^=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.StartMatchTokenType); + break; + } + this.next(parseInfo); break; - } - else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.DashMatchTokenType)); + case 42 /* TokenMap.STAR */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "*=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Star); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, 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, EnumToken.ImportantTokenType)); + case 38 /* TokenMap.AMPERSAND */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); 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)])); + case 124 /* TokenMap.PIPE */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + // '||' + if (this.match(parseInfo, "||")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); + break; + } + else if (this.match(parseInfo, "|=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.DashMatchTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Pipe); break; - } - 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; + case 33 /* TokenMap.EXCLAMATION */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, "!important")) { + this.next(parseInfo, 10); + yield this.makeToken(parseInfo, EnumToken.ImportantTokenType); + break; + } + this.next(parseInfo); + break; + case 47 /* TokenMap.SLASH */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (!this.match(parseInfo, "/*")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); + break; + } + this.next(parseInfo, 2); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 42 /* TokenMap.STAR */) { + if (this.match(parseInfo, "/")) { + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.CommentTokenType); + break; + } } } - // else { - // buffer += value; - // } - } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCommentTokenType)); - } - break; - case 62 /* TokenMap.GREATERTHAN */: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.GteTokenType)); + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo, EnumToken.BadCommentTokenType); + } 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 62 /* TokenMap.GREATERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + if (this.match(parseInfo, ">=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.GteTokenType); + break; + } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.GtTokenType); 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 60 /* TokenMap.LOWERTHAN */: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); } - if (parseInfo.currentPosition >= endPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCdoTokenType)); + if (this.match(parseInfo, "<=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.LteTokenType); + break; } - else { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.CDOCOMMTokenType)); + this.next(parseInfo); + if (this.match(parseInfo, "!--")) { + this.next(parseInfo, 3); + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == 45 /* TokenMap.MINUS */ && this.match(parseInfo, "->")) { + break; + } + } + if (parseInfo.currentPosition >= endPosition) { + yield this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + } + else { + this.next(parseInfo, 2); + yield 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) { + yield this.makeToken(parseInfo); + } + this.next(parseInfo); + break; + case 92 /* TokenMap.REVERSE_SOLIDUS */: + if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { break; } - // end of stream ignore \\ + this.next(parseInfo); + // EOF + if (!this.peek(parseInfo)) { + if (!yieldEOFToken) { + break; + } + // end of stream ignore \\ + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + break; + } + this.next(parseInfo); + break; + case 39 /* TokenMap.SINGLE_QUOTE */: + case 34 /* TokenMap.DOUBLE_QUOTE */: if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + yield this.makeToken(parseInfo); } + yield* this.consumeString(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); + case 46 /* TokenMap.DOT */: + const codepoint = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset + 1) + .charCodeAt(0); + if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { + this.next(parseInfo); + let tokensCount = this.consumeIdentToken(parseInfo); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); + break; + } + } + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + this.next(parseInfo, 2); + break; + } + this.next(parseInfo); break; - } - next(parseInfo); - break; - default: - next(parseInfo); + default: + this.next(parseInfo); + break; + } + if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { break; + } } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + yield this.makeToken(parseInfo, EnumToken.EOFTokenType); } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async *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); + } + yield* this.tokenize(parseInfo, done); + if (done) { + break; + } } - result.push(yieldResult(parseInfo, EnumToken.EOFTokenType)); + parseInfo.stream = parseInfo.source.getContent(); + yield* this.tokenize(parseInfo); } - parseInfo.time += performance.now() - startTime; - return result; +} +/** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ +function tokenize(parseInfo, yieldEOFToken = true) { + return new Tokenizer().tokenize(parseInfo, yieldEOFToken); } /** * 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; - } - } +function tokenizeStream(input, parseInfo) { + return new Tokenizer().tokenizeStream(input, parseInfo); } -export { SymbolsMapTokens, TokenMap, consumeString, hintsEnum, match, next, peek, tokenize, tokenizeStream, yieldResult }; +export { TokenMap, Tokenizer, hintsEnum, tokenize, tokenizeStream }; diff --git a/dist/lib/parser/utils/at-rule-container.js b/dist/lib/parser/utils/at-rule-container.js index 3fab097b..5bb9d716 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'; @@ -48,19 +48,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 +63,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 +88,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 +125,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 +162,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 +185,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 +216,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 +239,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, @@ -437,9 +266,6 @@ function parseAtRuleContainerQueryList(stream, context, options = {}) { 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); return acc; }, [])); 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..c4338a17 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]), }, ], }; diff --git a/dist/lib/parser/utils/at-rule-media.js b/dist/lib/parser/utils/at-rule-media.js index 94a81b32..53b215c0 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)), @@ -177,7 +177,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 +214,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 +244,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 +262,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 +283,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 +299,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 +309,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 +333,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; diff --git a/dist/lib/parser/utils/at-rule-support.js b/dist/lib/parser/utils/at-rule-support.js index d1a0f235..048c52db 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: [ diff --git a/dist/lib/parser/utils/at-rule-when-else.js b/dist/lib/parser/utils/at-rule-when-else.js index 57babcef..90e67d3f 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,20 +113,6 @@ 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)); 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..0236f852 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 @@ -234,7 +200,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 +238,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 +310,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 +342,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 +394,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 +431,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 +442,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 +459,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..f0d1f8b8 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); @@ -57,10 +61,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 +113,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 +125,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 +137,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 +149,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 +204,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 +234,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 +254,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 +271,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 +361,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 +377,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 +395,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 +483,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..2e6d9787 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, urlTokenMatcher, PARENT, tokensfuncSet, LOCSTA, LOCSRCID, colorPrecision } from '../syntax/constants.js'; +import { minifyNumber, reducegradientBackgroundPosition, reduceConicColorStops, reduceColorStops, parseColor, isWhiteSpace, toPrecisionAngle, 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 @@ -136,43 +137,34 @@ 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]; + // console.error({record}); + 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,6 +177,22 @@ 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); } @@ -192,23 +200,24 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } } 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]); } + // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** * Update position @@ -216,11 +225,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 +354,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 +361,23 @@ 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), - ]); + // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; + // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { + // sourcemaps.sources.push(node[LOCSTA] as number); + // } + // sourcemaps.maps.push([ + // ...linesMap!.getOffsets( + // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, + // ), + // node[LOCSTA], + // ...source!.getOffsets(node![LOCSTA]), + // ]); + // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); + } + else { + move(sourceLocation, linesMap, str); } } } diff --git a/dist/lib/syntax/color/color.js b/dist/lib/syntax/color/color.js index 4027b6b7..aeadb8e1 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'; @@ -86,7 +86,9 @@ function convertColor(token, to) { chi: [...(token.val == "color" ? [chi[offset]] : []), ...Object.values(components)], kin: ColorType[token.val.toUpperCase().replaceAll("-", "_")], }; - tk[LOC] = token[LOC]; + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk; } } diff --git a/dist/lib/syntax/color/relative-color.js b/dist/lib/syntax/color/relative-color.js index b5b34dfe..0787b11c 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'; @@ -103,19 +103,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 +134,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 +175,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 +220,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/constants.js b/dist/lib/syntax/constants.js index 012fc72b..f5f844ca 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"); @@ -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..8361c0a5 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -15,7 +15,12 @@ import { getSyntaxConfig } from '../validation/config.js'; // 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 @@ -841,75 +846,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 +886,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 +900,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)); } @@ -1088,4 +1008,4 @@ function toPrecisionAngle(angle, precision = colorPrecision, correctValue = true 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..8a48351c 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'; @@ -340,7 +340,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]), }, ], }; @@ -394,7 +394,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 +428,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 +472,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 +523,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 +535,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 +574,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 +607,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 +637,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]), }, ], }; @@ -680,7 +680,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 +702,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,7 +728,7 @@ 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]), }, ], }; @@ -775,7 +775,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 +870,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..b2bbbbdd 100644 --- a/dist/node.js +++ b/dist/node.js @@ -191,7 +191,7 @@ function parseSync(...args) { currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); } /** * Transform CSS @@ -348,7 +348,7 @@ 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 ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => (options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options))); } /** * Transform CSS file diff --git a/dist/web.js b/dist/web.js index 53779329..b9478de8 100644 --- a/dist/web.js +++ b/dist/web.js @@ -185,7 +185,9 @@ function parseSync(...args) { currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -318,7 +320,9 @@ 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 ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS 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/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/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/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/math/expression.ts b/src/lib/ast/math/expression.ts index 3e918600..9fba6563 100644 --- a/src/lib/ast/math/expression.ts +++ b/src/lib/ast/math/expression.ts @@ -16,7 +16,7 @@ import type { 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"; @@ -96,7 +96,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 +123,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 +156,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 +205,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 +255,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 +299,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 +336,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 +421,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 +444,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 +502,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 +521,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 +542,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 +602,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 +652,7 @@ 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] }]; } } } @@ -540,7 +674,12 @@ export function inlineExpression(token: Token): Token[] { } else { result.push( ...inlineExpression((token as BinaryExpressionToken).l), - { typ: (token as BinaryExpressionToken).op, [LOC]: (token as BinaryExpressionToken)[LOC] } as Token, + { + typ: (token as BinaryExpressionToken).op, + [LOCSRCID]: (token as BinaryExpressionToken)[LOCSRCID], + [LOCSTA]: (token as BinaryExpressionToken)[LOCSTA], + [LOCEND]: (token as BinaryExpressionToken)[LOCEND], + } as Token, ...inlineExpression((token as BinaryExpressionToken).r), ); } @@ -638,7 +777,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 +831,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..d7696c31 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; @@ -1526,7 +1527,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 ( 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/walk.ts b/src/lib/ast/walk.ts index df5c7825..1e198012 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, @@ -579,6 +580,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 diff --git a/src/lib/parser/arena.ts b/src/lib/parser/arena.ts index 4ea81862..1102e838 100644 --- a/src/lib/parser/arena.ts +++ b/src/lib/parser/arena.ts @@ -12,12 +12,18 @@ class ArenaData { 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(); } @@ -34,11 +40,14 @@ class ArenaData { 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..7e097770 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(); @@ -42,6 +44,7 @@ export class PropertyList { }); } + add(...declarations: AstNode[]) { let name: string | null; let syntaxRules: ValidationToken[] | null = null; @@ -51,14 +54,14 @@ export class PropertyList { name = declaration.typ != EnumToken.DeclarationNodeType ? null - : (declaration as AstDeclaration).nam.toLowerCase(); + : (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) @@ -89,11 +92,33 @@ export class PropertyList { ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.ValidationFailed; } + } // 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; } 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..e3ee21e6 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 { tokenize, Tokenizer, tokenizeStream } 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"; @@ -624,10 +637,7 @@ function parseVisitors( * @throws Error * @private */ -export function doParseSync( - iter: Array | Iterable, - options: ParserSyncOptions = {}, -): ParseResult { +export function doParseSync(iter: Generator, options: ParserSyncOptions = {}): ParseResult { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -693,59 +703,92 @@ 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 = iter.next().value) != null) { + // 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; + // console.error(item); + + 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,22 +797,54 @@ 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]; + tokens = [item]; do { - item = (iter as Array)[++currentItemIndex]; + tokenizer = iter.next().value; - if (item == null) { + if (tokenizer == null) { break; } - tokens.push(item.token); + 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; + } + + 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); @@ -778,18 +853,16 @@ export function doParseSync( 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) { + } 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; @@ -1064,7 +1137,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; @@ -1149,7 +1222,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 +1384,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 +1687,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(":")}'`, ); } } @@ -1709,7 +1782,7 @@ export function doParseSync( * @private */ export async function doParse( - iter: Array | Iterable | AsyncGenerator, + iter: Generator | AsyncGenerator, options: ParserOptions = {}, ): Promise { if (options.signal != null) { @@ -1784,70 +1857,99 @@ 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; // 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; - } + // if (Array.isArray(iter)) { + // // @ts-expect-error + // iter = iter[Symbol.iterator]() as Iterator; + // } while ( - (item = isAsync - ? // @ts-expect-error - ((await iter.next()).value as TokenizeResult) - : // @ts-expect-error - ((iter as Iterator).next().value as TokenizeResult)) + (tokenizer = isAsync + ? ((await iter.next()).value as Tokenizer) + : ((iter as Iterator).next().value as Tokenizer)) ) { - stats.bytesIn = item.bytesIn; + 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; + } + + item[LOCSRCID] = tokenizer.srcId as number; + item[LOCSTA] = tokenizer.sta as number; + item[LOCEND] = tokenizer.end as number; + + 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,26 +1960,56 @@ 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 = [item]; do { - item = isAsync - ? // @ts-expect-error - ((await iter.next()).value as TokenizeResult) - : // @ts-expect-error - ((iter as Iterator).next().value as TokenizeResult); + tokenizer = isAsync + ? ((await iter.next()).value as Tokenizer) + : ((iter as Generator).next().value as Tokenizer); - if (item == null) { + if (tokenizer == null) { break; } - tokens.push(item.token); + 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; + } + + 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); @@ -1886,18 +2018,16 @@ export async function doParse( 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) { + } 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; @@ -1962,6 +2092,7 @@ 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), @@ -2238,7 +2369,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; @@ -2356,7 +2487,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); @@ -2943,7 +3074,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 +3127,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 +3179,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 +3205,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 +3220,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 +3252,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 +3352,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 +3363,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 +3416,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 +3441,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 +3463,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 +3488,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 +3517,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 +3525,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 +3535,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 +3544,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 +3560,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, { @@ -3474,7 +3579,7 @@ export function parseAtRule( 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 +3602,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 +3614,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]]; @@ -3536,7 +3641,7 @@ export function parseAtRule( errors.push(...result.errors); } - 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; @@ -3559,7 +3664,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.ValidationFailed; atRule[ERRORS] = result.success ? [] : result.errors; @@ -3585,8 +3690,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 +3699,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]]; @@ -3650,7 +3755,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; @@ -3689,8 +3794,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; @@ -3767,7 +3871,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 +3879,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 +3888,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); @@ -3805,7 +3909,7 @@ export function parseAtRule( errors.push(...result.errors); } - 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 +3932,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 +3940,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 +3971,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 +3985,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 +3997,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 +4020,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 +4035,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 +4067,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 +4082,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 +4090,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 +4116,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; @@ -4047,10 +4152,9 @@ export function parseAtRule( 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 +4173,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 +4187,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] = []; @@ -4144,7 +4244,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), @@ -4158,10 +4258,8 @@ 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] = result.success ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.Invalid; atRule[ERRORS] = result.errors; @@ -4232,20 +4330,49 @@ export function parseString( options: { src?: string; parseColor?: boolean } | null = { parseColor: true }, errors?: ErrorDescription[], ): Token[] { - const parseInfo: ParseInfo = { - stream: src, - offset: 0, - time: 0, - source: new SourceFile(src, [], ""), - position: 0, - currentPosition: 0, - }; - - const tokenResults: TokenizeResult[] = tokenize(parseInfo); + // const parseInfo: ParseInfo = { + // stream: src, + // offset: 0, + // time: 0, + // source: new SourceFile(src, [], ""), + // position: 0, + // currentPosition: 0, + // }; + + const iter: Generator = tokenize(src); const mapped: Token[] = []; + let token: Token; + let tokenizer: Tokenizer; + + while ((tokenizer = iter.next().value)) { + 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; + } + + token[LOCSRCID] = tokenizer!.source!.id; + token[LOCEND] = tokenizer.end as number; + token[LOCSTA] = tokenizer.sta as number; - for (const token of tokenResults) { - mapped.push(token.token); + mapped.push(token); } const result: Token[] = parseTokens(mapped, options, errors); @@ -4306,7 +4433,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 +4458,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 +4494,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 +4502,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,7 +4644,7 @@ 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 []; 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..bca87381 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,23 +16,23 @@ 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 = { +const SymbolsMapTokens: Record = { "+": EnumToken.Plus, "=": EnumToken.DelimTokenType, "|": EnumToken.Pipe, @@ -80,6 +63,30 @@ export const SymbolsMapTokens: Record = { "\r": EnumToken.Whitespace, "\n": EnumToken.Whitespace, "\f": EnumToken.Whitespace, + ...flexUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.FlexTokenType; + return acc; + }, Object.create(null)), + ...dimensionUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.LengthTokenType; + return acc; + }, Object.create(null)), + ...resolutionUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.ResolutionTokenType; + return acc; + }, Object.create(null)), + ...angleUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.AngleTokenType; + return acc; + }, Object.create(null)), + ...timeUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.TimeTokenType; + return acc; + }, Object.create(null)), + ...frequencyUnits.reduce((acc, curr: string) => { + acc[curr] = EnumToken.FrequencyTokenType; + return acc; + }, Object.create(null)), ...pseudoElements.reduce((acc, curr: string) => { acc[curr] = EnumToken.PseudoElementTokenType; return acc; @@ -151,6 +158,8 @@ export const hintsEnum = new Set([ EnumToken.EOFTokenType, ]) as Set; +const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); + export const enum TokenMap { EXCLAMATION = 33, // '!', EXCLAMATION SLASH = 47, // '/' @@ -180,1010 +189,1959 @@ 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; - } - const sequence: string = peek(parseInfo, 7); - let escapeSequence: string = ""; - let codepoint: number; - let i; +function getSymbolHint(parseInfo: ParseInfo, start: number, end: number): EnumToken | null { + let i: number = SymbolsMapTokensKeys.length; + let j: number; + let ca: number; + let cb: number; + let match: boolean; + let index: number; - for (i = 1; i < sequence.length; i++) { - codepoint = sequence.charCodeAt(i); + const len: number = end - start; - if ( - codepoint == 0x20 || - (codepoint >= 0x61 && codepoint <= 0x66) || - (codepoint >= 0x41 && codepoint <= 0x46) || - (codepoint >= 0x30 && codepoint <= 0x39) - ) { - escapeSequence += sequence[i]; + while (i--) { + match = len == SymbolsMapTokensKeys[i].length; - if (codepoint == 0x20) { - break; - } + if (!match) { + continue; + } - continue; - } + for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { + index = start + j; + if (index > end) { + 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; - } + ca = SymbolsMapTokensKeys[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); - if (charCode == quote) { - next(parseInfo); - result.push( - yieldResult( - parseInfo, - /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, - decodeSegments ? { decodeSegments } : null, - ), - ); + // Normalize A-Z to a-z + if (ca >= 65 && ca <= 90) ca += 32; + if (cb >= 65 && cb <= 90) cb += 32; - return result; + if (ca != cb) { + match = false; + break; + } } - if (isNewLine(charCode)) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.BadStringTokenType)); - - return result; + if (!match) { + continue; } - next(parseInfo); + return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } - // EOF - 'Unclosed-string' fixed - result.push(yieldResult(parseInfo, EnumToken.StringTokenType)); - return result; + return null; } -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); - - if ( - codepoint == 0 || - // leading surrogate - (0xd800 <= codepoint && codepoint <= 0xdbff) || - // trailing surrogate - (0xdc00 <= codepoint && codepoint <= 0xdfff) || - codepoint > 0x10ffff - ) { - return "\uFFFD"; +function searchArray(array: string[], parseInfo: ParseInfo, start: number, end: number): string | null { + let i: number = array.length; + let j: number; + let ca: number; + let cb: number; + let match: boolean; + let index: number; + const len: number = end - start; + + while (i--) { + match = true; + for (j = 0; j < array[i].length; j++) { + if (len != array[i].length) { + match = false; + break; } - return String.fromCodePoint(codepoint); - }); - } - - if (hint != null) { - let searchArray: string[] | null = null; + index = start + j; - 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; + if (index > end) { + match = false; 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; - break; - } + } - if (searchArray != null) { - val = searchArray.find((v: string): boolean => equalsIgnoreCase(v, val)) as string; - } + ca = array[i].charCodeAt(j); + cb = parseInfo.stream.charCodeAt(index); - 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, - }; + // 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; } - } 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, - }; + if (match) { + return array[i]; + } } - // 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 }; + return null; } -export function match(parseInfo: ParseInfo, input: string): boolean { - let position: number = parseInfo.currentPosition - parseInfo.offset; +/** + * 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; + + /** + * + * @param parseInfo + * @returns + */ + *consumeString(parseInfo: ParseInfo): Generator { + const quote: number = this.next(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.next(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.next(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.next(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.next(parseInfo); + yield this.makeToken( + parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, + decodeSegments ? { decodeSegments } : null, + // ), + ); + + return; } - } else { - if (end < 0) { - j += end; - } else { - j = parseInfo.position + end; + + if (isNewLine(charCode)) { + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); + + return; } + + this.next(parseInfo); } + + // EOF - 'Unclosed-string' fixed + yield this.makeToken(parseInfo, EnumToken.StringTokenType); + // return result; } - j--; + /** + * + * @param parseInfo + * @returns + */ + *consumeURLToken(parseInfo: ParseInfo): Generator { + const quote: number = this.next(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.next(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.next(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.next(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.next(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.next(parseInfo, k); + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } -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.next(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.next(parseInfo, k); + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } + break; + } - while (i < j) { - if (parseInfo.stream.charAt(parseInfo.position - parseInfo.offset + i) != input.charAt(i)) { - return false; - } - i++; - } + // consume until the ')' + yield this.makeToken( + parseInfo, + /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, + decodeSegments ? { decodeSegments } : null, + ); - return true; -} + return; + // return result; + } + + if (isNewLine(charCode)) { + // bad string + this.next(parseInfo); -function isURLToken(parseInfo: ParseInfo): boolean { - let i: number = parseInfo.position - parseInfo.offset; - let c: number; + while ( + (charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode + ) { + if (charCode == TokenMap.REVERSE_SOLIDUS) { + this.next(parseInfo, 2); + continue; + } - while (++i < parseInfo.currentPosition) { - c = parseInfo.stream.charCodeAt(i) as number; + if (charCode == TokenMap.RIGHT_PARENTHESIS) { + yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return; + } - // single quote or double quote or start parenthesis or close parenthesis - if (isNonPrintable(c) || c == 0x27 || c == 0x22 || c == 0x28 || c == 0x29) { - return false; + this.next(parseInfo); + } + + yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); + return; + } + + this.next(parseInfo); } - // valid escape - if (c == TokenMap.REVERSE_SOLIDUS) { - i++; + // EOF - bad url token + yield 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 (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; - } - } + if (!hasDigits) { + return 0; + } - 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)); + if (!hasDigits) { + return 0; + } - break; + if (hasPercent) { + const slice = position; - // ')' - case TokenMap.RIGHT_PARENTHESIS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + codepoint = parseInfo.stream.charCodeAt(++position) as number; - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.EndParensTokenType)); - 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.LEFT_BRACKETS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + return 0; + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrStartTokenType)); - break; - // ']' - case TokenMap.RIGHT_BRACKETS: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + if (hasLetter) { + codepoint = parseInfo.stream.charCodeAt(position - 1) as number; - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.AttrEndTokenType)); - break; + // 'E' 'e' + const slice = codepoint == 0x45 || codepoint == 0x65 ? position - 1 : position; - case TokenMap.SEMICOLON: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + while (position + 1 <= parseInfo.stream.length) { + codepoint = parseInfo.stream.charCodeAt(++position) as number; + + if (!isLetter(codepoint)) { + break; } + } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.SemiColonTokenType)); - 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; + } - case TokenMap.COLON: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + return 0; + } - next(parseInfo); + return 0; + } - if (peek(parseInfo).charCodeAt(0) == TokenMap.COLON) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.DoubleColonTokenType)); - break; - } + /** + * + * @param parseInfo + * @returns + */ + consumeIdentToken(parseInfo: ParseInfo): number { + let position: number = parseInfo.currentPosition - parseInfo.offset; + let offset: number = position; - result.push(yieldResult(parseInfo, EnumToken.ColonTokenType)); - break; + let codepoint: number = parseInfo.stream.charCodeAt(position); - // \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)); - } + if (!isIdentStart(codepoint) && codepoint != TokenMap.MINUS) { + return 0; + } - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + if (codepoint == TokenMap.MINUS) { + position++; + codepoint = parseInfo.stream.charCodeAt(position); - while ( - nextCharCode == 0x20 || - (nextCharCode >= 0x9 && nextCharCode <= 0xd) || - nextCharCode == 0x2028 || - nextCharCode == 0x2029 + if (!isIdentStart(codepoint) && codepoint != TokenMap.MINUS) { + return 0; + } + } + + 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; + } + + // \n \r \f \v + if ( + codepoint == 0xa || + codepoint == 0xb || + codepoint == 0xc || + codepoint == 0xd || + codepoint == 0x2028 || + codepoint == 0x2029 ) { - next(parseInfo); - nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + return 0; } - result.push(yieldResult(parseInfo, EnumToken.WhitespaceTokenType)); + position += 2; + continue; + } - break; + 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; + } - case TokenMap.COMMA: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (codepoint != codepoint || isWhiteSpace(codepoint)) { + return position - offset; } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommaTokenType)); - break; + return 0; + } + } - case TokenMap.DOLLAR: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + 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; + } - if (match(parseInfo, "$=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.EndMatchTokenType)); + 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; + } + + /** + * + * @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 = (val as string).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 (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); - break; + if (this.typ == null) { + val = parseInfo.stream.slice( + parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset, + ); - case TokenMap.TILDA: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + 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); + }); + + 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; + } + + /** + * + * @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 + */ + next(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; + + 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) { + // nope + } else { + parseInfo.source.lineStarts.lineStarts.push(position + parseInfo.offset + i); } + } + } - if (match(parseInfo, "~=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.IncludeMatchTokenType)); - 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); - result.push(yieldResult(parseInfo, EnumToken.Tilda)); + j--; - break; + let codepoint: number = parseInfo.stream.charCodeAt(i) as number; + + // - + if (codepoint == 0x2d) { + let nextCodepoint: number; + + // 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; + } - // case '^': - case TokenMap.CARET: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + 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.StartMatchTokenType)); - 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); + continue; + } + + // is white space + if (c == 0x20 || c == 0x09) { break; + } + } + + return i == parseInfo.currentPosition; + } - case TokenMap.STAR: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + /** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ + *tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = true): Generator { + if (typeof parseInfo == "string") { + parseInfo = { + stream: parseInfo, + source: new SourceFile(parseInfo, [], ""), + offset: 0, + time: 0, + position: 0, + currentPosition: 0, + }; + } + + 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + slice: this.slice, + sign: charCode == TokenMap.MINUS ? "-" : charCode == TokenMap.PLUS ? "+" : null, + }); + continue; + } } - if (match(parseInfo, "*=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ContainMatchTokenType)); - break; + if (isIdentStart(charCode) || charCode == TokenMap.MINUS) { + tokensCount = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + + charCode = this.peek(parseInfo).charCodeAt(0); + + // do not match function + if (TokenMap.LEFT_PARENTHESIS != charCode) { + yield this.makeToken( + parseInfo, + this.startsWith(parseInfo, "--") + ? EnumToken.DashedIdenTokenType + : EnumToken.IdenTokenType, + ); + continue; + } + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Star)); + if (charCode == TokenMap.AT) { + this.next(parseInfo); - break; + charCode = this.peek(parseInfo).charCodeAt(0); + + // match at-rule + if (charCode == TokenMap.MINUS || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + // consume '@' + parseInfo.position = parseInfo.currentPosition; + tokensCount = this.consumeIdentToken(parseInfo); - case TokenMap.AMPERSAND: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + + yield this.makeToken(parseInfo, EnumToken.AtRuleTokenType); + continue; + } + } } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.NestingSelectorTokenType)); + if (charCode == TokenMap.HASH) { + tokensCount = this.consumeColor(parseInfo); - break; + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.ColorTokenType); + continue; + } + + this.next(parseInfo); + + tokensCount = this.consumeIdentToken(parseInfo); - case TokenMap.PIPE: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.HashTokenType); + continue; + } } + } + // EOF + switch (charCode) { + case TokenMap.EQUALS: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - // '||' - if (match(parseInfo, "||")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.ColumnCombinatorTokenType)); + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.DelimTokenType); break; - } else if (match(parseInfo, "|=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.DashMatchTokenType)); + + // '+' or '-' + case TokenMap.PLUS: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + this.next(parseInfo); + + charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); + + if (isDigit(charCode)) { + tokensCount = this.consumeNumericToken(parseInfo); + + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + slice: this.slice, + sign: "+", + }); + break; + } + } + + yield this.makeToken(parseInfo, EnumToken.Plus); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.Pipe)); + case TokenMap.MINUS: + if (parseInfo.position == parseInfo.currentPosition) { + nextCharCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); - break; + // not a number + if (isWhiteSpace(nextCharCode)) { + this.next(parseInfo); - case TokenMap.EXCLAMATION: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + yield this.makeToken(parseInfo, EnumToken.Sub); + break; + } + + if ( + charCode == TokenMap.MINUS && + (nextCharCode == TokenMap.MINUS || isIdentStart(nextCharCode)) + ) { + this.next(parseInfo); - if (match(parseInfo, "!important")) { - next(parseInfo, 10); - result.push(yieldResult(parseInfo, EnumToken.ImportantTokenType)); + tokensCount = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.IdenTokenType); + continue; + } + } + } + this.next(parseInfo); break; - } - next(parseInfo); - break; + // '{' + case TokenMap.LEFT_BRACE: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - case TokenMap.SLASH: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BlockStartTokenType); + break; + // '}' + case TokenMap.RIGHT_BRACE: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - if (!match(parseInfo, "/*")) { - next(parseInfo); - result.push( - yieldResult( - parseInfo, - SymbolsMapTokens[parseInfo.stream.slice(parseInfo.position, parseInfo.currentPosition)], - ), - ); + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.BlockEndTokenType); break; - } - next(parseInfo, 2); + // '(' + case TokenMap.LEFT_PARENTHESIS: + if (parseInfo.position < parseInfo.currentPosition) { + if ( + parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && + this.isPseudo(parseInfo) + ) { + this.next(parseInfo); + yield 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); + + yield this.makeToken(parseInfo, hint); + this.next(parseInfo); + + // consume '(' + parseInfo.position = parseInfo.currentPosition; + + if (hint === EnumToken.UrlFunctionTokenDefType) { + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.next(parseInfo); + } - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == TokenMap.STAR) { - if (match(parseInfo, "/")) { - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.CommentTokenType)); + charCode = this.peek(parseInfo).charCodeAt(0); + + if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { + yield* this.consumeURLToken(parseInfo); + } else { + do { + this.next(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } while ( + // !(value === "/" && this.match(parseInfo, "/*") && + charCode !== TokenMap.RIGHT_PARENTHESIS && + parseInfo.currentPosition < endPosition + ); + + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken( + parseInfo, + // parseInfo.position < parseInfo.currentPosition + (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || + !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType, + ); + } + } + } break; } } - // else { - // buffer += value; - // } - } - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo, EnumToken.BadCommentTokenType)); - } + this.next(parseInfo); + yield 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) { + yield this.makeToken(parseInfo); + } - if (match(parseInfo, ">=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.GteTokenType)); + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.EndParensTokenType); break; - } - next(parseInfo); - result.push(yieldResult(parseInfo, EnumToken.GtTokenType)); + // '[' + case TokenMap.LEFT_BRACKETS: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.AttrStartTokenType); + break; + // ']' + case TokenMap.RIGHT_BRACKETS: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - break; + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.AttrEndTokenType); + break; - case TokenMap.LOWERTHAN: - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - } + case TokenMap.SEMICOLON: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - if (match(parseInfo, "<=")) { - next(parseInfo, 2); - result.push(yieldResult(parseInfo, EnumToken.LteTokenType)); + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.SemiColonTokenType); break; - } - next(parseInfo); + case TokenMap.COLON: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } - if (match(parseInfo, "!--")) { - next(parseInfo, 3); + this.next(parseInfo); - while ((charCode = next(parseInfo).charCodeAt(0)) == charCode) { - if (charCode == TokenMap.MINUS && match(parseInfo, "->")) { - break; + if (this.peek(parseInfo).charCodeAt(0) == TokenMap.COLON) { + this.next(parseInfo); + + yield this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); + break; + } + + yield 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) { + yield this.makeToken(parseInfo); + } + + this.next(parseInfo); + nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); + + while ( + nextCharCode == 0x20 || + (nextCharCode >= 0x9 && nextCharCode <= 0xd) || + nextCharCode == 0x2028 || + nextCharCode == 0x2029 + ) { + this.next(parseInfo); + nextCharCode = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset) + .charCodeAt(0); + } + + yield this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); + + break; + + case TokenMap.COMMA: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.CommaTokenType); + break; + + case TokenMap.DOLLAR: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "$=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.EndMatchTokenType); + break; + } + + this.next(parseInfo); + break; + + case TokenMap.TILDA: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "~=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); + break; + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Tilda); + + break; + + // case '^': + case TokenMap.CARET: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "^=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.StartMatchTokenType); + break; + } + + this.next(parseInfo); + break; + + case TokenMap.STAR: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "*=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); + break; + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Star); + + break; + + case TokenMap.AMPERSAND: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); + + break; + + case TokenMap.PIPE: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + // '||' + if (this.match(parseInfo, "||")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); + break; + } else if (this.match(parseInfo, "|=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.DashMatchTokenType); + break; + } + + this.next(parseInfo); + yield this.makeToken(parseInfo, EnumToken.Pipe); + + break; + + case TokenMap.EXCLAMATION: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (this.match(parseInfo, "!important")) { + this.next(parseInfo, 10); + yield this.makeToken(parseInfo, EnumToken.ImportantTokenType); + + break; + } + + this.next(parseInfo); + break; + + case TokenMap.SLASH: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + if (!this.match(parseInfo, "/*")) { + this.next(parseInfo); + yield this.makeToken( + parseInfo, + + getSymbolHint( + parseInfo, + parseInfo.position - parseInfo.offset, + parseInfo.currentPosition - parseInfo.offset, + ), + ); + break; + } + + this.next(parseInfo, 2); + + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == TokenMap.STAR) { + if (this.match(parseInfo, "/")) { + this.next(parseInfo); + yield 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) { + yield 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) { + yield this.makeToken(parseInfo); + } - next(parseInfo); - break; + if (this.match(parseInfo, ">=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.GteTokenType); + break; + } + + this.next(parseInfo); + yield 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) { + yield this.makeToken(parseInfo); + } - // EOF - if (!peek(parseInfo)) { - if (!yieldEOFToken) { + if (this.match(parseInfo, "<=")) { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.LteTokenType); break; } - // end of stream ignore \\ + this.next(parseInfo); + + if (this.match(parseInfo, "!--")) { + this.next(parseInfo, 3); + + while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + if (charCode == TokenMap.MINUS && this.match(parseInfo, "->")) { + break; + } + } + + if (parseInfo.currentPosition >= endPosition) { + yield this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + } else { + this.next(parseInfo, 2); + yield this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); + } + } + + break; + + case TokenMap.HASH: if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + yield this.makeToken(parseInfo); } + this.next(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.next(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) { + yield this.makeToken(parseInfo); + } - if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); - next(parseInfo, 2); + break; + } + + this.next(parseInfo); break; - } - next(parseInfo); - break; - default: - next(parseInfo); + case TokenMap.SINGLE_QUOTE: + case TokenMap.DOUBLE_QUOTE: + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + yield* this.consumeString(parseInfo); + break; + + case TokenMap.DOT: + const codepoint = parseInfo.stream + .charAt(parseInfo.currentPosition - parseInfo.offset + 1) + .charCodeAt(0); + + if (isIdentStart(codepoint) || codepoint == TokenMap.MINUS) { + this.next(parseInfo); + let tokensCount: number = this.consumeIdentToken(parseInfo); + + if (tokensCount > 0) { + this.next(parseInfo, tokensCount); + yield this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); + break; + } + } + + if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + this.next(parseInfo, 2); + break; + } + + this.next(parseInfo); + break; + default: + this.next(parseInfo); + break; + } + + if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { break; + } } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; + if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + yield this.makeToken(parseInfo); + } + + yield this.makeToken(parseInfo, EnumToken.EOFTokenType); } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - result.push(yieldResult(parseInfo)); + /** + * tokenize readable stream + * @param input + * @param parseInfo + */ + async *tokenizeStream(input: ReadableStream, parseInfo: ParseInfo): AsyncGenerator { + 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 as string); + } + + yield* this.tokenize(parseInfo, done); + + if (done) { + break; + } } - result.push(yieldResult(parseInfo, EnumToken.EOFTokenType)); + parseInfo.stream = parseInfo.source.getContent(); + yield* this.tokenize(parseInfo); } +} - parseInfo.time += performance.now() - startTime; - return result; +/** + * Tokenize CSS string + * @param parseInfo + * @param yieldEOFToken + */ +export function tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = true): Generator { + return new Tokenizer().tokenize(parseInfo, yieldEOFToken); } /** @@ -1191,33 +2149,6 @@ export function tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = * @param input * @param parseInfo */ -export async function* tokenizeStream( - input: ReadableStream, - parseInfo: ParseInfo, -): AsyncGenerator { - 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 as string); - - parseInfo.stream = (parseInfo.stream.slice(parseInfo.position - parseInfo.offset) + stream) as string; - - parseInfo.offset = parseInfo.offset = parseInfo.position; - } else { - parseInfo.stream = ""; - } - - yield* tokenize(parseInfo, done); - - if (done) { - break; - } - } +export function tokenizeStream(input: ReadableStream, parseInfo: ParseInfo): AsyncGenerator { + return new Tokenizer().tokenizeStream(input, parseInfo); } diff --git a/src/lib/parser/utils/at-rule-container.ts b/src/lib/parser/utils/at-rule-container.ts index 91a56293..dc7f67e9 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"; @@ -87,20 +87,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 +106,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 +136,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 +178,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 +203,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 +218,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 +234,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 +248,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 +264,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 +279,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 +307,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 +338,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 +349,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 +356,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, @@ -573,10 +373,6 @@ 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); 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..f3ae715e 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); diff --git a/src/lib/parser/utils/at-rule-media.ts b/src/lib/parser/utils/at-rule-media.ts index 51d6da35..72956246 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)), @@ -225,7 +222,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 +237,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 +255,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 +268,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 +305,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 +317,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 +329,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 +352,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 +376,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 +410,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 +427,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 +435,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 +450,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 +473,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; diff --git a/src/lib/parser/utils/at-rule-support.ts b/src/lib/parser/utils/at-rule-support.ts index a6663833..cc5f3dc0 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: [ diff --git a/src/lib/parser/utils/at-rule-when-else.ts b/src/lib/parser/utils/at-rule-when-else.ts index 5205f371..a56bafe9 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,30 +151,10 @@ 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)); 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.ts b/src/lib/parser/utils/declaration.ts index e30b807d..41434e80 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,20 @@ 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({ @@ -172,45 +176,6 @@ export function parseDeclaration( ? 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 +218,14 @@ 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]]; @@ -321,7 +287,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,28 +337,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 +431,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 +473,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 +530,14 @@ 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 +580,10 @@ 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 +595,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 +615,18 @@ 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/selector.ts b/src/lib/parser/utils/selector.ts index 27ba815b..e72b11fa 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], }; } @@ -116,10 +121,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 +186,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 +202,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 +216,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 +231,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 +296,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 +330,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 +356,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 +374,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 +494,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 +504,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 +519,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 +545,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 +651,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..681dad8f 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -52,8 +52,9 @@ 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 { colorPrecision, LOCSRCID, LOCSTA, PARENT, pseudoElements, tokensfuncSet, urlTokenMatcher } from "../syntax/constants.ts"; import { + isWhiteSpace, minifyNumber, parseColor, reduceColorStops, @@ -264,44 +265,36 @@ 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) + node[LOCSTA] != null ) { - const source = options.sourcesMap!.get((node[LOC] as SourceLocation)!.srcId) as SourceFile; + + 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 @@ -309,9 +302,12 @@ function updateSourceMap( // @ts-ignore offsets[1] = record[2] as number; + // console.error({record}); + sourceContent = (record[3] as string) || null; 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; @@ -329,6 +325,32 @@ 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); } @@ -336,18 +358,18 @@ function updateSourceMap( sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); } } 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); @@ -355,9 +377,11 @@ function updateSourceMap( sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); } + + // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } - move(sourceLocation, linesMap, offset > 0 ? str.slice(offset) : str); + move(sourceLocation, linesMap, str, offset); } /** @@ -366,12 +390,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,7 +586,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 @@ -570,19 +594,28 @@ function renderAstNode( // color: red; // } // } - const source = options.sourcesMap!.get(node[LOC]!.srcId) as SourceFile; + // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; - if (!sourcemaps.sources.includes(node[LOC]!.srcId as number)) { - sourcemaps.sources.push(node[LOC]!.srcId as number); - } + // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { + // sourcemaps.sources.push(node[LOCSTA] as number); + // } - sourcemaps.maps.push([ - ...linesMap!.getOffsets( - sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - ), - node[LOC]!.srcId, - ...source!.getOffsets(node![LOC]!.sta), - ]); + // sourcemaps.maps.push([ + // ...linesMap!.getOffsets( + // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, + // ), + // node[LOCSTA], + // ...source!.getOffsets(node![LOCSTA]), + // ]); + + // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); + + // @ts-ignore + updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap!, str); + } + else { + + move(sourceLocation, linesMap!, str); } } } diff --git a/src/lib/syntax/color/color.ts b/src/lib/syntax/color/color.ts index d2f2dc18..1312dedb 100644 --- a/src/lib/syntax/color/color.ts +++ b/src/lib/syntax/color/color.ts @@ -132,7 +132,7 @@ import { rgb2cmykToken, } from "./cmyk.ts"; import { a98rgb2srgbvalues, srgb2a98values } from "./a98rgb.ts"; -import { epsilon, LOC } from "../constants.ts"; +import { epsilon, LOCEND, LOCSRCID, LOCSTA } from "../constants.ts"; import { colorFuncColorSpace, colorPrecision, anglePrecision } from "../constants.ts"; import { trimArray } from "../../validation/match.ts"; import { alpha } from "./alpha.ts"; @@ -230,7 +230,9 @@ export function convertColor(token: ColorToken, to: ColorType): ColorToken | nul kin: ColorType[token.val.toUpperCase().replaceAll("-", "_") as keyof typeof ColorType], }; - tk[LOC] = token[LOC]; + tk[LOCSRCID] = token[LOCSRCID]; + tk[LOCSTA] = token[LOCSTA]; + tk[LOCEND] = token[LOCEND]; token = tk as ColorToken; } } diff --git a/src/lib/syntax/color/relative-color.ts b/src/lib/syntax/color/relative-color.ts index 6ea62229..958a41db 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"; @@ -167,19 +167,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 +200,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 +249,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 +305,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/constants.ts b/src/lib/syntax/constants.ts index 4922119f..623c8b72 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"); @@ -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..a31721bd 100644 --- a/src/lib/syntax/syntax.ts +++ b/src/lib/syntax/syntax.ts @@ -15,36 +15,40 @@ import type { TimeToken, Token, } from "../../@types/index.d.ts"; -import { isOkLabClose } from "./color/utils/distance.ts"; -import { ColorType, EnumToken } from "../ast/types.ts"; -import { WalkerOptionEnum, walkValues } from "../ast/walk.ts"; -import { toDegrees } from "../parser/utils/angle.ts"; -import { memoize } from "../parser/utils/cache.ts"; -import { equalsIgnoreCase } from "../parser/utils/text.ts"; -import { trimArray } from "../validation/match.ts"; -import { splitTokenList } from "../validation/utils/list.ts"; -import { getColorSpace } from "./color/utils/colorspace.ts"; -import { getColorComponents } from "./color/utils/components.ts"; +import {isOkLabClose} from "./color/utils/distance.ts"; +import {ColorType, EnumToken} from "../ast/types.ts"; +import {WalkerOptionEnum, walkValues} from "../ast/walk.ts"; +import {toDegrees} from "../parser/utils/angle.ts"; +import {memoize} from "../parser/utils/cache.ts"; +import {equalsIgnoreCase} from "../parser/utils/text.ts"; +import {trimArray} from "../validation/match.ts"; +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"; +import {getSyntaxConfig} from "../validation/config.ts"; // 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; -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()); } /** @@ -1584,9 +1588,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; 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..65a8675c 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"; @@ -488,7 +487,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]), }, ], }; @@ -565,7 +564,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 +604,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 +669,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 +737,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 +751,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 +795,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 +830,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 +862,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]), }, ], }; @@ -925,7 +924,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 +949,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,7 +979,7 @@ 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]), }, ], }; @@ -1042,7 +1041,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 +1167,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 +1870,6 @@ function matchSyntax( }; case ValidationTokenEnum.FunctionDefinition: - if ( equalsIgnoreCase( (token as FunctionToken).val, diff --git a/src/node.ts b/src/node.ts index 26d58168..c5a72836 100644 --- a/src/node.ts +++ b/src/node.ts @@ -317,7 +317,7 @@ export function parseSync( } as ParseInfo; const result = doParseSync(tokenize(options.parseInfo), options) as ParseResult; - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); } /** @@ -670,7 +670,7 @@ export async function parse( return doParse( stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(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))); } /** diff --git a/src/utils/sync.ts b/src/utils/sync.ts index ac006a31..a2635c52 100644 --- a/src/utils/sync.ts +++ b/src/utils/sync.ts @@ -1,6 +1,5 @@ -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, ParseResult, ParserOptions, ParserSyncOptions } from "../@types/index.d.ts"; +import { EnumToken } from "../lib/ast/types.ts"; /** * parse result. process input sourcemap diff --git a/src/web.ts b/src/web.ts index 7a238d93..aa2cbd56 100644 --- a/src/web.ts +++ b/src/web.ts @@ -336,7 +336,9 @@ export function parseSync( } as ParseInfo; const result = doParseSync(tokenize(options.parseInfo), options); - return !options.module && !options.inputSourceMap && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** @@ -637,7 +639,11 @@ export async function parse( return doParse( stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(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), + ); } /** diff --git a/test/specs/code/calc.js b/test/specs/code/calc.js index 09a65e62..eae4a952 100644 --- a/test/specs/code/calc.js +++ b/test/specs/code/calc.js @@ -245,8 +245,8 @@ scale: rem(10 * 2, 1.7); height: 100px } .two { - width: 141px; - height: 141px + width: 141.421356px; + height: 141.421356px } .three { width: 250px; @@ -265,9 +265,9 @@ 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)) + -moz-transform: rotate(116.565deg); + line-height: 3.141593; + transform: rotate(5.1774deg) }`)); }); @@ -278,9 +278,11 @@ transform: rotate(atan2(e, 30)); a { width: calc(100px * log(8, 2)); + transform: rotate( tan(45deg)) } `).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { - width: 300px + width: 300px; + transform: rotate(1rad) }`)); }); @@ -468,8 +470,8 @@ width: calc(-2px *sign(-1);} height: 100px } .two { - width: 141px; - height: 141px + width: 141.421356px; + height: 141.421356px } .three { width: 250px; 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..9e6fae27 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 }`); }); 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); }); }); From 6194658625e943f4dc79ad7aaa3345c112020a54 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Sat, 29 Aug 2026 00:19:51 -0400 Subject: [PATCH 04/11] reduce the use of spread arguments --- .npmignore | 1 + CHANGELOG.md | 2 + dist/index-umd-web.js | 1416 ++++++++++-------- dist/index.cjs | 1424 +++++++++++-------- dist/lib/ast/expand.js | 28 +- dist/lib/ast/features/inlinecssvariables.js | 11 +- dist/lib/ast/features/prefix.js | 85 +- dist/lib/ast/features/shorthand.js | 8 +- dist/lib/ast/math/expression.js | 24 +- dist/lib/ast/minify.js | 42 +- dist/lib/ast/transform/compute.js | 8 +- dist/lib/ast/transform/utils.js | 26 +- dist/lib/ast/walk.js | 30 +- dist/lib/parser/declaration/list.js | 9 +- dist/lib/parser/declaration/map.js | 34 +- dist/lib/parser/declaration/set.js | 4 +- dist/lib/parser/parse.js | 89 +- dist/lib/parser/tokenize.js | 286 ++-- dist/lib/parser/utils/at-rule-container.js | 12 +- dist/lib/parser/utils/at-rule-import.js | 16 +- dist/lib/parser/utils/at-rule-media.js | 12 +- dist/lib/parser/utils/at-rule-support.js | 4 +- dist/lib/parser/utils/at-rule-when-else.js | 4 +- dist/lib/parser/utils/declaration.js | 4 +- dist/lib/parser/utils/selector.js | 4 +- dist/lib/renderer/render.js | 55 +- dist/lib/syntax/color/a98rgb.js | 18 +- dist/lib/syntax/color/cmyk.js | 28 +- dist/lib/syntax/color/color-mix.js | 55 +- dist/lib/syntax/color/color.js | 75 +- dist/lib/syntax/color/hsl.js | 30 +- dist/lib/syntax/color/hwb.js | 35 +- dist/lib/syntax/color/lab.js | 34 +- dist/lib/syntax/color/lch.js | 26 +- dist/lib/syntax/color/oklab.js | 21 +- dist/lib/syntax/color/oklch.js | 33 +- dist/lib/syntax/color/p3.js | 30 +- dist/lib/syntax/color/prophotorgb.js | 54 +- dist/lib/syntax/color/rec2020.js | 12 +- dist/lib/syntax/color/relative-color.js | 4 +- dist/lib/syntax/color/srgb.js | 9 +- dist/lib/syntax/color/utils/distance.js | 2 +- dist/lib/syntax/color/xyz.js | 4 +- dist/lib/syntax/color/xyzd50.js | 4 +- dist/lib/syntax/syntax.js | 21 +- dist/lib/validation/match.js | 19 +- dist/node.js | 8 +- jsr.json | 2 +- package.json | 2 +- src/lib/ast/expand.ts | 61 +- src/lib/ast/features/inlinecssvariables.ts | 12 +- src/lib/ast/features/prefix.ts | 159 ++- src/lib/ast/features/shorthand.ts | 8 +- src/lib/ast/math/expression.ts | 32 +- src/lib/ast/minify.ts | 49 +- src/lib/ast/transform/compute.ts | 10 +- src/lib/ast/transform/utils.ts | 26 +- src/lib/ast/walk.ts | 32 +- src/lib/parser/declaration/list.ts | 17 +- src/lib/parser/declaration/map.ts | 69 +- src/lib/parser/declaration/set.ts | 7 +- src/lib/parser/parse.ts | 102 +- src/lib/parser/tokenize.ts | 175 +-- src/lib/parser/utils/at-rule-container.ts | 13 +- src/lib/parser/utils/at-rule-import.ts | 17 +- src/lib/parser/utils/at-rule-media.ts | 15 +- src/lib/parser/utils/at-rule-page.ts | 5 +- src/lib/parser/utils/at-rule-support.ts | 6 +- src/lib/parser/utils/at-rule-when-else.ts | 5 +- src/lib/parser/utils/declaration-list.ts | 37 +- src/lib/parser/utils/declaration.ts | 20 +- src/lib/parser/utils/selector.ts | 5 +- src/lib/renderer/render.ts | 97 +- src/lib/syntax/color/a98rgb.ts | 22 +- src/lib/syntax/color/cmyk.ts | 28 +- src/lib/syntax/color/color-mix.ts | 65 +- src/lib/syntax/color/color.ts | 88 +- src/lib/syntax/color/hsl.ts | 35 +- src/lib/syntax/color/hwb.ts | 65 +- src/lib/syntax/color/lab.ts | 35 +- src/lib/syntax/color/lch.ts | 26 +- src/lib/syntax/color/oklab.ts | 23 +- src/lib/syntax/color/oklch.ts | 41 +- src/lib/syntax/color/p3.ts | 26 +- src/lib/syntax/color/prophotorgb.ts | 86 +- src/lib/syntax/color/rec2020.ts | 8 +- src/lib/syntax/color/relative-color.ts | 4 +- src/lib/syntax/color/rgb.ts | 1 - src/lib/syntax/color/srgb.ts | 9 +- src/lib/syntax/color/utils/distance.ts | 2 +- src/lib/syntax/color/utils/matrix.ts | 21 +- src/lib/syntax/color/xyz.ts | 4 +- src/lib/syntax/color/xyzd50.ts | 4 +- src/lib/syntax/syntax.ts | 48 +- src/lib/validation/match.ts | 21 +- src/node.ts | 10 +- 96 files changed, 3413 insertions(+), 2402 deletions(-) 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 bcf0140b..5f2c7439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Changelog +# v1.6.0 + - [x] added `tan()` function. # v1.5.0 diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index b8d8997e..28778162 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -7040,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); @@ -7082,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); @@ -7090,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); @@ -7104,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) { @@ -7145,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); } @@ -7214,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); } @@ -7224,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); @@ -7280,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]; @@ -7304,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); @@ -7334,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); @@ -7342,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); @@ -7350,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); @@ -7478,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); @@ -7494,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); @@ -7511,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); @@ -7681,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); @@ -7701,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); @@ -7709,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); @@ -7730,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 @@ -7824,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) { @@ -7908,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) ?? {}; @@ -7980,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); } @@ -8082,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; } @@ -8452,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); @@ -8509,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; @@ -8558,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) { @@ -8581,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); @@ -8602,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); @@ -8714,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 { @@ -8725,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; } @@ -8747,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); @@ -8771,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); @@ -8804,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; @@ -8828,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 @@ -8936,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 @@ -8945,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 @@ -8984,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) { @@ -8997,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": @@ -9110,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; @@ -9317,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 { @@ -9690,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); } } } @@ -9722,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 = []; @@ -9756,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); + } + } } } } @@ -9773,8 +9850,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); } } } @@ -9915,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]); @@ -10378,7 +10462,15 @@ : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -10396,12 +10488,18 @@ result.push(token); } else { - result.push(...inlineExpression$1(token.l), { + 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], - }, ...inlineExpression$1(token.r)); + }); + for (const child of inlineExpression$1(token.r)) { + result.push(child); + } } } else { @@ -10546,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) { @@ -10774,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); @@ -10876,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"; @@ -11904,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 @@ -12266,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); + } } } } @@ -12557,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(); @@ -12625,7 +12660,9 @@ }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** @@ -14508,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; } @@ -14544,9 +14581,12 @@ } 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("-", "_")], }; + for (const t of Object.values(components)) { + tk.chi.push(t); + } tk[LOCSRCID] = token[LOCSRCID]; tk[LOCSTA] = token[LOCSTA]; tk[LOCEND] = token[LOCEND]; @@ -14900,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; @@ -14953,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) { @@ -14992,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] }, @@ -15090,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. @@ -15439,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; @@ -15463,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; @@ -15561,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; @@ -15584,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; @@ -15880,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) { @@ -16320,8 +16345,8 @@ // typ: EnumToken.ResolutionTokenType, // unit: "x", // }); - // } - // else + // } + // else if (isPseudClass && value.typ == exports.EnumToken.PseudoElementTokenType) { // @ts-ignore value.typ = exports.EnumToken.PseudoClassTokenType; @@ -16334,7 +16359,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; @@ -16346,7 +16371,9 @@ }); } return acc.concat(curr); - }, [])); + }, [])) { + tokens.push(token); + } } return result; } @@ -16564,52 +16591,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; @@ -16622,7 +16625,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; @@ -16650,12 +16656,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); + } } } /** @@ -16726,7 +16736,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) { @@ -16734,17 +16746,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; } } @@ -16752,13 +16774,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 { @@ -17070,7 +17093,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; }, []), }, @@ -18792,10 +18817,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]); + } } } } @@ -18812,7 +18844,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; }, []), }); @@ -18947,7 +18981,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); @@ -19169,7 +19205,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({ @@ -19183,7 +19219,9 @@ // @ts-ignore acc.push(curr); return acc; - }, [])); + }, [])) { + acc[i].push(v); + } } } return acc; @@ -19201,7 +19239,9 @@ return acc; }, [])); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); if (this.config.mapping != null) { @@ -19269,10 +19309,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])) { @@ -19503,10 +19546,7 @@ let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != exports.EnumToken.DeclarationNodeType - ? null - : declaration.nam; + 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 || @@ -19669,7 +19709,9 @@ } if (values != declaration.val) { declaration.val.length = 0; - declaration.val.push(...values); + for (const v of values) { + declaration.val.push(v); + } } } [Symbol.iterator]() { @@ -19742,10 +19784,14 @@ // @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; } @@ -19913,22 +19959,34 @@ 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, @@ -20024,11 +20082,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); @@ -20039,7 +20097,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]; @@ -20715,6 +20773,7 @@ stripCommaToken(transformLists); let matrix = identity(); let mat; + let transforms; const cumulative = []; for (const transformList of splitTransformList(transformLists)) { mat = computeMatrix(transformList, identity()); @@ -20722,7 +20781,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) { @@ -20864,7 +20926,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") { @@ -21733,7 +21795,9 @@ typ: exports.EnumToken.CommaTokenType, }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }, [])); } @@ -21813,7 +21877,9 @@ 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; @@ -21845,7 +21911,9 @@ 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 === exports.EnumToken.CommentTokenType || (curr.typ === exports.EnumToken.WhitespaceTokenType && @@ -21897,8 +21965,9 @@ 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); @@ -22113,8 +22182,15 @@ 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]; @@ -22463,7 +22539,9 @@ if (acc.length > 0) { acc.push(","); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); } @@ -22632,9 +22710,13 @@ [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); @@ -22873,7 +22955,9 @@ acc.push(","); } unique.add(sig); - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } } return acc; }, []); @@ -22911,9 +22995,8 @@ 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 == exports.EnumToken.AtRuleNodeType && "chi" in node) { let hasRule = false; @@ -23033,6 +23116,13 @@ } 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; } @@ -23072,7 +23162,9 @@ 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 == exports.EnumToken.AtRuleNodeType) { let astAtRule = ast.chi[i]; @@ -23107,13 +23199,19 @@ values.push(r); } else if (r.typ == exports.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); } } @@ -24058,7 +24156,7 @@ 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 { @@ -24075,7 +24173,7 @@ 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]]); } // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } @@ -24544,7 +24642,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; @@ -24735,32 +24835,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": @@ -24865,24 +24978,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; } @@ -25222,118 +25347,63 @@ return values; } - 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, - ...flexUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.FlexTokenType; - return acc; - }, Object.create(null)), - ...dimensionUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.LengthTokenType; - return acc; - }, Object.create(null)), - ...resolutionUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.ResolutionTokenType; - return acc; - }, Object.create(null)), - ...angleUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.AngleTokenType; - return acc; - }, Object.create(null)), - ...timeUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.TimeTokenType; - return acc; - }, Object.create(null)), - ...frequencyUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.FrequencyTokenType; - return acc; - }, Object.create(null)), - ...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)), - }; + const SymbolsMapTokens = Object.create(null); + 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, @@ -25346,7 +25416,6 @@ exports.EnumToken.ColonTokenType, exports.EnumToken.EOFTokenType, ]); - const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); var TokenMap; (function (TokenMap) { TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; @@ -25455,20 +25524,67 @@ } return null; } + /** + * tokenizer class + */ class Tokenizer { + /** + * 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; + /** + * + * @param parseInfo + * @returns + */ *consumeString(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -25527,6 +25643,11 @@ yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); // return result; } + /** + * + * @param parseInfo + * @returns + */ *consumeURLToken(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -25860,6 +25981,11 @@ } return 0; } + /** + * + * @param parseInfo + * @returns + */ consumeIdentToken(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -25929,6 +26055,11 @@ } return position - offset; } + /** + * + * @param parseInfo + * @returns + */ consumeColor(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -25964,6 +26095,13 @@ } return 0; } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ makeToken(parseInfo, hint, options) { let val = null; this.typ = null; @@ -26128,6 +26266,12 @@ parseInfo.position = parseInfo.currentPosition; return this; } + /** + * + * @param parseInfo + * @param input + * @returns + */ equalsIgnoreCase(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; let ca; @@ -26146,6 +26290,12 @@ } return true; } + /** + * + * @param parseInfo + * @param input + * @returns + */ match(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; for (let i = 0; i < input.length; i++) { @@ -26155,6 +26305,12 @@ } return true; } + /** + * + * @param parseInfo + * @param count + * @returns + */ peek(parseInfo, count = 1) { if (count == 1) { return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); @@ -26162,6 +26318,12 @@ const position = parseInfo.currentPosition - parseInfo.offset; return parseInfo.stream.slice(position, position + count); } + /** + * + * @param parseInfo + * @param count + * @returns + */ next(parseInfo, count = 1) { let position = parseInfo.currentPosition - parseInfo.offset; let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); @@ -26186,6 +26348,13 @@ 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; @@ -26244,6 +26413,11 @@ } return true; } + /** + * + * @param parseInfo + * @returns + */ isPseudo(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let endPosition = parseInfo.currentPosition - parseInfo.offset; @@ -26256,6 +26430,12 @@ ? this.isIdentToken(parseInfo, 2) : this.isIdentToken(parseInfo, 1); } + /** + * + * @param parseInfo + * @param input + * @returns + */ startsWith(parseInfo, input) { let i = 0; let j = input.length; @@ -26267,6 +26447,11 @@ } return true; } + /** + * + * @param parseInfo + * @returns + */ isURLToken(parseInfo) { let i = parseInfo.position - parseInfo.offset; let c; @@ -26864,7 +27049,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 { @@ -27484,7 +27671,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]); + } } } } @@ -27923,7 +28112,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; @@ -28130,7 +28321,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; @@ -28140,7 +28333,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 { @@ -28358,7 +28553,9 @@ } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -28509,7 +28706,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, @@ -28519,15 +28718,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, @@ -28644,7 +28849,9 @@ } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -28672,7 +28879,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, @@ -28903,14 +29112,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) => { - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { @@ -29366,7 +29579,9 @@ } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { @@ -29383,7 +29598,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)) { @@ -29594,7 +29808,8 @@ } else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = iter.next().value; if (tokenizer == null) { @@ -29650,7 +29865,7 @@ }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -29663,7 +29878,7 @@ context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -29706,17 +29921,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) { @@ -30531,7 +30752,8 @@ } else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = isAsync ? (await iter.next()).value @@ -30589,7 +30811,7 @@ }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -30602,7 +30824,7 @@ context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -30655,7 +30877,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) { @@ -30692,17 +30916,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) { @@ -31780,7 +32011,9 @@ 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; @@ -31835,7 +32068,9 @@ 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[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; @@ -31852,7 +32087,9 @@ 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 }; @@ -31897,7 +32134,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); @@ -31946,7 +32185,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 && @@ -31978,7 +32219,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") { @@ -32046,7 +32289,9 @@ 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[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); @@ -32258,7 +32503,9 @@ 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), @@ -32320,13 +32567,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; @@ -32346,7 +32597,6 @@ i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } diff --git a/dist/index.cjs b/dist/index.cjs index 5b910a13..eb784f8f 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -7043,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); @@ -7085,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); @@ -7093,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); @@ -7107,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) { @@ -7148,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); } @@ -7217,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); } @@ -7227,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); @@ -7283,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]; @@ -7307,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); @@ -7337,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); @@ -7345,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); @@ -7353,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); @@ -7481,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); @@ -7497,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); @@ -7514,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); @@ -7684,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); @@ -7704,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); @@ -7712,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); @@ -7733,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 @@ -7827,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) { @@ -7911,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) ?? {}; @@ -7983,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); } @@ -8085,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; } @@ -8455,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); @@ -8512,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; @@ -8561,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) { @@ -8584,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); @@ -8605,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); @@ -8717,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 { @@ -8728,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; } @@ -8750,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); @@ -8774,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); @@ -8807,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; @@ -8831,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 @@ -8939,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 @@ -8948,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 @@ -8987,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) { @@ -9000,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": @@ -9113,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; @@ -9320,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 { @@ -9693,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); } } } @@ -9725,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 = []; @@ -9759,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); + } + } } } } @@ -9776,8 +9853,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); } } } @@ -9918,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]); @@ -10381,7 +10465,15 @@ function evaluateFunc(token) { : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -10399,12 +10491,18 @@ function inlineExpression$1(token) { result.push(token); } else { - result.push(...inlineExpression$1(token.l), { + 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], - }, ...inlineExpression$1(token.r)); + }); + for (const child of inlineExpression$1(token.r)) { + result.push(child); + } } } else { @@ -10549,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) { @@ -10777,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); @@ -10879,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"; @@ -11907,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 @@ -12269,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); + } } } } @@ -12560,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(); @@ -12628,7 +12663,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** @@ -14511,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; } @@ -14547,9 +14584,12 @@ 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("-", "_")], }; + for (const t of Object.values(components)) { + tk.chi.push(t); + } tk[LOCSRCID] = token[LOCSRCID]; tk[LOCSTA] = token[LOCSTA]; tk[LOCEND] = token[LOCEND]; @@ -14903,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; @@ -14956,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) { @@ -14995,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] }, @@ -15093,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. @@ -15442,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; @@ -15466,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; @@ -15564,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; @@ -15587,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; @@ -15883,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) { @@ -16323,8 +16348,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; @@ -16337,7 +16362,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; @@ -16349,7 +16374,9 @@ function replaceAstNodes(tokens, root) { }); } return acc.concat(curr); - }, [])); + }, [])) { + tokens.push(token); + } } return result; } @@ -16567,52 +16594,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; @@ -16625,7 +16628,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; @@ -16653,12 +16659,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); + } } } /** @@ -16729,7 +16739,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) { @@ -16737,17 +16749,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); + } } - tokens.push(...form, { typ: exports.EnumToken.CommaTokenType }); + for (const token of form) { + tokens.push(token); + } + 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; } } @@ -16755,13 +16777,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 { @@ -17073,7 +17096,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; }, []), }, @@ -18795,10 +18820,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]); + } } } } @@ -18815,7 +18847,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; }, []), }); @@ -18950,7 +18984,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); @@ -19172,7 +19208,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({ @@ -19186,7 +19222,9 @@ class PropertyMap { // @ts-ignore acc.push(curr); return acc; - }, [])); + }, [])) { + acc[i].push(v); + } } } return acc; @@ -19204,7 +19242,9 @@ class PropertyMap { return acc; }, [])); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); if (this.config.mapping != null) { @@ -19272,10 +19312,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])) { @@ -19506,10 +19549,7 @@ class PropertyList { let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != exports.EnumToken.DeclarationNodeType - ? null - : declaration.nam; + 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 || @@ -19672,7 +19712,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]() { @@ -19745,10 +19787,14 @@ 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; } @@ -19916,22 +19962,34 @@ function multiply(matrixA, matrixB) { 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, @@ -20027,11 +20085,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); @@ -20042,7 +20100,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]; @@ -20718,6 +20776,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()); @@ -20725,7 +20784,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) { @@ -20867,7 +20929,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") { @@ -21736,7 +21798,9 @@ function minifyAtRuleMedia(tokens) { typ: exports.EnumToken.CommaTokenType, }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }, [])); } @@ -21816,7 +21880,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; @@ -21848,7 +21914,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 === exports.EnumToken.CommentTokenType || (curr.typ === exports.EnumToken.WhitespaceTokenType && @@ -21900,8 +21968,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); @@ -22116,8 +22185,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]; @@ -22466,7 +22542,9 @@ function reduceSelector(acc, curr) { if (acc.length > 0) { acc.push(","); } - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } return acc; }, []); } @@ -22635,9 +22713,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); @@ -22876,7 +22958,9 @@ function reduceRuleSelector(node) { acc.push(","); } unique.add(sig); - acc.push(...curr); + for (const c of curr) { + acc.push(c); + } } return acc; }, []); @@ -22914,9 +22998,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 == exports.EnumToken.AtRuleNodeType && "chi" in node) { let hasRule = false; @@ -23036,6 +23119,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; } @@ -23075,7 +23165,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 == exports.EnumToken.AtRuleNodeType) { let astAtRule = ast.chi[i]; @@ -23110,13 +23202,19 @@ function expandRule(node) { values.push(r); } else if (r.typ == exports.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); } } @@ -24061,7 +24159,7 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines 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 { @@ -24078,7 +24176,7 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines 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]]); } // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } @@ -24547,7 +24645,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; @@ -24738,32 +24838,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": @@ -24868,24 +24981,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; } @@ -25225,118 +25350,63 @@ function filterValues(values) { return values; } -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, - ...flexUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.FlexTokenType; - return acc; - }, Object.create(null)), - ...dimensionUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.LengthTokenType; - return acc; - }, Object.create(null)), - ...resolutionUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.ResolutionTokenType; - return acc; - }, Object.create(null)), - ...angleUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.AngleTokenType; - return acc; - }, Object.create(null)), - ...timeUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.TimeTokenType; - return acc; - }, Object.create(null)), - ...frequencyUnits.reduce((acc, curr) => { - acc[curr] = exports.EnumToken.FrequencyTokenType; - return acc; - }, Object.create(null)), - ...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)), -}; +const SymbolsMapTokens = Object.create(null); +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, @@ -25349,7 +25419,6 @@ const hintsEnum = new Set([ exports.EnumToken.ColonTokenType, exports.EnumToken.EOFTokenType, ]); -const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); var TokenMap; (function (TokenMap) { TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; @@ -25458,20 +25527,67 @@ function searchArray(array, parseInfo, start, end) { } return null; } +/** + * tokenizer class + */ class Tokenizer { + /** + * 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; + /** + * + * @param parseInfo + * @returns + */ *consumeString(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -25530,6 +25646,11 @@ class Tokenizer { yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); // return result; } + /** + * + * @param parseInfo + * @returns + */ *consumeURLToken(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -25863,6 +25984,11 @@ class Tokenizer { } return 0; } + /** + * + * @param parseInfo + * @returns + */ consumeIdentToken(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -25932,6 +26058,11 @@ class Tokenizer { } return position - offset; } + /** + * + * @param parseInfo + * @returns + */ consumeColor(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -25967,6 +26098,13 @@ class Tokenizer { } return 0; } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ makeToken(parseInfo, hint, options) { let val = null; this.typ = null; @@ -26131,6 +26269,12 @@ class Tokenizer { parseInfo.position = parseInfo.currentPosition; return this; } + /** + * + * @param parseInfo + * @param input + * @returns + */ equalsIgnoreCase(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; let ca; @@ -26149,6 +26293,12 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @param input + * @returns + */ match(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; for (let i = 0; i < input.length; i++) { @@ -26158,6 +26308,12 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @param count + * @returns + */ peek(parseInfo, count = 1) { if (count == 1) { return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); @@ -26165,6 +26321,12 @@ class Tokenizer { const position = parseInfo.currentPosition - parseInfo.offset; return parseInfo.stream.slice(position, position + count); } + /** + * + * @param parseInfo + * @param count + * @returns + */ next(parseInfo, count = 1) { let position = parseInfo.currentPosition - parseInfo.offset; let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); @@ -26189,6 +26351,13 @@ class Tokenizer { 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; @@ -26247,6 +26416,11 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @returns + */ isPseudo(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let endPosition = parseInfo.currentPosition - parseInfo.offset; @@ -26259,6 +26433,12 @@ class Tokenizer { ? this.isIdentToken(parseInfo, 2) : this.isIdentToken(parseInfo, 1); } + /** + * + * @param parseInfo + * @param input + * @returns + */ startsWith(parseInfo, input) { let i = 0; let j = input.length; @@ -26270,6 +26450,11 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @returns + */ isURLToken(parseInfo) { let i = parseInfo.position - parseInfo.offset; let c; @@ -26867,7 +27052,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 { @@ -27487,7 +27674,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]); + } } } } @@ -27926,7 +28115,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; @@ -28133,7 +28324,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; @@ -28143,7 +28336,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 { @@ -28361,7 +28556,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 }; } @@ -28512,7 +28709,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, @@ -28522,15 +28721,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, @@ -28647,7 +28852,9 @@ function matchAtRuleWhenElseSyntax(stream, context, options = {}) { } } stream.length = 0; - stream.push(...trimArray(tokens)); + for (const token of trimArray(tokens)) { + stream.push(token); + } return { success, errors }; } @@ -28675,7 +28882,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, @@ -28906,14 +29115,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) => { - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { @@ -29369,7 +29582,9 @@ function parseVisitors(visitorsDef, errors) { } } else { - visitors.push(...Object.entries(value)); + for (const val of Object.entries(value)) { + visitors.push(val); + } } } else { @@ -29386,7 +29601,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)) { @@ -29597,7 +29811,8 @@ function doParseSync(iter, options = {}) { } else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = iter.next().value; if (tokenizer == null) { @@ -29653,7 +29868,7 @@ function doParseSync(iter, options = {}) { }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -29666,7 +29881,7 @@ function doParseSync(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -29709,17 +29924,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) { @@ -30534,7 +30755,8 @@ async function doParse(iter, options = {}) { } else if (item.typ == exports.EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = isAsync ? (await iter.next()).value @@ -30592,7 +30814,7 @@ async function doParse(iter, options = {}) { }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === exports.EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -30605,7 +30827,7 @@ async function doParse(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -30658,7 +30880,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) { @@ -30695,17 +30919,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) { @@ -31783,7 +32014,9 @@ 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; @@ -31838,7 +32071,9 @@ 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[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; @@ -31855,7 +32090,9 @@ 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 }; @@ -31900,7 +32137,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); @@ -31949,7 +32188,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 && @@ -31981,7 +32222,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") { @@ -32049,7 +32292,9 @@ 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[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); @@ -32261,7 +32506,9 @@ 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), @@ -32323,13 +32570,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; @@ -32349,7 +32600,6 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } @@ -32957,7 +33207,9 @@ function parseSync(...args) { currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -33114,7 +33366,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS file 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/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..60b36dd3 100644 --- a/dist/lib/ast/features/shorthand.js +++ b/dist/lib/ast/features/shorthand.js @@ -46,10 +46,14 @@ 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; } diff --git a/dist/lib/ast/math/expression.js b/dist/lib/ast/math/expression.js index 0317e6a8..5c0bab0a 100644 --- a/dist/lib/ast/math/expression.js +++ b/dist/lib/ast/math/expression.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]); @@ -491,7 +493,15 @@ function evaluateFunc(token) { : Math.ceil(val / val2) * val2; } // @ts-ignore - return [{ ...values[0], val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -509,12 +519,18 @@ function inlineExpression(token) { result.push(token); } else { - result.push(...inlineExpression(token.l), { + for (const child of inlineExpression(token.l)) { + result.push(child); + } + result.push({ typ: token.op, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], - }, ...inlineExpression(token.r)); + }); + for (const child of inlineExpression(token.r)) { + result.push(child); + } } } else { diff --git a/dist/lib/ast/minify.js b/dist/lib/ast/minify.js index 2124e9bd..3004ef6b 100644 --- a/dist/lib/ast/minify.js +++ b/dist/lib/ast/minify.js @@ -287,7 +287,9 @@ function minifyAtRuleMedia(tokens) { typ: EnumToken.CommaTokenType, }); } - acc.push(...t); + for (const token of t) { + acc.push(token); + } return acc; }, [])); } @@ -367,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; @@ -399,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 && @@ -451,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); @@ -667,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]; @@ -1017,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; }, []); } @@ -1186,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); @@ -1427,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/transform/compute.js b/dist/lib/ast/transform/compute.js index 4401951d..dba77b24 100644 --- a/dist/lib/ast/transform/compute.js +++ b/dist/lib/ast/transform/compute.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) { @@ -166,7 +170,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/utils.js b/dist/lib/ast/transform/utils.js index 453e3056..a1b5140c 100644 --- a/dist/lib/ast/transform/utils.js +++ b/dist/lib/ast/transform/utils.js @@ -46,22 +46,34 @@ function multiply(matrixA, matrixB) { 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, @@ -157,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); @@ -172,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 337ac363..2cf0cba1 100644 --- a/dist/lib/ast/walk.js +++ b/dist/lib/ast/walk.js @@ -282,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); } } } @@ -314,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 = []; @@ -348,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); + } + } } } } @@ -365,8 +382,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); } } } diff --git a/dist/lib/parser/declaration/list.js b/dist/lib/parser/declaration/list.js index 4181137f..7b0f6498 100644 --- a/dist/lib/parser/declaration/list.js +++ b/dist/lib/parser/declaration/list.js @@ -31,10 +31,7 @@ class PropertyList { let syntaxRules = null; let result; for (const declaration of declarations) { - name = - declaration.typ != EnumToken.DeclarationNodeType - ? null - : declaration.nam; + name = declaration.typ != EnumToken.DeclarationNodeType ? null : declaration.nam; if (declaration[STATE] == EnumAstNodeStatus.Invalid || declaration[STATE] == EnumAstNodeStatus.Unknown || declaration[STATE] == EnumAstNodeStatus.ValidationFailed || @@ -197,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/parse.js b/dist/lib/parser/parse.js index cc1909bf..e2d1a4ac 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.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)) { @@ -582,7 +583,8 @@ function doParseSync(iter, options = {}) { } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = iter.next().value; if (tokenizer == null) { @@ -638,7 +640,7 @@ function doParseSync(iter, options = {}) { }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -651,7 +653,7 @@ function doParseSync(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -694,17 +696,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) { @@ -1519,7 +1527,8 @@ async function doParse(iter, options = {}) { } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = isAsync ? (await iter.next()).value @@ -1577,7 +1586,7 @@ async function doParse(iter, options = {}) { }); } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options, errors, stats, invalidNodes); @@ -1590,7 +1599,7 @@ async function doParse(iter, options = {}) { context.chi[context.chi.length - 1] == previousNode) { context.chi.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -1643,7 +1652,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) { @@ -1680,17 +1691,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) { @@ -2768,7 +2786,9 @@ 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; @@ -2823,7 +2843,9 @@ 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[LOCEND] = (stream.at(-1) ?? atRule)[LOCEND]; atRule[TOKENS] = stream; @@ -2840,7 +2862,9 @@ 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 }; @@ -2885,7 +2909,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); @@ -2934,7 +2960,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 && @@ -2966,7 +2994,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") { @@ -3034,7 +3064,9 @@ 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[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; atRule[TOKENS] = stream.slice(); @@ -3246,7 +3278,9 @@ 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), @@ -3308,13 +3342,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; @@ -3334,7 +3372,6 @@ function parseAtRule(stream, context, options, errors, parseAsBlock = null) { i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index 871a4ae1..520ec41f 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -3,118 +3,63 @@ import { wildCardFuncs, whenElseFunc, mathFuncs, timingFunc, supportFunc, timeli import { isWhiteSpace, isNewLine, isDigit, isLetter, isIdentStart, isIdentCodepoint, isNonPrintable, timeUnits, angleUnits, flexUnits, dimensionUnits, resolutionUnits, frequencyUnits } from '../syntax/syntax.js'; import { SourceFile } from './source.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, - ...flexUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.FlexTokenType; - return acc; - }, Object.create(null)), - ...dimensionUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.LengthTokenType; - return acc; - }, Object.create(null)), - ...resolutionUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.ResolutionTokenType; - return acc; - }, Object.create(null)), - ...angleUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.AngleTokenType; - return acc; - }, Object.create(null)), - ...timeUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.TimeTokenType; - return acc; - }, Object.create(null)), - ...frequencyUnits.reduce((acc, curr) => { - acc[curr] = EnumToken.FrequencyTokenType; - return acc; - }, Object.create(null)), - ...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); +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, @@ -127,7 +72,6 @@ const hintsEnum = new Set([ EnumToken.ColonTokenType, EnumToken.EOFTokenType, ]); -const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); var TokenMap; (function (TokenMap) { TokenMap[TokenMap["EXCLAMATION"] = 33] = "EXCLAMATION"; @@ -236,20 +180,67 @@ function searchArray(array, parseInfo, start, end) { } return null; } +/** + * tokenizer class + */ class Tokenizer { + /** + * 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; + /** + * + * @param parseInfo + * @returns + */ *consumeString(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -308,6 +299,11 @@ class Tokenizer { yield this.makeToken(parseInfo, EnumToken.StringTokenType); // return result; } + /** + * + * @param parseInfo + * @returns + */ *consumeURLToken(parseInfo) { const quote = this.next(parseInfo).charCodeAt(0); let charCode; @@ -641,6 +637,11 @@ class Tokenizer { } return 0; } + /** + * + * @param parseInfo + * @returns + */ consumeIdentToken(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -710,6 +711,11 @@ class Tokenizer { } return position - offset; } + /** + * + * @param parseInfo + * @returns + */ consumeColor(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let offset = position; @@ -745,6 +751,13 @@ class Tokenizer { } return 0; } + /** + * + * @param parseInfo + * @param hint + * @param options + * @returns + */ makeToken(parseInfo, hint, options) { let val = null; this.typ = null; @@ -909,6 +922,12 @@ class Tokenizer { parseInfo.position = parseInfo.currentPosition; return this; } + /** + * + * @param parseInfo + * @param input + * @returns + */ equalsIgnoreCase(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; let ca; @@ -927,6 +946,12 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @param input + * @returns + */ match(parseInfo, input) { let position = parseInfo.currentPosition - parseInfo.offset; for (let i = 0; i < input.length; i++) { @@ -936,6 +961,12 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @param count + * @returns + */ peek(parseInfo, count = 1) { if (count == 1) { return parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset); @@ -943,6 +974,12 @@ class Tokenizer { const position = parseInfo.currentPosition - parseInfo.offset; return parseInfo.stream.slice(position, position + count); } + /** + * + * @param parseInfo + * @param count + * @returns + */ next(parseInfo, count = 1) { let position = parseInfo.currentPosition - parseInfo.offset; let char = count == 1 ? parseInfo.stream.charAt(position) : parseInfo.stream.slice(position, position + count); @@ -967,6 +1004,13 @@ class Tokenizer { 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; @@ -1025,6 +1069,11 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @returns + */ isPseudo(parseInfo) { let position = parseInfo.currentPosition - parseInfo.offset; let endPosition = parseInfo.currentPosition - parseInfo.offset; @@ -1037,6 +1086,12 @@ class Tokenizer { ? this.isIdentToken(parseInfo, 2) : this.isIdentToken(parseInfo, 1); } + /** + * + * @param parseInfo + * @param input + * @returns + */ startsWith(parseInfo, input) { let i = 0; let j = input.length; @@ -1048,6 +1103,11 @@ class Tokenizer { } return true; } + /** + * + * @param parseInfo + * @returns + */ isURLToken(parseInfo) { let i = parseInfo.position - parseInfo.offset; let c; diff --git a/dist/lib/parser/utils/at-rule-container.js b/dist/lib/parser/utils/at-rule-container.js index 5bb9d716..c70b54cb 100644 --- a/dist/lib/parser/utils/at-rule-container.js +++ b/dist/lib/parser/utils/at-rule-container.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, @@ -259,14 +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) => { - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, [])); return { diff --git a/dist/lib/parser/utils/at-rule-import.js b/dist/lib/parser/utils/at-rule-import.js index c4338a17..69c21674 100644 --- a/dist/lib/parser/utils/at-rule-import.js +++ b/dist/lib/parser/utils/at-rule-import.js @@ -153,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, @@ -163,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 53b215c0..f971a3f3 100644 --- a/dist/lib/parser/utils/at-rule-media.js +++ b/dist/lib/parser/utils/at-rule-media.js @@ -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; @@ -352,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; @@ -362,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 048c52db..9751c7d5 100644 --- a/dist/lib/parser/utils/at-rule-support.js +++ b/dist/lib/parser/utils/at-rule-support.js @@ -210,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 90e67d3f..954f5fee 100644 --- a/dist/lib/parser/utils/at-rule-when-else.js +++ b/dist/lib/parser/utils/at-rule-when-else.js @@ -114,7 +114,9 @@ function matchAtRuleWhenElseSyntax(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/declaration.js b/dist/lib/parser/utils/declaration.js index 0236f852..c093ee84 100644 --- a/dist/lib/parser/utils/declaration.js +++ b/dist/lib/parser/utils/declaration.js @@ -182,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]); + } } } } diff --git a/dist/lib/parser/utils/selector.js b/dist/lib/parser/utils/selector.js index f0d1f8b8..560cd9e8 100644 --- a/dist/lib/parser/utils/selector.js +++ b/dist/lib/parser/utils/selector.js @@ -49,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 { diff --git a/dist/lib/renderer/render.js b/dist/lib/renderer/render.js index 2e6d9787..08d5d795 100644 --- a/dist/lib/renderer/render.js +++ b/dist/lib/renderer/render.js @@ -196,7 +196,7 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines 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 { @@ -213,7 +213,7 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines 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]]); } // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } @@ -682,7 +682,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; @@ -873,32 +875,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": @@ -1003,24 +1018,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; } 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 aeadb8e1..b4a0e6cb 100644 --- a/dist/lib/syntax/color/color.js +++ b/dist/lib/syntax/color/color.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,9 +83,12 @@ 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("-", "_")], }; + for (const t of Object.values(components)) { + tk.chi.push(t); + } tk[LOCSRCID] = token[LOCSRCID]; tk[LOCSTA] = token[LOCSTA]; tk[LOCEND] = token[LOCEND]; @@ -439,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; @@ -492,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) { @@ -531,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 0787b11c..68e56a13 100644 --- a/dist/lib/syntax/color/relative-color.js +++ b/dist/lib/syntax/color/relative-color.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) { 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/syntax.js b/dist/lib/syntax/syntax.js index 8361c0a5..6de8ed7e 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -236,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; @@ -260,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; @@ -358,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; @@ -381,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; @@ -677,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) { diff --git a/dist/lib/validation/match.js b/dist/lib/validation/match.js index 8a48351c..05d5cf88 100644 --- a/dist/lib/validation/match.js +++ b/dist/lib/validation/match.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 @@ -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); + } } } } @@ -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(); @@ -734,7 +735,9 @@ function matchSelectorSyntax(stream, errors, options, nested = true) { }; } stream.length = 0; - stream.push(...tokens); + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } /** diff --git a/dist/node.js b/dist/node.js index b2bbbbdd..94457b7a 100644 --- a/dist/node.js +++ b/dist/node.js @@ -191,7 +191,9 @@ function parseSync(...args) { currentPosition: 0, }; const result = doParseSync(tokenize(options.parseInfo), options); - return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** * Transform CSS @@ -348,7 +350,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options))); + return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options)); } /** * Transform CSS 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/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/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..277c0b69 100644 --- a/src/lib/ast/features/shorthand.ts +++ b/src/lib/ast/features/shorthand.ts @@ -71,9 +71,13 @@ 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; diff --git a/src/lib/ast/math/expression.ts b/src/lib/ast/math/expression.ts index 9fba6563..36981651 100644 --- a/src/lib/ast/math/expression.ts +++ b/src/lib/ast/math/expression.ts @@ -54,7 +54,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; }); @@ -652,7 +654,15 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { } // @ts-ignore - return [{ ...values[0], val, [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND] }]; + return [ + { + ...values[0], + val, + [LOCSRCID]: token[LOCSRCID], + [LOCSTA]: token[LOCSTA], + [LOCEND]: token[LOCEND], + }, + ]; } } } @@ -672,16 +682,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), - { + + 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, - ...inlineExpression((token as BinaryExpressionToken).r), - ); + } as Token); + + for (const child of inlineExpression((token as BinaryExpressionToken).r)) { + result.push(child); + } + } } else { result.push(token); diff --git a/src/lib/ast/minify.ts b/src/lib/ast/minify.ts index d7696c31..e3f65511 100644 --- a/src/lib/ast/minify.ts +++ b/src/lib/ast/minify.ts @@ -427,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[]), ); @@ -536,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); @@ -581,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 + @@ -651,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); @@ -929,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); @@ -1363,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; }, []); @@ -1585,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); } @@ -1896,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/transform/compute.ts b/src/lib/ast/transform/compute.ts index cbcd6a4f..4548ffed 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); @@ -216,7 +222,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/utils.ts b/src/lib/ast/transform/utils.ts index 479c6612..764d5608 100644 --- a/src/lib/ast/transform/utils.ts +++ b/src/lib/ast/transform/utils.ts @@ -60,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, @@ -208,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); @@ -228,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 1e198012..970fc7e7 100644 --- a/src/lib/ast/walk.ts +++ b/src/lib/ast/walk.ts @@ -491,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); + } + } } } } @@ -530,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[] = []; @@ -567,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); + } + } } } } @@ -589,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/parser/declaration/list.ts b/src/lib/parser/declaration/list.ts index 7e097770..5e9dc0ae 100644 --- a/src/lib/parser/declaration/list.ts +++ b/src/lib/parser/declaration/list.ts @@ -30,7 +30,7 @@ export class PropertyList { protected options: PropertyListOptions = { removeDuplicateDeclarations: true, computeShorthand: true }; protected declarations: Map; - // ketsey = new Map; + // ketsey = new Map; constructor(options: PropertyListOptions = {}) { this.options = options; this.declarations = new Map(); @@ -44,24 +44,20 @@ export class PropertyList { }); } - add(...declarations: AstNode[]) { let name: string | null; let syntaxRules: ValidationToken[] | null = null; let result: ValidationMatch; for (const declaration of declarations) { - name = - declaration.typ != EnumToken.DeclarationNodeType - ? null - : (declaration as AstDeclaration).nam; + 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 || - equalsIgnoreCase("composes" , name as string) || + equalsIgnoreCase("composes", name as string) || (typeof this.options.removeDuplicateDeclarations === "string" && this.options.removeDuplicateDeclarations === name) || (Array.isArray(this.options.removeDuplicateDeclarations) @@ -92,12 +88,10 @@ export class PropertyList { ? EnumAstNodeStatus.Validated : EnumAstNodeStatus.ValidationFailed; } - } // do not compute shorthand for invalid declarations if (declaration[STATE] !== EnumAstNodeStatus.Validated) { - // const key = objectHash(declaration); // if (!this.ketsey.has(key)) { // this.ketsey.set(key, [declaration.nam]); @@ -259,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/parse.ts b/src/lib/parser/parse.ts index e3ee21e6..37db35b5 100644 --- a/src/lib/parser/parse.ts +++ b/src/lib/parser/parse.ts @@ -504,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` }); @@ -526,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 ( @@ -799,7 +799,9 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio } } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock: number = 1; - tokens = [item]; + + tokens.length = 0; + tokens.push(item); do { tokenizer = iter.next().value; @@ -858,7 +860,7 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); @@ -876,7 +878,7 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio context.chi!.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -929,12 +931,18 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio 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; } } @@ -942,7 +950,9 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio // @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) { @@ -1962,7 +1972,8 @@ export async function doParse( } } else if (item.typ == EnumToken.BlockStartTokenType) { let inBlock: number = 1; - tokens = [item]; + tokens.length = 0; + tokens.push(item); do { tokenizer = isAsync @@ -2023,7 +2034,7 @@ export async function doParse( } } - tokens = []; + tokens.length = 0; } else if ((parensMatch === 0 || curlyBracketMatch === 0) && item.typ === EnumToken.BlockEndTokenType) { parseNode(tokens, context, options as ParserOptions, errors, stats, invalidNodes); @@ -2041,7 +2052,7 @@ export async function doParse( context.chi!.pop(); } - tokens = []; + tokens.length = 0; parensMatch = 0; curlyBracketMatch = 0; } @@ -2111,7 +2122,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 @@ -2156,12 +2169,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; } } @@ -2169,7 +2187,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) { @@ -3573,7 +3594,9 @@ 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; @@ -3638,7 +3661,9 @@ 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[LOCEND] = (stream.at(-1)! ?? atRule)[LOCEND]; @@ -3658,7 +3683,9 @@ 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 @@ -3720,7 +3747,9 @@ export function parseAtRule( ); if (!result.success) { - errors.push(...result.errors); + for (const error of result.errors) { + errors.push(error); + } } // else { // parseUrlToken(stream); @@ -3782,7 +3811,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 && @@ -3827,7 +3858,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; @@ -3906,7 +3939,9 @@ 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[LOCEND] = stream.at(-1)?.[LOCEND] ?? atRule[LOCEND]; @@ -4147,7 +4182,9 @@ 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, @@ -4222,13 +4259,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) { @@ -4252,7 +4293,6 @@ export function parseAtRule( i = index; stream.splice(index + 1, 1); stack.pop(); - // continue; } } } diff --git a/src/lib/parser/tokenize.ts b/src/lib/parser/tokenize.ts index bca87381..dde7d1c8 100644 --- a/src/lib/parser/tokenize.ts +++ b/src/lib/parser/tokenize.ts @@ -32,118 +32,67 @@ import { } from "../syntax/syntax.ts"; import { SourceFile } from "./source.ts"; -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, - ...flexUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.FlexTokenType; - return acc; - }, Object.create(null)), - ...dimensionUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.LengthTokenType; - return acc; - }, Object.create(null)), - ...resolutionUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.ResolutionTokenType; - return acc; - }, Object.create(null)), - ...angleUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.AngleTokenType; - return acc; - }, Object.create(null)), - ...timeUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.TimeTokenType; - return acc; - }, Object.create(null)), - ...frequencyUnits.reduce((acc, curr: string) => { - acc[curr] = EnumToken.FrequencyTokenType; - return acc; - }, Object.create(null)), - ...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); + +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([ @@ -158,8 +107,6 @@ export const hintsEnum = new Set([ EnumToken.EOFTokenType, ]) as Set; -const SymbolsMapTokensKeys = Object.keys(SymbolsMapTokens); - export const enum TokenMap { EXCLAMATION = 33, // '!', EXCLAMATION SLASH = 47, // '/' diff --git a/src/lib/parser/utils/at-rule-container.ts b/src/lib/parser/utils/at-rule-container.ts index dc7f67e9..11d89e0d 100644 --- a/src/lib/parser/utils/at-rule-container.ts +++ b/src/lib/parser/utils/at-rule-container.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, @@ -364,7 +366,10 @@ export function parseAtRuleContainerQueryList( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const token of trimArray(tokens)) { + stream.push(token); + } } } @@ -373,7 +378,9 @@ export function parseAtRuleContainerQueryList( ...parts .filter((p) => p.length > 0 && p[0].typ !== EnumToken.InvalidMediaQueryTokenType) .reduce((acc, b) => { - acc.push(...b); + for (const token of b) { + acc.push(token); + } return acc; }, []), diff --git a/src/lib/parser/utils/at-rule-import.ts b/src/lib/parser/utils/at-rule-import.ts index f3ae715e..08d12c43 100644 --- a/src/lib/parser/utils/at-rule-import.ts +++ b/src/lib/parser/utils/at-rule-import.ts @@ -257,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, @@ -270,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) { @@ -281,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 72956246..cfced660 100644 --- a/src/lib/parser/utils/at-rule-media.ts +++ b/src/lib/parser/utils/at-rule-media.ts @@ -208,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; } @@ -497,7 +500,10 @@ export function parseMediaqueryList( } stream.length = 0; - stream.push(...trimArray(tokens)); + + for (const t of trimArray(tokens)) { + stream.push(t); + } } } @@ -510,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 cc5f3dc0..12cee750 100644 --- a/src/lib/parser/utils/at-rule-support.ts +++ b/src/lib/parser/utils/at-rule-support.ts @@ -284,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 a56bafe9..edff047a 100644 --- a/src/lib/parser/utils/at-rule-when-else.ts +++ b/src/lib/parser/utils/at-rule-when-else.ts @@ -156,7 +156,10 @@ export function matchAtRuleWhenElseSyntax( } 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/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 41434e80..804c8b01 100644 --- a/src/lib/parser/utils/declaration.ts +++ b/src/lib/parser/utils/declaration.ts @@ -30,7 +30,7 @@ import { STATE, LOCEND, LOCSTA, - LOCSRCID + LOCSRCID, } from "../../syntax/constants.ts"; import { isColor, isWhiteSpace, parseColor, renamedStandardProperties } from "../../syntax/syntax.ts"; import { getSyntaxRule, getParsedSyntax, ValidationSyntaxRule } from "../../validation/config.ts"; @@ -127,10 +127,8 @@ export function parseDeclaration( (name.typ !== EnumToken.IdenTokenType && name.typ !== EnumToken.DashedIdenTokenType) || tokens[i]?.typ !== EnumToken.ColonTokenType ) { - if (tokens[tokens.length - 1]?.[LOCEND] != null) { - - name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND] + name[LOCEND] = tokens[tokens.length - 1]?.[LOCEND]; } name[STATE] = EnumAstNodeStatus.Unparsed; @@ -175,7 +173,6 @@ export function parseDeclaration( rules.acceptAnyDeclaration && rules.acceptAnyRule ? getParsedSyntax(ValidationSyntaxGroupEnum.Declarations, name.val.toLowerCase()) : rules.getBlockRules(); - } } } else { @@ -222,10 +219,9 @@ export function parseDeclaration( }); if (tokens[tokens.length - 1]?.[LOCEND] != null) { - name[LOCEND] = tokens[tokens.length - 1][LOCEND]; } - + name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = [errors[errors.length - 1]]; @@ -263,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]); + } } } } @@ -337,7 +335,6 @@ export function parseDeclaration( break; case EnumToken.EndParensTokenType: - if (stack.at(-1)?.typ === EnumToken.StartParensTokenType || tokensfuncDefMap.has(stack.at(-1)?.typ)) { index = tokens.indexOf(stack.at(-1)!); @@ -534,10 +531,9 @@ export function parseDeclaration( }); if (tokens[tokens.length - 1][LOCEND] != null) { - name[LOCEND] = tokens[tokens.length - 1][LOCEND]; } - + name[STATE] = EnumAstNodeStatus.Invalid; name[ERRORS] = result?.errors ?? []; @@ -580,7 +576,6 @@ export function parseDeclaration( } if (validate && syntaxRules == null && name.typ === EnumToken.IdenTokenType) { - if (tokens[tokens.length - 1]?.[LOCEND] != null) { name[LOCEND] = tokens[tokens.length - 1][LOCEND]; } @@ -618,7 +613,6 @@ export function parseDeclaration( [LOCSRCID]: tokens[0][LOCSRCID], [LOCSTA]: tokens[0][LOCSTA], [LOCEND]: index != -1 ? right![right!.length - 1]?.[LOCEND] : left[left.length - 1][LOCEND], - } as ComposesSelectorToken, ]; } diff --git a/src/lib/parser/utils/selector.ts b/src/lib/parser/utils/selector.ts index e72b11fa..f3a5aaea 100644 --- a/src/lib/parser/utils/selector.ts +++ b/src/lib/parser/utils/selector.ts @@ -107,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[]), ); diff --git a/src/lib/renderer/render.ts b/src/lib/renderer/render.ts index 681dad8f..a0f5c053 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -52,7 +52,15 @@ 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, LOCSRCID, LOCSTA, PARENT, pseudoElements, tokensfuncSet, urlTokenMatcher } from "../syntax/constants.ts"; +import { + colorPrecision, + LOCSRCID, + LOCSTA, + PARENT, + pseudoElements, + tokensfuncSet, + urlTokenMatcher, +} from "../syntax/constants.ts"; import { isWhiteSpace, minifyNumber, @@ -274,10 +282,7 @@ function updateSourceMap( move(sourceLocation, linesMap, str, 0, offset + 1); } - if ( - node[LOCSTA] != null - ) { - + if (node[LOCSTA] != null) { const source = options.sourcesMap!.get(node[LOCSRCID]!) as SourceFile; const inputSourceMap = source.getInputSourceMap(); const offsets: [number, number] = source.getOffsets(node[LOCSTA]) as [number, number]; @@ -288,13 +293,11 @@ function updateSourceMap( 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; + let newId: number | null = null; for (const record of records) { - newId = null; - + // @ts-ignore sourceFileName = (record[0] as string) || null; // @ts-ignore @@ -307,7 +310,6 @@ function updateSourceMap( sourceContent = (record[3] as string) || null; 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; @@ -338,12 +340,7 @@ function updateSourceMap( } if (newId == null) { - - const source = new SourceFile( - sourceContent as string, - [], - sourceFileName, - ) + const source = new SourceFile(sourceContent as string, [], sourceFileName); options.sourcesMap!.set(source.id, source); newId = source.id; @@ -355,7 +352,7 @@ function updateSourceMap( 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:")) { @@ -375,10 +372,10 @@ function updateSourceMap( sourcemaps.sources.push(srcId); } - sourcemaps.maps.push([newLine, newColumn, srcId, ...offsets]); + sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } - // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); + // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } move(sourceLocation, linesMap, str, offset); @@ -586,7 +583,6 @@ function renderAstNode( children += str; if (sourcemaps != null && str !== "") { - if (node.typ == EnumToken.DeclarationNodeType && recordDeclarationSourceMap) { // if declaration is child of at-rule, then record it // .rule { @@ -612,10 +608,8 @@ function renderAstNode( // @ts-ignore updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap!, str); - } - else { - - move(sourceLocation, linesMap!, str); + } else { + move(sourceLocation, linesMap!, str); } } } @@ -1037,7 +1031,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); + } } } @@ -1275,7 +1271,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) { @@ -1283,7 +1281,9 @@ export function renderValue( result.push({ typ: EnumToken.WhitespaceTokenType }); } - result.push(...size); + for (const token of size) { + result.push(token); + } } if (positions.length > 0) { @@ -1294,25 +1294,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; @@ -1468,13 +1479,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) { @@ -1483,15 +1500,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; } 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 1312dedb..eba94a94 100644 --- a/src/lib/syntax/color/color.ts +++ b/src/lib/syntax/color/color.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,10 +227,14 @@ 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], }; + for (const t of Object.values(components)) { + tk.chi.push(t); + } + tk[LOCSRCID] = token[LOCSRCID]; tk[LOCSTA] = token[LOCSTA]; tk[LOCEND] = token[LOCEND]; @@ -699,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 { @@ -765,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; } @@ -806,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..f78dbbc7 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); + 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 958a41db..f09b38d7 100644 --- a/src/lib/syntax/color/relative-color.ts +++ b/src/lib/syntax/color/relative-color.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 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/syntax.ts b/src/lib/syntax/syntax.ts index a31721bd..097e2ba5 100644 --- a/src/lib/syntax/syntax.ts +++ b/src/lib/syntax/syntax.ts @@ -15,16 +15,16 @@ import type { TimeToken, Token, } from "../../@types/index.d.ts"; -import {isOkLabClose} from "./color/utils/distance.ts"; -import {ColorType, EnumToken} from "../ast/types.ts"; -import {WalkerOptionEnum, walkValues} from "../ast/walk.ts"; -import {toDegrees} from "../parser/utils/angle.ts"; -import {memoize} from "../parser/utils/cache.ts"; -import {equalsIgnoreCase} from "../parser/utils/text.ts"; -import {trimArray} from "../validation/match.ts"; -import {splitTokenList} from "../validation/utils/list.ts"; -import {getColorSpace} from "./color/utils/colorspace.ts"; -import {getColorComponents} from "./color/utils/components.ts"; +import { isOkLabClose } from "./color/utils/distance.ts"; +import { ColorType, EnumToken } from "../ast/types.ts"; +import { WalkerOptionEnum, walkValues } from "../ast/walk.ts"; +import { toDegrees } from "../parser/utils/angle.ts"; +import { memoize } from "../parser/utils/cache.ts"; +import { equalsIgnoreCase } from "../parser/utils/text.ts"; +import { trimArray } from "../validation/match.ts"; +import { splitTokenList } from "../validation/utils/list.ts"; +import { getColorSpace } from "./color/utils/colorspace.ts"; +import { getColorComponents } from "./color/utils/components.ts"; import { anglePrecision, colorFuncColorSpace, @@ -36,7 +36,7 @@ import { nonStandardColors, systemColors, } from "./constants.ts"; -import {getSyntaxConfig} from "../validation/config.ts"; +import { getSyntaxConfig } from "../validation/config.ts"; // https://www.w3.org/TR/CSS21/syndata.html#syntax // https://www.w3.org/TR/2021/CRD-css-syntax-3-20211224/#typedef-ident-token @@ -605,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; @@ -634,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]); + } } } @@ -759,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; @@ -787,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); + } } } @@ -1191,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 diff --git a/src/lib/validation/match.ts b/src/lib/validation/match.ts index 65a8675c..8f285544 100644 --- a/src/lib/validation/match.ts +++ b/src/lib/validation/match.ts @@ -51,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 @@ -542,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); + } } } } @@ -908,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); + } } } @@ -986,7 +992,10 @@ export function matchSelectorSyntax( } stream.length = 0; - stream.push(...tokens); + + for (let i = 0; i < tokens.length; i++) { + stream.push(tokens[i]); + } return { success, errors }; } diff --git a/src/node.ts b/src/node.ts index c5a72836..aed6f03b 100644 --- a/src/node.ts +++ b/src/node.ts @@ -317,7 +317,9 @@ export function parseSync( } as ParseInfo; const result = doParseSync(tokenize(options.parseInfo), options) as ParseResult; - return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); + return options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options); } /** @@ -670,7 +672,11 @@ export async function parse( return doParse( stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options, - ).then((result) => (options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options))); + ).then((result) => + options.module == null && options.inputSourceMap == null && !options.sourcemap + ? result + : parseResult(result, options), + ); } /** From 218ffb5b1516b536841d23e20d36940ee56e8579 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Sun, 30 Aug 2026 14:48:46 -0400 Subject: [PATCH 05/11] support input sourcemap from inline sourcemap file --- CHANGELOG.md | 25 ++++++++++++++++ dist/index-umd-web.js | 28 +++++++++++++++++- dist/index.cjs | 36 +++++++++++++++++++---- dist/index.d.ts | 46 +++++++++++++++-------------- dist/node.js | 11 +++---- dist/types.d.ts | 6 +++- dist/types.js | 4 +++ dist/utils/sync.js | 23 ++++++++++++++- dist/web.js | 3 ++ files/sourcemap.md | 25 ++++++++++++++++ src/@types/index.d.ts | 3 +- src/node.ts | 14 +++++---- src/types.ts | 9 ++++-- src/utils/sync.ts | 36 +++++++++++++++++++++-- src/web.ts | 4 +++ test/specs/code/modules.js | 59 ++++++++++++++++++++++++++++++++++++++ 16 files changed, 286 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f2c7439..a81c17fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,31 @@ # v1.6.0 - [x] added `tan()` function. +- [x] support input sourcemap from inlince 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 diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 28778162..1cccfa9e 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -32940,6 +32940,10 @@ * return an arraybuffer */ ResponseType[ResponseType["ArrayBuffer"] = 2] = "ArrayBuffer"; + /** + * return a json object + */ + ResponseType[ResponseType["JSON"] = 3] = "JSON"; })(exports.ResponseType || (exports.ResponseType = {})); /** @@ -32959,7 +32963,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); + } } } } @@ -33077,6 +33100,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(); }); } diff --git a/dist/index.cjs b/dist/index.cjs index eb784f8f..dda6208e 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -32943,6 +32943,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 = {})); /** @@ -32962,7 +32966,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); + } } } } @@ -33068,6 +33091,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(); @@ -33076,8 +33102,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); @@ -33088,9 +33114,7 @@ async function load(url, currentDirectory = ".", responseType = false) { })); } } - catch (error) { - console.warn(error); - } + catch (error) { } throw new Error(`File not found: '${resolved.absolute || url}'`); } /** diff --git a/dist/index.d.ts b/dist/index.d.ts index 886d91f1..30aaefc0 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -4412,6 +4412,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; } @@ -5211,7 +5233,7 @@ export declare type LoadResult = | Promise> | ReadableStream | string - | Promise; + | Promise | object; /** * CSS module parser options @@ -6099,24 +6121,6 @@ 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 @@ -6570,7 +6574,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 @@ -6942,5 +6946,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/node.js b/dist/node.js index 94457b7a..bd547853 100644 --- a/dist/node.js +++ b/dist/node.js @@ -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}'`); } /** 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 b9478de8..99eee874 100644 --- a/dist/web.js +++ b/dist/web.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(); }); } diff --git a/files/sourcemap.md b/files/sourcemap.md index c8568696..c6835dd9 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/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/node.ts b/src/node.ts index aed6f03b..cc7b7c28 100644 --- a/src/node.ts +++ b/src/node.ts @@ -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}'`); } 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 a2635c52..f3957bbc 100644 --- a/src/utils/sync.ts +++ b/src/utils/sync.ts @@ -1,5 +1,14 @@ -import type { AstComment, ParseResult, ParserOptions, ParserSyncOptions } from "../@types/index.d.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 @@ -20,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 aa2cbd56..c156010e 100644 --- a/src/web.ts +++ b/src/web.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>>; } diff --git a/test/specs/code/modules.js b/test/specs/code/modules.js index 9e6fae27..54c8959a 100644 --- a/test/specs/code/modules.js +++ b/test/specs/code/modules.js @@ -1008,5 +1008,64 @@ 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 +}`); + }); + }); }); } From 05d2164f0521eda53292cef84b38eea0455de88e Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Sun, 30 Aug 2026 21:27:56 -0400 Subject: [PATCH 06/11] add test coverage --- CHANGELOG.md | 4 +- files/sourcemap.md | 2 +- test/specs/code/modules.js | 117 ++++++++++++++++++++++++++++++++++++- typedoc.config.js | 2 +- 4 files changed, 120 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a81c17fa..c391b423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,8 @@ # v1.6.0 -- [x] added `tan()` function. -- [x] support input sourcemap from inlince sourcemap file. This is only supported by the async parser. +- [x] added support for math function `tan()`. +- [x] support input sourcemap from inline sourcemap file. This is only supported by the async parser. ```css diff --git a/files/sourcemap.md b/files/sourcemap.md index c6835dd9..5b2e112e 100644 --- a/files/sourcemap.md +++ b/files/sourcemap.md @@ -107,7 +107,7 @@ result = await transform(css, { console.log(result.map.toJSON()); ``` -Parsing reference to the input sourcemap file is only supported when using the async api +Parsing reference to the input sourcemap file is only supported when using the async api. ```css table.colortable { diff --git a/test/specs/code/modules.js b/test/specs/code/modules.js index 54c8959a..2d32c524 100644 --- a/test/specs/code/modules.js +++ b/test/specs/code/modules.js @@ -1019,7 +1019,6 @@ a span { 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; @@ -1067,5 +1066,121 @@ a span { }`); }); }); + + 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/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'], From 36cda33a02bea0fc5d586fbfa2a2744542e6b3e4 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Mon, 31 Aug 2026 16:32:17 -0400 Subject: [PATCH 07/11] remove calls to string.slice() --- CHANGELOG.md | 3 + dist/index-umd-web.js | 746 ++++++++++------------- dist/index.cjs | 746 ++++++++++------------- dist/index.d.ts | 11 +- dist/lib/ast/features/shorthand.js | 5 +- dist/lib/parser/parse.js | 66 +- dist/lib/parser/tokenize.js | 650 +++++++++----------- dist/lib/renderer/render.js | 16 +- dist/lib/renderer/sourcemap/sourcemap.js | 7 +- dist/node.js | 8 +- dist/web.js | 8 +- src/lib/ast/features/shorthand.ts | 14 +- src/lib/ast/math/expression.ts | 3 +- src/lib/parser/parse.ts | 90 +-- src/lib/parser/tokenize.ts | 653 ++++++++++---------- src/lib/renderer/render.ts | 22 +- src/lib/renderer/sourcemap/sourcemap.ts | 23 +- src/lib/syntax/color/oklch.ts | 2 +- src/node.ts | 10 +- src/web.ts | 10 +- 20 files changed, 1413 insertions(+), 1680 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c391b423..19eb043f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ # v1.6.0 - [x] added support for math function `tan()`. + +## Improvements +- [x] faster tokenizer - [x] support input sourcemap from inline sourcemap file. This is only supported by the async parser. ```css diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 1cccfa9e..f810afb7 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -19795,8 +19795,9 @@ } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi.length = 0; + // @ts-expect-error + ast.chi.push(...properties, ...rules); return ast; } } @@ -23450,15 +23451,12 @@ 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)) { @@ -24075,7 +24073,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()} */`; @@ -24123,7 +24121,6 @@ offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; - // console.error({record}); sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { @@ -24175,7 +24172,6 @@ } sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } - // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } move(sourceLocation, linesMap, str, offset); } @@ -24321,18 +24317,6 @@ // color: red; // } // } - // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; - // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { - // sourcemaps.sources.push(node[LOCSTA] as number); - // } - // sourcemaps.maps.push([ - // ...linesMap!.getOffsets( - // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - // ), - // node[LOCSTA], - // ...source!.getOffsets(node![LOCSTA]), - // ]); - // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); // @ts-ignore updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); } @@ -25348,6 +25332,22 @@ } 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; @@ -25449,65 +25449,52 @@ TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { - let i = SymbolsMapTokensKeys.length; - let j; - let ca; - let cb; - let match; - let index; const len = end - start; - while (i--) { - match = len == SymbolsMapTokensKeys[i].length; - if (!match) { + 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; - } - for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { - index = start + j; - if (index > end) { - match = false; - break; - } - ca = SymbolsMapTokensKeys[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + // 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) { + if (ca !== cb) { match = false; break; } } - if (!match) { - continue; + if (match) { + return SymbolsMapTokens[key]; } - return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } return null; } function searchArray(array, parseInfo, start, end) { - let i = array.length; - let j; - let ca; - let cb; - let match; - let index; 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--) { - match = true; - for (j = 0; j < array[i].length; j++) { - if (len != array[i].length) { - match = false; - break; - } - index = start + j; - if (index > end) { - match = false; - break; - } - ca = array[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + 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; @@ -25519,7 +25506,7 @@ } } if (match) { - return array[i]; + return arrayItem; } } return null; @@ -25528,6 +25515,8 @@ * tokenizer class */ class Tokenizer { + parseInfo; + input; /** * token type */ @@ -25580,19 +25569,36 @@ * 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.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -25620,27 +25626,25 @@ ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); - yield this.makeToken(parseInfo, + this.advance(parseInfo); + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; } if (isNewLine(charCode)) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); - return; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - 'Unclosed-string' fixed - yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + return this.makeToken(parseInfo, exports.EnumToken.StringTokenType); // return result; } /** @@ -25648,14 +25652,14 @@ * @param parseInfo * @returns */ - *consumeURLToken(parseInfo) { - const quote = this.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -25683,14 +25687,14 @@ ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); + this.advance(parseInfo); let k = 1; let end = parseInfo.stream.length - parseInfo.offset; let position = parseInfo.currentPosition - parseInfo.offset; @@ -25698,49 +25702,44 @@ charCode = parseInfo.stream.charCodeAt(position); // NaN != NaN if (charCode != charCode) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } if (isWhiteSpace(charCode)) { - this.next(parseInfo, k); + this.advance(parseInfo, k); k++; continue; } if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } break; } // consume until the ')' - yield this.makeToken(parseInfo, + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; // return result; } if (isNewLine(charCode)) { // bad string - this.next(parseInfo); + this.advance(parseInfo); while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } - yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); - return; + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - bad url token - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); // return result; } /** @@ -26095,6 +26094,31 @@ } return 0; } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.advance(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } 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.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + // } + } /** * * @param parseInfo @@ -26196,18 +26220,7 @@ val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); } if (this.decodeString) { - 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); - }); + val = decodeEscapeSequences(val); } if (hintsEnum.has(hint)) { this.typ = hint; @@ -26242,18 +26255,7 @@ if (this.typ == null) { val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); 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); - }); + val = decodeEscapeSequences(val); this.decodeString = true; } this.typ = exports.EnumToken.LiteralTokenType; @@ -26305,6 +26307,14 @@ } 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 @@ -26324,13 +26334,14 @@ * @param count * @returns */ - next(parseInfo, count = 1) { + 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[i].charCodeAt(0); + codepoint = char.charCodeAt(i); if (codepoint == 0xa || // \n codepoint == 0xb || // \v codepoint == 0xc || // \f @@ -26341,7 +26352,7 @@ // \r\n if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; else { - parseInfo.source.lineStarts.lineStarts.push(position + parseInfo.offset + i); + lineStarts.push(position + parseInfo.offset + i); } } } @@ -26481,22 +26492,16 @@ } return i == parseInfo.currentPosition; } + done() { + return this.typ === exports.EnumToken.EOF; + } /** * Tokenize CSS string * @param parseInfo * @param yieldEOFToken */ - *tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; this.source = parseInfo.source; let charCode; let nextCharCode; @@ -26505,7 +26510,11 @@ 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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 */ || @@ -26513,30 +26522,28 @@ isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + 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, }); - continue; } } if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); + this.advance(parseInfo, tokensCount); charCode = this.peek(parseInfo).charCodeAt(0); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { - yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") ? exports.EnumToken.DashedIdenTokenType : exports.EnumToken.IdenTokenType); - continue; } } } if (charCode == 64 /* TokenMap.AT */) { - this.next(parseInfo); + this.advance(parseInfo); charCode = this.peek(parseInfo).charCodeAt(0); // match at-rule if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { @@ -26544,25 +26551,22 @@ parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); } } } if (charCode == 35 /* TokenMap.HASH */) { tokensCount = this.consumeColor(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); } - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.HashTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.HashTokenType); } } } @@ -26570,162 +26574,123 @@ switch (charCode) { case 61 /* TokenMap.EQUALS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); if (isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { slice: this.slice, sign: "+", }); - break; } } - yield this.makeToken(parseInfo, exports.EnumToken.Plus); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Sub); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Sub); } if (charCode == 45 /* TokenMap.MINUS */ && (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); } } } - this.next(parseInfo); + this.advance(parseInfo); break; // '{' case 123 /* TokenMap.LEFT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); // '}' case 125 /* TokenMap.RIGHT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); - break; + 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); - yield this.makeToken(parseInfo, hint); - this.next(parseInfo); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); // consume '(' parseInfo.position = parseInfo.currentPosition; if (hint === exports.EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { - this.next(parseInfo); - } - charCode = this.peek(parseInfo).charCodeAt(0); - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - yield* this.consumeURLToken(parseInfo); - } - else { - do { - this.next(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && this.match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || - !this.isURLToken(parseInfo) - ? exports.EnumToken.BadUrlTokenType - : exports.EnumToken.UrlTokenTokenType); - } - } + this.state = hint; } - break; + return this; } } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); // ')' case 41 /* TokenMap.RIGHT_PARENTHESIS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); } - yield this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); - break; + return this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); // \n \r \f \v \t space case 0x9: case 0x20: @@ -26736,246 +26701,226 @@ case 0x2028: case 0x2029: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(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.next(parseInfo); + this.advance(parseInfo); nextCharCode = parseInfo.stream .charAt(parseInfo.currentPosition - parseInfo.offset) .charCodeAt(0); } - yield this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); - break; + return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "$=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "~=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Tilda); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "^=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "*=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Star); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Star); case 38 /* TokenMap.AMPERSAND */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } // '||' if (this.match(parseInfo, "||")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); } else if (this.match(parseInfo, "|=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Pipe); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Pipe); case 33 /* TokenMap.EXCLAMATION */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "!important")) { - this.next(parseInfo, 10); - yield this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); - break; + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (!this.match(parseInfo, "/*")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); } - this.next(parseInfo, 2); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { if (charCode == 42 /* TokenMap.STAR */) { if (this.match(parseInfo, "/")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); } } } if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); } break; case 62 /* TokenMap.GREATERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, ">=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.GteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.GtTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.GtTokenType); case 60 /* TokenMap.LOWERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "<=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.LteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.LteTokenType); } - this.next(parseInfo); + this.advance(parseInfo); if (this.match(parseInfo, "!--")) { - this.next(parseInfo, 3); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + 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) { - yield this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); } else { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); } } break; case 35 /* TokenMap.HASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } - this.next(parseInfo); + // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } + this.advance(parseInfo); // EOF if (!this.peek(parseInfo)) { - if (!yieldEOFToken) { - break; - } + // if (!yieldEOFToken) { + // break; + // } // end of stream ignore \\ if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } break; } - this.next(parseInfo); + this.advance(parseInfo); break; case 39 /* TokenMap.SINGLE_QUOTE */: case 34 /* TokenMap.DOUBLE_QUOTE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - yield* this.consumeString(parseInfo); - break; + return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); + .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - this.next(parseInfo); + this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); - break; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); } } if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - this.next(parseInfo, 2); - break; + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; } - this.next(parseInfo); + this.advance(parseInfo); break; default: - this.next(parseInfo); + this.advance(parseInfo); break; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - } - yield this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); + // 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(input, parseInfo) { + async tokenizeStream() { const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; parseInfo.stream = ""; while (true) { const { done, value } = await reader.read(); @@ -26983,31 +26928,14 @@ if (!done) { parseInfo.source.append(stream); } - yield* this.tokenize(parseInfo, done); - if (done) { + else { break; } } parseInfo.stream = parseInfo.source.getContent(); - yield* this.tokenize(parseInfo); + return this; // .next(); } } - /** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ - function tokenize(parseInfo, yieldEOFToken = true) { - return new Tokenizer().tokenize(parseInfo, yieldEOFToken); - } - /** - * tokenize readable stream - * @param input - * @param parseInfo - */ - function tokenizeStream(input, parseInfo) { - return new Tokenizer().tokenizeStream(input, parseInfo); - } /** * parse selector @@ -29665,7 +29593,7 @@ * @throws Error * @private */ - function doParseSync(iter, options = {}) { + function doParseSync(tokenizer, options = {}) { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -29730,8 +29658,9 @@ // let currentItemIndex: number; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; - let tokenizer; - while ((tokenizer = iter.next().value) != null) { + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); // item = (iter as Array)[currentItemIndex]; if (tokenizer.unit != null) { item = { @@ -29767,7 +29696,6 @@ item[LOCSRCID] = tokenizer.srcId; item[LOCSTA] = tokenizer.sta; item[LOCEND] = tokenizer.end; - // console.error(item); stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; if (BadTokensTypes.includes(item.typ)) { @@ -29811,10 +29739,7 @@ tokens.length = 0; tokens.push(item); do { - tokenizer = iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -29856,7 +29781,7 @@ else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -30659,11 +30584,9 @@ 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; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; @@ -30672,9 +30595,8 @@ // // @ts-expect-error // iter = iter[Symbol.iterator]() as Iterator; // } - while ((tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -30755,12 +30677,7 @@ tokens.length = 0; tokens.push(item); do { - tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -30802,7 +30719,7 @@ else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -30865,7 +30782,9 @@ 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, @@ -31188,7 +31107,9 @@ 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, @@ -31329,13 +31250,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, @@ -32627,7 +32548,7 @@ */ async function parseDeclarations(declaration) { const stream = `.x{${declaration}}`; - return doParse(tokenize({ + return doParse(new Tokenizer({ stream, offset: 0, position: 0, @@ -32668,11 +32589,20 @@ // position: 0, // currentPosition: 0, // }; - const iter = tokenize(src); + const tokenizer = new Tokenizer({ + stream: src, + buffer: "", + src: options?.src ?? "", + offset: 0, + time: 0, + source: new SourceFile(src, [], options?.src ?? ""), + position: 0, + currentPosition: 0, + }); const mapped = []; let token; - let tokenizer; - while ((tokenizer = iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { token = { typ: tokenizer.typ, @@ -33229,7 +33159,7 @@ position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -33365,7 +33295,9 @@ position: 0, currentPosition: 0, }; - return doParse(stream instanceof ReadableStream ? tokenizeStream(stream, options.parseInfo) : tokenize(options.parseInfo), options).then((result) => options.module == null && options.inputSourceMap == null && !options.sourcemap + 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)); } diff --git a/dist/index.cjs b/dist/index.cjs index dda6208e..dd03f118 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -19798,8 +19798,9 @@ class ComputeShorthandFeature { } k = l; } - // @ts-ignore - ast.chi = [...properties, ...rules]; + ast.chi.length = 0; + // @ts-expect-error + ast.chi.push(...properties, ...rules); return ast; } } @@ -23453,15 +23454,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)) { @@ -24078,7 +24076,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()} */`; @@ -24126,7 +24124,6 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; - // console.error({record}); sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { @@ -24178,7 +24175,6 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } - // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } move(sourceLocation, linesMap, str, offset); } @@ -24324,18 +24320,6 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro // color: red; // } // } - // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; - // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { - // sourcemaps.sources.push(node[LOCSTA] as number); - // } - // sourcemaps.maps.push([ - // ...linesMap!.getOffsets( - // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - // ), - // node[LOCSTA], - // ...source!.getOffsets(node![LOCSTA]), - // ]); - // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); // @ts-ignore updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); } @@ -25351,6 +25335,22 @@ function filterValues(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; @@ -25452,65 +25452,52 @@ var TokenMap; TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { - let i = SymbolsMapTokensKeys.length; - let j; - let ca; - let cb; - let match; - let index; const len = end - start; - while (i--) { - match = len == SymbolsMapTokensKeys[i].length; - if (!match) { + 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; - } - for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { - index = start + j; - if (index > end) { - match = false; - break; - } - ca = SymbolsMapTokensKeys[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + // 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) { + if (ca !== cb) { match = false; break; } } - if (!match) { - continue; + if (match) { + return SymbolsMapTokens[key]; } - return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } return null; } function searchArray(array, parseInfo, start, end) { - let i = array.length; - let j; - let ca; - let cb; - let match; - let index; 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--) { - match = true; - for (j = 0; j < array[i].length; j++) { - if (len != array[i].length) { - match = false; - break; - } - index = start + j; - if (index > end) { - match = false; - break; - } - ca = array[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + 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; @@ -25522,7 +25509,7 @@ function searchArray(array, parseInfo, start, end) { } } if (match) { - return array[i]; + return arrayItem; } } return null; @@ -25531,6 +25518,8 @@ function searchArray(array, parseInfo, start, end) { * tokenizer class */ class Tokenizer { + parseInfo; + input; /** * token type */ @@ -25583,19 +25572,36 @@ class Tokenizer { * 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.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -25623,27 +25629,25 @@ class Tokenizer { ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); - yield this.makeToken(parseInfo, + this.advance(parseInfo); + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; } if (isNewLine(charCode)) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); - return; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - 'Unclosed-string' fixed - yield this.makeToken(parseInfo, exports.EnumToken.StringTokenType); + return this.makeToken(parseInfo, exports.EnumToken.StringTokenType); // return result; } /** @@ -25651,14 +25655,14 @@ class Tokenizer { * @param parseInfo * @returns */ - *consumeURLToken(parseInfo) { - const quote = this.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -25686,14 +25690,14 @@ class Tokenizer { ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); + this.advance(parseInfo); let k = 1; let end = parseInfo.stream.length - parseInfo.offset; let position = parseInfo.currentPosition - parseInfo.offset; @@ -25701,49 +25705,44 @@ class Tokenizer { charCode = parseInfo.stream.charCodeAt(position); // NaN != NaN if (charCode != charCode) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } if (isWhiteSpace(charCode)) { - this.next(parseInfo, k); + this.advance(parseInfo, k); k++; continue; } if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } break; } // consume until the ')' - yield this.makeToken(parseInfo, + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ exports.EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; // return result; } if (isNewLine(charCode)) { // bad string - this.next(parseInfo); + this.advance(parseInfo); while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); - return; + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } - yield this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); - return; + return this.makeToken(parseInfo, exports.EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - bad url token - yield this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadUrlTokenType); // return result; } /** @@ -26098,6 +26097,31 @@ class Tokenizer { } return 0; } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.advance(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } 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.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + ? exports.EnumToken.BadUrlTokenType + : exports.EnumToken.UrlTokenTokenType); + // } + } /** * * @param parseInfo @@ -26199,18 +26223,7 @@ class Tokenizer { val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); } if (this.decodeString) { - 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); - }); + val = decodeEscapeSequences(val); } if (hintsEnum.has(hint)) { this.typ = hint; @@ -26245,18 +26258,7 @@ class Tokenizer { if (this.typ == null) { val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); 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); - }); + val = decodeEscapeSequences(val); this.decodeString = true; } this.typ = exports.EnumToken.LiteralTokenType; @@ -26308,6 +26310,14 @@ class Tokenizer { } 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 @@ -26327,13 +26337,14 @@ class Tokenizer { * @param count * @returns */ - next(parseInfo, count = 1) { + 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[i].charCodeAt(0); + codepoint = char.charCodeAt(i); if (codepoint == 0xa || // \n codepoint == 0xb || // \v codepoint == 0xc || // \f @@ -26344,7 +26355,7 @@ class Tokenizer { // \r\n if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; else { - parseInfo.source.lineStarts.lineStarts.push(position + parseInfo.offset + i); + lineStarts.push(position + parseInfo.offset + i); } } } @@ -26484,22 +26495,16 @@ class Tokenizer { } return i == parseInfo.currentPosition; } + done() { + return this.typ === exports.EnumToken.EOF; + } /** * Tokenize CSS string * @param parseInfo * @param yieldEOFToken */ - *tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; this.source = parseInfo.source; let charCode; let nextCharCode; @@ -26508,7 +26513,11 @@ class Tokenizer { 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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 */ || @@ -26516,30 +26525,28 @@ class Tokenizer { isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + 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, }); - continue; } } if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); + this.advance(parseInfo, tokensCount); charCode = this.peek(parseInfo).charCodeAt(0); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { - yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") ? exports.EnumToken.DashedIdenTokenType : exports.EnumToken.IdenTokenType); - continue; } } } if (charCode == 64 /* TokenMap.AT */) { - this.next(parseInfo); + this.advance(parseInfo); charCode = this.peek(parseInfo).charCodeAt(0); // match at-rule if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { @@ -26547,25 +26554,22 @@ class Tokenizer { parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.AtRuleTokenType); } } } if (charCode == 35 /* TokenMap.HASH */) { tokensCount = this.consumeColor(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ColorTokenType); } - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.HashTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.HashTokenType); } } } @@ -26573,162 +26577,123 @@ class Tokenizer { switch (charCode) { case 61 /* TokenMap.EQUALS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); if (isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, this.hint ?? exports.EnumToken.NumberTokenType, { slice: this.slice, sign: "+", }); - break; } } - yield this.makeToken(parseInfo, exports.EnumToken.Plus); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Sub); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Sub); } if (charCode == 45 /* TokenMap.MINUS */ && (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.IdenTokenType); } } } - this.next(parseInfo); + this.advance(parseInfo); break; // '{' case 123 /* TokenMap.LEFT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.BlockStartTokenType); // '}' case 125 /* TokenMap.RIGHT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.BlockEndTokenType); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.PseudoClassFunctionTokenDefType); - break; + 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); - yield this.makeToken(parseInfo, hint); - this.next(parseInfo); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); // consume '(' parseInfo.position = parseInfo.currentPosition; if (hint === exports.EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { - this.next(parseInfo); - } - charCode = this.peek(parseInfo).charCodeAt(0); - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - yield* this.consumeURLToken(parseInfo); - } - else { - do { - this.next(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && this.match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || - !this.isURLToken(parseInfo) - ? exports.EnumToken.BadUrlTokenType - : exports.EnumToken.UrlTokenTokenType); - } - } + this.state = hint; } - break; + return this; } } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.StartParensTokenType); // ')' case 41 /* TokenMap.RIGHT_PARENTHESIS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); } - yield this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); - break; + return this.makeToken(parseInfo, exports.EnumToken.ColonTokenType); // \n \r \f \v \t space case 0x9: case 0x20: @@ -26739,246 +26704,226 @@ class Tokenizer { case 0x2028: case 0x2029: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(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.next(parseInfo); + this.advance(parseInfo); nextCharCode = parseInfo.stream .charAt(parseInfo.currentPosition - parseInfo.offset) .charCodeAt(0); } - yield this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); - break; + return this.makeToken(parseInfo, exports.EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "$=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.EndMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "~=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.IncludeMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Tilda); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "^=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.StartMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "*=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ContainMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Star); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Star); case 38 /* TokenMap.AMPERSAND */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } // '||' if (this.match(parseInfo, "||")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.ColumnCombinatorTokenType); } else if (this.match(parseInfo, "|=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.DashMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.Pipe); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.Pipe); case 33 /* TokenMap.EXCLAMATION */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "!important")) { - this.next(parseInfo, 10); - yield this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); - break; + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, exports.EnumToken.ImportantTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (!this.match(parseInfo, "/*")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); } - this.next(parseInfo, 2); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { if (charCode == 42 /* TokenMap.STAR */) { if (this.match(parseInfo, "/")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.CommentTokenType); } } } if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadCommentTokenType); } break; case 62 /* TokenMap.GREATERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, ">=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.GteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.GteTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, exports.EnumToken.GtTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, exports.EnumToken.GtTokenType); case 60 /* TokenMap.LOWERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "<=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.LteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.LteTokenType); } - this.next(parseInfo); + this.advance(parseInfo); if (this.match(parseInfo, "!--")) { - this.next(parseInfo, 3); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + 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) { - yield this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); + return this.makeToken(parseInfo, exports.EnumToken.BadCdoTokenType); } else { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, exports.EnumToken.CDOCOMMTokenType); } } break; case 35 /* TokenMap.HASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } - this.next(parseInfo); + // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } + this.advance(parseInfo); // EOF if (!this.peek(parseInfo)) { - if (!yieldEOFToken) { - break; - } + // if (!yieldEOFToken) { + // break; + // } // end of stream ignore \\ if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } break; } - this.next(parseInfo); + this.advance(parseInfo); break; case 39 /* TokenMap.SINGLE_QUOTE */: case 34 /* TokenMap.DOUBLE_QUOTE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - yield* this.consumeString(parseInfo); - break; + return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); + .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - this.next(parseInfo); + this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); - break; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, exports.EnumToken.ClassSelectorTokenType); } } if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - this.next(parseInfo, 2); - break; + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; } - this.next(parseInfo); + this.advance(parseInfo); break; default: - this.next(parseInfo); + this.advance(parseInfo); break; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - } - yield this.makeToken(parseInfo, exports.EnumToken.EOFTokenType); + // 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(input, parseInfo) { + async tokenizeStream() { const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; parseInfo.stream = ""; while (true) { const { done, value } = await reader.read(); @@ -26986,31 +26931,14 @@ class Tokenizer { if (!done) { parseInfo.source.append(stream); } - yield* this.tokenize(parseInfo, done); - if (done) { + else { break; } } parseInfo.stream = parseInfo.source.getContent(); - yield* this.tokenize(parseInfo); + return this; // .next(); } } -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -function tokenize(parseInfo, yieldEOFToken = true) { - return new Tokenizer().tokenize(parseInfo, yieldEOFToken); -} -/** - * tokenize readable stream - * @param input - * @param parseInfo - */ -function tokenizeStream(input, parseInfo) { - return new Tokenizer().tokenizeStream(input, parseInfo); -} /** * parse selector @@ -29668,7 +29596,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); } @@ -29733,8 +29661,9 @@ function doParseSync(iter, options = {}) { // let currentItemIndex: number; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; - let tokenizer; - while ((tokenizer = iter.next().value) != null) { + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); // item = (iter as Array)[currentItemIndex]; if (tokenizer.unit != null) { item = { @@ -29770,7 +29699,6 @@ function doParseSync(iter, options = {}) { item[LOCSRCID] = tokenizer.srcId; item[LOCSTA] = tokenizer.sta; item[LOCEND] = tokenizer.end; - // console.error(item); stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; if (BadTokensTypes.includes(item.typ)) { @@ -29814,10 +29742,7 @@ function doParseSync(iter, options = {}) { tokens.length = 0; tokens.push(item); do { - tokenizer = iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -29859,7 +29784,7 @@ function doParseSync(iter, options = {}) { else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -30662,11 +30587,9 @@ 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; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; @@ -30675,9 +30598,8 @@ async function doParse(iter, options = {}) { // // @ts-expect-error // iter = iter[Symbol.iterator]() as Iterator; // } - while ((tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -30758,12 +30680,7 @@ async function doParse(iter, options = {}) { tokens.length = 0; tokens.push(item); do { - tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -30805,7 +30722,7 @@ async function doParse(iter, options = {}) { else if (item.typ === exports.EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -30868,7 +30785,9 @@ async function doParse(iter, options = {}) { 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, @@ -31191,7 +31110,9 @@ 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, @@ -31332,13 +31253,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, @@ -32630,7 +32551,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, @@ -32671,11 +32592,20 @@ function parseString(src, options = { parseColor: true }, errors) { // position: 0, // currentPosition: 0, // }; - const iter = tokenize(src); + const tokenizer = new Tokenizer({ + stream: src, + buffer: "", + src: options?.src ?? "", + offset: 0, + time: 0, + source: new SourceFile(src, [], options?.src ?? ""), + position: 0, + currentPosition: 0, + }); const mapped = []; let token; - let tokenizer; - while ((tokenizer = iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { token = { typ: tokenizer.typ, @@ -33230,7 +33160,7 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -33390,7 +33320,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap + 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)); } diff --git a/dist/index.d.ts b/dist/index.d.ts index 30aaefc0..3314d9ec 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -4001,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 */ diff --git a/dist/lib/ast/features/shorthand.js b/dist/lib/ast/features/shorthand.js index 60b36dd3..7309bfb0 100644 --- a/dist/lib/ast/features/shorthand.js +++ b/dist/lib/ast/features/shorthand.js @@ -57,8 +57,9 @@ class ComputeShorthandFeature { } 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/parser/parse.js b/dist/lib/parser/parse.js index e2d1a4ac..ee5055c2 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -5,7 +5,7 @@ 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 { 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'; @@ -440,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); } @@ -505,8 +505,9 @@ function doParseSync(iter, options = {}) { // let currentItemIndex: number; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; - let tokenizer; - while ((tokenizer = iter.next().value) != null) { + // let tokenizer: Tokenizer; + while (!tokenizer.done()) { + tokenizer.next(); // item = (iter as Array)[currentItemIndex]; if (tokenizer.unit != null) { item = { @@ -542,7 +543,6 @@ function doParseSync(iter, options = {}) { item[LOCSRCID] = tokenizer.srcId; item[LOCSTA] = tokenizer.sta; item[LOCEND] = tokenizer.end; - // console.error(item); stats.bytesIn = tokenizer.bytesIn; stats.tokensCount++; if (BadTokensTypes.includes(item.typ)) { @@ -586,10 +586,7 @@ function doParseSync(iter, options = {}) { tokens.length = 0; tokens.push(item); do { - tokenizer = iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -631,7 +628,7 @@ function doParseSync(iter, options = {}) { else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -1434,11 +1431,9 @@ 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; + let tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; ast[LOCSRCID] = options.source.id; ast[LOCSTA] = 0; @@ -1447,9 +1442,8 @@ async function doParse(iter, options = {}) { // // @ts-expect-error // iter = iter[Symbol.iterator]() as Iterator; // } - while ((tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -1530,12 +1524,7 @@ async function doParse(iter, options = {}) { tokens.length = 0; tokens.push(item); do { - tokenizer = isAsync - ? (await iter.next()).value - : iter.next().value; - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { typ: tokenizer.typ, @@ -1577,7 +1566,7 @@ async function doParse(iter, options = {}) { else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ action: "drop", @@ -1640,7 +1629,9 @@ async function doParse(iter, options = {}) { 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, @@ -1963,7 +1954,9 @@ 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, @@ -2104,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, @@ -3402,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, @@ -3443,11 +3436,20 @@ function parseString(src, options = { parseColor: true }, errors) { // position: 0, // currentPosition: 0, // }; - const iter = tokenize(src); + const tokenizer = new Tokenizer({ + stream: src, + buffer: "", + src: options?.src ?? "", + offset: 0, + time: 0, + source: new SourceFile(src, [], options?.src ?? ""), + position: 0, + currentPosition: 0, + }); const mapped = []; let token; - let tokenizer; - while ((tokenizer = iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); if (tokenizer.unit != null) { token = { typ: tokenizer.typ, diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index 520ec41f..b92e6245 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -4,6 +4,22 @@ import { isWhiteSpace, isNewLine, isDigit, isLetter, isIdentStart, isIdentCodepo import { SourceFile } from './source.js'; 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; @@ -105,65 +121,52 @@ var TokenMap; TokenMap[TokenMap["PERCENTAGE"] = 37] = "PERCENTAGE"; })(TokenMap || (TokenMap = {})); function getSymbolHint(parseInfo, start, end) { - let i = SymbolsMapTokensKeys.length; - let j; - let ca; - let cb; - let match; - let index; const len = end - start; - while (i--) { - match = len == SymbolsMapTokensKeys[i].length; - if (!match) { + 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; - } - for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { - index = start + j; - if (index > end) { - match = false; - break; - } - ca = SymbolsMapTokensKeys[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + // 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) { + if (ca !== cb) { match = false; break; } } - if (!match) { - continue; + if (match) { + return SymbolsMapTokens[key]; } - return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } return null; } function searchArray(array, parseInfo, start, end) { - let i = array.length; - let j; - let ca; - let cb; - let match; - let index; 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--) { - match = true; - for (j = 0; j < array[i].length; j++) { - if (len != array[i].length) { - match = false; - break; - } - index = start + j; - if (index > end) { - match = false; - break; - } - ca = array[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + 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; @@ -175,7 +178,7 @@ function searchArray(array, parseInfo, start, end) { } } if (match) { - return array[i]; + return arrayItem; } } return null; @@ -184,6 +187,8 @@ function searchArray(array, parseInfo, start, end) { * tokenizer class */ class Tokenizer { + parseInfo; + input; /** * token type */ @@ -236,19 +241,36 @@ class Tokenizer { * 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.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -276,27 +298,25 @@ class Tokenizer { ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); - yield this.makeToken(parseInfo, + this.advance(parseInfo); + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; } if (isNewLine(charCode)) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); - return; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - 'Unclosed-string' fixed - yield this.makeToken(parseInfo, EnumToken.StringTokenType); + return this.makeToken(parseInfo, EnumToken.StringTokenType); // return result; } /** @@ -304,14 +324,14 @@ class Tokenizer { * @param parseInfo * @returns */ - *consumeURLToken(parseInfo) { - const quote = this.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } const sequence = this.peek(parseInfo, 7); @@ -339,14 +359,14 @@ class Tokenizer { ? 1 : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); + this.advance(parseInfo); let k = 1; let end = parseInfo.stream.length - parseInfo.offset; let position = parseInfo.currentPosition - parseInfo.offset; @@ -354,49 +374,44 @@ class Tokenizer { charCode = parseInfo.stream.charCodeAt(position); // NaN != NaN if (charCode != charCode) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } if (isWhiteSpace(charCode)) { - this.next(parseInfo, k); + this.advance(parseInfo, k); k++; continue; } if (charCode != 41 /* TokenMap.RIGHT_PARENTHESIS */) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } break; } // consume until the ')' - yield this.makeToken(parseInfo, + return this.makeToken(parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null); - return; // return result; } if (isNewLine(charCode)) { // bad string - this.next(parseInfo); + this.advance(parseInfo); while ((charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode) { if (charCode == 92 /* TokenMap.REVERSE_SOLIDUS */) { - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == 41 /* TokenMap.RIGHT_PARENTHESIS */) { - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } - yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); - return; + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - bad url token - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); // return result; } /** @@ -751,6 +766,31 @@ class Tokenizer { } return 0; } + parseURLToken(parseInfo, endPosition) { + let charCode; + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.advance(parseInfo); + } + charCode = this.peek(parseInfo).charCodeAt(0); + if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { + return this.consumeURLToken(parseInfo); + } + do { + this.advance(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } 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.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType); + // } + } /** * * @param parseInfo @@ -852,18 +892,7 @@ class Tokenizer { val = parseInfo.stream.slice(options?.slice ?? parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); } if (this.decodeString) { - 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); - }); + val = decodeEscapeSequences(val); } if (hintsEnum.has(hint)) { this.typ = hint; @@ -898,18 +927,7 @@ class Tokenizer { if (this.typ == null) { val = parseInfo.stream.slice(parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset); 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); - }); + val = decodeEscapeSequences(val); this.decodeString = true; } this.typ = EnumToken.LiteralTokenType; @@ -961,6 +979,14 @@ class Tokenizer { } 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 @@ -980,13 +1006,14 @@ class Tokenizer { * @param count * @returns */ - next(parseInfo, count = 1) { + 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[i].charCodeAt(0); + codepoint = char.charCodeAt(i); if (codepoint == 0xa || // \n codepoint == 0xb || // \v codepoint == 0xc || // \f @@ -997,7 +1024,7 @@ class Tokenizer { // \r\n if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) ; else { - parseInfo.source.lineStarts.lineStarts.push(position + parseInfo.offset + i); + lineStarts.push(position + parseInfo.offset + i); } } } @@ -1137,22 +1164,16 @@ class Tokenizer { } return i == parseInfo.currentPosition; } + done() { + return this.typ === EnumToken.EOF; + } /** * Tokenize CSS string * @param parseInfo * @param yieldEOFToken */ - *tokenize(parseInfo, yieldEOFToken = true) { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } + next( /* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */) { + const parseInfo = this.parseInfo; this.source = parseInfo.source; let charCode; let nextCharCode; @@ -1161,7 +1182,11 @@ class Tokenizer { 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.peek(parseInfo).charCodeAt(0)) == charCode) { + 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 */ || @@ -1169,30 +1194,28 @@ class Tokenizer { isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + 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, }); - continue; } } if (isIdentStart(charCode) || charCode == 45 /* TokenMap.MINUS */) { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); + this.advance(parseInfo, tokensCount); charCode = this.peek(parseInfo).charCodeAt(0); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { - yield this.makeToken(parseInfo, this.startsWith(parseInfo, "--") + return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") ? EnumToken.DashedIdenTokenType : EnumToken.IdenTokenType); - continue; } } } if (charCode == 64 /* TokenMap.AT */) { - this.next(parseInfo); + this.advance(parseInfo); charCode = this.peek(parseInfo).charCodeAt(0); // match at-rule if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { @@ -1200,25 +1223,22 @@ class Tokenizer { parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.AtRuleTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.AtRuleTokenType); } } } if (charCode == 35 /* TokenMap.HASH */) { tokensCount = this.consumeColor(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.ColorTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ColorTokenType); } - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.HashTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.HashTokenType); } } } @@ -1226,162 +1246,123 @@ class Tokenizer { switch (charCode) { case 61 /* TokenMap.EQUALS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.DelimTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.DelimTokenType); // '+' or '-' case 43 /* TokenMap.PLUS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); if (isDigit(charCode)) { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { slice: this.slice, sign: "+", }); - break; } } - yield this.makeToken(parseInfo, EnumToken.Plus); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Sub); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Sub); } if (charCode == 45 /* TokenMap.MINUS */ && (nextCharCode == 45 /* TokenMap.MINUS */ || isIdentStart(nextCharCode))) { - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.IdenTokenType); - continue; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.IdenTokenType); } } } - this.next(parseInfo); + this.advance(parseInfo); break; // '{' case 123 /* TokenMap.LEFT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BlockStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockStartTokenType); // '}' case 125 /* TokenMap.RIGHT_BRACE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BlockEndTokenType); - break; + 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.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); - break; + 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); - yield this.makeToken(parseInfo, hint); - this.next(parseInfo); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); // consume '(' parseInfo.position = parseInfo.currentPosition; if (hint === EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { - this.next(parseInfo); - } - charCode = this.peek(parseInfo).charCodeAt(0); - if (charCode == 34 /* TokenMap.DOUBLE_QUOTE */ || charCode == 39 /* TokenMap.SINGLE_QUOTE */) { - yield* this.consumeURLToken(parseInfo); - } - else { - do { - this.next(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && this.match(parseInfo, "/*") && - charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && - parseInfo.currentPosition < endPosition); - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || - !this.isURLToken(parseInfo) - ? EnumToken.BadUrlTokenType - : EnumToken.UrlTokenTokenType); - } - } + this.state = hint; } - break; + return this; } } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.StartParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.StartParensTokenType); // ')' case 41 /* TokenMap.RIGHT_PARENTHESIS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.EndParensTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.EndParensTokenType); // '[' case 91 /* TokenMap.LEFT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.AttrStartTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrStartTokenType); // ']' case 93 /* TokenMap.RIGHT_BRACKETS */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.AttrEndTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrEndTokenType); case 59 /* TokenMap.SEMICOLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.SemiColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.SemiColonTokenType); case 58 /* TokenMap.COLON */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); } - yield this.makeToken(parseInfo, EnumToken.ColonTokenType); - break; + return this.makeToken(parseInfo, EnumToken.ColonTokenType); // \n \r \f \v \t space case 0x9: case 0x20: @@ -1392,246 +1373,226 @@ class Tokenizer { case 0x2028: case 0x2029: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(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.next(parseInfo); + this.advance(parseInfo); nextCharCode = parseInfo.stream .charAt(parseInfo.currentPosition - parseInfo.offset) .charCodeAt(0); } - yield this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); - break; + return this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); case 44 /* TokenMap.COMMA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.CommaTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommaTokenType); case 36 /* TokenMap.DOLLAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "$=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.EndMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.EndMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 126 /* TokenMap.TILDA */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "~=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Tilda); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Tilda); // case '^': case 94 /* TokenMap.CARET */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "^=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.StartMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.StartMatchTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 42 /* TokenMap.STAR */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "*=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Star); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Star); case 38 /* TokenMap.AMPERSAND */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); case 124 /* TokenMap.PIPE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } // '||' if (this.match(parseInfo, "||")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); } else if (this.match(parseInfo, "|=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.DashMatchTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.DashMatchTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Pipe); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Pipe); case 33 /* TokenMap.EXCLAMATION */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "!important")) { - this.next(parseInfo, 10); - yield this.makeToken(parseInfo, EnumToken.ImportantTokenType); - break; + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, EnumToken.ImportantTokenType); } - this.next(parseInfo); + this.advance(parseInfo); break; case 47 /* TokenMap.SLASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (!this.match(parseInfo, "/*")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, getSymbolHint(parseInfo, parseInfo.position - parseInfo.offset, parseInfo.currentPosition - parseInfo.offset)); } - this.next(parseInfo, 2); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + this.advance(parseInfo, 2); + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { if (charCode == 42 /* TokenMap.STAR */) { if (this.match(parseInfo, "/")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.CommentTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommentTokenType); } } } if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, EnumToken.BadCommentTokenType); + return this.makeToken(parseInfo, EnumToken.BadCommentTokenType); } break; case 62 /* TokenMap.GREATERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, ">=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.GteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.GteTokenType); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.GtTokenType); - break; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.GtTokenType); case 60 /* TokenMap.LOWERTHAN */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "<=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.LteTokenType); - break; + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.LteTokenType); } - this.next(parseInfo); + this.advance(parseInfo); if (this.match(parseInfo, "!--")) { - this.next(parseInfo, 3); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + 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) { - yield this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + return this.makeToken(parseInfo, EnumToken.BadCdoTokenType); } else { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); } } break; case 35 /* TokenMap.HASH */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); break; case 92 /* TokenMap.REVERSE_SOLIDUS */: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } - this.next(parseInfo); + // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } + this.advance(parseInfo); // EOF if (!this.peek(parseInfo)) { - if (!yieldEOFToken) { - break; - } + // if (!yieldEOFToken) { + // break; + // } // end of stream ignore \\ if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } break; } - this.next(parseInfo); + this.advance(parseInfo); break; case 39 /* TokenMap.SINGLE_QUOTE */: case 34 /* TokenMap.DOUBLE_QUOTE */: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - yield* this.consumeString(parseInfo); - break; + return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); + .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == 45 /* TokenMap.MINUS */) { - this.next(parseInfo); + this.advance(parseInfo); let tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); - break; + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); } } if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - this.next(parseInfo, 2); - break; + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; } - this.next(parseInfo); + this.advance(parseInfo); break; default: - this.next(parseInfo); + this.advance(parseInfo); break; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - } - yield this.makeToken(parseInfo, EnumToken.EOFTokenType); + // if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } + return this.makeToken(parseInfo, EnumToken.EOFTokenType); + // } } /** * tokenize readable stream * @param input * @param parseInfo */ - async *tokenizeStream(input, parseInfo) { + async tokenizeStream() { const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); + const reader = this.input.getReader(); + let parseInfo = this.parseInfo; parseInfo.stream = ""; while (true) { const { done, value } = await reader.read(); @@ -1639,30 +1600,13 @@ class Tokenizer { if (!done) { parseInfo.source.append(stream); } - yield* this.tokenize(parseInfo, done); - if (done) { + else { break; } } parseInfo.stream = parseInfo.source.getContent(); - yield* this.tokenize(parseInfo); + return this; // .next(); } } -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -function tokenize(parseInfo, yieldEOFToken = true) { - return new Tokenizer().tokenize(parseInfo, yieldEOFToken); -} -/** - * tokenize readable stream - * @param input - * @param parseInfo - */ -function tokenizeStream(input, parseInfo) { - return new Tokenizer().tokenizeStream(input, parseInfo); -} -export { TokenMap, Tokenizer, hintsEnum, tokenize, tokenizeStream }; +export { TokenMap, Tokenizer, hintsEnum }; diff --git a/dist/lib/renderer/render.js b/dist/lib/renderer/render.js index 08d5d795..24c167a6 100644 --- a/dist/lib/renderer/render.js +++ b/dist/lib/renderer/render.js @@ -115,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()} */`; @@ -163,7 +163,6 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines offsets[0] = record[1]; // @ts-ignore offsets[1] = record[2]; - // console.error({record}); sourceContent = record[3] || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { if (cache[sourceFileName] == null) { @@ -215,7 +214,6 @@ function updateSourceMap(node, options, cache, sourcemaps, sourceLocation, lines } sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } - // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } move(sourceLocation, linesMap, str, offset); } @@ -361,18 +359,6 @@ function renderAstNode(data, options, sourcemaps, sourceLocation, linesMap, erro // color: red; // } // } - // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; - // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { - // sourcemaps.sources.push(node[LOCSTA] as number); - // } - // sourcemaps.maps.push([ - // ...linesMap!.getOffsets( - // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - // ), - // node[LOCSTA], - // ...source!.getOffsets(node![LOCSTA]), - // ]); - // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); // @ts-ignore updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap, str); } 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/node.js b/dist/node.js index bd547853..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'; @@ -191,7 +191,7 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -351,7 +351,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap + 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)); } diff --git a/dist/web.js b/dist/web.js index 99eee874..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'; @@ -187,7 +187,7 @@ function parseSync(...args) { position: 0, currentPosition: 0, }; - const result = doParseSync(tokenize(options.parseInfo), options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -323,7 +323,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap + 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)); } diff --git a/src/lib/ast/features/shorthand.ts b/src/lib/ast/features/shorthand.ts index 277c0b69..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; } @@ -83,8 +76,9 @@ export class ComputeShorthandFeature { 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/math/expression.ts b/src/lib/ast/math/expression.ts index 36981651..7e9abdb7 100644 --- a/src/lib/ast/math/expression.ts +++ b/src/lib/ast/math/expression.ts @@ -12,6 +12,7 @@ import type { LiteralToken, NumberToken, ParensToken, + PercentageToken, ResolutionToken, TimeToken, Token, @@ -661,7 +662,7 @@ export function evaluateFunc(token: FunctionToken): Token[] | null { [LOCSRCID]: token[LOCSRCID], [LOCSTA]: token[LOCSTA], [LOCEND]: token[LOCEND], - }, + } as NumberToken | PercentageToken | DimensionToken | AngleToken, ]; } } diff --git a/src/lib/parser/parse.ts b/src/lib/parser/parse.ts index 37db35b5..d57b5202 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, Tokenizer, tokenizeStream } from "./tokenize.ts"; +import { Tokenizer } from "./tokenize.ts"; import type { AstAtRule, AstComment, @@ -637,7 +637,7 @@ function parseVisitors( * @throws Error * @private */ -export function doParseSync(iter: Generator, options: ParserSyncOptions = {}): ParseResult { +export function doParseSync(tokenizer: Tokenizer, options: ParserSyncOptions = {}): ParseResult { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -714,9 +714,10 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio ast[LOCSRCID] = options.source!.id; ast[LOCSTA] = 0; - let tokenizer: Tokenizer; + // let tokenizer: Tokenizer; - while ((tokenizer = iter.next().value) != null) { + while (!tokenizer.done()) { + tokenizer.next(); // item = (iter as Array)[currentItemIndex]; if (tokenizer.unit != null) { @@ -751,8 +752,6 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio item[LOCSTA] = tokenizer.sta as number; item[LOCEND] = tokenizer.end as number; - // console.error(item); - stats.bytesIn = tokenizer.bytesIn as number; stats.tokensCount++; @@ -804,11 +803,7 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio tokens.push(item); do { - tokenizer = iter.next().value; - - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { @@ -849,7 +844,7 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio } else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ @@ -1791,10 +1786,7 @@ export function doParseSync(iter: Generator, options: ParserSyncOptio * @throws Error * @private */ -export async function doParse( - iter: Generator | AsyncGenerator, - options: ParserOptions = {}, -): Promise { +export async function doParse(iter: Tokenizer | Promise, options: ParserOptions = {}): Promise { if (options.signal != null) { options.signal.addEventListener("abort", reject); } @@ -1874,7 +1866,7 @@ export async function doParse( let isAsync: boolean = typeof iter[Symbol.asyncIterator] === "function"; let parensMatch: number = 0; let curlyBracketMatch: number = 0; - let tokenizer: Tokenizer; + let tokenizer: Tokenizer = iter instanceof Promise ? await iter : iter; // ast[ROOT] = ast; @@ -1887,11 +1879,9 @@ export async function doParse( // iter = iter[Symbol.iterator]() as Iterator; // } - while ( - (tokenizer = isAsync - ? ((await iter.next()).value as Tokenizer) - : ((iter as Iterator).next().value as Tokenizer)) - ) { + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { item = { typ: tokenizer.typ as EnumToken, @@ -1976,13 +1966,7 @@ export async function doParse( tokens.push(item); do { - tokenizer = isAsync - ? ((await iter.next()).value as Tokenizer) - : ((iter as Generator).next().value as Tokenizer); - - if (tokenizer == null) { - break; - } + tokenizer.next(); if (tokenizer.unit != null) { item = { @@ -2023,7 +2007,7 @@ export async function doParse( } else if (item.typ === EnumToken.BlockEndTokenType) { inBlock--; } - } while (inBlock != 0); + } while (inBlock != 0 && !tokenizer.done()); if (tokens.length > 0) { errors.push({ @@ -2106,7 +2090,9 @@ export async function doParse( 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, @@ -2499,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, @@ -2688,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, @@ -4328,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, @@ -4379,12 +4371,22 @@ export function parseString( // currentPosition: 0, // }; - const iter: Generator = tokenize(src); + const tokenizer: Tokenizer = new Tokenizer({ + stream: src, + buffer: "", + src: options?.src ?? "", + offset: 0, + time: 0, + source: new SourceFile(src, [], options?.src ?? ""), + position: 0, + currentPosition: 0, + } as ParseInfo); const mapped: Token[] = []; let token: Token; - let tokenizer: Tokenizer; - while ((tokenizer = iter.next().value)) { + while (!tokenizer.done()) { + tokenizer.next(); + if (tokenizer.unit != null) { token = { typ: tokenizer.typ as EnumToken, diff --git a/src/lib/parser/tokenize.ts b/src/lib/parser/tokenize.ts index dde7d1c8..8220ae66 100644 --- a/src/lib/parser/tokenize.ts +++ b/src/lib/parser/tokenize.ts @@ -34,6 +34,28 @@ import { SourceFile } from "./source.ts"; 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; @@ -140,79 +162,60 @@ export const enum TokenMap { } function getSymbolHint(parseInfo: ParseInfo, start: number, end: number): EnumToken | null { - let i: number = SymbolsMapTokensKeys.length; - let j: number; - let ca: number; - let cb: number; - let match: boolean; - let index: number; - const len: number = end - start; + const keysLength = SymbolsMapTokensKeys.length; - while (i--) { - match = len == SymbolsMapTokensKeys[i].length; - - if (!match) { - continue; - } + // Early exit for impossible lengths + if (len < 0) return null; - for (j = 0; j < SymbolsMapTokensKeys[i].length; j++) { - index = start + j; + for (let i = 0; i < keysLength; i++) { + const key = SymbolsMapTokensKeys[i]; + if (key.length !== len) continue; - if (index > end) { - match = false; - break; - } + // Match character by character + let match = true; - ca = SymbolsMapTokensKeys[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + 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) { + if (ca !== cb) { match = false; break; } } - if (!match) { - continue; + if (match) { + return SymbolsMapTokens[key]; } - - return SymbolsMapTokens[SymbolsMapTokensKeys[i]]; } return null; } function searchArray(array: string[], parseInfo: ParseInfo, start: number, end: number): string | null { - let i: number = array.length; - let j: number; - let ca: number; - let cb: number; - let match: boolean; - let index: number; const len: number = end - start; - while (i--) { - match = true; - for (j = 0; j < array[i].length; j++) { - if (len != array[i].length) { - match = false; - break; - } + // Early exit for impossible lengths + if (len < 0) return null; - index = start + j; + // Use a simple linear search optimized with length pre-filtering + let i: number = array.length; - if (index > end) { - match = false; - break; - } + while (i--) { + if (array[i].length !== len) continue; - ca = array[i].charCodeAt(j); - cb = parseInfo.stream.charCodeAt(index); + // Match character by character + let match = true; + const arrayItem = array[i]; + + for (let j: number = 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; @@ -225,7 +228,7 @@ function searchArray(array: string[], parseInfo: ParseInfo, start: number, end: } if (match) { - return array[i]; + return arrayItem; } } @@ -288,21 +291,40 @@ export class Tokenizer { * 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, + }; + } + } + } /** * * @param parseInfo * @returns */ - *consumeString(parseInfo: ParseInfo): Generator { - const quote: number = this.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } @@ -343,38 +365,34 @@ export class Tokenizer { : 0); decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); - yield this.makeToken( + this.advance(parseInfo); + return this.makeToken( parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null, // ), ); - - return; } if (isNewLine(charCode)) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); - - return; + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - 'Unclosed-string' fixed - yield this.makeToken(parseInfo, EnumToken.StringTokenType); + return this.makeToken(parseInfo, EnumToken.StringTokenType); // return result; } @@ -383,15 +401,15 @@ export class Tokenizer { * @param parseInfo * @returns */ - *consumeURLToken(parseInfo: ParseInfo): Generator { - const quote: number = this.next(parseInfo).charCodeAt(0); + 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.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } @@ -433,17 +451,17 @@ export class Tokenizer { decodeSegments = true; - this.next(parseInfo, length); + this.advance(parseInfo, length); continue; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == quote) { - this.next(parseInfo); + this.advance(parseInfo); let k: number = 1; let end: number = parseInfo.stream.length - parseInfo.offset; @@ -454,65 +472,59 @@ export class Tokenizer { // NaN != NaN if (charCode != charCode) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } if (isWhiteSpace(charCode)) { - this.next(parseInfo, k); + this.advance(parseInfo, k); k++; continue; } if (charCode != TokenMap.RIGHT_PARENTHESIS) { - this.next(parseInfo, k); - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + this.advance(parseInfo, k); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } break; } // consume until the ')' - yield this.makeToken( + return this.makeToken( parseInfo, /* hasNewLine ? EnumToken.BadStringTokenType : */ EnumToken.StringTokenType, decodeSegments ? { decodeSegments } : null, ); - - return; // return result; } if (isNewLine(charCode)) { // bad string - this.next(parseInfo); + this.advance(parseInfo); while ( (charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset)) == charCode ) { if (charCode == TokenMap.REVERSE_SOLIDUS) { - this.next(parseInfo, 2); + this.advance(parseInfo, 2); continue; } if (charCode == TokenMap.RIGHT_PARENTHESIS) { - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); - return; + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } - yield this.makeToken(parseInfo, EnumToken.BadStringTokenType); - return; + return this.makeToken(parseInfo, EnumToken.BadStringTokenType); } - this.next(parseInfo); + this.advance(parseInfo); } // EOF - bad url token - yield this.makeToken(parseInfo, EnumToken.BadUrlTokenType); + return this.makeToken(parseInfo, EnumToken.BadUrlTokenType); // return result; } @@ -947,6 +959,39 @@ export class Tokenizer { return 0; } + parseURLToken(parseInfo: ParseInfo, endPosition: number): this { + let charCode: number; + + // consume an + while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + this.advance(parseInfo); + } + + charCode = this.peek(parseInfo).charCodeAt(0); + + if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { + return this.consumeURLToken(parseInfo); + } + + do { + this.advance(parseInfo); + charCode = this.peek(parseInfo).charCodeAt(0); + } 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.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + ? EnumToken.BadUrlTokenType + : EnumToken.UrlTokenTokenType, + ); + // } + } /** * * @param parseInfo @@ -1066,22 +1111,7 @@ export class Tokenizer { } if (this.decodeString) { - val = (val as string).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); - }); + val = decodeEscapeSequences(val as string); } if (hintsEnum.has(hint)) { @@ -1122,23 +1152,7 @@ export class Tokenizer { ); 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); - }); - + val = decodeEscapeSequences(val); this.decodeString = true; } @@ -1201,6 +1215,15 @@ export class Tokenizer { 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); + } + /** * * @param parseInfo @@ -1222,16 +1245,17 @@ export class Tokenizer { * @param count * @returns */ - next(parseInfo: ParseInfo, count: number = 1): string { + 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[i].charCodeAt(0); + codepoint = char.charCodeAt(i); if ( codepoint == 0xa || // \n @@ -1245,7 +1269,7 @@ export class Tokenizer { if (codepoint == 0xa && i > 0 && char.charCodeAt(i - 1) == 0xd) { // nope } else { - parseInfo.source.lineStarts.lineStarts.push(position + parseInfo.offset + i); + lineStarts.push(position + parseInfo.offset + i); } } } @@ -1414,22 +1438,17 @@ export class Tokenizer { return i == parseInfo.currentPosition; } + done(): boolean { + return this.typ === EnumToken.EOF; + } + /** * Tokenize CSS string * @param parseInfo * @param yieldEOFToken */ - *tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = true): Generator { - if (typeof parseInfo == "string") { - parseInfo = { - stream: parseInfo, - source: new SourceFile(parseInfo, [], ""), - offset: 0, - time: 0, - position: 0, - currentPosition: 0, - }; - } + next(/* parseInfo: ParseInfo | string, yieldEOFToken: boolean = true */): this { + const parseInfo: ParseInfo = this.parseInfo as ParseInfo; this.source = parseInfo.source; @@ -1442,7 +1461,13 @@ export class Tokenizer { let tokensCount: number; // NaN is not equal to NaN - while ((charCode = this.peek(parseInfo).charCodeAt(0)) == charCode) { + 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 || @@ -1453,8 +1478,8 @@ export class Tokenizer { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { slice: this.slice, sign: charCode == TokenMap.MINUS ? "-" : charCode == TokenMap.PLUS ? "+" : null, }); @@ -1466,13 +1491,13 @@ export class Tokenizer { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); + this.advance(parseInfo, tokensCount); charCode = this.peek(parseInfo).charCodeAt(0); // do not match function if (TokenMap.LEFT_PARENTHESIS != charCode) { - yield this.makeToken( + return this.makeToken( parseInfo, this.startsWith(parseInfo, "--") ? EnumToken.DashedIdenTokenType @@ -1484,7 +1509,7 @@ export class Tokenizer { } if (charCode == TokenMap.AT) { - this.next(parseInfo); + this.advance(parseInfo); charCode = this.peek(parseInfo).charCodeAt(0); @@ -1495,9 +1520,9 @@ export class Tokenizer { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); + this.advance(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.AtRuleTokenType); + return this.makeToken(parseInfo, EnumToken.AtRuleTokenType); continue; } } @@ -1507,18 +1532,18 @@ export class Tokenizer { tokensCount = this.consumeColor(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.ColorTokenType); + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ColorTokenType); continue; } - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.HashTokenType); + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.HashTokenType); continue; } } @@ -1527,20 +1552,20 @@ export class Tokenizer { switch (charCode) { case TokenMap.EQUALS: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.DelimTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.DelimTokenType); break; // '+' or '-' case TokenMap.PLUS: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); charCode = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset); @@ -1548,8 +1573,8 @@ export class Tokenizer { tokensCount = this.consumeNumericToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, this.hint ?? EnumToken.NumberTokenType, { slice: this.slice, sign: "+", }); @@ -1557,7 +1582,7 @@ export class Tokenizer { } } - yield this.makeToken(parseInfo, EnumToken.Plus); + return this.makeToken(parseInfo, EnumToken.Plus); break; case TokenMap.MINUS: @@ -1566,9 +1591,9 @@ export class Tokenizer { // not a number if (isWhiteSpace(nextCharCode)) { - this.next(parseInfo); + this.advance(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Sub); + return this.makeToken(parseInfo, EnumToken.Sub); break; } @@ -1576,38 +1601,38 @@ export class Tokenizer { charCode == TokenMap.MINUS && (nextCharCode == TokenMap.MINUS || isIdentStart(nextCharCode)) ) { - this.next(parseInfo); + this.advance(parseInfo); tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.IdenTokenType); + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.IdenTokenType); continue; } } } - this.next(parseInfo); + this.advance(parseInfo); break; // '{' case TokenMap.LEFT_BRACE: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BlockStartTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockStartTokenType); break; // '}' case TokenMap.RIGHT_BRACE: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.BlockEndTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.BlockEndTokenType); break; // '(' @@ -1617,8 +1642,8 @@ export class Tokenizer { parseInfo.stream[parseInfo.position - parseInfo.offset] === ":" && this.isPseudo(parseInfo) ) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.PseudoClassFunctionTokenDefType); break; } else if (this.isIdentToken(parseInfo)) { @@ -1630,107 +1655,79 @@ export class Tokenizer { parseInfo.currentPosition - parseInfo.offset + 1, ) ?? EnumToken.FunctionTokenDefType); - yield this.makeToken(parseInfo, hint); - this.next(parseInfo); + this.makeToken(parseInfo, hint); + this.advance(parseInfo); // consume '(' parseInfo.position = parseInfo.currentPosition; if (hint === EnumToken.UrlFunctionTokenDefType) { - // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { - this.next(parseInfo); - } - - charCode = this.peek(parseInfo).charCodeAt(0); - - if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { - yield* this.consumeURLToken(parseInfo); - } else { - do { - this.next(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); - } while ( - // !(value === "/" && this.match(parseInfo, "/*") && - charCode !== TokenMap.RIGHT_PARENTHESIS && - parseInfo.currentPosition < endPosition - ); - - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken( - parseInfo, - // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || - !this.isURLToken(parseInfo) - ? EnumToken.BadUrlTokenType - : EnumToken.UrlTokenTokenType, - ); - } - } + this.state = hint; } + return this; break; } } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.StartParensTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.StartParensTokenType); break; // ')' case TokenMap.RIGHT_PARENTHESIS: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.EndParensTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.EndParensTokenType); break; // '[' case TokenMap.LEFT_BRACKETS: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.AttrStartTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrStartTokenType); break; // ']' case TokenMap.RIGHT_BRACKETS: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.AttrEndTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.AttrEndTokenType); break; case TokenMap.SEMICOLON: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.SemiColonTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.SemiColonTokenType); break; case TokenMap.COLON: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); if (this.peek(parseInfo).charCodeAt(0) == TokenMap.COLON) { - this.next(parseInfo); + this.advance(parseInfo); - yield this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); + return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); break; } - yield this.makeToken(parseInfo, EnumToken.ColonTokenType); + return this.makeToken(parseInfo, EnumToken.ColonTokenType); break; // \n \r \f \v \t space @@ -1743,10 +1740,10 @@ export class Tokenizer { case 0x2028: case 0x2029: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); nextCharCode = parseInfo.stream.charAt(parseInfo.currentPosition - parseInfo.offset).charCodeAt(0); while ( @@ -1755,140 +1752,140 @@ export class Tokenizer { nextCharCode == 0x2028 || nextCharCode == 0x2029 ) { - this.next(parseInfo); + this.advance(parseInfo); nextCharCode = parseInfo.stream .charAt(parseInfo.currentPosition - parseInfo.offset) .charCodeAt(0); } - yield this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); + return this.makeToken(parseInfo, EnumToken.WhitespaceTokenType); break; case TokenMap.COMMA: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.CommaTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommaTokenType); break; case TokenMap.DOLLAR: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "$=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.EndMatchTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.EndMatchTokenType); break; } - this.next(parseInfo); + this.advance(parseInfo); break; case TokenMap.TILDA: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "~=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.IncludeMatchTokenType); break; } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Tilda); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Tilda); break; // case '^': case TokenMap.CARET: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "^=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.StartMatchTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.StartMatchTokenType); break; } - this.next(parseInfo); + this.advance(parseInfo); break; case TokenMap.STAR: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "*=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ContainMatchTokenType); break; } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Star); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Star); break; case TokenMap.AMPERSAND: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.NestingSelectorTokenType); break; case TokenMap.PIPE: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } // '||' if (this.match(parseInfo, "||")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.ColumnCombinatorTokenType); break; } else if (this.match(parseInfo, "|=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.DashMatchTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.DashMatchTokenType); break; } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.Pipe); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.Pipe); break; case TokenMap.EXCLAMATION: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "!important")) { - this.next(parseInfo, 10); - yield this.makeToken(parseInfo, EnumToken.ImportantTokenType); + this.advance(parseInfo, 10); + return this.makeToken(parseInfo, EnumToken.ImportantTokenType); break; } - this.next(parseInfo); + this.advance(parseInfo); break; case TokenMap.SLASH: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (!this.match(parseInfo, "/*")) { - this.next(parseInfo); - yield this.makeToken( + this.advance(parseInfo); + return this.makeToken( parseInfo, getSymbolHint( @@ -1900,13 +1897,13 @@ export class Tokenizer { break; } - this.next(parseInfo, 2); + this.advance(parseInfo, 2); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { if (charCode == TokenMap.STAR) { if (this.match(parseInfo, "/")) { - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.CommentTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.CommentTokenType); break; } @@ -1914,54 +1911,54 @@ export class Tokenizer { } if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo, EnumToken.BadCommentTokenType); + return this.makeToken(parseInfo, EnumToken.BadCommentTokenType); } break; case TokenMap.GREATERTHAN: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, ">=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.GteTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.GteTokenType); break; } - this.next(parseInfo); - yield this.makeToken(parseInfo, EnumToken.GtTokenType); + this.advance(parseInfo); + return this.makeToken(parseInfo, EnumToken.GtTokenType); break; case TokenMap.LOWERTHAN: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } if (this.match(parseInfo, "<=")) { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.LteTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.LteTokenType); break; } - this.next(parseInfo); + this.advance(parseInfo); if (this.match(parseInfo, "!--")) { - this.next(parseInfo, 3); + this.advance(parseInfo, 3); - while ((charCode = this.next(parseInfo).charCodeAt(0)) == charCode) { + while ((charCode = this.advance(parseInfo).charCodeAt(0)) == charCode) { if (charCode == TokenMap.MINUS && this.match(parseInfo, "->")) { break; } } if (parseInfo.currentPosition >= endPosition) { - yield this.makeToken(parseInfo, EnumToken.BadCdoTokenType); + return this.makeToken(parseInfo, EnumToken.BadCdoTokenType); } else { - this.next(parseInfo, 2); - yield this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); + this.advance(parseInfo, 2); + return this.makeToken(parseInfo, EnumToken.CDOCOMMTokenType); } } @@ -1969,86 +1966,86 @@ export class Tokenizer { case TokenMap.HASH: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - this.next(parseInfo); + this.advance(parseInfo); break; case TokenMap.REVERSE_SOLIDUS: - if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } + // if (!yieldEOFToken && parseInfo.stream.length == parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } - this.next(parseInfo); + this.advance(parseInfo); // EOF if (!this.peek(parseInfo)) { - if (!yieldEOFToken) { - break; - } + // if (!yieldEOFToken) { + // break; + // } // end of stream ignore \\ if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } break; } - this.next(parseInfo); + this.advance(parseInfo); break; case TokenMap.SINGLE_QUOTE: case TokenMap.DOUBLE_QUOTE: if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); + return this.makeToken(parseInfo); } - yield* this.consumeString(parseInfo); + return this.consumeString(parseInfo); break; case TokenMap.DOT: const codepoint = parseInfo.stream - .charAt(parseInfo.currentPosition - parseInfo.offset + 1) - .charCodeAt(0); + .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == TokenMap.MINUS) { - this.next(parseInfo); + this.advance(parseInfo); let tokensCount: number = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { - this.next(parseInfo, tokensCount); - yield this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); + this.advance(parseInfo, tokensCount); + return this.makeToken(parseInfo, EnumToken.ClassSelectorTokenType); break; } } if (!isDigit(codepoint) && parseInfo.position !== parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - this.next(parseInfo, 2); + this.makeToken(parseInfo); + this.advance(parseInfo, 2); + return this; break; } - this.next(parseInfo); + this.advance(parseInfo); break; default: - this.next(parseInfo); + this.advance(parseInfo); break; } - if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { - break; - } + // if (!yieldEOFToken && endPosition <= parseInfo.currentPosition - parseInfo.offset + 1) { + // break; + // } } - if (yieldEOFToken) { - if (parseInfo.position < parseInfo.currentPosition) { - yield this.makeToken(parseInfo); - } - - yield this.makeToken(parseInfo, EnumToken.EOFTokenType); + // if (yieldEOFToken) { + if (parseInfo.position < parseInfo.currentPosition) { + return this.makeToken(parseInfo); } + + return this.makeToken(parseInfo, EnumToken.EOFTokenType); + // } } /** @@ -2056,9 +2053,11 @@ export class Tokenizer { * @param input * @param parseInfo */ - async *tokenizeStream(input: ReadableStream, parseInfo: ParseInfo): AsyncGenerator { + async tokenizeStream(): Promise { const decoder = new TextDecoder("utf-8"); - const reader = input.getReader(); + const reader = this.input!.getReader(); + + let parseInfo: ParseInfo = this.parseInfo as ParseInfo; parseInfo.stream = ""; @@ -2068,34 +2067,12 @@ export class Tokenizer { if (!done) { parseInfo.source.append(stream as string); - } - - yield* this.tokenize(parseInfo, done); - - if (done) { + } else { break; } } parseInfo.stream = parseInfo.source.getContent(); - yield* this.tokenize(parseInfo); + return this; // .next(); } } - -/** - * Tokenize CSS string - * @param parseInfo - * @param yieldEOFToken - */ -export function tokenize(parseInfo: ParseInfo | string, yieldEOFToken: boolean = true): Generator { - return new Tokenizer().tokenize(parseInfo, yieldEOFToken); -} - -/** - * tokenize readable stream - * @param input - * @param parseInfo - */ -export function tokenizeStream(input: ReadableStream, parseInfo: ParseInfo): AsyncGenerator { - return new Tokenizer().tokenizeStream(input, parseInfo); -} diff --git a/src/lib/renderer/render.ts b/src/lib/renderer/render.ts index a0f5c053..16a05689 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -237,7 +237,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") { @@ -305,8 +305,6 @@ function updateSourceMap( // @ts-ignore offsets[1] = record[2] as number; - // console.error({record}); - sourceContent = (record[3] as string) || null; if (sourceFileName != null && options.output != null && !sourceFileName.startsWith("data:")) { @@ -374,8 +372,6 @@ function updateSourceMap( sourcemaps.maps.push([newLine, newColumn, srcId, offsets[0], offsets[1]]); } - - // console.error([newLine, newColumn, srcId, ...offsets, EnumToken[node.typ], node.nam ?? node.sel]); } move(sourceLocation, linesMap, str, offset); @@ -590,22 +586,6 @@ function renderAstNode( // color: red; // } // } - // const source = options.sourcesMap!.get(node[LOCSTA]) as SourceFile; - - // if (!sourcemaps.sources.includes(node[LOCSTA] as number)) { - // sourcemaps.sources.push(node[LOCSTA] as number); - // } - - // sourcemaps.maps.push([ - // ...linesMap!.getOffsets( - // sourceLocation.end - str.length + options.newLine!.length + indentSub.length, - // ), - // node[LOCSTA], - // ...source!.getOffsets(node![LOCSTA]), - // ]); - - // console.error(options.sourcesMap.get(node[LOCSTA])?.getSourceLocation(node[LOCSTA]), linesMap?.getOffsets(sourceLocation.end), node.nam); - // @ts-ignore updateSourceMap(node, options, cache, sourcemaps, sourceLocation, linesMap!, str); } else { 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/oklch.ts b/src/lib/syntax/color/oklch.ts index f78dbbc7..33b988d0 100644 --- a/src/lib/syntax/color/oklch.ts +++ b/src/lib/syntax/color/oklch.ts @@ -149,7 +149,7 @@ export function hsl2oklchvalues(token: ColorToken): number[] | null { } export function hwb2oklchvalues(token: ColorToken): number[] { - const values = hwb2oklabvalues(token); + const values = hwb2oklabvalues(token) as number[]; return labvalues2lchvalues(values[0], values[1], values[2], values[3]); } diff --git a/src/node.ts b/src/node.ts index cc7b7c28..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"; @@ -320,7 +320,7 @@ export function parseSync( currentPosition: 0, } as ParseInfo; - const result = doParseSync(tokenize(options.parseInfo), options) as ParseResult; + const result = doParseSync(new Tokenizer(options.parseInfo), options) as ParseResult; return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -637,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; @@ -674,7 +675,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap @@ -893,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/web.ts b/src/web.ts index c156010e..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"; @@ -339,7 +339,7 @@ export function parseSync( currentPosition: 0, } as ParseInfo; - const result = doParseSync(tokenize(options.parseInfo), options); + const result = doParseSync(new Tokenizer(options.parseInfo), options); return options.module == null && options.inputSourceMap == null && !options.sourcemap ? result : parseResult(result, options); @@ -600,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 }), ); @@ -641,7 +642,9 @@ 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 == null && options.inputSourceMap == null && !options.sourcemap @@ -811,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 }), ); From e92da39543bb5ecf9db0b03319271aeb99136f87 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Mon, 31 Aug 2026 20:43:20 -0400 Subject: [PATCH 08/11] replace peek() with peekCharCode() --- dist/index-umd-web.js | 21 ++++++++++----------- dist/index.cjs | 21 ++++++++++----------- dist/lib/ast/features/shorthand.js | 2 +- dist/lib/parser/tokenize.js | 19 +++++++++---------- src/lib/parser/tokenize.ts | 19 +++++++++---------- 5 files changed, 39 insertions(+), 43 deletions(-) diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index f810afb7..3e3b17fb 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -19758,7 +19758,7 @@ options.features.push(new ComputeShorthandFeature(options)); } } - run(ast, options = {}, parent, context) { + run(ast, options) { if (!("chi" in ast)) { return null; } @@ -26097,16 +26097,16 @@ parseURLToken(parseInfo, endPosition) { let charCode; // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + while (isWhiteSpace(this.peekCharCode(parseInfo))) { this.advance(parseInfo); } - charCode = this.peek(parseInfo).charCodeAt(0); + 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.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); } while ( // !(value === "/" && this.match(parseInfo, "/*") && charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && @@ -26114,7 +26114,7 @@ // if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo, // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) ? exports.EnumToken.BadUrlTokenType : exports.EnumToken.UrlTokenTokenType); // } @@ -26533,7 +26533,7 @@ tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { this.advance(parseInfo, tokensCount); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") @@ -26544,9 +26544,9 @@ } if (charCode == 64 /* TokenMap.AT */) { this.advance(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // match at-rule - if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { // consume '@' parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); @@ -26686,7 +26686,7 @@ return this.makeToken(parseInfo); } this.advance(parseInfo); - if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); } @@ -26880,8 +26880,7 @@ } return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + 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); diff --git a/dist/index.cjs b/dist/index.cjs index dd03f118..d9c9f282 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -19761,7 +19761,7 @@ class ComputeShorthandFeature { options.features.push(new ComputeShorthandFeature(options)); } } - run(ast, options = {}, parent, context) { + run(ast, options) { if (!("chi" in ast)) { return null; } @@ -26100,16 +26100,16 @@ class Tokenizer { parseURLToken(parseInfo, endPosition) { let charCode; // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + while (isWhiteSpace(this.peekCharCode(parseInfo))) { this.advance(parseInfo); } - charCode = this.peek(parseInfo).charCodeAt(0); + 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.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); } while ( // !(value === "/" && this.match(parseInfo, "/*") && charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && @@ -26117,7 +26117,7 @@ class Tokenizer { // if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo, // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) ? exports.EnumToken.BadUrlTokenType : exports.EnumToken.UrlTokenTokenType); // } @@ -26536,7 +26536,7 @@ class Tokenizer { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { this.advance(parseInfo, tokensCount); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") @@ -26547,9 +26547,9 @@ class Tokenizer { } if (charCode == 64 /* TokenMap.AT */) { this.advance(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // match at-rule - if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { // consume '@' parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); @@ -26689,7 +26689,7 @@ class Tokenizer { return this.makeToken(parseInfo); } this.advance(parseInfo); - if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); return this.makeToken(parseInfo, exports.EnumToken.DoubleColonTokenType); } @@ -26883,8 +26883,7 @@ class Tokenizer { } return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + 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); diff --git a/dist/lib/ast/features/shorthand.js b/dist/lib/ast/features/shorthand.js index 7309bfb0..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; } diff --git a/dist/lib/parser/tokenize.js b/dist/lib/parser/tokenize.js index b92e6245..3d76a7a8 100644 --- a/dist/lib/parser/tokenize.js +++ b/dist/lib/parser/tokenize.js @@ -769,16 +769,16 @@ class Tokenizer { parseURLToken(parseInfo, endPosition) { let charCode; // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + while (isWhiteSpace(this.peekCharCode(parseInfo))) { this.advance(parseInfo); } - charCode = this.peek(parseInfo).charCodeAt(0); + 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.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); } while ( // !(value === "/" && this.match(parseInfo, "/*") && charCode !== 41 /* TokenMap.RIGHT_PARENTHESIS */ && @@ -786,7 +786,7 @@ class Tokenizer { // if (parseInfo.position < parseInfo.currentPosition) { return this.makeToken(parseInfo, // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) ? EnumToken.BadUrlTokenType : EnumToken.UrlTokenTokenType); // } @@ -1205,7 +1205,7 @@ class Tokenizer { tokensCount = this.consumeIdentToken(parseInfo); if (tokensCount > 0) { this.advance(parseInfo, tokensCount); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // do not match function if (40 /* TokenMap.LEFT_PARENTHESIS */ != charCode) { return this.makeToken(parseInfo, this.startsWith(parseInfo, "--") @@ -1216,9 +1216,9 @@ class Tokenizer { } if (charCode == 64 /* TokenMap.AT */) { this.advance(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // match at-rule - if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + if (charCode == 45 /* TokenMap.MINUS */ || isIdentStart(this.peekCharCode(parseInfo))) { // consume '@' parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); @@ -1358,7 +1358,7 @@ class Tokenizer { return this.makeToken(parseInfo); } this.advance(parseInfo); - if (this.peek(parseInfo).charCodeAt(0) == 58 /* TokenMap.COLON */) { + if (this.peekCharCode(parseInfo) == 58 /* TokenMap.COLON */) { this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); } @@ -1552,8 +1552,7 @@ class Tokenizer { } return this.consumeString(parseInfo); case 46 /* TokenMap.DOT */: - const codepoint = parseInfo.stream - .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + 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); diff --git a/src/lib/parser/tokenize.ts b/src/lib/parser/tokenize.ts index 8220ae66..8c007075 100644 --- a/src/lib/parser/tokenize.ts +++ b/src/lib/parser/tokenize.ts @@ -963,11 +963,11 @@ export class Tokenizer { let charCode: number; // consume an - while (isWhiteSpace(this.peek(parseInfo).charCodeAt(0))) { + while (isWhiteSpace(this.peekCharCode(parseInfo))) { this.advance(parseInfo); } - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); if (charCode == TokenMap.DOUBLE_QUOTE || charCode == TokenMap.SINGLE_QUOTE) { return this.consumeURLToken(parseInfo); @@ -975,7 +975,7 @@ export class Tokenizer { do { this.advance(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); } while ( // !(value === "/" && this.match(parseInfo, "/*") && charCode !== TokenMap.RIGHT_PARENTHESIS && @@ -986,7 +986,7 @@ export class Tokenizer { return this.makeToken( parseInfo, // parseInfo.position < parseInfo.currentPosition - (charCode = this.peek(parseInfo).charCodeAt(0)) != charCode || !this.isURLToken(parseInfo) + (charCode = this.peekCharCode(parseInfo)) != charCode || !this.isURLToken(parseInfo) ? EnumToken.BadUrlTokenType : EnumToken.UrlTokenTokenType, ); @@ -1493,7 +1493,7 @@ export class Tokenizer { if (tokensCount > 0) { this.advance(parseInfo, tokensCount); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // do not match function if (TokenMap.LEFT_PARENTHESIS != charCode) { @@ -1511,10 +1511,10 @@ export class Tokenizer { if (charCode == TokenMap.AT) { this.advance(parseInfo); - charCode = this.peek(parseInfo).charCodeAt(0); + charCode = this.peekCharCode(parseInfo); // match at-rule - if (charCode == TokenMap.MINUS || isIdentStart(this.peek(parseInfo).charCodeAt(0))) { + if (charCode == TokenMap.MINUS || isIdentStart(this.peekCharCode(parseInfo))) { // consume '@' parseInfo.position = parseInfo.currentPosition; tokensCount = this.consumeIdentToken(parseInfo); @@ -1720,7 +1720,7 @@ export class Tokenizer { this.advance(parseInfo); - if (this.peek(parseInfo).charCodeAt(0) == TokenMap.COLON) { + if (this.peekCharCode(parseInfo) == TokenMap.COLON) { this.advance(parseInfo); return this.makeToken(parseInfo, EnumToken.DoubleColonTokenType); @@ -2006,8 +2006,7 @@ export class Tokenizer { break; case TokenMap.DOT: - const codepoint = parseInfo.stream - .charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); + const codepoint = parseInfo.stream.charCodeAt(parseInfo.currentPosition - parseInfo.offset + 1); if (isIdentStart(codepoint) || codepoint == TokenMap.MINUS) { this.advance(parseInfo); From ffd59d7ff2619943105715b3d93953c452aaa123 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Tue, 1 Sep 2026 21:24:00 -0400 Subject: [PATCH 09/11] ensure transform: rotate(360deg) is not converted to transform: none --- dist/index-umd-web.js | 86 +++++-- dist/index.cjs | 86 +++++-- dist/lib/ast/features/transform.js | 2 +- dist/lib/ast/transform/compute.js | 57 ++++- dist/lib/ast/transform/minify.js | 2 +- dist/lib/renderer/render.js | 22 +- dist/lib/syntax/constants.js | 2 +- dist/lib/syntax/syntax.js | 7 +- src/lib/ast/features/transform.ts | 2 +- src/lib/ast/transform/compute.ts | 70 +++++- src/lib/ast/transform/minify.ts | 2 +- src/lib/renderer/render.ts | 25 ++- src/lib/syntax/color/color.ts | 4 +- src/lib/syntax/constants.ts | 2 +- src/lib/syntax/syntax.ts | 6 +- test/specs/code/angle.js | 6 +- test/specs/code/calc.js | 346 ++++++++++++++++------------- 17 files changed, 498 insertions(+), 229 deletions(-) diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 3e3b17fb..2ef13c01 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -6403,7 +6403,7 @@ /** * Angle precision */ - const anglePrecision = 0.001; + const anglePrecision = 3; /** * Color range definitions */ @@ -16222,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; } @@ -20641,7 +20638,7 @@ } function minifyTransformFunctions(transform) { const name = transform.val.toLowerCase(); - if ("skewx" == name) { + if ("skewX" == name) { transform.val = "skew"; return transform; } @@ -20801,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 = []; @@ -21104,7 +21156,7 @@ } } run(ast) { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } let i = 0; @@ -25125,29 +25177,29 @@ 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; @@ -25155,7 +25207,7 @@ } 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/index.cjs b/dist/index.cjs index d9c9f282..8b6c4f0c 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -6406,7 +6406,7 @@ const colorPrecision = 6; /** * Angle precision */ -const anglePrecision = 0.001; +const anglePrecision = 3; /** * Color range definitions */ @@ -16225,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; } @@ -20644,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; } @@ -20804,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 = []; @@ -21107,7 +21159,7 @@ class TransformCssFeature { } } run(ast) { - if (!("chi" in ast)) { + if (ast.chi == null) { return null; } let i = 0; @@ -25128,29 +25180,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; @@ -25158,7 +25210,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/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/transform/compute.js b/dist/lib/ast/transform/compute.js index dba77b24..ddd93996 100644 --- a/dist/lib/ast/transform/compute.js +++ b/dist/lib/ast/transform/compute.js @@ -44,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 = []; diff --git a/dist/lib/ast/transform/minify.js b/dist/lib/ast/transform/minify.js index 6a35f512..b1113e22 100644 --- a/dist/lib/ast/transform/minify.js +++ b/dist/lib/ast/transform/minify.js @@ -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; } diff --git a/dist/lib/renderer/render.js b/dist/lib/renderer/render.js index 24c167a6..000f21c0 100644 --- a/dist/lib/renderer/render.js +++ b/dist/lib/renderer/render.js @@ -3,8 +3,8 @@ 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, LOCSTA, LOCSRCID, colorPrecision } from '../syntax/constants.js'; -import { minifyNumber, reducegradientBackgroundPosition, reduceConicColorStops, reduceColorStops, parseColor, isWhiteSpace, 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'; @@ -1167,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; @@ -1197,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/syntax/constants.js b/dist/lib/syntax/constants.js index f5f844ca..75f5d4d9 100644 --- a/dist/lib/syntax/constants.js +++ b/dist/lib/syntax/constants.js @@ -62,7 +62,7 @@ const colorPrecision = 6; /** * Angle precision */ -const anglePrecision = 0.001; +const anglePrecision = 3; /** * Color range definitions */ diff --git a/dist/lib/syntax/syntax.js b/dist/lib/syntax/syntax.js index 6de8ed7e..38072456 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -8,7 +8,7 @@ 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 @@ -1001,14 +1001,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; } 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/transform/compute.ts b/src/lib/ast/transform/compute.ts index 4548ffed..2f25767e 100644 --- a/src/lib/ast/transform/compute.ts +++ b/src/lib/ast/transform/compute.ts @@ -68,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 { diff --git a/src/lib/ast/transform/minify.ts b/src/lib/ast/transform/minify.ts index 41b7e0aa..8281f783 100644 --- a/src/lib/ast/transform/minify.ts +++ b/src/lib/ast/transform/minify.ts @@ -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; } diff --git a/src/lib/renderer/render.ts b/src/lib/renderer/render.ts index 16a05689..88f51b85 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -53,6 +53,7 @@ import { ColorType, EnumToken } from "../ast/types.ts"; import { expand } from "../ast/expand.ts"; import { SourceMap } from "./sourcemap/sourcemap.ts"; import { + anglePrecision, colorPrecision, LOCSRCID, LOCSTA, @@ -1685,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; @@ -1702,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; @@ -1714,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; @@ -1725,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/syntax/color/color.ts b/src/lib/syntax/color/color.ts index eba94a94..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, LOCEND, LOCSRCID, LOCSTA } 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"; diff --git a/src/lib/syntax/constants.ts b/src/lib/syntax/constants.ts index 623c8b72..9d53c8e5 100644 --- a/src/lib/syntax/constants.ts +++ b/src/lib/syntax/constants.ts @@ -65,7 +65,7 @@ export const colorPrecision = 6; /** * Angle precision */ -export const anglePrecision = 0.001; +export const anglePrecision = 3; /** * Color range definitions diff --git a/src/lib/syntax/syntax.ts b/src/lib/syntax/syntax.ts index 097e2ba5..1e1fccce 100644 --- a/src/lib/syntax/syntax.ts +++ b/src/lib/syntax/syntax.ts @@ -1785,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); @@ -1794,10 +1794,6 @@ export function toPrecisionAngle( angle %= 360; } - if (Math.abs(angle) < anglePrecision) { - angle = 0; - } - if (correctValue && angle < 0) { angle += 360; } 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 eae4a952..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)) */ @@ -251,11 +245,11 @@ scale: rem(10 * 2, 1.7); .three { width: 250px; height: 250px -}`)); +}`), + ); }); - it('pow() #21', function () { - + it("pow() #21", function () { return parse(` a { @@ -264,15 +258,16 @@ a { line-height: calc(pi); transform: rotate(atan2(e, 30)); } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { - -moz-transform: rotate(116.565deg); +`).then((result) => + expect(render(result.ast, { minify: false }).code).equals(`a { + -moz-transform: rotate(.324turn); line-height: 3.141593; - transform: rotate(5.1774deg) -}`)); + transform: rotate(.09rad) +}`), + ); }); - it('log() #22', function () { - + it("log() #22", function () { return parse(` a { @@ -280,162 +275,193 @@ a { width: calc(100px * log(8, 2)); transform: rotate( tan(45deg)) } -`).then(result => expect(render(result.ast, {minify: false}).code).equals(`a { +`).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; @@ -459,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)) */ @@ -476,52 +505,65 @@ width: calc(-2px *sign(-1);} .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) +}`), + ); + }); + }); +} From 77fcc2f4e35445bea229cf2e4e7e671a8f1dfb26 Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Tue, 1 Sep 2026 21:52:30 -0400 Subject: [PATCH 10/11] faster tokenizer #148 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19eb043f..5d676788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ## 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 From 3a81f6f695b295581520787e8b4e4ca1ee4e3fa9 Mon Sep 17 00:00:00 2001 From: Thierry Bela Date: Tue, 1 Sep 2026 23:26:04 -0400 Subject: [PATCH 11/11] fix windows file resoluion #148 --- dist/index-umd-web.js | 18 +- dist/index.cjs | 18 +- dist/index.d.ts | 362 +++++++++++++++++++-------------------- dist/lib/fs/resolve.js | 13 +- dist/lib/parser/parse.js | 5 +- src/lib/fs/resolve.ts | 17 +- src/lib/parser/parse.ts | 8 +- 7 files changed, 238 insertions(+), 203 deletions(-) diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 2ef13c01..28299453 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -23723,6 +23723,7 @@ * match url */ const matchUrl = /^(https?:)?\/\//; + const windowsPathnameRegexp = /^\/?[a-zA-Z]:\/?/; /** * return the directory name of a path * @param path @@ -23795,6 +23796,9 @@ 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 == "/") { @@ -23867,8 +23871,13 @@ 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), @@ -30104,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) { @@ -31097,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) { @@ -32899,7 +32908,6 @@ node, location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } diff --git a/dist/index.cjs b/dist/index.cjs index 8b6c4f0c..a651d369 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -23726,6 +23726,7 @@ class LineMap { * match url */ const matchUrl = /^(https?:)?\/\//; +const windowsPathnameRegexp = /^\/?[a-zA-Z]:\/?/; /** * return the directory name of a path * @param path @@ -23798,6 +23799,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 == "/") { @@ -23870,8 +23874,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), @@ -30107,7 +30116,7 @@ function doParseSync(tokenizer, 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) { @@ -31100,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) { @@ -32902,7 +32911,6 @@ function parseTokens(tokens, options, errors) { node, location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } diff --git a/dist/index.d.ts b/dist/index.d.ts index 3314d9ec..c505142f 100644 --- a/dist/index.d.ts +++ b/dist/index.d.ts @@ -987,7 +987,7 @@ declare const OPTIMIZED: unique symbol; /** * Literal token */ -export declare interface LiteralToken extends BaseToken { +declare interface LiteralToken extends BaseToken { /** * @inheritdoc */ @@ -1001,7 +1001,7 @@ export declare interface LiteralToken extends BaseToken { /** * Class selector token */ -export declare interface ClassSelectorToken extends BaseToken { +declare interface ClassSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1015,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 */ @@ -1029,7 +1029,7 @@ export declare interface InvalidClassSelectorToken extends BaseToken { /** * Universal selector token */ -export declare interface UniversalSelectorToken extends BaseToken { +declare interface UniversalSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1039,7 +1039,7 @@ export declare interface UniversalSelectorToken extends BaseToken { /** * Ident token */ -export declare interface IdentToken extends BaseToken { +declare interface IdentToken extends BaseToken { /** * @inheritdoc */ @@ -1053,7 +1053,7 @@ export declare interface IdentToken extends BaseToken { /** * Ident list token */ -export declare interface IdentListToken extends BaseToken { +declare interface IdentListToken extends BaseToken { /** * @inheritdoc */ @@ -1067,7 +1067,7 @@ export declare interface IdentListToken extends BaseToken { /** * Dashed ident token */ -export declare interface DashedIdentToken extends BaseToken { +declare interface DashedIdentToken extends BaseToken { /** * @inheritdoc */ @@ -1081,7 +1081,7 @@ export declare interface DashedIdentToken extends BaseToken { /** * Comma token */ -export declare interface CommaToken extends BaseToken { +declare interface CommaToken extends BaseToken { /** * @inheritdoc */ @@ -1091,7 +1091,7 @@ export declare interface CommaToken extends BaseToken { /** * Colon token */ -export declare interface ColonToken extends BaseToken { +declare interface ColonToken extends BaseToken { /** * @inheritdoc */ @@ -1101,7 +1101,7 @@ export declare interface ColonToken extends BaseToken { /** * Double colon token */ -export declare interface DoubleColonToken extends BaseToken { +declare interface DoubleColonToken extends BaseToken { /** * @inheritdoc */ @@ -1111,7 +1111,7 @@ export declare interface DoubleColonToken extends BaseToken { /** * Semicolon token */ -export declare interface SemiColonToken extends BaseToken { +declare interface SemiColonToken extends BaseToken { /** * @inheritdoc */ @@ -1121,7 +1121,7 @@ export declare interface SemiColonToken extends BaseToken { /** * Nesting selector token */ -export declare interface NestingSelectorToken extends BaseToken { +declare interface NestingSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -1131,7 +1131,7 @@ export declare interface NestingSelectorToken extends BaseToken { /** * Number token */ -export declare interface NumberToken extends BaseToken { +declare interface NumberToken extends BaseToken { /** * @inheritdoc */ @@ -1149,7 +1149,7 @@ export declare interface NumberToken extends BaseToken { /** * At rule token */ -export declare interface AtRuleToken extends BaseToken { +declare interface AtRuleToken extends BaseToken { /** * @inheritdoc */ @@ -1167,7 +1167,7 @@ export declare interface AtRuleToken extends BaseToken { /** * Percentage token */ -export declare interface PercentageToken extends BaseToken { +declare interface PercentageToken extends BaseToken { /** * @inheritdoc */ @@ -1181,7 +1181,7 @@ export declare interface PercentageToken extends BaseToken { /** * Flex token */ -export declare interface FlexToken extends BaseToken { +declare interface FlexToken extends BaseToken { /** * @inheritdoc */ @@ -1195,7 +1195,7 @@ export declare interface FlexToken extends BaseToken { /** * Function token */ -export declare interface FunctionToken extends BaseToken { +declare interface FunctionToken extends BaseToken { /** * function type */ @@ -1225,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 */ @@ -1243,7 +1243,7 @@ export declare interface GridTemplateFuncToken extends BaseToken { /** * Function URL token */ -export declare interface FunctionURLToken extends BaseToken { +declare interface FunctionURLToken extends BaseToken { /** * @inheritdoc */ @@ -1261,7 +1261,7 @@ export declare interface FunctionURLToken extends BaseToken { /** * Function image token */ -export declare interface FunctionImageToken extends BaseToken { +declare interface FunctionImageToken extends BaseToken { /** * @inheritdoc */ @@ -1288,7 +1288,7 @@ export declare interface FunctionImageToken extends BaseToken { /** * Timing function token */ -export declare interface TimingFunctionToken extends BaseToken { +declare interface TimingFunctionToken extends BaseToken { /** * @inheritdoc */ @@ -1306,7 +1306,7 @@ export declare interface TimingFunctionToken extends BaseToken { /** * Timeline function token */ -export declare interface TimelineFunctionToken extends BaseToken { +declare interface TimelineFunctionToken extends BaseToken { /** * @inheritdoc */ @@ -1324,7 +1324,7 @@ export declare interface TimelineFunctionToken extends BaseToken { /** * String token */ -export declare interface StringToken extends BaseToken { +declare interface StringToken extends BaseToken { /** * @inheritdoc */ @@ -1338,7 +1338,7 @@ export declare interface StringToken extends BaseToken { /** * Bad string token */ -export declare interface BadStringToken extends BaseToken { +declare interface BadStringToken extends BaseToken { /** * @inheritdoc */ @@ -1352,7 +1352,7 @@ export declare interface BadStringToken extends BaseToken { /** * Unclosed string token */ -export declare interface UnclosedStringToken extends BaseToken { +declare interface UnclosedStringToken extends BaseToken { /** * @inheritdoc */ @@ -1366,7 +1366,7 @@ export declare interface UnclosedStringToken extends BaseToken { /** * Dimension token */ -export declare interface DimensionToken extends BaseToken { +declare interface DimensionToken extends BaseToken { /** * @inheritdoc */ @@ -1384,7 +1384,7 @@ export declare interface DimensionToken extends BaseToken { /** * Length token */ -export declare interface LengthToken extends BaseToken { +declare interface LengthToken extends BaseToken { /** * @inheritdoc */ @@ -1402,7 +1402,7 @@ export declare interface LengthToken extends BaseToken { /** * Angle token */ -export declare interface AngleToken extends BaseToken { +declare interface AngleToken extends BaseToken { /** * @inheritdoc */ @@ -1420,7 +1420,7 @@ export declare interface AngleToken extends BaseToken { /** * Time token */ -export declare interface TimeToken extends BaseToken { +declare interface TimeToken extends BaseToken { /** * @inheritdoc */ @@ -1438,7 +1438,7 @@ export declare interface TimeToken extends BaseToken { /** * Frequency token */ -export declare interface FrequencyToken extends BaseToken { +declare interface FrequencyToken extends BaseToken { /** * @inheritdoc */ @@ -1456,7 +1456,7 @@ export declare interface FrequencyToken extends BaseToken { /** * Resolution token */ -export declare interface ResolutionToken extends BaseToken { +declare interface ResolutionToken extends BaseToken { /** * @inheritdoc */ @@ -1474,7 +1474,7 @@ export declare interface ResolutionToken extends BaseToken { /** * Hash token */ -export declare interface HashToken extends BaseToken { +declare interface HashToken extends BaseToken { /** * @inheritdoc */ @@ -1488,7 +1488,7 @@ export declare interface HashToken extends BaseToken { /** * Block start token */ -export declare interface BlockStartToken extends BaseToken { +declare interface BlockStartToken extends BaseToken { /** * @inheritdoc */ @@ -1498,7 +1498,7 @@ export declare interface BlockStartToken extends BaseToken { /** * Block end token */ -export declare interface BlockEndToken extends BaseToken { +declare interface BlockEndToken extends BaseToken { /** * @inheritdoc */ @@ -1508,7 +1508,7 @@ export declare interface BlockEndToken extends BaseToken { /** * Attribute start token */ -export declare interface AttrStartToken extends BaseToken { +declare interface AttrStartToken extends BaseToken { /** * @inheritdoc */ @@ -1522,7 +1522,7 @@ export declare interface AttrStartToken extends BaseToken { /** * Attribute end token */ -export declare interface AttrEndToken extends BaseToken { +declare interface AttrEndToken extends BaseToken { /** * @inheritdoc */ @@ -1532,7 +1532,7 @@ export declare interface AttrEndToken extends BaseToken { /** * Parenthesis start token */ -export declare interface ParensStartToken extends BaseToken { +declare interface ParensStartToken extends BaseToken { /** * @inheritdoc */ @@ -1542,7 +1542,7 @@ export declare interface ParensStartToken extends BaseToken { /** * Parenthesis end token */ -export declare interface ParensEndToken extends BaseToken { +declare interface ParensEndToken extends BaseToken { /** * @inheritdoc */ @@ -1552,7 +1552,7 @@ export declare interface ParensEndToken extends BaseToken { /** * Parenthesis token */ -export declare interface ParensToken extends BaseToken { +declare interface ParensToken extends BaseToken { /** * @inheritdoc */ @@ -1566,7 +1566,7 @@ export declare interface ParensToken extends BaseToken { /** * Whitespace token */ -export declare interface WhitespaceToken extends BaseToken { +declare interface WhitespaceToken extends BaseToken { /** * @inheritdoc */ @@ -1580,7 +1580,7 @@ export declare interface WhitespaceToken extends BaseToken { /** * Comment token */ -export declare interface CommentToken extends BaseToken { +declare interface CommentToken extends BaseToken { /** * @inheritdoc */ @@ -1594,7 +1594,7 @@ export declare interface CommentToken extends BaseToken { /** * Bad comment token */ -export declare interface BadCommentToken extends BaseToken { +declare interface BadCommentToken extends BaseToken { /** * @inheritdoc */ @@ -1608,7 +1608,7 @@ export declare interface BadCommentToken extends BaseToken { /** * CDO comment token */ -export declare interface CDOCommentToken extends BaseToken { +declare interface CDOCommentToken extends BaseToken { /** * @inheritdoc */ @@ -1622,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 */ @@ -1636,7 +1636,7 @@ export declare interface BadCDOCommentToken extends BaseToken { /** * Include match token */ -export declare interface IncludeMatchToken extends BaseToken { +declare interface IncludeMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1647,7 +1647,7 @@ export declare interface IncludeMatchToken extends BaseToken { /** * Dash match token */ -export declare interface DashMatchToken extends BaseToken { +declare interface DashMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1658,7 +1658,7 @@ export declare interface DashMatchToken extends BaseToken { /** * Equal match token */ -export declare interface EqualMatchToken extends BaseToken { +declare interface EqualMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1669,7 +1669,7 @@ export declare interface EqualMatchToken extends BaseToken { /** * Start match token */ -export declare interface StartMatchToken extends BaseToken { +declare interface StartMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1680,7 +1680,7 @@ export declare interface StartMatchToken extends BaseToken { /** * End match token */ -export declare interface EndMatchToken extends BaseToken { +declare interface EndMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1691,7 +1691,7 @@ export declare interface EndMatchToken extends BaseToken { /** * Contain match token */ -export declare interface ContainMatchToken extends BaseToken { +declare interface ContainMatchToken extends BaseToken { /** * @inheritdoc */ @@ -1702,7 +1702,7 @@ export declare interface ContainMatchToken extends BaseToken { /** * Less than token */ -export declare interface LessThanToken extends BaseToken { +declare interface LessThanToken extends BaseToken { /** * @inheritdoc */ @@ -1712,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 */ @@ -1722,7 +1722,7 @@ export declare interface LessThanOrEqualToken extends BaseToken { /** * Greater than token */ -export declare interface GreaterThanToken extends BaseToken { +declare interface GreaterThanToken extends BaseToken { /** * @inheritdoc */ @@ -1732,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 */ @@ -1742,7 +1742,7 @@ export declare interface GreaterThanOrEqualToken extends BaseToken { /** * Column combinator token */ -export declare interface ColumnCombinatorToken extends BaseToken { +declare interface ColumnCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -1752,7 +1752,7 @@ export declare interface ColumnCombinatorToken extends BaseToken { /** * Pseudo class token */ -export declare interface PseudoClassToken extends BaseToken { +declare interface PseudoClassToken extends BaseToken { /** * @inheritdoc */ @@ -1766,7 +1766,7 @@ export declare interface PseudoClassToken extends BaseToken { /** * Pseudo element token */ -export declare interface PseudoElementToken extends BaseToken { +declare interface PseudoElementToken extends BaseToken { /** * @inheritdoc */ @@ -1780,7 +1780,7 @@ export declare interface PseudoElementToken extends BaseToken { /** * Pseudo page token */ -export declare interface PseudoPageToken extends BaseToken { +declare interface PseudoPageToken extends BaseToken { /** * @inheritdoc */ @@ -1794,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 */ @@ -1812,7 +1812,7 @@ export declare interface PseudoClassFunctionToken extends BaseToken { /** * Delim token */ -export declare interface DelimToken extends BaseToken { +declare interface DelimToken extends BaseToken { /** * @inheritdoc */ @@ -1822,7 +1822,7 @@ export declare interface DelimToken extends BaseToken { /** * Bad URL token */ -export declare interface BadUrlToken extends BaseToken { +declare interface BadUrlToken extends BaseToken { /** * @inheritdoc */ @@ -1836,7 +1836,7 @@ export declare interface BadUrlToken extends BaseToken { /** * URL token */ -export declare interface UrlToken extends BaseToken { +declare interface UrlToken extends BaseToken { /** * @inheritdoc */ @@ -1850,7 +1850,7 @@ export declare interface UrlToken extends BaseToken { /** * EOF token */ -export declare interface EOFToken extends BaseToken { +declare interface EOFToken extends BaseToken { /** * @inheritdoc */ @@ -1860,7 +1860,7 @@ export declare interface EOFToken extends BaseToken { /** * Important token */ -export declare interface ImportantToken extends BaseToken { +declare interface ImportantToken extends BaseToken { /** * @inheritdoc */ @@ -1870,7 +1870,7 @@ export declare interface ImportantToken extends BaseToken { /** * Color token */ -export declare interface ColorToken extends BaseToken { +declare interface ColorToken extends BaseToken { /** * @inheritdoc */ @@ -1896,7 +1896,7 @@ export declare interface ColorToken extends BaseToken { /** * Attribute token */ -export declare interface AttrToken extends BaseToken { +declare interface AttrToken extends BaseToken { /** * @inheritdoc */ @@ -1910,7 +1910,7 @@ export declare interface AttrToken extends BaseToken { /** * Invalid attribute token */ -export declare interface InvalidAttrToken extends BaseToken { +declare interface InvalidAttrToken extends BaseToken { /** * @inheritdoc */ @@ -1924,7 +1924,7 @@ export declare interface InvalidAttrToken extends BaseToken { /** * Child combinator token */ -export declare interface ChildCombinatorToken extends BaseToken { +declare interface ChildCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -1934,7 +1934,7 @@ export declare interface ChildCombinatorToken extends BaseToken { /** * Media feature token */ -export declare interface MediaFeatureToken extends BaseToken { +declare interface MediaFeatureToken extends BaseToken { /** * @inheritdoc */ @@ -1948,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 */ @@ -1962,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 */ @@ -1976,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 */ @@ -1986,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 */ @@ -1996,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 */ @@ -2011,7 +2011,7 @@ export declare interface MediaQueryUnaryFeatureToken extends BaseToken { r: Token$1[]; } -export declare interface SupportsQueryUnaryConditionToken extends BaseToken { +declare interface SupportsQueryUnaryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2026,7 +2026,7 @@ export declare interface SupportsQueryUnaryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface SupportsQueryConditionToken extends BaseToken { +declare interface SupportsQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2045,7 +2045,7 @@ export declare interface SupportsQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface WhenElseQueryConditionToken extends BaseToken { +declare interface WhenElseQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2064,7 +2064,7 @@ export declare interface WhenElseQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface WhenElseUnaryConditionToken extends BaseToken { +declare interface WhenElseUnaryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2079,7 +2079,7 @@ export declare interface WhenElseUnaryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface MediaQueryConditionToken extends BaseToken { +declare interface MediaQueryConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2106,7 +2106,7 @@ export declare interface MediaQueryConditionToken extends BaseToken { r: Token$1[]; } -export declare interface IfConditionToken extends BaseToken { +declare interface IfConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2121,7 +2121,7 @@ export declare interface IfConditionToken extends BaseToken { r: Token$1[]; } -export declare interface IfElseConditionToken extends BaseToken { +declare interface IfElseConditionToken extends BaseToken { /** * @inheritdoc */ @@ -2136,7 +2136,7 @@ export declare interface IfElseConditionToken extends BaseToken { r: IfConditionToken; } -export declare interface ContainerStyleRangeToken extends BaseToken { +declare interface ContainerStyleRangeToken extends BaseToken { /** * @inheritdoc */ @@ -2159,7 +2159,7 @@ export declare interface ContainerStyleRangeToken extends BaseToken { /** * @inheritdoc */ -export declare interface MediaRangeQueryToken extends BaseToken { +declare interface MediaRangeQueryToken extends BaseToken { /** * @inheritdoc */ @@ -2189,7 +2189,7 @@ export declare interface MediaRangeQueryToken extends BaseToken { /** * @inheritdoc */ -export declare interface InvalidMediaQueryToken extends BaseToken { +declare interface InvalidMediaQueryToken extends BaseToken { /** * @inheritdoc */ @@ -2204,7 +2204,7 @@ export declare interface InvalidMediaQueryToken extends BaseToken { /** * Descendant combinator token */ -export declare interface DescendantCombinatorToken extends BaseToken { +declare interface DescendantCombinatorToken extends BaseToken { /** * @inheritdoc */ @@ -2214,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 */ @@ -2224,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 */ @@ -2234,7 +2234,7 @@ export declare interface SubsequentCombinatorToken extends BaseToken { /** * Add token */ -export declare interface AddToken extends BaseToken { +declare interface AddToken extends BaseToken { /** * @inheritdoc */ @@ -2244,7 +2244,7 @@ export declare interface AddToken extends BaseToken { /** * Sub token */ -export declare interface SubToken extends BaseToken { +declare interface SubToken extends BaseToken { /** * @inheritdoc */ @@ -2254,7 +2254,7 @@ export declare interface SubToken extends BaseToken { /** * Div token */ -export declare interface DivToken extends BaseToken { +declare interface DivToken extends BaseToken { /** * @inheritdoc */ @@ -2264,7 +2264,7 @@ export declare interface DivToken extends BaseToken { /** * Mul token */ -export declare interface MulToken extends BaseToken { +declare interface MulToken extends BaseToken { /** * @inheritdoc */ @@ -2274,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 */ @@ -2288,7 +2288,7 @@ export declare interface WrappedValuesToken extends BaseToken { /** * Unary expression token */ -export declare interface UnaryExpression extends BaseToken { +declare interface UnaryExpression extends BaseToken { /** * @inheritdoc */ @@ -2306,7 +2306,7 @@ export declare interface UnaryExpression extends BaseToken { /** * Fraction token */ -export declare interface FractionToken extends BaseToken { +declare interface FractionToken extends BaseToken { /** * @inheritdoc */ @@ -2324,7 +2324,7 @@ export declare interface FractionToken extends BaseToken { /** * Binary expression token */ -export declare interface BinaryExpressionToken extends BaseToken { +declare interface BinaryExpressionToken extends BaseToken { /** * @inheritdoc */ @@ -2346,7 +2346,7 @@ export declare interface BinaryExpressionToken extends BaseToken { /** * Match expression token */ -export declare interface MatchExpressionToken extends BaseToken { +declare interface MatchExpressionToken extends BaseToken { /** * @inheritdoc */ @@ -2372,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 */ @@ -2390,7 +2390,7 @@ export declare interface NameSpaceAttributeToken extends BaseToken { /** * List token */ -export declare interface ListToken extends BaseToken { +declare interface ListToken extends BaseToken { /** * @inheritdoc */ @@ -2404,7 +2404,7 @@ export declare interface ListToken extends BaseToken { /** * Composes selector token */ -export declare interface ComposesSelectorToken extends BaseToken { +declare interface ComposesSelectorToken extends BaseToken { /** * @inheritdoc */ @@ -2422,7 +2422,7 @@ export declare interface ComposesSelectorToken extends BaseToken { /** * Css variable token */ -export declare interface CssVariableToken extends BaseToken { +declare interface CssVariableToken extends BaseToken { /** * @inheritdoc */ @@ -2440,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 */ @@ -2458,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 */ @@ -2476,7 +2476,7 @@ export declare interface CssVariableMapTokenType extends BaseToken { /** * Function definition token */ -export declare interface FunctionDefToken extends BaseToken { +declare interface FunctionDefToken extends BaseToken { /** * @inheritdoc */ @@ -2504,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 */ @@ -2518,7 +2518,7 @@ export declare interface RawNodeToken extends BaseToken, EnumAstNodeStatus$1 { /** * Unary expression node */ -export declare type UnaryExpressionNode = +declare type UnaryExpressionNode = | BinaryExpressionNode | NumberToken | DimensionToken @@ -2530,7 +2530,7 @@ export declare type UnaryExpressionNode = /** * Binary expression node */ -export declare type BinaryExpressionNode = +declare type BinaryExpressionNode = | NumberToken | DimensionToken | PercentageToken @@ -2546,7 +2546,7 @@ export declare type BinaryExpressionNode = /** * Token */ -export declare type Token$1 = +declare type Token$1 = | InvalidClassSelectorToken | InvalidAttrToken | LiteralToken @@ -2654,7 +2654,7 @@ export declare type Token$1 = /** * token or node location */ -export declare interface SourceLocation { +declare interface SourceLocation { /** * start position */ @@ -2672,7 +2672,7 @@ export declare interface SourceLocation { /** * Common token interface */ -export declare interface BaseToken { +declare interface BaseToken { /** * token type */ @@ -2745,7 +2745,7 @@ export declare interface BaseToken { /** * Ast node state */ -export declare interface AstNodeStatus { +declare interface AstNodeStatus { /** * Node state */ @@ -2759,7 +2759,7 @@ export declare interface AstNodeStatus { /** * comment node */ -export declare interface AstComment extends BaseToken { +declare interface AstComment extends BaseToken { /** * token type */ @@ -2773,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 */ @@ -2791,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 */ @@ -2820,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 */ @@ -2839,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 */ @@ -2858,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 */ @@ -2880,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 */ @@ -2911,7 +2911,7 @@ export declare interface OptimizedSelector { * * @private */ -export declare interface OptimizedSelectorToken { +declare interface OptimizedSelectorToken { /** * match */ @@ -2933,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 */ @@ -2955,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 */ @@ -2985,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 */ @@ -3011,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 */ @@ -3033,7 +3033,7 @@ export declare interface AstKeyframesAtRule extends BaseToken, AstNodeStatus { /** * rule list node */ -export declare type AstRuleList = +declare type AstRuleList = | AstStyleSheet | AstAtRule | AstRule @@ -3044,7 +3044,7 @@ export declare type AstRuleList = /** * stylesheet node */ -export declare interface AstStyleSheet extends BaseToken { +declare interface AstStyleSheet extends BaseToken { /** * token type */ @@ -3058,7 +3058,7 @@ export declare interface AstStyleSheet extends BaseToken { /** * ast node */ -export declare type AstNode$1 = +declare type AstNode$1 = | AstStyleSheet | AstRuleList | AstComment @@ -3338,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, @@ -3360,7 +3360,7 @@ export declare type GenericVisitorSyncHandler = ( /** * Generic visitor handler */ -export declare type GenericVisitorAstNodeSyncHandlerMap = +declare type GenericVisitorAstNodeSyncHandlerMap = | Record> | GenericVisitorSyncHandler | { type: WalkerEvent; handler: GenericVisitorSyncHandler } @@ -3369,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 * @@ -3634,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, @@ -3643,7 +3643,7 @@ export declare type GenericVisitorHandler = ( /** * Generic visitor handler */ -export declare type GenericVisitorAstNodeHandlerMap = +declare type GenericVisitorAstNodeHandlerMap = | Record> | GenericVisitorHandler | { type: WalkerEvent; handler: GenericVisitorHandler } @@ -3652,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 * @@ -4147,7 +4147,7 @@ declare class SourceFile { getInputSourceMap(): SourceMap | null; } -export declare interface PropertyListOptions { +declare interface PropertyListOptions { removeDuplicateDeclarations?: boolean | string | string[]; computeShorthand?: boolean; } @@ -4155,7 +4155,7 @@ export declare interface PropertyListOptions { /** * parse info */ -export declare interface ParseInfo$1 { +declare interface ParseInfo$1 { /** * stream */ @@ -4531,7 +4531,7 @@ interface ShorthandType { /** * @private */ -export declare interface PropertiesConfig { +declare interface PropertiesConfig { /** * shorthand property minification rules */ @@ -4940,7 +4940,7 @@ interface BorderRadius { /** * node walker options */ -export declare interface WalkerOptions { +declare interface WalkerOptions { /** * walk in reverse */ @@ -4959,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 @@ -4969,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: @@ -4980,7 +4980,7 @@ 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, @@ -4990,7 +4990,7 @@ export declare type WalkerValueFilter = ( /** * walker result */ -export declare interface WalkResult { +declare interface WalkResult { /** * current node */ @@ -5012,7 +5012,7 @@ export declare interface WalkResult { /** * walker result */ -export declare interface WalkAttributesResult { +declare interface WalkAttributesResult { /** * current node */ @@ -5042,7 +5042,7 @@ export declare interface WalkAttributesResult { /** * Error description */ -export declare interface ErrorDescription$1 { +declare interface ErrorDescription$1 { /** * Drop rule or declaration */ @@ -5220,7 +5220,7 @@ interface MinifyOptions { /** * Result of options.load() function call. */ -export declare type LoadResult = +declare type LoadResult = | Promise> | ReadableStream | string @@ -5229,7 +5229,7 @@ export declare type LoadResult = /** * CSS module parser options */ -export declare interface ModuleSyncOptions { +declare interface ModuleSyncOptions { /** * Use local scope vs global scope */ @@ -5339,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 @@ -5434,7 +5434,7 @@ export declare interface ModuleAsyncOptions extends ModuleSyncOptions { /** * Input file options */ -export declare interface ParseInputFileOptions { +declare interface ParseInputFileOptions { /** * File path or url */ @@ -5449,7 +5449,7 @@ export declare interface ParseInputFileOptions { /** * Input options for string or stream */ -export declare interface ParseInputOptions { +declare interface ParseInputOptions { /** * Input string or stream */ @@ -5458,7 +5458,7 @@ export declare interface ParseInputOptions { /** * Input options for string or stream */ -export declare interface ParseInputStreamOptions { +declare interface ParseInputStreamOptions { /** * Input string or stream */ @@ -5469,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 @@ -5485,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 */ @@ -5499,7 +5499,7 @@ export declare interface ParserSourceMapOptions { /** * Sync parseroptions */ -export declare interface ParserSyncOptions +declare interface ParserSyncOptions extends MinifyOptions, ParserSourceMapOptions, @@ -5610,7 +5610,7 @@ export declare interface ParserSyncOptions /** * Parser options */ -export declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOptions { +declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOptions { /** * Resolve import */ @@ -5645,7 +5645,7 @@ export declare interface ParserOptions extends ParserSyncOptions, ModuleAsyncOpt * * @internal */ -export declare interface MinifyFeatureOptions { +declare interface MinifyFeatureOptions { /** * Minify features * @@ -5659,7 +5659,7 @@ export declare interface MinifyFeatureOptions { * * @internal */ -export declare interface MinifyFeature { +declare interface MinifyFeature { /** * Accepted tokens */ @@ -5701,7 +5701,7 @@ export declare interface MinifyFeature { * Resolved path * @internal */ -export declare interface ResolvedPath { +declare interface ResolvedPath { /** * Absolute path */ @@ -5715,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 */ @@ -5807,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 */ @@ -5871,7 +5871,7 @@ export declare interface ParseResultStats { /** * Parse result object */ -export declare interface ParseResult { +declare interface ParseResult { /** * Parsed ast tree */ @@ -5912,7 +5912,7 @@ export declare interface ParseResult { /** * Render result object */ -export declare interface RenderResult { +declare interface RenderResult { /** * Rendered CSS */ @@ -5939,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 */ @@ -5986,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 */ @@ -6007,7 +6007,7 @@ export declare interface TokenizeResult { * Matched selector object * @internal */ -export declare interface MatchedSelector { +declare interface MatchedSelector { /** * Matched selector */ @@ -6030,7 +6030,7 @@ export declare interface MatchedSelector { * Variable scope info object * @internal */ -export declare interface VariableScopeInfo { +declare interface VariableScopeInfo { /** * Global scope */ @@ -6061,7 +6061,7 @@ export declare interface VariableScopeInfo { * Source map object * @internal */ -export declare interface SourceMapObject { +declare interface SourceMapObject { /** * Source map version */ @@ -6116,7 +6116,7 @@ declare const resolve: (url: string, currentDirectory?: string, cwd?: string) => * Validation syntax * @internal */ -export declare interface ValidationSyntaxNode { +declare interface ValidationSyntaxNode { /** * mdn data syntax */ @@ -6146,7 +6146,7 @@ interface ValidationSelectorOptions extends ValidationOptions { * Validation media feature * @internal */ -export declare interface ValidationMediaFeature { +declare interface ValidationMediaFeature { /** * media feature type */ @@ -6169,7 +6169,7 @@ export declare interface ValidationMediaFeature { * Validation configuration * @internal */ -export declare type ValidationConfiguration = Record< +declare type ValidationConfiguration = Record< ValidationSyntaxGroupEnum, ValidationSyntaxNode | Record | Record >; 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/parse.js b/dist/lib/parser/parse.js index ee5055c2..1ab703dd 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -900,7 +900,7 @@ function doParseSync(tokenizer, 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) { @@ -1893,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) { @@ -3695,7 +3695,6 @@ function parseTokens(tokens, options, errors) { node, location: options.source.getSourceLocation(node[LOCSTA]), }); - // return []; } return tokens; } 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/parse.ts b/src/lib/parser/parse.ts index d57b5202..bc4d1375 100644 --- a/src/lib/parser/parse.ts +++ b/src/lib/parser/parse.ts @@ -1175,7 +1175,7 @@ export function doParseSync(tokenizer: Tokenizer, options: ParserSyncOptions = { 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") { @@ -2409,7 +2409,7 @@ export async function doParse(iter: Tokenizer | Promise, options: Par 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") { @@ -4374,7 +4374,7 @@ export function parseString( const tokenizer: Tokenizer = new Tokenizer({ stream: src, buffer: "", - src: options?.src ?? "", + src: options?.src ?? "", offset: 0, time: 0, source: new SourceFile(src, [], options?.src ?? ""), @@ -4688,8 +4688,6 @@ export function parseTokens( node, location: options.source!.getSourceLocation(node[LOCSTA]!), }); - - // return []; } return tokens;