Spaces:
Paused
Paused
| /** | |
| * Parse CSS following the {@link https://drafts.csswg.org/css-syntax/#parsing | CSS Syntax Level 3 specification}. | |
| * | |
| * @remarks | |
| * The tokenizing and parsing tools provided by CSS Tools are designed to be low level and generic with strong ties to their respective specifications. | |
| * | |
| * Any analysis or mutation of CSS source code should be done with the least powerful tool that can accomplish the task. | |
| * For many applications it is sufficient to work with tokens. | |
| * For others you might need to use {@link https://github.com/csstools/postcss-plugins/tree/main/packages/css-parser-algorithms | @csstools/css-parser-algorithms} or a more specific parser. | |
| * | |
| * The implementation of the AST nodes is kept lightweight and simple. | |
| * Do not expect magic methods, instead assume that arrays and class instances behave like any other JavaScript. | |
| * | |
| * @example | |
| * Parse a string of CSS into a component value: | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseComponentValue } from '@csstools/css-parser-algorithms'; | |
| * | |
| * const myCSS = `calc(1px * 2)`; | |
| * | |
| * const componentValue = parseComponentValue(tokenize({ | |
| * css: myCSS, | |
| * })); | |
| * | |
| * console.log(componentValue); | |
| * ``` | |
| * | |
| * @example | |
| * Use the right algorithm for the job. | |
| * | |
| * Algorithms that can parse larger structures (comma-separated lists, ...) can also parse smaller structures. | |
| * However, the opposite is not true. | |
| * | |
| * If your context allows a list of component values, use {@link parseListOfComponentValues}: | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseListOfComponentValues } from '@csstools/css-parser-algorithms'; | |
| * | |
| * parseListOfComponentValues(tokenize({ css: `10x 20px` })); | |
| * ``` | |
| * | |
| * If your context allows a comma-separated list of component values, use {@link parseCommaSeparatedListOfComponentValues}: | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseCommaSeparatedListOfComponentValues } from '@csstools/css-parser-algorithms'; | |
| * | |
| * parseCommaSeparatedListOfComponentValues(tokenize({ css: `20deg, 50%, 30%` })); | |
| * ``` | |
| * | |
| * @example | |
| * Use the stateful walkers to keep track of the context of a given component value. | |
| * | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseComponentValue, isSimpleBlockNode } from '@csstools/css-parser-algorithms'; | |
| * | |
| * const myCSS = `calc(1px * (5 / 2))`; | |
| * | |
| * const componentValue = parseComponentValue(tokenize({ css: myCSS })); | |
| * | |
| * let state = { inSimpleBlock: false }; | |
| * componentValue.walk((entry) => { | |
| * if (isSimpleBlockNode(entry)) { | |
| * entry.state.inSimpleBlock = true; | |
| * return; | |
| * } | |
| * | |
| * if (entry.state.inSimpleBlock) { | |
| * console.log(entry.node.toString()); // `5`, ... | |
| * } | |
| * }, state); | |
| * ``` | |
| * | |
| * @packageDocumentation | |
| */ | |
| import type { CSSToken } from '@csstools/css-tokenizer'; | |
| import { ParseError } from '@csstools/css-tokenizer'; | |
| import type { TokenFunction } from '@csstools/css-tokenizer'; | |
| export declare class CommentNode { | |
| /** | |
| * The node type, always `ComponentValueType.Comment` | |
| */ | |
| type: ComponentValueType; | |
| /** | |
| * The comment token. | |
| */ | |
| value: CSSToken; | |
| constructor(value: CSSToken); | |
| /** | |
| * Retrieve the tokens for the current comment. | |
| * This is the inverse of parsing from a list of tokens. | |
| */ | |
| tokens(): Array<CSSToken>; | |
| /** | |
| * Convert the current comment to a string. | |
| * This is not a true serialization. | |
| * It is purely a concatenation of the string representation of the tokens. | |
| */ | |
| toString(): string; | |
| /** | |
| * @internal | |
| * | |
| * A debug helper to convert the current object to a JSON representation. | |
| * This is useful in asserts and to store large ASTs in files. | |
| */ | |
| toJSON(): Record<string, unknown>; | |
| /** | |
| * @internal | |
| */ | |
| isCommentNode(): this is CommentNode; | |
| /** | |
| * @internal | |
| */ | |
| static isCommentNode(x: unknown): x is CommentNode; | |
| } | |
| export declare type ComponentValue = FunctionNode | SimpleBlockNode | WhitespaceNode | CommentNode | TokenNode; | |
| export declare enum ComponentValueType { | |
| Function = "function", | |
| SimpleBlock = "simple-block", | |
| Whitespace = "whitespace", | |
| Comment = "comment", | |
| Token = "token" | |
| } | |
| export declare type ContainerNode = FunctionNode | SimpleBlockNode; | |
| export declare abstract class ContainerNodeBaseClass { | |
| /** | |
| * The contents of the `Function` or `Simple Block`. | |
| * This is a list of component values. | |
| */ | |
| value: Array<ComponentValue>; | |
| /** | |
| * Retrieve the index of the given item in the current node. | |
| * For most node types this will be trivially implemented as `this.value.indexOf(item)`. | |
| */ | |
| indexOf(item: ComponentValue): number | string; | |
| /** | |
| * Retrieve the item at the given index in the current node. | |
| * For most node types this will be trivially implemented as `this.value[index]`. | |
| */ | |
| at(index: number | string): ComponentValue | undefined; | |
| /** | |
| * Iterates over each item in the `value` array of the current node. | |
| * | |
| * @param cb - The callback function to execute for each item. | |
| * The function receives an object containing the current node (`node`), its parent (`parent`), | |
| * and an optional `state` object. | |
| * A second parameter is the index of the current node. | |
| * The function can return `false` to stop the iteration. | |
| * | |
| * @param state - An optional state object that can be used to pass additional information to the callback function. | |
| * The state object is cloned for each iteration. This means that changes to the state object are not reflected in the next iteration. | |
| * | |
| * @returns `false` if the iteration was halted, `undefined` otherwise. | |
| */ | |
| forEach<T extends Record<string, unknown>, U extends ContainerNode>(this: U, cb: (entry: { | |
| node: ComponentValue; | |
| parent: ContainerNode; | |
| state?: T; | |
| }, index: number | string) => boolean | void, state?: T): false | undefined; | |
| /** | |
| * Walks the current node and all its children. | |
| * | |
| * @param cb - The callback function to execute for each item. | |
| * The function receives an object containing the current node (`node`), its parent (`parent`), | |
| * and an optional `state` object. | |
| * A second parameter is the index of the current node. | |
| * The function can return `false` to stop the iteration. | |
| * | |
| * @param state - An optional state object that can be used to pass additional information to the callback function. | |
| * The state object is cloned for each iteration. This means that changes to the state object are not reflected in the next iteration. | |
| * However changes are passed down to child node iterations. | |
| * | |
| * @returns `false` if the iteration was halted, `undefined` otherwise. | |
| */ | |
| walk<T extends Record<string, unknown>, U extends ContainerNode>(this: U, cb: (entry: { | |
| node: ComponentValue; | |
| parent: ContainerNode; | |
| state?: T; | |
| }, index: number | string) => boolean | void, state?: T): false | undefined; | |
| } | |
| /** | |
| * Iterates over each item in a list of component values. | |
| * | |
| * @param cb - The callback function to execute for each item. | |
| * The function receives an object containing the current node (`node`), its parent (`parent`), | |
| * and an optional `state` object. | |
| * A second parameter is the index of the current node. | |
| * The function can return `false` to stop the iteration. | |
| * | |
| * @param state - An optional state object that can be used to pass additional information to the callback function. | |
| * The state object is cloned for each iteration. This means that changes to the state object are not reflected in the next iteration. | |
| * | |
| * @returns `false` if the iteration was halted, `undefined` otherwise. | |
| */ | |
| export declare function forEach<T extends Record<string, unknown>>(componentValues: Array<ComponentValue>, cb: (entry: { | |
| node: ComponentValue; | |
| parent: ContainerNode | { | |
| value: Array<ComponentValue>; | |
| }; | |
| state?: T; | |
| }, index: number | string) => boolean | void, state?: T): false | undefined; | |
| /** | |
| * A function node. | |
| * | |
| * @example | |
| * ```js | |
| * const node = parseComponentValue(tokenize('calc(1 + 1)')); | |
| * | |
| * isFunctionNode(node); // true | |
| * node.getName(); // 'calc' | |
| * ``` | |
| */ | |
| export declare class FunctionNode extends ContainerNodeBaseClass { | |
| /** | |
| * The node type, always `ComponentValueType.Function` | |
| */ | |
| type: ComponentValueType; | |
| /** | |
| * The token for the name of the function. | |
| */ | |
| name: TokenFunction; | |
| /** | |
| * The token for the closing parenthesis of the function. | |
| * If the function is unclosed, this will be an EOF token. | |
| */ | |
| endToken: CSSToken; | |
| constructor(name: TokenFunction, endToken: CSSToken, value: Array<ComponentValue>); | |
| /** | |
| * Retrieve the name of the current function. | |
| * This is the parsed and unescaped name of the function. | |
| */ | |
| getName(): string; | |
| /** | |
| * Normalize the current function: | |
| * 1. if the "endToken" is EOF, replace with a ")-token" | |
| */ | |
| normalize(): void; | |
| /** | |
| * Retrieve the tokens for the current function. | |
| * This is the inverse of parsing from a list of tokens. | |
| */ | |
| tokens(): Array<CSSToken>; | |
| /** | |
| * Convert the current function to a string. | |
| * This is not a true serialization. | |
| * It is purely a concatenation of the string representation of the tokens. | |
| */ | |
| toString(): string; | |
| /** | |
| * @internal | |
| * | |
| * A debug helper to convert the current object to a JSON representation. | |
| * This is useful in asserts and to store large ASTs in files. | |
| */ | |
| toJSON(): unknown; | |
| /** | |
| * @internal | |
| */ | |
| isFunctionNode(): this is FunctionNode; | |
| /** | |
| * @internal | |
| */ | |
| static isFunctionNode(x: unknown): x is FunctionNode; | |
| } | |
| /** | |
| * AST nodes do not have a `parent` property or method. | |
| * This makes it harder to traverse the AST upwards. | |
| * This function builds a `Map<Child, Parent>` that can be used to lookup ancestors of a node. | |
| * | |
| * @remarks | |
| * There is no magic behind this or the map it returns. | |
| * Mutating the AST will not update the map. | |
| * | |
| * Types are erased and any content of the map has type `unknown`. | |
| * If someone knows a clever way to type this, please let us know. | |
| * | |
| * @example | |
| * ```js | |
| * const ancestry = gatherNodeAncestry(mediaQuery); | |
| * mediaQuery.walk((entry) => { | |
| * const node = entry.node; // directly exposed | |
| * const parent = entry.parent; // directly exposed | |
| * const grandParent: unknown = ancestry.get(parent); // lookup | |
| * | |
| * console.log('node', node); | |
| * console.log('parent', parent); | |
| * console.log('grandParent', grandParent); | |
| * }); | |
| * ``` | |
| */ | |
| export declare function gatherNodeAncestry(node: { | |
| walk(cb: (entry: { | |
| node: unknown; | |
| parent: unknown; | |
| }, index: number | string) => boolean | void): false | undefined; | |
| }): Map<unknown, unknown>; | |
| /** | |
| * Check if the current object is a `CommentNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isCommentNode(x: unknown): x is CommentNode; | |
| /** | |
| * Check if the current object is a `FunctionNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isFunctionNode(x: unknown): x is FunctionNode; | |
| /** | |
| * Check if the current object is a `SimpleBlockNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isSimpleBlockNode(x: unknown): x is SimpleBlockNode; | |
| /** | |
| * Check if the current object is a `TokenNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isTokenNode(x: unknown): x is TokenNode; | |
| /** | |
| * Check if the current object is a `WhitespaceNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isWhitespaceNode(x: unknown): x is WhitespaceNode; | |
| /** | |
| * Check if the current object is a `WhiteSpaceNode` or a `CommentNode`. | |
| * This is a type guard. | |
| */ | |
| export declare function isWhiteSpaceOrCommentNode(x: unknown): x is WhitespaceNode | CommentNode; | |
| /** | |
| * Parse a comma-separated list of component values. | |
| * | |
| * @example | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseCommaSeparatedListOfComponentValues } from '@csstools/css-parser-algorithms'; | |
| * | |
| * parseCommaSeparatedListOfComponentValues(tokenize({ css: `20deg, 50%, 30%` })); | |
| * ``` | |
| */ | |
| export declare function parseCommaSeparatedListOfComponentValues(tokens: Array<CSSToken>, options?: { | |
| onParseError?: (error: ParseError) => void; | |
| }): Array<Array<ComponentValue>>; | |
| /** | |
| * Parse a single component value. | |
| * | |
| * @example | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseComponentValue } from '@csstools/css-parser-algorithms'; | |
| * | |
| * parseComponentValue(tokenize({ css: `10px` })); | |
| * parseComponentValue(tokenize({ css: `calc((10px + 1x) * 4)` })); | |
| * ``` | |
| */ | |
| export declare function parseComponentValue(tokens: Array<CSSToken>, options?: { | |
| onParseError?: (error: ParseError) => void; | |
| }): ComponentValue | undefined; | |
| /** | |
| * Parse a list of component values. | |
| * | |
| * @example | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseListOfComponentValues } from '@csstools/css-parser-algorithms'; | |
| * | |
| * parseListOfComponentValues(tokenize({ css: `20deg 30%` })); | |
| * ``` | |
| */ | |
| export declare function parseListOfComponentValues(tokens: Array<CSSToken>, options?: { | |
| onParseError?: (error: ParseError) => void; | |
| }): Array<ComponentValue>; | |
| /** | |
| * Replace specific component values in a list of component values. | |
| * A helper for the most common and simplistic cases when mutating an AST. | |
| */ | |
| export declare function replaceComponentValues(componentValuesList: Array<Array<ComponentValue>>, replaceWith: (componentValue: ComponentValue) => Array<ComponentValue> | ComponentValue | void): Array<Array<ComponentValue>>; | |
| /** | |
| * A simple block node. | |
| * | |
| * @example | |
| * ```js | |
| * const node = parseComponentValue(tokenize('[foo=bar]')); | |
| * | |
| * isSimpleBlockNode(node); // true | |
| * node.startToken; // [TokenType.OpenSquare, '[', 0, 0, undefined] | |
| * ``` | |
| */ | |
| export declare class SimpleBlockNode extends ContainerNodeBaseClass { | |
| /** | |
| * The node type, always `ComponentValueType.SimpleBlock` | |
| */ | |
| type: ComponentValueType; | |
| /** | |
| * The token for the opening token of the block. | |
| */ | |
| startToken: CSSToken; | |
| /** | |
| * The token for the closing token of the block. | |
| * If the block is closed it will be the mirror variant of the `startToken`. | |
| * If the block is unclosed, this will be an EOF token. | |
| */ | |
| endToken: CSSToken; | |
| constructor(startToken: CSSToken, endToken: CSSToken, value: Array<ComponentValue>); | |
| /** | |
| * Normalize the current simple block | |
| * 1. if the "endToken" is EOF, replace with the mirror token of the "startToken" | |
| */ | |
| normalize(): void; | |
| /** | |
| * Retrieve the tokens for the current simple block. | |
| * This is the inverse of parsing from a list of tokens. | |
| */ | |
| tokens(): Array<CSSToken>; | |
| /** | |
| * Convert the current simple block to a string. | |
| * This is not a true serialization. | |
| * It is purely a concatenation of the string representation of the tokens. | |
| */ | |
| toString(): string; | |
| /** | |
| * @internal | |
| * | |
| * A debug helper to convert the current object to a JSON representation. | |
| * This is useful in asserts and to store large ASTs in files. | |
| */ | |
| toJSON(): unknown; | |
| /** | |
| * @internal | |
| */ | |
| isSimpleBlockNode(): this is SimpleBlockNode; | |
| /** | |
| * @internal | |
| */ | |
| static isSimpleBlockNode(x: unknown): x is SimpleBlockNode; | |
| } | |
| /** | |
| * Returns the start and end index of a node in the CSS source string. | |
| */ | |
| export declare function sourceIndices(x: { | |
| tokens(): Array<CSSToken>; | |
| } | Array<{ | |
| tokens(): Array<CSSToken>; | |
| }>): [number, number]; | |
| /** | |
| * Concatenate the string representation of a collection of component values. | |
| * This is not a proper serializer that will handle escaping and whitespace. | |
| * It only produces valid CSS for token lists that are also valid. | |
| */ | |
| export declare function stringify(componentValueLists: Array<Array<ComponentValue>>): string; | |
| export declare class TokenNode { | |
| /** | |
| * The node type, always `ComponentValueType.Token` | |
| */ | |
| type: ComponentValueType; | |
| /** | |
| * The token. | |
| */ | |
| value: CSSToken; | |
| constructor(value: CSSToken); | |
| /** | |
| * This is the inverse of parsing from a list of tokens. | |
| */ | |
| tokens(): [CSSToken]; | |
| /** | |
| * Convert the current token to a string. | |
| * This is not a true serialization. | |
| * It is purely the string representation of token. | |
| */ | |
| toString(): string; | |
| /** | |
| * @internal | |
| * | |
| * A debug helper to convert the current object to a JSON representation. | |
| * This is useful in asserts and to store large ASTs in files. | |
| */ | |
| toJSON(): Record<string, unknown>; | |
| /** | |
| * @internal | |
| */ | |
| isTokenNode(): this is TokenNode; | |
| /** | |
| * @internal | |
| */ | |
| static isTokenNode(x: unknown): x is TokenNode; | |
| } | |
| /** | |
| * Walks each item in a list of component values all of their children. | |
| * | |
| * @param cb - The callback function to execute for each item. | |
| * The function receives an object containing the current node (`node`), its parent (`parent`), | |
| * and an optional `state` object. | |
| * A second parameter is the index of the current node. | |
| * The function can return `false` to stop the iteration. | |
| * | |
| * @param state - An optional state object that can be used to pass additional information to the callback function. | |
| * The state object is cloned for each iteration. This means that changes to the state object are not reflected in the next iteration. | |
| * However changes are passed down to child node iterations. | |
| * | |
| * @returns `false` if the iteration was halted, `undefined` otherwise. | |
| * | |
| * @example | |
| * ```js | |
| * import { tokenize } from '@csstools/css-tokenizer'; | |
| * import { parseListOfComponentValues, isSimpleBlockNode } from '@csstools/css-parser-algorithms'; | |
| * | |
| * const myCSS = `calc(1px * (5 / 2)) 10px`; | |
| * | |
| * const componentValues = parseListOfComponentValues(tokenize({ css: myCSS })); | |
| * | |
| * let state = { inSimpleBlock: false }; | |
| * walk(componentValues, (entry) => { | |
| * if (isSimpleBlockNode(entry)) { | |
| * entry.state.inSimpleBlock = true; | |
| * return; | |
| * } | |
| * | |
| * if (entry.state.inSimpleBlock) { | |
| * console.log(entry.node.toString()); // `5`, ... | |
| * } | |
| * }, state); | |
| * ``` | |
| */ | |
| export declare function walk<T extends Record<string, unknown>>(componentValues: Array<ComponentValue>, cb: (entry: { | |
| node: ComponentValue; | |
| parent: ContainerNode | { | |
| value: Array<ComponentValue>; | |
| }; | |
| state?: T; | |
| }, index: number | string) => boolean | void, state?: T): false | undefined; | |
| /** | |
| * Generate a function that finds the next element that should be visited when walking an AST. | |
| * Rules : | |
| * 1. the previous iteration is used as a reference, so any checks are relative to the start of the current iteration. | |
| * 2. the next element always appears after the current index. | |
| * 3. the next element always exists in the list. | |
| * 4. replacing an element does not cause the replaced element to be visited. | |
| * 5. removing an element does not cause elements to be skipped. | |
| * 6. an element added later in the list will be visited. | |
| */ | |
| export declare function walkerIndexGenerator<T>(initialList: Array<T>): (list: Array<T>, child: T, index: number) => number; | |
| export declare class WhitespaceNode { | |
| /** | |
| * The node type, always `ComponentValueType.WhiteSpace` | |
| */ | |
| type: ComponentValueType; | |
| /** | |
| * The list of consecutive whitespace tokens. | |
| */ | |
| value: Array<CSSToken>; | |
| constructor(value: Array<CSSToken>); | |
| /** | |
| * Retrieve the tokens for the current whitespace. | |
| * This is the inverse of parsing from a list of tokens. | |
| */ | |
| tokens(): Array<CSSToken>; | |
| /** | |
| * Convert the current whitespace to a string. | |
| * This is not a true serialization. | |
| * It is purely a concatenation of the string representation of the tokens. | |
| */ | |
| toString(): string; | |
| /** | |
| * @internal | |
| * | |
| * A debug helper to convert the current object to a JSON representation. | |
| * This is useful in asserts and to store large ASTs in files. | |
| */ | |
| toJSON(): Record<string, unknown>; | |
| /** | |
| * @internal | |
| */ | |
| isWhitespaceNode(): this is WhitespaceNode; | |
| /** | |
| * @internal | |
| */ | |
| static isWhitespaceNode(x: unknown): x is WhitespaceNode; | |
| } | |
| export { } | |