diff --git a/packages/css-parser-algorithms/CHANGELOG.md b/packages/css-parser-algorithms/CHANGELOG.md index 4e2617a70..8801d8f99 100644 --- a/packages/css-parser-algorithms/CHANGELOG.md +++ b/packages/css-parser-algorithms/CHANGELOG.md @@ -1,8 +1,11 @@ # Changes to CSS Parser Algorithms -### Unreleased (patch) +### Unreleased (minor) - Small fixes in type definitions +- Only `walk` child nodes if they are still part of the current AST tree [#1202](https://github.com/csstools/postcss-plugins/issues/1202) +- Make `walk` methods safe for mutations [#1204](https://github.com/csstools/postcss-plugins/issues/1204) +- Add a `forEach` method to `FunctionNode` and `SimpleBlockNode` ### 2.3.2 diff --git a/packages/css-parser-algorithms/dist/consume/consume-component-block-function.d.ts b/packages/css-parser-algorithms/dist/consume/consume-component-block-function.d.ts index 59cdf944a..f8272d80f 100644 --- a/packages/css-parser-algorithms/dist/consume/consume-component-block-function.d.ts +++ b/packages/css-parser-algorithms/dist/consume/consume-component-block-function.d.ts @@ -7,40 +7,129 @@ export declare function consumeComponentValue(ctx: Context, tokens: Array; + /** + * 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. + * + * @template T - The type of the `state` object. + * @template U - The type of the current node. + */ + forEach, 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. + * + * @template T - The type of the `state` object. + * @template U - The type of the current node. + */ + walk, U extends ContainerNode>(this: U, cb: (entry: { + node: ComponentValue; + parent: ContainerNode; + state?: T; + }, index: number | string) => boolean | void, state?: T): false | undefined; +} +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; - value: Array; constructor(name: TokenFunction, endToken: CSSToken, value: Array); + /** + * Retrieve the name of the current Function. + * This is the parsed and unescaped name of the function. + */ getName(): string; /** * Normalize the current Function: * - 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; + /** + * 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; - indexOf(item: ComponentValue): number | string; - at(index: number | string): ComponentValue | undefined; - walk>(cb: (entry: { - node: ComponentValue; - parent: ContainerNode; - state?: T; - }, index: number | string) => boolean | void, state?: T): false | undefined; + /** + * 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; + /** + * Check if the current object is a FunctionNode. + * This is a type guard to help with type narrowing. + */ isFunctionNode(): this is FunctionNode; + /** + * Check if the given object is a FunctionNode. + * This is a type guard to help with type narrowing. + */ static isFunctionNode(x: unknown): x is FunctionNode; } export declare function consumeFunction(ctx: Context, tokens: Array): { advance: number; node: FunctionNode; }; -export declare class SimpleBlockNode { +export declare class SimpleBlockNode extends ContainerNodeBaseClass { type: ComponentValueType; startToken: CSSToken; endToken: CSSToken; - value: Array; constructor(startToken: CSSToken, endToken: CSSToken, value: Array); /** * Normalize the current Simple Block: @@ -51,11 +140,6 @@ export declare class SimpleBlockNode { toString(): string; indexOf(item: ComponentValue): number | string; at(index: number | string): ComponentValue | undefined; - walk>(cb: (entry: { - node: ComponentValue; - parent: ContainerNode; - state?: T; - }, index: number | string) => boolean | void, state?: T): false | undefined; toJSON(): unknown; isSimpleBlockNode(): this is SimpleBlockNode; static isSimpleBlockNode(x: unknown): x is SimpleBlockNode; @@ -116,3 +200,4 @@ export declare class TokenNode { isTokenNode(): this is TokenNode; static isTokenNode(x: unknown): x is TokenNode; } +export {}; diff --git a/packages/css-parser-algorithms/dist/index.cjs b/packages/css-parser-algorithms/dist/index.cjs index 4405dce4d..a1eaf2076 100644 --- a/packages/css-parser-algorithms/dist/index.cjs +++ b/packages/css-parser-algorithms/dist/index.cjs @@ -1 +1 @@ -"use strict";var e,n=require("@csstools/css-tokenizer");function consumeComponentValue(e,o){const t=o[0];if(t[0]===n.TokenType.OpenParen||t[0]===n.TokenType.OpenCurly||t[0]===n.TokenType.OpenSquare){const n=consumeSimpleBlock(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Function){const n=consumeFunction(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Whitespace){const n=consumeWhitespace(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Comment){const n=consumeComment(e,o);return{advance:n.advance,node:n.node}}return{advance:1,node:new TokenNode(t)}}exports.ComponentValueType=void 0,(e=exports.ComponentValueType||(exports.ComponentValueType={})).Function="function",e.SimpleBlock="simple-block",e.Whitespace="whitespace",e.Comment="comment",e.Token="token";class FunctionNode{type=exports.ComponentValueType.Function;name;endToken;value;constructor(e,n,o){this.name=e,this.endToken=n,this.value=o}getName(){return this.name[4].value}normalize(){this.endToken[0]===n.TokenType.EOF&&(this.endToken=[n.TokenType.CloseParen,")",-1,-1,void 0])}tokens(){return this.endToken[0]===n.TokenType.EOF?[this.name,...this.value.flatMap((e=>e.tokens()))]:[this.name,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n.isToken(e)?n.stringify(e):e.toString())).join("");return n.stringify(this.name)+e+n.stringify(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}walk(e,n){let o=!1;if(this.value.forEach(((t,s)=>{if(o)return;let i;n&&(i={...n}),!1!==e({node:t,parent:this,state:i},s)?"walk"in t&&!1===t.walk(e,i)&&(o=!0):o=!0})),o)return!1}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isFunctionNode(){return FunctionNode.isFunctionNode(this)}static isFunctionNode(e){return!!e&&(e instanceof FunctionNode&&e.type===exports.ComponentValueType.Function)}}function consumeFunction(e,o){const t=[];let s=1;for(;;){const i=o[s];if(!i||i[0]===n.TokenType.EOF)return e.onParseError(new n.ParseError("Unexpected EOF while consuming a function.",o[0][2],o[o.length-1][3],["5.4.9. Consume a function","Unexpected EOF"])),{advance:o.length,node:new FunctionNode(o[0],i,t)};if(i[0]===n.TokenType.CloseParen)return{advance:s+1,node:new FunctionNode(o[0],i,t)};if(i[0]===n.TokenType.Comment||i[0]===n.TokenType.Whitespace){const n=consumeAllCommentsAndWhitespace(e,o.slice(s));s+=n.advance,t.push(...n.nodes);continue}const r=consumeComponentValue(e,o.slice(s));s+=r.advance,t.push(r.node)}}class SimpleBlockNode{type=exports.ComponentValueType.SimpleBlock;startToken;endToken;value;constructor(e,n,o){this.startToken=e,this.endToken=n,this.value=o}normalize(){if(this.endToken[0]===n.TokenType.EOF){const e=n.mirrorVariant(this.startToken);e&&(this.endToken=e)}}tokens(){return this.endToken[0]===n.TokenType.EOF?[this.startToken,...this.value.flatMap((e=>e.tokens()))]:[this.startToken,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n.isToken(e)?n.stringify(e):e.toString())).join("");return n.stringify(this.startToken)+e+n.stringify(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}walk(e,n){let o=!1;if(this.value.forEach(((t,s)=>{if(o)return;let i;n&&(i={...n}),!1!==e({node:t,parent:this,state:i},s)?"walk"in t&&!1===t.walk(e,i)&&(o=!0):o=!0})),o)return!1}toJSON(){return{type:this.type,startToken:this.startToken,tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isSimpleBlockNode(){return SimpleBlockNode.isSimpleBlockNode(this)}static isSimpleBlockNode(e){return!!e&&(e instanceof SimpleBlockNode&&e.type===exports.ComponentValueType.SimpleBlock)}}function consumeSimpleBlock(e,o){const t=n.mirrorVariantType(o[0][0]);if(!t)throw new Error("Failed to parse, a mirror variant must exist for all block open tokens.");const s=[];let i=1;for(;;){const r=o[i];if(!r||r[0]===n.TokenType.EOF)return e.onParseError(new n.ParseError("Unexpected EOF while consuming a simple block.",o[0][2],o[o.length-1][3],["5.4.8. Consume a simple block","Unexpected EOF"])),{advance:o.length,node:new SimpleBlockNode(o[0],r,s)};if(r[0]===t)return{advance:i+1,node:new SimpleBlockNode(o[0],r,s)};if(r[0]===n.TokenType.Comment||r[0]===n.TokenType.Whitespace){const n=consumeAllCommentsAndWhitespace(e,o.slice(i));i+=n.advance,s.push(...n.nodes);continue}const a=consumeComponentValue(e,o.slice(i));i+=a.advance,s.push(a.node)}}class WhitespaceNode{type=exports.ComponentValueType.Whitespace;value;constructor(e){this.value=e}tokens(){return this.value}toString(){return n.stringify(...this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isWhitespaceNode(){return WhitespaceNode.isWhitespaceNode(this)}static isWhitespaceNode(e){return!!e&&(e instanceof WhitespaceNode&&e.type===exports.ComponentValueType.Whitespace)}}function consumeWhitespace(e,o){let t=0;for(;;){if(o[t][0]!==n.TokenType.Whitespace)return{advance:t,node:new WhitespaceNode(o.slice(0,t))};t++}}class CommentNode{type=exports.ComponentValueType.Comment;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return n.stringify(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isCommentNode(){return CommentNode.isCommentNode(this)}static isCommentNode(e){return!!e&&(e instanceof CommentNode&&e.type===exports.ComponentValueType.Comment)}}function consumeComment(e,n){return{advance:1,node:new CommentNode(n[0])}}function consumeAllCommentsAndWhitespace(e,o){const t=[];let s=0;for(;;)if(o[s][0]!==n.TokenType.Whitespace){if(o[s][0]!==n.TokenType.Comment)return{advance:s,nodes:t};t.push(new CommentNode(o[s])),s++}else{const e=consumeWhitespace(0,o.slice(s));s+=e.advance,t.push(e.node)}}class TokenNode{type=exports.ComponentValueType.Token;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return n.stringify(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isTokenNode(){return TokenNode.isTokenNode(this)}static isTokenNode(e){return!!e&&(e instanceof TokenNode&&e.type===exports.ComponentValueType.Token)}}function isSimpleBlockNode(e){return SimpleBlockNode.isSimpleBlockNode(e)}function isFunctionNode(e){return FunctionNode.isFunctionNode(e)}exports.CommentNode=CommentNode,exports.FunctionNode=FunctionNode,exports.SimpleBlockNode=SimpleBlockNode,exports.TokenNode=TokenNode,exports.WhitespaceNode=WhitespaceNode,exports.consumeAllCommentsAndWhitespace=consumeAllCommentsAndWhitespace,exports.consumeComment=consumeComment,exports.consumeComponentValue=consumeComponentValue,exports.consumeFunction=consumeFunction,exports.consumeSimpleBlock=consumeSimpleBlock,exports.consumeWhitespace=consumeWhitespace,exports.gatherNodeAncestry=function gatherNodeAncestry(e){const n=new Map;return e.walk((e=>{Array.isArray(e.node)?e.node.forEach((o=>{n.set(o,e.parent)})):n.set(e.node,e.parent)})),n},exports.isCommentNode=function isCommentNode(e){return CommentNode.isCommentNode(e)},exports.isFunctionNode=isFunctionNode,exports.isSimpleBlockNode=isSimpleBlockNode,exports.isTokenNode=function isTokenNode(e){return TokenNode.isTokenNode(e)},exports.isWhitespaceNode=function isWhitespaceNode(e){return WhitespaceNode.isWhitespaceNode(e)},exports.parseCommaSeparatedListOfComponentValues=function parseCommaSeparatedListOfComponentValues(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];if(0===e.length)return[];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=[],a=0;for(;;){if(!s[a]||s[a][0]===n.TokenType.EOF)return r.length&&i.push(r),i;if(s[a][0]===n.TokenType.Comma){i.push(r),r=[],a++;continue}const o=consumeComponentValue(t,e.slice(a));r.push(o.node),a+=o.advance}},exports.parseComponentValue=function parseComponentValue(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=consumeComponentValue(t,s);if(s[Math.min(i.advance,s.length-1)][0]===n.TokenType.EOF)return i.node;t.onParseError(new n.ParseError("Expected EOF after parsing a component value.",e[0][2],e[e.length-1][3],["5.3.9. Parse a component value","Expected EOF"]))},exports.parseListOfComponentValues=function parseListOfComponentValues(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=0;for(;;){if(!s[r]||s[r][0]===n.TokenType.EOF)return i;const e=consumeComponentValue(t,s.slice(r));i.push(e.node),r+=e.advance}},exports.replaceComponentValues=function replaceComponentValues(e,n){for(let o=0;o{if("number"!=typeof o)return;const t=e.node,s=n(t);s&&e.parent.value.splice(o,1,s)}))}}return e},exports.sourceIndices=function sourceIndices(e){if(Array.isArray(e)){const n=e[0];if(!n)return[0,0];const o=e[e.length-1]||n;return[sourceIndices(n)[0],sourceIndices(o)[1]]}const n=e.tokens(),o=n[0],t=n[n.length-1];return o&&t?[o[2],t[3]]:[0,0]},exports.stringify=function stringify(e){return e.map((e=>e.map((e=>n.stringify(...e.tokens()))).join(""))).join(",")}; +"use strict";var e,n=require("@csstools/css-tokenizer");function walkerIndexGenerator(e){let n=e.slice();return(e,o,t)=>{let s=-1;for(let i=n.indexOf(o);i=e.length)?-1:(n=e.slice(),s)}}function consumeComponentValue(e,o){const t=o[0];if(t[0]===n.TokenType.OpenParen||t[0]===n.TokenType.OpenCurly||t[0]===n.TokenType.OpenSquare){const n=consumeSimpleBlock(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Function){const n=consumeFunction(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Whitespace){const n=consumeWhitespace(e,o);return{advance:n.advance,node:n.node}}if(t[0]===n.TokenType.Comment){const n=consumeComment(e,o);return{advance:n.advance,node:n.node}}return{advance:1,node:new TokenNode(t)}}exports.ComponentValueType=void 0,(e=exports.ComponentValueType||(exports.ComponentValueType={})).Function="function",e.SimpleBlock="simple-block",e.Whitespace="whitespace",e.Comment="comment",e.Token="token";class ContainerNodeBaseClass{value=[];indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}forEach(e,n){if(0===this.value.length)return;const o=walkerIndexGenerator(this.value);let t=0;for(;t!1!==e(n,o)&&((!("walk"in n.node)||!this.value.includes(n.node)||!1!==n.node.walk(e,n.state))&&void 0)),n)}}class FunctionNode extends ContainerNodeBaseClass{type=exports.ComponentValueType.Function;name;endToken;constructor(e,n,o){super(),this.name=e,this.endToken=n,this.value=o}getName(){return this.name[4].value}normalize(){this.endToken[0]===n.TokenType.EOF&&(this.endToken=[n.TokenType.CloseParen,")",-1,-1,void 0])}tokens(){return this.endToken[0]===n.TokenType.EOF?[this.name,...this.value.flatMap((e=>e.tokens()))]:[this.name,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n.isToken(e)?n.stringify(e):e.toString())).join("");return n.stringify(this.name)+e+n.stringify(this.endToken)}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isFunctionNode(){return FunctionNode.isFunctionNode(this)}static isFunctionNode(e){return!!e&&(e instanceof FunctionNode&&e.type===exports.ComponentValueType.Function)}}function consumeFunction(e,o){const t=[];let s=1;for(;;){const i=o[s];if(!i||i[0]===n.TokenType.EOF)return e.onParseError(new n.ParseError("Unexpected EOF while consuming a function.",o[0][2],o[o.length-1][3],["5.4.9. Consume a function","Unexpected EOF"])),{advance:o.length,node:new FunctionNode(o[0],i,t)};if(i[0]===n.TokenType.CloseParen)return{advance:s+1,node:new FunctionNode(o[0],i,t)};if(i[0]===n.TokenType.Comment||i[0]===n.TokenType.Whitespace){const n=consumeAllCommentsAndWhitespace(e,o.slice(s));s+=n.advance,t.push(...n.nodes);continue}const r=consumeComponentValue(e,o.slice(s));s+=r.advance,t.push(r.node)}}class SimpleBlockNode extends ContainerNodeBaseClass{type=exports.ComponentValueType.SimpleBlock;startToken;endToken;constructor(e,n,o){super(),this.startToken=e,this.endToken=n,this.value=o}normalize(){if(this.endToken[0]===n.TokenType.EOF){const e=n.mirrorVariant(this.startToken);e&&(this.endToken=e)}}tokens(){return this.endToken[0]===n.TokenType.EOF?[this.startToken,...this.value.flatMap((e=>e.tokens()))]:[this.startToken,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n.isToken(e)?n.stringify(e):e.toString())).join("");return n.stringify(this.startToken)+e+n.stringify(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}toJSON(){return{type:this.type,startToken:this.startToken,tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isSimpleBlockNode(){return SimpleBlockNode.isSimpleBlockNode(this)}static isSimpleBlockNode(e){return!!e&&(e instanceof SimpleBlockNode&&e.type===exports.ComponentValueType.SimpleBlock)}}function consumeSimpleBlock(e,o){const t=n.mirrorVariantType(o[0][0]);if(!t)throw new Error("Failed to parse, a mirror variant must exist for all block open tokens.");const s=[];let i=1;for(;;){const r=o[i];if(!r||r[0]===n.TokenType.EOF)return e.onParseError(new n.ParseError("Unexpected EOF while consuming a simple block.",o[0][2],o[o.length-1][3],["5.4.8. Consume a simple block","Unexpected EOF"])),{advance:o.length,node:new SimpleBlockNode(o[0],r,s)};if(r[0]===t)return{advance:i+1,node:new SimpleBlockNode(o[0],r,s)};if(r[0]===n.TokenType.Comment||r[0]===n.TokenType.Whitespace){const n=consumeAllCommentsAndWhitespace(e,o.slice(i));i+=n.advance,s.push(...n.nodes);continue}const a=consumeComponentValue(e,o.slice(i));i+=a.advance,s.push(a.node)}}class WhitespaceNode{type=exports.ComponentValueType.Whitespace;value;constructor(e){this.value=e}tokens(){return this.value}toString(){return n.stringify(...this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isWhitespaceNode(){return WhitespaceNode.isWhitespaceNode(this)}static isWhitespaceNode(e){return!!e&&(e instanceof WhitespaceNode&&e.type===exports.ComponentValueType.Whitespace)}}function consumeWhitespace(e,o){let t=0;for(;;){if(o[t][0]!==n.TokenType.Whitespace)return{advance:t,node:new WhitespaceNode(o.slice(0,t))};t++}}class CommentNode{type=exports.ComponentValueType.Comment;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return n.stringify(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isCommentNode(){return CommentNode.isCommentNode(this)}static isCommentNode(e){return!!e&&(e instanceof CommentNode&&e.type===exports.ComponentValueType.Comment)}}function consumeComment(e,n){return{advance:1,node:new CommentNode(n[0])}}function consumeAllCommentsAndWhitespace(e,o){const t=[];let s=0;for(;;)if(o[s][0]!==n.TokenType.Whitespace){if(o[s][0]!==n.TokenType.Comment)return{advance:s,nodes:t};t.push(new CommentNode(o[s])),s++}else{const e=consumeWhitespace(0,o.slice(s));s+=e.advance,t.push(e.node)}}class TokenNode{type=exports.ComponentValueType.Token;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return n.stringify(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isTokenNode(){return TokenNode.isTokenNode(this)}static isTokenNode(e){return!!e&&(e instanceof TokenNode&&e.type===exports.ComponentValueType.Token)}}function isSimpleBlockNode(e){return SimpleBlockNode.isSimpleBlockNode(e)}function isFunctionNode(e){return FunctionNode.isFunctionNode(e)}exports.CommentNode=CommentNode,exports.FunctionNode=FunctionNode,exports.SimpleBlockNode=SimpleBlockNode,exports.TokenNode=TokenNode,exports.WhitespaceNode=WhitespaceNode,exports.consumeAllCommentsAndWhitespace=consumeAllCommentsAndWhitespace,exports.consumeComment=consumeComment,exports.consumeComponentValue=consumeComponentValue,exports.consumeFunction=consumeFunction,exports.consumeSimpleBlock=consumeSimpleBlock,exports.consumeWhitespace=consumeWhitespace,exports.gatherNodeAncestry=function gatherNodeAncestry(e){const n=new Map;return e.walk((e=>{Array.isArray(e.node)?e.node.forEach((o=>{n.set(o,e.parent)})):n.set(e.node,e.parent)})),n},exports.isCommentNode=function isCommentNode(e){return CommentNode.isCommentNode(e)},exports.isFunctionNode=isFunctionNode,exports.isSimpleBlockNode=isSimpleBlockNode,exports.isTokenNode=function isTokenNode(e){return TokenNode.isTokenNode(e)},exports.isWhitespaceNode=function isWhitespaceNode(e){return WhitespaceNode.isWhitespaceNode(e)},exports.parseCommaSeparatedListOfComponentValues=function parseCommaSeparatedListOfComponentValues(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];if(0===e.length)return[];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=[],a=0;for(;;){if(!s[a]||s[a][0]===n.TokenType.EOF)return r.length&&i.push(r),i;if(s[a][0]===n.TokenType.Comma){i.push(r),r=[],a++;continue}const o=consumeComponentValue(t,e.slice(a));r.push(o.node),a+=o.advance}},exports.parseComponentValue=function parseComponentValue(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=consumeComponentValue(t,s);if(s[Math.min(i.advance,s.length-1)][0]===n.TokenType.EOF)return i.node;t.onParseError(new n.ParseError("Expected EOF after parsing a component value.",e[0][2],e[e.length-1][3],["5.3.9. Parse a component value","Expected EOF"]))},exports.parseListOfComponentValues=function parseListOfComponentValues(e,o){const t={onParseError:(null==o?void 0:o.onParseError)??(()=>{})},s=[...e];s[s.length-1][0]!==n.TokenType.EOF&&s.push([n.TokenType.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=0;for(;;){if(!s[r]||s[r][0]===n.TokenType.EOF)return i;const e=consumeComponentValue(t,s.slice(r));i.push(e.node),r+=e.advance}},exports.replaceComponentValues=function replaceComponentValues(e,n){for(let o=0;o{if("number"!=typeof o)return;const t=e.node,s=n(t);s&&e.parent.value.splice(o,1,s)}))}}return e},exports.sourceIndices=function sourceIndices(e){if(Array.isArray(e)){const n=e[0];if(!n)return[0,0];const o=e[e.length-1]||n;return[sourceIndices(n)[0],sourceIndices(o)[1]]}const n=e.tokens(),o=n[0],t=n[n.length-1];return o&&t?[o[2],t[3]]:[0,0]},exports.stringify=function stringify(e){return e.map((e=>e.map((e=>n.stringify(...e.tokens()))).join(""))).join(",")},exports.walkerIndexGenerator=walkerIndexGenerator; diff --git a/packages/css-parser-algorithms/dist/index.d.ts b/packages/css-parser-algorithms/dist/index.d.ts index 47c3cec9e..a219a756a 100644 --- a/packages/css-parser-algorithms/dist/index.d.ts +++ b/packages/css-parser-algorithms/dist/index.d.ts @@ -5,6 +5,7 @@ export { parseCommaSeparatedListOfComponentValues } from './parse/parse-comma-se export { gatherNodeAncestry } from './util/node-ancestry'; export { replaceComponentValues } from './util/replace-component-values'; export { stringify } from './util/stringify'; +export { walkerIndexGenerator } from './util/walker-index-generator'; export { ComponentValueType } from './util/component-value-type'; export { isCommentNode, isFunctionNode, isSimpleBlockNode, isTokenNode, isWhitespaceNode, } from './util/type-predicates'; export { sourceIndices } from './util/source-indices'; diff --git a/packages/css-parser-algorithms/dist/index.mjs b/packages/css-parser-algorithms/dist/index.mjs index cc63349e9..2dcec4f1d 100644 --- a/packages/css-parser-algorithms/dist/index.mjs +++ b/packages/css-parser-algorithms/dist/index.mjs @@ -1 +1 @@ -import{TokenType as e,isToken as n,stringify as t,ParseError as o,mirrorVariant as s,mirrorVariantType as i}from"@csstools/css-tokenizer";var r;function consumeComponentValue(n,t){const o=t[0];if(o[0]===e.OpenParen||o[0]===e.OpenCurly||o[0]===e.OpenSquare){const e=consumeSimpleBlock(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Function){const e=consumeFunction(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Whitespace){const e=consumeWhitespace(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Comment){const e=consumeComment(n,t);return{advance:e.advance,node:e.node}}return{advance:1,node:new TokenNode(o)}}!function(e){e.Function="function",e.SimpleBlock="simple-block",e.Whitespace="whitespace",e.Comment="comment",e.Token="token"}(r||(r={}));class FunctionNode{type=r.Function;name;endToken;value;constructor(e,n,t){this.name=e,this.endToken=n,this.value=t}getName(){return this.name[4].value}normalize(){this.endToken[0]===e.EOF&&(this.endToken=[e.CloseParen,")",-1,-1,void 0])}tokens(){return this.endToken[0]===e.EOF?[this.name,...this.value.flatMap((e=>e.tokens()))]:[this.name,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n(e)?t(e):e.toString())).join("");return t(this.name)+e+t(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}walk(e,n){let t=!1;if(this.value.forEach(((o,s)=>{if(t)return;let i;n&&(i={...n}),!1!==e({node:o,parent:this,state:i},s)?"walk"in o&&!1===o.walk(e,i)&&(t=!0):t=!0})),t)return!1}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isFunctionNode(){return FunctionNode.isFunctionNode(this)}static isFunctionNode(e){return!!e&&(e instanceof FunctionNode&&e.type===r.Function)}}function consumeFunction(n,t){const s=[];let i=1;for(;;){const r=t[i];if(!r||r[0]===e.EOF)return n.onParseError(new o("Unexpected EOF while consuming a function.",t[0][2],t[t.length-1][3],["5.4.9. Consume a function","Unexpected EOF"])),{advance:t.length,node:new FunctionNode(t[0],r,s)};if(r[0]===e.CloseParen)return{advance:i+1,node:new FunctionNode(t[0],r,s)};if(r[0]===e.Comment||r[0]===e.Whitespace){const e=consumeAllCommentsAndWhitespace(n,t.slice(i));i+=e.advance,s.push(...e.nodes);continue}const a=consumeComponentValue(n,t.slice(i));i+=a.advance,s.push(a.node)}}class SimpleBlockNode{type=r.SimpleBlock;startToken;endToken;value;constructor(e,n,t){this.startToken=e,this.endToken=n,this.value=t}normalize(){if(this.endToken[0]===e.EOF){const e=s(this.startToken);e&&(this.endToken=e)}}tokens(){return this.endToken[0]===e.EOF?[this.startToken,...this.value.flatMap((e=>e.tokens()))]:[this.startToken,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n(e)?t(e):e.toString())).join("");return t(this.startToken)+e+t(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}walk(e,n){let t=!1;if(this.value.forEach(((o,s)=>{if(t)return;let i;n&&(i={...n}),!1!==e({node:o,parent:this,state:i},s)?"walk"in o&&!1===o.walk(e,i)&&(t=!0):t=!0})),t)return!1}toJSON(){return{type:this.type,startToken:this.startToken,tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isSimpleBlockNode(){return SimpleBlockNode.isSimpleBlockNode(this)}static isSimpleBlockNode(e){return!!e&&(e instanceof SimpleBlockNode&&e.type===r.SimpleBlock)}}function consumeSimpleBlock(n,t){const s=i(t[0][0]);if(!s)throw new Error("Failed to parse, a mirror variant must exist for all block open tokens.");const r=[];let a=1;for(;;){const i=t[a];if(!i||i[0]===e.EOF)return n.onParseError(new o("Unexpected EOF while consuming a simple block.",t[0][2],t[t.length-1][3],["5.4.8. Consume a simple block","Unexpected EOF"])),{advance:t.length,node:new SimpleBlockNode(t[0],i,r)};if(i[0]===s)return{advance:a+1,node:new SimpleBlockNode(t[0],i,r)};if(i[0]===e.Comment||i[0]===e.Whitespace){const e=consumeAllCommentsAndWhitespace(n,t.slice(a));a+=e.advance,r.push(...e.nodes);continue}const c=consumeComponentValue(n,t.slice(a));a+=c.advance,r.push(c.node)}}class WhitespaceNode{type=r.Whitespace;value;constructor(e){this.value=e}tokens(){return this.value}toString(){return t(...this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isWhitespaceNode(){return WhitespaceNode.isWhitespaceNode(this)}static isWhitespaceNode(e){return!!e&&(e instanceof WhitespaceNode&&e.type===r.Whitespace)}}function consumeWhitespace(n,t){let o=0;for(;;){if(t[o][0]!==e.Whitespace)return{advance:o,node:new WhitespaceNode(t.slice(0,o))};o++}}class CommentNode{type=r.Comment;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return t(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isCommentNode(){return CommentNode.isCommentNode(this)}static isCommentNode(e){return!!e&&(e instanceof CommentNode&&e.type===r.Comment)}}function consumeComment(e,n){return{advance:1,node:new CommentNode(n[0])}}function consumeAllCommentsAndWhitespace(n,t){const o=[];let s=0;for(;;)if(t[s][0]!==e.Whitespace){if(t[s][0]!==e.Comment)return{advance:s,nodes:o};o.push(new CommentNode(t[s])),s++}else{const e=consumeWhitespace(0,t.slice(s));s+=e.advance,o.push(e.node)}}class TokenNode{type=r.Token;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return t(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isTokenNode(){return TokenNode.isTokenNode(this)}static isTokenNode(e){return!!e&&(e instanceof TokenNode&&e.type===r.Token)}}function parseComponentValue(n,t){const s={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},i=[...n];i[i.length-1][0]!==e.EOF&&i.push([e.EOF,"",i[i.length-1][2],i[i.length-1][3],void 0]);const r=consumeComponentValue(s,i);if(i[Math.min(r.advance,i.length-1)][0]===e.EOF)return r.node;s.onParseError(new o("Expected EOF after parsing a component value.",n[0][2],n[n.length-1][3],["5.3.9. Parse a component value","Expected EOF"]))}function parseListOfComponentValues(n,t){const o={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},s=[...n];s[s.length-1][0]!==e.EOF&&s.push([e.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=0;for(;;){if(!s[r]||s[r][0]===e.EOF)return i;const n=consumeComponentValue(o,s.slice(r));i.push(n.node),r+=n.advance}}function parseCommaSeparatedListOfComponentValues(n,t){const o={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},s=[...n];if(0===n.length)return[];s[s.length-1][0]!==e.EOF&&s.push([e.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=[],a=0;for(;;){if(!s[a]||s[a][0]===e.EOF)return r.length&&i.push(r),i;if(s[a][0]===e.Comma){i.push(r),r=[],a++;continue}const t=consumeComponentValue(o,n.slice(a));r.push(t.node),a+=t.advance}}function gatherNodeAncestry(e){const n=new Map;return e.walk((e=>{Array.isArray(e.node)?e.node.forEach((t=>{n.set(t,e.parent)})):n.set(e.node,e.parent)})),n}function isSimpleBlockNode(e){return SimpleBlockNode.isSimpleBlockNode(e)}function isFunctionNode(e){return FunctionNode.isFunctionNode(e)}function isWhitespaceNode(e){return WhitespaceNode.isWhitespaceNode(e)}function isCommentNode(e){return CommentNode.isCommentNode(e)}function isTokenNode(e){return TokenNode.isTokenNode(e)}function replaceComponentValues(e,n){for(let t=0;t{if("number"!=typeof t)return;const o=e.node,s=n(o);s&&e.parent.value.splice(t,1,s)}))}}return e}function stringify(e){return e.map((e=>e.map((e=>t(...e.tokens()))).join(""))).join(",")}function sourceIndices(e){if(Array.isArray(e)){const n=e[0];if(!n)return[0,0];const t=e[e.length-1]||n;return[sourceIndices(n)[0],sourceIndices(t)[1]]}const n=e.tokens(),t=n[0],o=n[n.length-1];return t&&o?[t[2],o[3]]:[0,0]}export{CommentNode,r as ComponentValueType,FunctionNode,SimpleBlockNode,TokenNode,WhitespaceNode,consumeAllCommentsAndWhitespace,consumeComment,consumeComponentValue,consumeFunction,consumeSimpleBlock,consumeWhitespace,gatherNodeAncestry,isCommentNode,isFunctionNode,isSimpleBlockNode,isTokenNode,isWhitespaceNode,parseCommaSeparatedListOfComponentValues,parseComponentValue,parseListOfComponentValues,replaceComponentValues,sourceIndices,stringify}; +import{TokenType as e,isToken as n,stringify as t,ParseError as o,mirrorVariant as s,mirrorVariantType as i}from"@csstools/css-tokenizer";var r;function walkerIndexGenerator(e){let n=e.slice();return(e,t,o)=>{let s=-1;for(let i=n.indexOf(t);i=e.length)?-1:(n=e.slice(),s)}}function consumeComponentValue(n,t){const o=t[0];if(o[0]===e.OpenParen||o[0]===e.OpenCurly||o[0]===e.OpenSquare){const e=consumeSimpleBlock(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Function){const e=consumeFunction(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Whitespace){const e=consumeWhitespace(n,t);return{advance:e.advance,node:e.node}}if(o[0]===e.Comment){const e=consumeComment(n,t);return{advance:e.advance,node:e.node}}return{advance:1,node:new TokenNode(o)}}!function(e){e.Function="function",e.SimpleBlock="simple-block",e.Whitespace="whitespace",e.Comment="comment",e.Token="token"}(r||(r={}));class ContainerNodeBaseClass{value=[];indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}forEach(e,n){if(0===this.value.length)return;const t=walkerIndexGenerator(this.value);let o=0;for(;o!1!==e(n,t)&&((!("walk"in n.node)||!this.value.includes(n.node)||!1!==n.node.walk(e,n.state))&&void 0)),n)}}class FunctionNode extends ContainerNodeBaseClass{type=r.Function;name;endToken;constructor(e,n,t){super(),this.name=e,this.endToken=n,this.value=t}getName(){return this.name[4].value}normalize(){this.endToken[0]===e.EOF&&(this.endToken=[e.CloseParen,")",-1,-1,void 0])}tokens(){return this.endToken[0]===e.EOF?[this.name,...this.value.flatMap((e=>e.tokens()))]:[this.name,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n(e)?t(e):e.toString())).join("");return t(this.name)+e+t(this.endToken)}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isFunctionNode(){return FunctionNode.isFunctionNode(this)}static isFunctionNode(e){return!!e&&(e instanceof FunctionNode&&e.type===r.Function)}}function consumeFunction(n,t){const s=[];let i=1;for(;;){const r=t[i];if(!r||r[0]===e.EOF)return n.onParseError(new o("Unexpected EOF while consuming a function.",t[0][2],t[t.length-1][3],["5.4.9. Consume a function","Unexpected EOF"])),{advance:t.length,node:new FunctionNode(t[0],r,s)};if(r[0]===e.CloseParen)return{advance:i+1,node:new FunctionNode(t[0],r,s)};if(r[0]===e.Comment||r[0]===e.Whitespace){const e=consumeAllCommentsAndWhitespace(n,t.slice(i));i+=e.advance,s.push(...e.nodes);continue}const a=consumeComponentValue(n,t.slice(i));i+=a.advance,s.push(a.node)}}class SimpleBlockNode extends ContainerNodeBaseClass{type=r.SimpleBlock;startToken;endToken;constructor(e,n,t){super(),this.startToken=e,this.endToken=n,this.value=t}normalize(){if(this.endToken[0]===e.EOF){const e=s(this.startToken);e&&(this.endToken=e)}}tokens(){return this.endToken[0]===e.EOF?[this.startToken,...this.value.flatMap((e=>e.tokens()))]:[this.startToken,...this.value.flatMap((e=>e.tokens())),this.endToken]}toString(){const e=this.value.map((e=>n(e)?t(e):e.toString())).join("");return t(this.startToken)+e+t(this.endToken)}indexOf(e){return this.value.indexOf(e)}at(e){if("number"==typeof e)return e<0&&(e=this.value.length+e),this.value[e]}toJSON(){return{type:this.type,startToken:this.startToken,tokens:this.tokens(),value:this.value.map((e=>e.toJSON()))}}isSimpleBlockNode(){return SimpleBlockNode.isSimpleBlockNode(this)}static isSimpleBlockNode(e){return!!e&&(e instanceof SimpleBlockNode&&e.type===r.SimpleBlock)}}function consumeSimpleBlock(n,t){const s=i(t[0][0]);if(!s)throw new Error("Failed to parse, a mirror variant must exist for all block open tokens.");const r=[];let a=1;for(;;){const i=t[a];if(!i||i[0]===e.EOF)return n.onParseError(new o("Unexpected EOF while consuming a simple block.",t[0][2],t[t.length-1][3],["5.4.8. Consume a simple block","Unexpected EOF"])),{advance:t.length,node:new SimpleBlockNode(t[0],i,r)};if(i[0]===s)return{advance:a+1,node:new SimpleBlockNode(t[0],i,r)};if(i[0]===e.Comment||i[0]===e.Whitespace){const e=consumeAllCommentsAndWhitespace(n,t.slice(a));a+=e.advance,r.push(...e.nodes);continue}const c=consumeComponentValue(n,t.slice(a));a+=c.advance,r.push(c.node)}}class WhitespaceNode{type=r.Whitespace;value;constructor(e){this.value=e}tokens(){return this.value}toString(){return t(...this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isWhitespaceNode(){return WhitespaceNode.isWhitespaceNode(this)}static isWhitespaceNode(e){return!!e&&(e instanceof WhitespaceNode&&e.type===r.Whitespace)}}function consumeWhitespace(n,t){let o=0;for(;;){if(t[o][0]!==e.Whitespace)return{advance:o,node:new WhitespaceNode(t.slice(0,o))};o++}}class CommentNode{type=r.Comment;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return t(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isCommentNode(){return CommentNode.isCommentNode(this)}static isCommentNode(e){return!!e&&(e instanceof CommentNode&&e.type===r.Comment)}}function consumeComment(e,n){return{advance:1,node:new CommentNode(n[0])}}function consumeAllCommentsAndWhitespace(n,t){const o=[];let s=0;for(;;)if(t[s][0]!==e.Whitespace){if(t[s][0]!==e.Comment)return{advance:s,nodes:o};o.push(new CommentNode(t[s])),s++}else{const e=consumeWhitespace(0,t.slice(s));s+=e.advance,o.push(e.node)}}class TokenNode{type=r.Token;value;constructor(e){this.value=e}tokens(){return[this.value]}toString(){return t(this.value)}toJSON(){return{type:this.type,tokens:this.tokens()}}isTokenNode(){return TokenNode.isTokenNode(this)}static isTokenNode(e){return!!e&&(e instanceof TokenNode&&e.type===r.Token)}}function parseComponentValue(n,t){const s={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},i=[...n];i[i.length-1][0]!==e.EOF&&i.push([e.EOF,"",i[i.length-1][2],i[i.length-1][3],void 0]);const r=consumeComponentValue(s,i);if(i[Math.min(r.advance,i.length-1)][0]===e.EOF)return r.node;s.onParseError(new o("Expected EOF after parsing a component value.",n[0][2],n[n.length-1][3],["5.3.9. Parse a component value","Expected EOF"]))}function parseListOfComponentValues(n,t){const o={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},s=[...n];s[s.length-1][0]!==e.EOF&&s.push([e.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=0;for(;;){if(!s[r]||s[r][0]===e.EOF)return i;const n=consumeComponentValue(o,s.slice(r));i.push(n.node),r+=n.advance}}function parseCommaSeparatedListOfComponentValues(n,t){const o={onParseError:(null==t?void 0:t.onParseError)??(()=>{})},s=[...n];if(0===n.length)return[];s[s.length-1][0]!==e.EOF&&s.push([e.EOF,"",s[s.length-1][2],s[s.length-1][3],void 0]);const i=[];let r=[],a=0;for(;;){if(!s[a]||s[a][0]===e.EOF)return r.length&&i.push(r),i;if(s[a][0]===e.Comma){i.push(r),r=[],a++;continue}const t=consumeComponentValue(o,n.slice(a));r.push(t.node),a+=t.advance}}function gatherNodeAncestry(e){const n=new Map;return e.walk((e=>{Array.isArray(e.node)?e.node.forEach((t=>{n.set(t,e.parent)})):n.set(e.node,e.parent)})),n}function isSimpleBlockNode(e){return SimpleBlockNode.isSimpleBlockNode(e)}function isFunctionNode(e){return FunctionNode.isFunctionNode(e)}function isWhitespaceNode(e){return WhitespaceNode.isWhitespaceNode(e)}function isCommentNode(e){return CommentNode.isCommentNode(e)}function isTokenNode(e){return TokenNode.isTokenNode(e)}function replaceComponentValues(e,n){for(let t=0;t{if("number"!=typeof t)return;const o=e.node,s=n(o);s&&e.parent.value.splice(t,1,s)}))}}return e}function stringify(e){return e.map((e=>e.map((e=>t(...e.tokens()))).join(""))).join(",")}function sourceIndices(e){if(Array.isArray(e)){const n=e[0];if(!n)return[0,0];const t=e[e.length-1]||n;return[sourceIndices(n)[0],sourceIndices(t)[1]]}const n=e.tokens(),t=n[0],o=n[n.length-1];return t&&o?[t[2],o[3]]:[0,0]}export{CommentNode,r as ComponentValueType,FunctionNode,SimpleBlockNode,TokenNode,WhitespaceNode,consumeAllCommentsAndWhitespace,consumeComment,consumeComponentValue,consumeFunction,consumeSimpleBlock,consumeWhitespace,gatherNodeAncestry,isCommentNode,isFunctionNode,isSimpleBlockNode,isTokenNode,isWhitespaceNode,parseCommaSeparatedListOfComponentValues,parseComponentValue,parseListOfComponentValues,replaceComponentValues,sourceIndices,stringify,walkerIndexGenerator}; diff --git a/packages/css-parser-algorithms/dist/util/walker-index-generator.d.ts b/packages/css-parser-algorithms/dist/util/walker-index-generator.d.ts new file mode 100644 index 000000000..2fffc0c69 --- /dev/null +++ b/packages/css-parser-algorithms/dist/util/walker-index-generator.d.ts @@ -0,0 +1,11 @@ +/** + * Generate a function that finds the next element that should be visited when walking an AST. + * Rules : + * - the previous iteration is used as a reference, so any checks are relative to the start of the current iteration. + * - the next element always appears after the current index. + * - the next element always exists in the list. + * - replacing an element does not cause the replaced element to be visited. + * - removing an element does not cause elements to be skipped. + * - an element added later in the list will be visited. + */ +export declare function walkerIndexGenerator(initialList: Array): (list: Array, child: T, index: number) => number; diff --git a/packages/css-parser-algorithms/src/consume/consume-component-block-function.ts b/packages/css-parser-algorithms/src/consume/consume-component-block-function.ts index 85703c3e2..cf51e4694 100644 --- a/packages/css-parser-algorithms/src/consume/consume-component-block-function.ts +++ b/packages/css-parser-algorithms/src/consume/consume-component-block-function.ts @@ -1,6 +1,7 @@ import { CSSToken, mirrorVariantType, mirrorVariant, stringify, TokenType, isToken, TokenFunction, ParseError } from '@csstools/css-tokenizer'; import { Context } from '../interfaces/context'; import { ComponentValueType } from '../util/component-value-type'; +import { walkerIndexGenerator } from '../util/walker-index-generator'; export type ContainerNode = FunctionNode | SimpleBlockNode; @@ -51,19 +52,147 @@ export function consumeComponentValue(ctx: Context, tokens: Array): { }; } -export class FunctionNode { +abstract class ContainerNodeBaseClass { + /** + * The contents of the `Function` or `Simple Block`. + * This is a list of component values. + */ + value: Array = []; + + /** + * 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 { + return this.value.indexOf(item); + } + + /** + * 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 { + if (typeof index === 'number') { + if (index < 0) { + index = this.value.length + index; + } + return this.value[index]; + } + } + + /** + * 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. + * + * @template T - The type of the `state` object. + * @template U - The type of the current node. + */ + forEach, U extends ContainerNode>(this: U, cb: (entry: { node: ComponentValue, parent: ContainerNode, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { + if (this.value.length === 0) { + return; + } + + const indexGenerator = walkerIndexGenerator(this.value); + + let index = 0; + while (index < this.value.length) { + const child = this.value[index]; + + let stateClone: T | undefined = undefined; + if (state) { + stateClone = { + ...state, + }; + } + + if (cb({ node: child, parent: this, state: stateClone }, index) === false) { + return false; + } + + index = indexGenerator(this.value, child, index); + if (index === -1) { + break; + } + } + } + + /** + * 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. + * + * @template T - The type of the `state` object. + * @template U - The type of the current node. + */ + walk, U extends ContainerNode>(this: U, cb: (entry: { node: ComponentValue, parent: ContainerNode, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { + if (this.value.length === 0) { + return; + } + + this.forEach((entry, index) => { + if (cb(entry, index) === false) { + return false; + } + + if ('walk' in entry.node && this.value.includes(entry.node)) { + if (entry.node.walk(cb, entry.state) === false) { + return false; + } + } + }, state); + } +} + +export class FunctionNode extends ContainerNodeBaseClass { + /** + * The node type + * Always `ComponentValueType.Function` + */ type: ComponentValueType = ComponentValueType.Function; + /** + * 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; - value: Array; constructor(name: TokenFunction, endToken: CSSToken, value: Array) { + super(); + this.name = name; this.endToken = endToken; this.value = value; } + /** + * Retrieve the name of the current Function. + * This is the parsed and unescaped name of the function. + */ getName(): string { return this.name[4].value; } @@ -78,6 +207,10 @@ export class FunctionNode { } } + /** + * Retrieve the tokens for the current Function. + * This is the inverse of parsing from a list of tokens. + */ tokens(): Array { if (this.endToken[0] === TokenType.EOF) { return [ @@ -97,6 +230,11 @@ export class FunctionNode { ]; } + /** + * 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 { const valueString = this.value.map((x) => { if (isToken(x)) { @@ -109,52 +247,10 @@ export class FunctionNode { return stringify(this.name) + valueString + stringify(this.endToken); } - indexOf(item: ComponentValue): number | string { - return this.value.indexOf(item); - } - - at(index: number | string): ComponentValue | undefined { - if (typeof index === 'number') { - if (index < 0) { - index = this.value.length + index; - } - return this.value[index]; - } - } - - walk>(cb: (entry: { node: ComponentValue, parent: ContainerNode, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { - let aborted = false; - - this.value.forEach((child, index) => { - if (aborted) { - return; - } - - let stateClone: T | undefined = undefined; - if (state) { - stateClone = { - ...state, - }; - } - - if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; - } - - if ('walk' in child) { - if (child.walk(cb, stateClone) === false) { - aborted = true; - return; - } - } - }); - - if (aborted) { - return false; - } - } - + /** + * 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 { return { type: this.type, @@ -164,10 +260,18 @@ export class FunctionNode { }; } + /** + * Check if the current object is a FunctionNode. + * This is a type guard to help with type narrowing. + */ isFunctionNode(): this is FunctionNode { return FunctionNode.isFunctionNode(this); } + /** + * Check if the given object is a FunctionNode. + * This is a type guard to help with type narrowing. + */ static isFunctionNode(x: unknown): x is FunctionNode { if (!x) { return false; @@ -227,14 +331,15 @@ export function consumeFunction(ctx: Context, tokens: Array): { advanc } } -export class SimpleBlockNode { +export class SimpleBlockNode extends ContainerNodeBaseClass { type: ComponentValueType = ComponentValueType.SimpleBlock; startToken: CSSToken; endToken: CSSToken; - value: Array; constructor(startToken: CSSToken, endToken: CSSToken, value: Array) { + super(); + this.startToken = startToken; this.endToken = endToken; this.value = value; @@ -297,39 +402,6 @@ export class SimpleBlockNode { } } - walk>(cb: (entry: { node: ComponentValue, parent: ContainerNode, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { - let aborted = false; - - this.value.forEach((child, index) => { - if (aborted) { - return; - } - - let stateClone: T | undefined = undefined; - if (state) { - stateClone = { - ...state, - }; - } - - if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; - } - - if ('walk' in child) { - if (child.walk(cb, stateClone) === false) { - aborted = true; - return; - } - } - }); - - if (aborted) { - return false; - } - } - toJSON(): unknown { return { type: this.type, diff --git a/packages/css-parser-algorithms/src/index.ts b/packages/css-parser-algorithms/src/index.ts index 1c6512473..b636b057e 100644 --- a/packages/css-parser-algorithms/src/index.ts +++ b/packages/css-parser-algorithms/src/index.ts @@ -5,6 +5,7 @@ export { parseCommaSeparatedListOfComponentValues } from './parse/parse-comma-se export { gatherNodeAncestry } from './util/node-ancestry'; export { replaceComponentValues } from './util/replace-component-values'; export { stringify } from './util/stringify'; +export { walkerIndexGenerator } from './util/walker-index-generator'; export { ComponentValueType } from './util/component-value-type'; export { isCommentNode, diff --git a/packages/css-parser-algorithms/src/util/walker-index-generator.ts b/packages/css-parser-algorithms/src/util/walker-index-generator.ts new file mode 100644 index 000000000..f17ac3ecb --- /dev/null +++ b/packages/css-parser-algorithms/src/util/walker-index-generator.ts @@ -0,0 +1,56 @@ +/** + * Generate a function that finds the next element that should be visited when walking an AST. + * Rules : + * - the previous iteration is used as a reference, so any checks are relative to the start of the current iteration. + * - the next element always appears after the current index. + * - the next element always exists in the list. + * - replacing an element does not cause the replaced element to be visited. + * - removing an element does not cause elements to be skipped. + * - an element added later in the list will be visited. + */ +export function walkerIndexGenerator(initialList: Array) { + // 1. Keep a reference of the original ordered list. + let reference: Array = initialList.slice(); + + return (list: Array, child: T, index: number): number => { + // 2. Lookup the index of the original element in the original list. + const originalElementIndex = reference.indexOf(child); + let nextIndex = -1; + // 3. Iterate over the original list from the index of the current element. + for (let refIndex = originalElementIndex; refIndex < reference.length; refIndex++) { + // 4. Lookup the index of a potential next element in the new list. + nextIndex = list.indexOf(reference[refIndex]); + + // 5. If the potential next element is not in the new list, continue. + if (nextIndex === -1) { + continue; + } + + // 6. If the potential next element appears before the current index, continue. + if (nextIndex < index) { + continue; + } + + break; + } + + // 7. If the next element is not in the list, return -1. + if (nextIndex === -1) { + return -1; + } + + // 8. If the next element is the current element, increment the found index. + if (nextIndex === index && child === list[index]) { + nextIndex++; + if (nextIndex >= list.length) { + return -1; + } + } + + // 9. Update the reference list so that it reflects the current list. + reference = list.slice(); + + // 10. Return the next index. + return nextIndex; + }; +} diff --git a/packages/css-parser-algorithms/test/cases/replacer/0002.mjs b/packages/css-parser-algorithms/test/cases/replacer/0002.mjs new file mode 100644 index 000000000..de35f9631 --- /dev/null +++ b/packages/css-parser-algorithms/test/cases/replacer/0002.mjs @@ -0,0 +1,26 @@ +import { TokenType, tokenize } from '@csstools/css-tokenizer'; +import assert from 'assert'; +import {replaceComponentValues, parseComponentValue, isFunctionNode, TokenNode } from '@csstools/css-parser-algorithms'; + +// https://github.com/csstools/postcss-plugins/issues/1202 +{ + let visited = []; + + const value = parseComponentValue(tokenize({ css: 'foo(bar(baz)bar2())' })); + replaceComponentValues([[value]], node => { + visited.push(node.toString()); + if (isFunctionNode(node) && node.getName() === 'bar') { + return new TokenNode([TokenType.Delim, '/', node.value[2], node.value[3], { value: '/' }]); + } + }); + + assert.deepStrictEqual( + visited, + ['foo(bar(baz)bar2())', 'bar(baz)', 'bar2()'], + ); + + assert.deepStrictEqual( + value.toString(), + 'foo(/bar2())', + ); +} diff --git a/packages/css-parser-algorithms/test/cases/walker/0002.mjs b/packages/css-parser-algorithms/test/cases/walker/0002.mjs new file mode 100644 index 000000000..a5a1fa4e9 --- /dev/null +++ b/packages/css-parser-algorithms/test/cases/walker/0002.mjs @@ -0,0 +1,461 @@ +import { tokenize } from '@csstools/css-tokenizer'; +import assert from 'assert'; +import { parseComponentValue } from '@csstools/css-parser-algorithms'; + +const onParseError = (err) => { + throw err; +}; + +// Simple, shallow walk without mutations. +// This is purely a baseline. +{ + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + { index: 3, node: '/', parent: 'foo(a/b/c)' }, + { index: 4, node: 'c', parent: 'foo(a/b/c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/b/c)', + ); +} + +// Delete 2 nodes at the end. +{ + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.splice(index, 2); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + { index: 2, node: 'c', parent: 'foo(a/c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/c)', + ); +} + +// Delete a single node in the middle. +{ + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.splice(index, 1); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + { index: 2, node: '/', parent: 'foo(a//c)' }, + { index: 3, node: 'c', parent: 'foo(a//c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a//c)', + ); +} + +// Delete 2 nodes in the middle. +{ + const tokens = tokenize({ css: 'foo(a/b,c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === '/') { + entry.parent.value.splice(index, 2); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b,c)' }, + { index: 1, node: '/', parent: 'foo(a/b,c)' }, + { index: 1, node: ',', parent: 'foo(a,c)' }, + { index: 2, node: 'c', parent: 'foo(a,c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a,c)', + ); +} + +// Delete 2 nodes but the parent is a block, not a function +{ + const tokens = tokenize({ css: '(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.splice(index, 2); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: '(a/b/c)' }, + { index: 1, node: '/', parent: '(a/b/c)' }, + { index: 2, node: 'b', parent: '(a/b/c)' }, + { index: 2, node: 'c', parent: '(a/c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + '(a/c)', + ); +} + +// Setting the list to an empty array works. +{ + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value = []; + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo()', + ); +} + +// Reversing an array stops the iteration. +{ + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.reverse(); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + { index: 3, node: '/', parent: 'foo(c/b/a)' }, + { index: 4, node: 'a', parent: 'foo(c/b/a)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(c/b/a)', + ); +} + +// Insert a sub tree at the current position +{ + const tokensSubTree = tokenize({ css: 'bar(d)' }, { onParseError: onParseError }); + const componentValueSubTree = parseComponentValue(tokensSubTree, { onParseError: onParseError }); + + const tokens = tokenize({ css: 'foo(a/b/c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.splice(index, 1, componentValueSubTree); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b/c)' }, + { index: 1, node: '/', parent: 'foo(a/b/c)' }, + { index: 2, node: 'b', parent: 'foo(a/b/c)' }, + { index: 3, node: '/', parent: 'foo(a/bar(d)/c)' }, + { index: 4, node: 'c', parent: 'foo(a/bar(d)/c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/bar(d)/c)', + ); +} + +// Insert a sub tree at the next position +{ + const tokensSubTree = tokenize({ css: 'bar(d)' }, { onParseError: onParseError }); + const componentValueSubTree = parseComponentValue(tokensSubTree, { onParseError: onParseError }); + + const tokens = tokenize({ css: 'foo(a/b,c)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === '/') { + entry.parent.value.splice(index+1, 1, componentValueSubTree); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b,c)' }, + { index: 1, node: '/', parent: 'foo(a/b,c)' }, + { index: 2, node: 'bar(d)', parent: 'foo(a/bar(d),c)' }, + { index: 0, node: 'd', parent: 'bar(d)' }, + { index: 3, node: ',', parent: 'foo(a/bar(d),c)' }, + { index: 4, node: 'c', parent: 'foo(a/bar(d),c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/bar(d),c)', + ); +} + +// Remove the last item +{ + const tokens = tokenize({ css: 'foo(a/b)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.splice(index, 1); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b)' }, + { index: 1, node: '/', parent: 'foo(a/b)' }, + { index: 2, node: 'b', parent: 'foo(a/b)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/)', + ); +} + +// Remove the next item, that item is the last item +{ + const tokens = tokenize({ css: 'foo(a/b)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === '/') { + entry.parent.value.splice(index+1, 1); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b)' }, + { index: 1, node: '/', parent: 'foo(a/b)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/)', + ); +} + +// Empty thing +{ + const tokens = tokenize({ css: 'foo()' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + }); + + assert.deepStrictEqual( + result, + [], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo()', + ); +} + +// Append an item +{ + const otherTokens = tokenize({ css: '#c' }, { onParseError: onParseError }); + const otherComponentValue = parseComponentValue(otherTokens, { onParseError: onParseError }); + + const tokens = tokenize({ css: 'foo(a/b)' }, { onParseError: onParseError }); + const componentValue = parseComponentValue(tokens, { onParseError: onParseError }); + assert.ok(componentValue); + + const result = []; + componentValue.walk((entry, index) => { + result.push({ + index: index, + node: entry.node.toString(), + parent: entry.parent.toString(), + }); + + if (entry.node.toString() === 'b') { + entry.parent.value.push(otherComponentValue); + } + }); + + assert.deepStrictEqual( + result, + [ + { index: 0, node: 'a', parent: 'foo(a/b)' }, + { index: 1, node: '/', parent: 'foo(a/b)' }, + { index: 2, node: 'b', parent: 'foo(a/b)' }, + { index: 3, node: '#c', parent: 'foo(a/b#c)' }, + ], + ); + + assert.strictEqual( + componentValue.toString(), + 'foo(a/b#c)', + ); +} diff --git a/packages/css-parser-algorithms/test/test.mjs b/packages/css-parser-algorithms/test/test.mjs index 249abe7be..98779d117 100644 --- a/packages/css-parser-algorithms/test/test.mjs +++ b/packages/css-parser-algorithms/test/test.mjs @@ -17,6 +17,7 @@ import './cases/query-with-type/0002.mjs'; import './cases/query-with-type/0003.mjs'; import './cases/replacer/0001.mjs'; +import './cases/replacer/0002.mjs'; import './cases/source-indices/0001.mjs'; @@ -43,6 +44,7 @@ import './cases/various/0020.mjs'; import './cases/various/0021.mjs'; import './cases/walker/0001.mjs'; +import './cases/walker/0002.mjs'; import './cases/wpt/0001.mjs'; import './cases/wpt/0002.mjs'; diff --git a/packages/media-query-list-parser/CHANGELOG.md b/packages/media-query-list-parser/CHANGELOG.md index 3e31a4419..053bb70ee 100644 --- a/packages/media-query-list-parser/CHANGELOG.md +++ b/packages/media-query-list-parser/CHANGELOG.md @@ -3,6 +3,8 @@ ### Unreleased (patch) - Small fixes in type definitions +- Only `walk` child nodes if they are still part of the current AST tree [#1202](https://github.com/csstools/postcss-plugins/issues/1202) +- Make `walk` methods safe for mutations [#1204](https://github.com/csstools/postcss-plugins/issues/1204) ### 2.1.5 diff --git a/packages/media-query-list-parser/dist/index.cjs b/packages/media-query-list-parser/dist/index.cjs index aabcfbcc6..2603d9206 100644 --- a/packages/media-query-list-parser/dist/index.cjs +++ b/packages/media-query-list-parser/dist/index.cjs @@ -1 +1 @@ -"use strict";var e,t=require("@csstools/css-parser-algorithms"),i=require("@csstools/css-tokenizer");exports.NodeType=void 0,(e=exports.NodeType||(exports.NodeType={})).CustomMedia="custom-media",e.GeneralEnclosed="general-enclosed",e.MediaAnd="media-and",e.MediaCondition="media-condition",e.MediaConditionListWithAnd="media-condition-list-and",e.MediaConditionListWithOr="media-condition-list-or",e.MediaFeature="media-feature",e.MediaFeatureBoolean="mf-boolean",e.MediaFeatureName="mf-name",e.MediaFeaturePlain="mf-plain",e.MediaFeatureRangeNameValue="mf-range-name-value",e.MediaFeatureRangeValueName="mf-range-value-name",e.MediaFeatureRangeValueNameValue="mf-range-value-name-value",e.MediaFeatureValue="mf-value",e.MediaInParens="media-in-parens",e.MediaNot="media-not",e.MediaOr="media-or",e.MediaQueryWithType="media-query-with-type",e.MediaQueryWithoutType="media-query-without-type",e.MediaQueryInvalid="media-query-invalid";const a=/[A-Z]/g;function toLowerCaseAZ(e){return e.replace(a,(e=>String.fromCharCode(e.charCodeAt(0)+32)))}class MediaCondition{type=exports.NodeType.MediaCondition;media;constructor(e){this.media=e}tokens(){return this.media.tokens()}toString(){return this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,media:this.media.toJSON()}}isMediaCondition(){return MediaCondition.isMediaCondition(this)}static isMediaCondition(e){return!!e&&(e instanceof MediaCondition&&e.type===exports.NodeType.MediaCondition)}}class MediaInParens{type=exports.NodeType.MediaInParens;media;before;after;constructor(e,t=[],i=[]){this.media=e,this.before=t,this.after=i}tokens(){return[...this.before,...this.media.tokens(),...this.after]}toString(){return i.stringify(...this.before)+this.media.toString()+i.stringify(...this.after)}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&("walk"in this.media?this.media.walk(e,i):void 0)}toJSON(){return{type:this.type,media:this.media.toJSON(),before:this.before,after:this.after}}isMediaInParens(){return MediaInParens.isMediaInParens(this)}static isMediaInParens(e){return!!e&&(e instanceof MediaInParens&&e.type===exports.NodeType.MediaInParens)}}class MediaQueryWithType{type=exports.NodeType.MediaQueryWithType;modifier;mediaType;and=void 0;media=void 0;constructor(e,t,i,a){this.modifier=e,this.mediaType=t,i&&a&&(this.and=i,this.media=a)}getModifier(){if(!this.modifier.length)return"";for(let e=0;ee.tokens()))}toString(){return this.media.map((e=>e.toString())).join("")}walk(e,t){let i=!1;if(this.media.forEach(((a,r)=>{if(i)return;let n;t&&(n={...t}),!1!==e({node:a,parent:this,state:n},r)?"walk"in a&&!1===a.walk(e,n)&&(i=!0):i=!0})),i)return!1}toJSON(){return{type:this.type,string:this.toString(),media:this.media}}isMediaQueryInvalid(){return MediaQueryInvalid.isMediaQueryInvalid(this)}static isMediaQueryInvalid(e){return!!e&&(e instanceof MediaQueryInvalid&&e.type===exports.NodeType.MediaQueryInvalid)}}class GeneralEnclosed{type=exports.NodeType.GeneralEnclosed;value;constructor(e){this.value=e}tokens(){return this.value.tokens()}toString(){return this.value.toString()}indexOf(e){return e===this.value?"value":-1}at(e){if("value"===e)return this.value}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,tokens:this.tokens()}}isGeneralEnclosed(){return GeneralEnclosed.isGeneralEnclosed(this)}static isGeneralEnclosed(e){return!!e&&(e instanceof GeneralEnclosed&&e.type===exports.NodeType.GeneralEnclosed)}}class MediaAnd{type=exports.NodeType.MediaAnd;modifier;media;constructor(e,t){this.modifier=e,this.media=t}tokens(){return[...this.modifier,...this.media.tokens()]}toString(){return i.stringify(...this.modifier)+this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){return"media"===e?this.media:null}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,modifier:this.modifier,media:this.media.toJSON()}}isMediaAnd(){return MediaAnd.isMediaAnd(this)}static isMediaAnd(e){return!!e&&(e instanceof MediaAnd&&e.type===exports.NodeType.MediaAnd)}}class MediaConditionListWithAnd{type=exports.NodeType.MediaConditionListWithAnd;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return i.stringify(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+i.stringify(...this.after)}indexOf(e){return e===this.leading?"leading":"media-and"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,t){let i;if(t&&(i={...t}),!1===e({node:this.leading,parent:this,state:i},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,i))return!1;let a=!1;return this.list.forEach(((r,n)=>{a||(t&&(i={...t}),!1!==e({node:r,parent:this,state:i},n)?"walk"in r&&!1===r.walk(e,i)&&(a=!0):a=!0)})),!a&&void 0}toJSON(){return{type:this.type,leading:this.leading.toJSON(),list:this.list.map((e=>e.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===exports.NodeType.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=exports.NodeType.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return i.stringify(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+i.stringify(...this.after)}indexOf(e){return e===this.leading?"leading":"media-or"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,t){let i;if(t&&(i={...t}),!1===e({node:this.leading,parent:this,state:i},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,i))return!1;let a=!1;return this.list.forEach(((r,n)=>{a||(t&&(i={...t}),!1!==e({node:r,parent:this,state:i},n)?"walk"in r&&!1===r.walk(e,i)&&(a=!0):a=!0)})),!a&&void 0}toJSON(){return{type:this.type,leading:this.leading.toJSON(),list:this.list.map((e=>e.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===exports.NodeType.MediaConditionListWithOr)}}function isNumber(e){return!!(e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Number||e.type===t.ComponentValueType.Function&&r.has(toLowerCaseAZ(e.name[4].value)))}const r=new Set(["abs","acos","asin","atan","atan2","calc","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(e){return e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Dimension}function isIdent(e){return e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Ident}function isEnvironmentVariable(e){return e.type===t.ComponentValueType.Function&&"env"===toLowerCaseAZ(e.name[4].value)}class MediaFeatureName{type=exports.NodeType.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return i.stringify(...this.before)+this.name.toString()+i.stringify(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===exports.NodeType.MediaFeatureName)}}function parseMediaFeatureName(e){let i=-1;for(let a=0;ae.tokens())),e.slice(i+1).flatMap((e=>e.tokens())))}class MediaFeatureBoolean{type=exports.NodeType.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===exports.NodeType.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=exports.NodeType.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap((e=>e.tokens())),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?i.stringify(...this.before)+this.value.map((e=>e.toString())).join("")+i.stringify(...this.after):i.stringify(...this.before)+this.value.toString()+i.stringify(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(e,t){if(Array.isArray(this.value)){let i=!1;if(this.value.forEach(((a,r)=>{if(i)return;let n;t&&(n={...t}),!1!==e({node:a,parent:this,state:n},r)?"walk"in a&&!1===a.walk(e,n)&&(i=!0):i=!0})),i)return!1}else{let i;if(t&&(i={...t}),!1===e({node:this.value,parent:this,state:i},"value"))return!1;if("walk"in this.value)return this.value.walk(e,i)}}toJSON(){return Array.isArray(this.value)?{type:this.type,value:this.value.map((e=>e.toJSON())),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===exports.NodeType.MediaFeatureValue)}}function parseMediaFeatureValue(e,i=!1){let a=-1,r=-1;for(let n=0;ne.tokens())),e.slice(r+1).flatMap((e=>e.tokens())))}function matchesRatioExactly(e){let t=-1,i=-1;const a=matchesRatio(e);if(-1===a)return-1;t=a[0],i=a[1];for(let t=i+1;t2)return!1;if(e[0][0]!==i.TokenType.Delim)return!1;if(1===e.length)switch(e[0][4].value){case exports.MediaFeatureEQ.EQ:return exports.MediaFeatureEQ.EQ;case exports.MediaFeatureLT.LT:return exports.MediaFeatureLT.LT;case exports.MediaFeatureGT.GT:return exports.MediaFeatureGT.GT;default:return!1}if(e[1][0]!==i.TokenType.Delim)return!1;if(e[1][4].value!==exports.MediaFeatureEQ.EQ)return!1;switch(e[0][4].value){case exports.MediaFeatureLT.LT:return exports.MediaFeatureLT.LT_OR_EQ;case exports.MediaFeatureGT.GT:return exports.MediaFeatureGT.GT_OR_EQ;default:return!1}}exports.MediaFeatureLT=void 0,(n=exports.MediaFeatureLT||(exports.MediaFeatureLT={})).LT="<",n.LT_OR_EQ="<=",exports.MediaFeatureGT=void 0,(s=exports.MediaFeatureGT||(exports.MediaFeatureGT={})).GT=">",s.GT_OR_EQ=">=",exports.MediaFeatureEQ=void 0,(exports.MediaFeatureEQ||(exports.MediaFeatureEQ={})).EQ="=";class MediaFeatureRangeNameValue{type=exports.NodeType.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+i.stringify(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===exports.NodeType.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=exports.NodeType.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+i.stringify(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===exports.NodeType.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=exports.NodeType.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,r){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=r}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+i.stringify(...this.valueOneOperator)+this.name.toString()+i.stringify(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===exports.NodeType.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(e){let a=!1,r=!1;for(let n=0;ne.tokens())),-1!==r&&(o=e.slice(a+1,r+1).flatMap((e=>e.tokens())))):-1!==r&&(o=e.slice(0,r+1).flatMap((e=>e.tokens())));const u=parseMediaConditionWithoutOr(e.slice(Math.max(a,r,n)+1));return!1===u?new MediaQueryWithType(s,[...o,...e.slice(r+1).flatMap((e=>e.tokens()))]):new MediaQueryWithType(s,o,e.slice(r+1,n+1).flatMap((e=>e.tokens())),u)}}function parseMediaConditionListWithOr(e){let i=!1;const a=[];let r=-1,n=-1;for(let s=0;se.tokens())),e.slice(n+1).flatMap((e=>e.tokens())))}function parseMediaConditionListWithAnd(e){let i=!1;const a=[];let r=-1,n=-1;for(let s=0;se.tokens())),e.slice(n+1).flatMap((e=>e.tokens())))}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionListWithOr(e);if(!1!==a)return new MediaCondition(a);const r=parseMediaInParens(e);return!1!==r&&new MediaCondition(r)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaInParens(e);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(e){let a=-1;for(let i=0;ie.tokens())),r.startToken],s=[r.endToken,...e.slice(a+1).flatMap((e=>e.tokens()))],o=parseMediaFeature(r,n,s);if(!1!==o)return new MediaInParens(o);const u=parseMediaCondition(r.value);return!1!==u?new MediaInParens(u,n,s):new MediaInParens(new GeneralEnclosed(r),e.slice(0,a).flatMap((e=>e.tokens())),e.slice(a+1).flatMap((e=>e.tokens())))}function parseMediaInParensFromSimpleBlock(e){if(e.startToken[0]!==i.TokenType.OpenParen)return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const a=parseMediaCondition(e.value);return!1!==a?new MediaInParens(a,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}function parseMediaNot(e){let i=!1,a=null;for(let r=0;re.tokens())),t)}}}return a||!1}function parseMediaOr(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseMediaAnd(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseFromTokens(e,i){const a=t.parseCommaSeparatedListOfComponentValues(e,{onParseError:null==i?void 0:i.onParseError});return a.map(((e,t)=>{const r=parseMediaQuery(e);return 0==r&&!0===(null==i?void 0:i.preserveInvalidMediaQueries)?new MediaQueryInvalid(a[t]):r})).filter((e=>!!e))}exports.MediaQueryModifier=void 0,(o=exports.MediaQueryModifier||(exports.MediaQueryModifier={})).Not="not",o.Only="only";class CustomMedia{type=exports.NodeType.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON()))}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===exports.NodeType.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let a=[],r=e;for(let t=0;tString.fromCharCode(e.charCodeAt(0)+32)))}class MediaCondition{type=exports.NodeType.MediaCondition;media;constructor(e){this.media=e}tokens(){return this.media.tokens()}toString(){return this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,media:this.media.toJSON()}}isMediaCondition(){return MediaCondition.isMediaCondition(this)}static isMediaCondition(e){return!!e&&(e instanceof MediaCondition&&e.type===exports.NodeType.MediaCondition)}}class MediaInParens{type=exports.NodeType.MediaInParens;media;before;after;constructor(e,t=[],i=[]){this.media=e,this.before=t,this.after=i}tokens(){return[...this.before,...this.media.tokens(),...this.after]}toString(){return i.stringify(...this.before)+this.media.toString()+i.stringify(...this.after)}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&("walk"in this.media?this.media.walk(e,i):void 0)}toJSON(){return{type:this.type,media:this.media.toJSON(),before:this.before,after:this.after}}isMediaInParens(){return MediaInParens.isMediaInParens(this)}static isMediaInParens(e){return!!e&&(e instanceof MediaInParens&&e.type===exports.NodeType.MediaInParens)}}class MediaQueryWithType{type=exports.NodeType.MediaQueryWithType;modifier;mediaType;and=void 0;media=void 0;constructor(e,t,i,a){this.modifier=e,this.mediaType=t,i&&a&&(this.and=i,this.media=a)}getModifier(){if(!this.modifier.length)return"";for(let e=0;ee.tokens()))}toString(){return this.media.map((e=>e.toString())).join("")}walk(e,i){if(0===this.media.length)return;const a=t.walkerIndexGenerator(this.media);let r=0;for(;re.tokens())),...this.after]}toString(){return i.stringify(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+i.stringify(...this.after)}indexOf(e){return e===this.leading?"leading":"media-and"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,i){let a;if(i&&(a={...i}),!1===e({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,a))return!1;if(0===this.list.length)return;const r=t.walkerIndexGenerator(this.list);let n=0;for(;ne.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===exports.NodeType.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=exports.NodeType.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return i.stringify(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+i.stringify(...this.after)}indexOf(e){return e===this.leading?"leading":"media-or"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,i){let a;if(i&&(a={...i}),!1===e({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,a))return!1;if(0===this.list.length)return;const r=t.walkerIndexGenerator(this.list);let n=0;for(;ne.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===exports.NodeType.MediaConditionListWithOr)}}function isNumber(e){return!!(e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Number||e.type===t.ComponentValueType.Function&&r.has(toLowerCaseAZ(e.name[4].value)))}const r=new Set(["abs","acos","asin","atan","atan2","calc","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(e){return e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Dimension}function isIdent(e){return e.type===t.ComponentValueType.Token&&e.value[0]===i.TokenType.Ident}function isEnvironmentVariable(e){return e.type===t.ComponentValueType.Function&&"env"===toLowerCaseAZ(e.name[4].value)}class MediaFeatureName{type=exports.NodeType.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return i.stringify(...this.before)+this.name.toString()+i.stringify(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===exports.NodeType.MediaFeatureName)}}function parseMediaFeatureName(e){let i=-1;for(let a=0;ae.tokens())),e.slice(i+1).flatMap((e=>e.tokens())))}class MediaFeatureBoolean{type=exports.NodeType.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===exports.NodeType.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=exports.NodeType.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap((e=>e.tokens())),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?i.stringify(...this.before)+this.value.map((e=>e.toString())).join("")+i.stringify(...this.after):i.stringify(...this.before)+this.value.toString()+i.stringify(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(e,i){if(Array.isArray(this.value)){if(0===this.value.length)return;const a=t.walkerIndexGenerator(this.value);let r=0;for(;re.toJSON())),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===exports.NodeType.MediaFeatureValue)}}function parseMediaFeatureValue(e,i=!1){let a=-1,r=-1;for(let n=0;ne.tokens())),e.slice(r+1).flatMap((e=>e.tokens())))}function matchesRatioExactly(e){let t=-1,i=-1;const a=matchesRatio(e);if(-1===a)return-1;t=a[0],i=a[1];for(let t=i+1;t2)return!1;if(e[0][0]!==i.TokenType.Delim)return!1;if(1===e.length)switch(e[0][4].value){case exports.MediaFeatureEQ.EQ:return exports.MediaFeatureEQ.EQ;case exports.MediaFeatureLT.LT:return exports.MediaFeatureLT.LT;case exports.MediaFeatureGT.GT:return exports.MediaFeatureGT.GT;default:return!1}if(e[1][0]!==i.TokenType.Delim)return!1;if(e[1][4].value!==exports.MediaFeatureEQ.EQ)return!1;switch(e[0][4].value){case exports.MediaFeatureLT.LT:return exports.MediaFeatureLT.LT_OR_EQ;case exports.MediaFeatureGT.GT:return exports.MediaFeatureGT.GT_OR_EQ;default:return!1}}exports.MediaFeatureLT=void 0,(n=exports.MediaFeatureLT||(exports.MediaFeatureLT={})).LT="<",n.LT_OR_EQ="<=",exports.MediaFeatureGT=void 0,(s=exports.MediaFeatureGT||(exports.MediaFeatureGT={})).GT=">",s.GT_OR_EQ=">=",exports.MediaFeatureEQ=void 0,(exports.MediaFeatureEQ||(exports.MediaFeatureEQ={})).EQ="=";class MediaFeatureRangeNameValue{type=exports.NodeType.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+i.stringify(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===exports.NodeType.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=exports.NodeType.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+i.stringify(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===exports.NodeType.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=exports.NodeType.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,r){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=r}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+i.stringify(...this.valueOneOperator)+this.name.toString()+i.stringify(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===exports.NodeType.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(e){let a=!1,r=!1;for(let n=0;ne.tokens())),-1!==r&&(o=e.slice(a+1,r+1).flatMap((e=>e.tokens())))):-1!==r&&(o=e.slice(0,r+1).flatMap((e=>e.tokens())));const u=parseMediaConditionWithoutOr(e.slice(Math.max(a,r,n)+1));return!1===u?new MediaQueryWithType(s,[...o,...e.slice(r+1).flatMap((e=>e.tokens()))]):new MediaQueryWithType(s,o,e.slice(r+1,n+1).flatMap((e=>e.tokens())),u)}}function parseMediaConditionListWithOr(e){let i=!1;const a=[];let r=-1,n=-1;for(let s=0;se.tokens())),e.slice(n+1).flatMap((e=>e.tokens())))}function parseMediaConditionListWithAnd(e){let i=!1;const a=[];let r=-1,n=-1;for(let s=0;se.tokens())),e.slice(n+1).flatMap((e=>e.tokens())))}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionListWithOr(e);if(!1!==a)return new MediaCondition(a);const r=parseMediaInParens(e);return!1!==r&&new MediaCondition(r)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaInParens(e);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(e){let a=-1;for(let i=0;ie.tokens())),r.startToken],s=[r.endToken,...e.slice(a+1).flatMap((e=>e.tokens()))],o=parseMediaFeature(r,n,s);if(!1!==o)return new MediaInParens(o);const u=parseMediaCondition(r.value);return!1!==u?new MediaInParens(u,n,s):new MediaInParens(new GeneralEnclosed(r),e.slice(0,a).flatMap((e=>e.tokens())),e.slice(a+1).flatMap((e=>e.tokens())))}function parseMediaInParensFromSimpleBlock(e){if(e.startToken[0]!==i.TokenType.OpenParen)return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const a=parseMediaCondition(e.value);return!1!==a?new MediaInParens(a,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}function parseMediaNot(e){let i=!1,a=null;for(let r=0;re.tokens())),t)}}}return a||!1}function parseMediaOr(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseMediaAnd(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseFromTokens(e,i){const a=t.parseCommaSeparatedListOfComponentValues(e,{onParseError:null==i?void 0:i.onParseError});return a.map(((e,t)=>{const r=parseMediaQuery(e);return 0==r&&!0===(null==i?void 0:i.preserveInvalidMediaQueries)?new MediaQueryInvalid(a[t]):r})).filter((e=>!!e))}exports.MediaQueryModifier=void 0,(o=exports.MediaQueryModifier||(exports.MediaQueryModifier={})).Not="not",o.Only="only";class CustomMedia{type=exports.NodeType.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON()))}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===exports.NodeType.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let a=[],r=e;for(let t=0;tString.fromCharCode(e.charCodeAt(0)+32)))}class MediaCondition{type=f.MediaCondition;media;constructor(e){this.media=e}tokens(){return this.media.tokens()}toString(){return this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,media:this.media.toJSON()}}isMediaCondition(){return MediaCondition.isMediaCondition(this)}static isMediaCondition(e){return!!e&&(e instanceof MediaCondition&&e.type===f.MediaCondition)}}class MediaInParens{type=f.MediaInParens;media;before;after;constructor(e,t=[],i=[]){this.media=e,this.before=t,this.after=i}tokens(){return[...this.before,...this.media.tokens(),...this.after]}toString(){return u(...this.before)+this.media.toString()+u(...this.after)}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&("walk"in this.media?this.media.walk(e,i):void 0)}toJSON(){return{type:this.type,media:this.media.toJSON(),before:this.before,after:this.after}}isMediaInParens(){return MediaInParens.isMediaInParens(this)}static isMediaInParens(e){return!!e&&(e instanceof MediaInParens&&e.type===f.MediaInParens)}}class MediaQueryWithType{type=f.MediaQueryWithType;modifier;mediaType;and=void 0;media=void 0;constructor(e,t,i,a){this.modifier=e,this.mediaType=t,i&&a&&(this.and=i,this.media=a)}getModifier(){if(!this.modifier.length)return"";for(let e=0;ee.tokens()))}toString(){return this.media.map((e=>e.toString())).join("")}walk(e,t){let i=!1;if(this.media.forEach(((a,n)=>{if(i)return;let r;t&&(r={...t}),!1!==e({node:a,parent:this,state:r},n)?"walk"in a&&!1===a.walk(e,r)&&(i=!0):i=!0})),i)return!1}toJSON(){return{type:this.type,string:this.toString(),media:this.media}}isMediaQueryInvalid(){return MediaQueryInvalid.isMediaQueryInvalid(this)}static isMediaQueryInvalid(e){return!!e&&(e instanceof MediaQueryInvalid&&e.type===f.MediaQueryInvalid)}}class GeneralEnclosed{type=f.GeneralEnclosed;value;constructor(e){this.value=e}tokens(){return this.value.tokens()}toString(){return this.value.toString()}indexOf(e){return e===this.value?"value":-1}at(e){if("value"===e)return this.value}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,tokens:this.tokens()}}isGeneralEnclosed(){return GeneralEnclosed.isGeneralEnclosed(this)}static isGeneralEnclosed(e){return!!e&&(e instanceof GeneralEnclosed&&e.type===f.GeneralEnclosed)}}class MediaAnd{type=f.MediaAnd;modifier;media;constructor(e,t){this.modifier=e,this.media=t}tokens(){return[...this.modifier,...this.media.tokens()]}toString(){return u(...this.modifier)+this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){return"media"===e?this.media:null}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,modifier:this.modifier,media:this.media.toJSON()}}isMediaAnd(){return MediaAnd.isMediaAnd(this)}static isMediaAnd(e){return!!e&&(e instanceof MediaAnd&&e.type===f.MediaAnd)}}class MediaConditionListWithAnd{type=f.MediaConditionListWithAnd;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return u(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+u(...this.after)}indexOf(e){return e===this.leading?"leading":"media-and"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,t){let i;if(t&&(i={...t}),!1===e({node:this.leading,parent:this,state:i},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,i))return!1;let a=!1;return this.list.forEach(((n,r)=>{a||(t&&(i={...t}),!1!==e({node:n,parent:this,state:i},r)?"walk"in n&&!1===n.walk(e,i)&&(a=!0):a=!0)})),!a&&void 0}toJSON(){return{type:this.type,leading:this.leading.toJSON(),list:this.list.map((e=>e.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===f.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=f.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return u(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+u(...this.after)}indexOf(e){return e===this.leading?"leading":"media-or"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(e,t){let i;if(t&&(i={...t}),!1===e({node:this.leading,parent:this,state:i},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(e,i))return!1;let a=!1;return this.list.forEach(((n,r)=>{a||(t&&(i={...t}),!1!==e({node:n,parent:this,state:i},r)?"walk"in n&&!1===n.walk(e,i)&&(a=!0):a=!0)})),!a&&void 0}toJSON(){return{type:this.type,leading:this.leading.toJSON(),list:this.list.map((e=>e.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===f.MediaConditionListWithOr)}}function isNumber(t){return!!(t.type===e.Token&&t.value[0]===d.Number||t.type===e.Function&&M.has(toLowerCaseAZ(t.name[4].value)))}const M=new Set(["abs","acos","asin","atan","atan2","calc","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(t){return t.type===e.Token&&t.value[0]===d.Dimension}function isIdent(t){return t.type===e.Token&&t.value[0]===d.Ident}function isEnvironmentVariable(t){return t.type===e.Function&&"env"===toLowerCaseAZ(t.name[4].value)}class MediaFeatureName{type=f.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return u(...this.before)+this.name.toString()+u(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===f.MediaFeatureName)}}function parseMediaFeatureName(t){let i=-1;for(let a=0;ae.tokens())),t.slice(i+1).flatMap((e=>e.tokens())))}class MediaFeatureBoolean{type=f.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===f.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=f.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap((e=>e.tokens())),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?u(...this.before)+this.value.map((e=>e.toString())).join("")+u(...this.after):u(...this.before)+this.value.toString()+u(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(e,t){if(Array.isArray(this.value)){let i=!1;if(this.value.forEach(((a,n)=>{if(i)return;let r;t&&(r={...t}),!1!==e({node:a,parent:this,state:r},n)?"walk"in a&&!1===a.walk(e,r)&&(i=!0):i=!0})),i)return!1}else{let i;if(t&&(i={...t}),!1===e({node:this.value,parent:this,state:i},"value"))return!1;if("walk"in this.value)return this.value.walk(e,i)}}toJSON(){return Array.isArray(this.value)?{type:this.type,value:this.value.map((e=>e.toJSON())),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===f.MediaFeatureValue)}}function parseMediaFeatureValue(t,i=!1){let a=-1,n=-1;for(let r=0;re.tokens())),t.slice(n+1).flatMap((e=>e.tokens())))}function matchesRatioExactly(e){let t=-1,i=-1;const a=matchesRatio(e);if(-1===a)return-1;t=a[0],i=a[1];for(let t=i+1;t2)return!1;if(e[0][0]!==d.Delim)return!1;if(1===e.length)switch(e[0][4].value){case v.EQ:return v.EQ;case p.LT:return p.LT;case y.GT:return y.GT;default:return!1}if(e[1][0]!==d.Delim)return!1;if(e[1][4].value!==v.EQ)return!1;switch(e[0][4].value){case p.LT:return p.LT_OR_EQ;case y.GT:return y.GT_OR_EQ;default:return!1}}function invertComparison(e){switch(e){case v.EQ:return v.EQ;case p.LT:return y.GT;case p.LT_OR_EQ:return y.GT_OR_EQ;case y.GT:return p.LT;case y.GT_OR_EQ:return p.LT_OR_EQ;default:return!1}}!function(e){e.LT="<",e.LT_OR_EQ="<="}(p||(p={})),function(e){e.GT=">",e.GT_OR_EQ=">="}(y||(y={})),function(e){e.EQ="="}(v||(v={}));class MediaFeatureRangeNameValue{type=f.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+u(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===f.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=f.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+u(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===f.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=f.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,n){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=n}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+u(...this.valueOneOperator)+this.name.toString()+u(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===f.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(t){let i=!1,a=!1;for(let n=0;ne.tokens())),-1!==i&&(u=e.slice(t+1,i+1).flatMap((e=>e.tokens())))):-1!==i&&(u=e.slice(0,i+1).flatMap((e=>e.tokens())));const l=parseMediaConditionWithoutOr(e.slice(Math.max(t,i,s)+1));return!1===l?new MediaQueryWithType(o,[...u,...e.slice(i+1).flatMap((e=>e.tokens()))]):new MediaQueryWithType(o,u,e.slice(i+1,s+1).flatMap((e=>e.tokens())),l)}}function parseMediaConditionListWithOr(t){let i=!1;const a=[];let n=-1,r=-1;for(let o=0;oe.tokens())),t.slice(r+1).flatMap((e=>e.tokens())))}function parseMediaConditionListWithAnd(t){let i=!1;const a=[];let n=-1,r=-1;for(let o=0;oe.tokens())),t.slice(r+1).flatMap((e=>e.tokens())))}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionListWithOr(e);if(!1!==a)return new MediaCondition(a);const n=parseMediaInParens(e);return!1!==n&&new MediaCondition(n)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaInParens(e);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(t){let i=-1;for(let a=0;ae.tokens())),a.startToken],r=[a.endToken,...t.slice(i+1).flatMap((e=>e.tokens()))],o=parseMediaFeature(a,n,r);if(!1!==o)return new MediaInParens(o);const u=parseMediaCondition(a.value);return!1!==u?new MediaInParens(u,n,r):new MediaInParens(new GeneralEnclosed(a),t.slice(0,i).flatMap((e=>e.tokens())),t.slice(i+1).flatMap((e=>e.tokens())))}function parseMediaInParensFromSimpleBlock(e){if(e.startToken[0]!==d.OpenParen)return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const i=parseMediaCondition(e.value);return!1!==i?new MediaInParens(i,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}function parseMediaNot(t){let i=!1,a=null;for(let n=0;ne.tokens())),e)}}}return a||!1}function parseMediaOr(t){let i=!1;for(let a=0;ae.tokens())),e)}}return!1}}return!1}function parseMediaAnd(t){let i=!1;for(let a=0;ae.tokens())),e)}}return!1}}return!1}function parseFromTokens(e,t){const i=o(e,{onParseError:null==t?void 0:t.onParseError});return i.map(((e,a)=>{const n=parseMediaQuery(e);return 0==n&&!0===(null==t?void 0:t.preserveInvalidMediaQueries)?new MediaQueryInvalid(i[a]):n})).filter((e=>!!e))}function parse(e,t){const i=h({css:e},{onParseError:null==t?void 0:t.onParseError}),a=[];for(;!i.endOfFile();)a.push(i.nextToken());return a.push(i.nextToken()),parseFromTokens(a,t)}!function(e){e.Not="not",e.Only="only"}(g||(g={}));class CustomMedia{type=f.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON()))}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===f.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let i=[],a=e;for(let t=0;tString.fromCharCode(e.charCodeAt(0)+32)))}class MediaCondition{type=c.MediaCondition;media;constructor(e){this.media=e}tokens(){return this.media.tokens()}toString(){return this.media.toString()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,media:this.media.toJSON()}}isMediaCondition(){return MediaCondition.isMediaCondition(this)}static isMediaCondition(e){return!!e&&(e instanceof MediaCondition&&e.type===c.MediaCondition)}}class MediaInParens{type=c.MediaInParens;media;before;after;constructor(e,t=[],i=[]){this.media=e,this.before=t,this.after=i}tokens(){return[...this.before,...this.media.tokens(),...this.after]}toString(){return d(...this.before)+this.media.toString()+d(...this.after)}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&("walk"in this.media?this.media.walk(e,i):void 0)}toJSON(){return{type:this.type,media:this.media.toJSON(),before:this.before,after:this.after}}isMediaInParens(){return MediaInParens.isMediaInParens(this)}static isMediaInParens(e){return!!e&&(e instanceof MediaInParens&&e.type===c.MediaInParens)}}class MediaQueryWithType{type=c.MediaQueryWithType;modifier;mediaType;and=void 0;media=void 0;constructor(e,t,i,a){this.modifier=e,this.mediaType=t,i&&a&&(this.and=i,this.media=a)}getModifier(){if(!this.modifier.length)return"";for(let e=0;ee.tokens()))}toString(){return this.media.map((e=>e.toString())).join("")}walk(t,i){if(0===this.media.length)return;const a=e(this.media);let n=0;for(;ne.tokens())),...this.after]}toString(){return d(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+d(...this.after)}indexOf(e){return e===this.leading?"leading":"media-and"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===c.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=c.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap((e=>e.tokens())),...this.after]}toString(){return d(...this.before)+this.leading.toString()+this.list.map((e=>e.toString())).join("")+d(...this.after)}indexOf(e){return e===this.leading?"leading":"media-or"===e.type?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON())),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===c.MediaConditionListWithOr)}}function isNumber(e){return!!(e.type===t.Token&&e.value[0]===l.Number||e.type===t.Function&&p.has(toLowerCaseAZ(e.name[4].value)))}const p=new Set(["abs","acos","asin","atan","atan2","calc","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(e){return e.type===t.Token&&e.value[0]===l.Dimension}function isIdent(e){return e.type===t.Token&&e.value[0]===l.Ident}function isEnvironmentVariable(e){return e.type===t.Function&&"env"===toLowerCaseAZ(e.name[4].value)}class MediaFeatureName{type=c.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return d(...this.before)+this.name.toString()+d(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===c.MediaFeatureName)}}function parseMediaFeatureName(e){let i=-1;for(let a=0;ae.tokens())),e.slice(i+1).flatMap((e=>e.tokens())))}class MediaFeatureBoolean{type=c.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===c.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=c.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap((e=>e.tokens())),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?d(...this.before)+this.value.map((e=>e.toString())).join("")+d(...this.after):d(...this.before)+this.value.toString()+d(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(t,i){if(Array.isArray(this.value)){if(0===this.value.length)return;const a=e(this.value);let n=0;for(;ne.toJSON())),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===c.MediaFeatureValue)}}function parseMediaFeatureValue(e,i=!1){let a=-1,n=-1;for(let r=0;re.tokens())),e.slice(n+1).flatMap((e=>e.tokens())))}function matchesRatioExactly(e){let t=-1,i=-1;const a=matchesRatio(e);if(-1===a)return-1;t=a[0],i=a[1];for(let t=i+1;t2)return!1;if(e[0][0]!==l.Delim)return!1;if(1===e.length)switch(e[0][4].value){case g.EQ:return g.EQ;case y.LT:return y.LT;case v.GT:return v.GT;default:return!1}if(e[1][0]!==l.Delim)return!1;if(e[1][4].value!==g.EQ)return!1;switch(e[0][4].value){case y.LT:return y.LT_OR_EQ;case v.GT:return v.GT_OR_EQ;default:return!1}}function invertComparison(e){switch(e){case g.EQ:return g.EQ;case y.LT:return v.GT;case y.LT_OR_EQ:return v.GT_OR_EQ;case v.GT:return y.LT;case v.GT_OR_EQ:return y.LT_OR_EQ;default:return!1}}!function(e){e.LT="<",e.LT_OR_EQ="<="}(y||(y={})),function(e){e.GT=">",e.GT_OR_EQ=">="}(v||(v={})),function(e){e.EQ="="}(g||(g={}));class MediaFeatureRangeNameValue{type=c.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+d(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===c.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=c.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+d(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===c.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=c.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,n){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=n}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+d(...this.valueOneOperator)+this.name.toString()+d(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===c.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(e){let i=!1,a=!1;for(let n=0;ne.tokens())),-1!==i&&(u=e.slice(t+1,i+1).flatMap((e=>e.tokens())))):-1!==i&&(u=e.slice(0,i+1).flatMap((e=>e.tokens())));const d=parseMediaConditionWithoutOr(e.slice(Math.max(t,i,a)+1));return!1===d?new MediaQueryWithType(o,[...u,...e.slice(i+1).flatMap((e=>e.tokens()))]):new MediaQueryWithType(o,u,e.slice(i+1,a+1).flatMap((e=>e.tokens())),d)}}function parseMediaConditionListWithOr(e){let i=!1;const a=[];let n=-1,r=-1;for(let s=0;se.tokens())),e.slice(r+1).flatMap((e=>e.tokens())))}function parseMediaConditionListWithAnd(e){let i=!1;const a=[];let n=-1,r=-1;for(let s=0;se.tokens())),e.slice(r+1).flatMap((e=>e.tokens())))}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionListWithOr(e);if(!1!==a)return new MediaCondition(a);const n=parseMediaInParens(e);return!1!==n&&new MediaCondition(n)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaInParens(e);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(e){let i=-1;for(let a=0;ae.tokens())),a.startToken],r=[a.endToken,...e.slice(i+1).flatMap((e=>e.tokens()))],s=parseMediaFeature(a,n,r);if(!1!==s)return new MediaInParens(s);const u=parseMediaCondition(a.value);return!1!==u?new MediaInParens(u,n,r):new MediaInParens(new GeneralEnclosed(a),e.slice(0,i).flatMap((e=>e.tokens())),e.slice(i+1).flatMap((e=>e.tokens())))}function parseMediaInParensFromSimpleBlock(e){if(e.startToken[0]!==l.OpenParen)return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const i=parseMediaCondition(e.value);return!1!==i?new MediaInParens(i,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}function parseMediaNot(e){let i=!1,a=null;for(let n=0;ne.tokens())),t)}}}return a||!1}function parseMediaOr(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseMediaAnd(e){let i=!1;for(let a=0;ae.tokens())),t)}}return!1}}return!1}function parseFromTokens(e,t){const i=u(e,{onParseError:null==t?void 0:t.onParseError});return i.map(((e,a)=>{const n=parseMediaQuery(e);return 0==n&&!0===(null==t?void 0:t.preserveInvalidMediaQueries)?new MediaQueryInvalid(i[a]):n})).filter((e=>!!e))}function parse(e,t){const i=m({css:e},{onParseError:null==t?void 0:t.onParseError}),a=[];for(;!i.endOfFile();)a.push(i.nextToken());return a.push(i.nextToken()),parseFromTokens(a,t)}!function(e){e.Not="not",e.Only="only"}(k||(k={}));class CustomMedia{type=c.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON()))}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===c.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let i=[],a=e;for(let t=0;t { - if (aborted) { - return; - } + const indexGenerator = walkerIndexGenerator(this.list); + + let index = 0; + while (index < this.list.length) { + const child = this.list[index]; if (state) { stateClone = { @@ -91,20 +95,19 @@ export class MediaConditionListWithAnd { } if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; + return false; } - if ('walk' in child) { + if ('walk' in child && this.list.includes(child)) { if (child.walk(cb, stateClone) === false) { - aborted = true; - return; + return false; } } - }); - if (aborted) { - return false; + index = indexGenerator(this.list, child, index); + if (index === -1) { + break; + } } } @@ -209,12 +212,15 @@ export class MediaConditionListWithOr { } } - let aborted = false; + if (this.list.length === 0) { + return; + } - this.list.forEach((child, index) => { - if (aborted) { - return; - } + const indexGenerator = walkerIndexGenerator(this.list); + + let index = 0; + while (index < this.list.length) { + const child = this.list[index]; if (state) { stateClone = { @@ -223,20 +229,19 @@ export class MediaConditionListWithOr { } if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; + return false; } - if ('walk' in child) { + if ('walk' in child && this.list.includes(child)) { if (child.walk(cb, stateClone) === false) { - aborted = true; - return; + return false; } } - }); - if (aborted) { - return false; + index = indexGenerator(this.list, child, index); + if (index === -1) { + break; + } } } diff --git a/packages/media-query-list-parser/src/nodes/media-feature-value.ts b/packages/media-query-list-parser/src/nodes/media-feature-value.ts index f82fe6241..87f53323c 100644 --- a/packages/media-query-list-parser/src/nodes/media-feature-value.ts +++ b/packages/media-query-list-parser/src/nodes/media-feature-value.ts @@ -1,4 +1,4 @@ -import { ComponentValue, ComponentValueType, ContainerNode } from '@csstools/css-parser-algorithms'; +import { ComponentValue, ComponentValueType, ContainerNode, walkerIndexGenerator } from '@csstools/css-parser-algorithms'; import { CSSToken, stringify, TokenType } from '@csstools/css-tokenizer'; import { isDimension, isEnvironmentVariable, isIdent, isNumber } from '../util/component-value-is'; import { NodeType } from '../util/node-type'; @@ -68,12 +68,15 @@ export class MediaFeatureValue { walk>(cb: (entry: { node: MediaFeatureValueWalkerEntry, parent: MediaFeatureValueWalkerParent, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { if (Array.isArray(this.value)) { - let aborted = false; + if (this.value.length === 0) { + return; + } - this.value.forEach((child, index) => { - if (aborted) { - return; - } + const indexGenerator = walkerIndexGenerator(this.value); + + let index = 0; + while (index < this.value.length) { + const child = this.value[index]; let stateClone: T | undefined = undefined; if (state) { @@ -83,20 +86,19 @@ export class MediaFeatureValue { } if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; + return false; } - if ('walk' in child) { + if ('walk' in child && this.value.includes(child)) { if (child.walk(cb, stateClone) === false) { - aborted = true; - return; + return false; } } - }); - if (aborted) { - return false; + index = indexGenerator(this.value, child, index); + if (index === -1) { + break; + } } } else { let stateClone: T | undefined = undefined; diff --git a/packages/media-query-list-parser/src/nodes/media-query.ts b/packages/media-query-list-parser/src/nodes/media-query.ts index 9ec8fd69f..9d034f5b3 100644 --- a/packages/media-query-list-parser/src/nodes/media-query.ts +++ b/packages/media-query-list-parser/src/nodes/media-query.ts @@ -1,4 +1,4 @@ -import { ComponentValue } from '@csstools/css-parser-algorithms'; +import { ComponentValue, walkerIndexGenerator } from '@csstools/css-parser-algorithms'; import { CSSToken, stringify, TokenType } from '@csstools/css-tokenizer'; import { NodeType } from '../util/node-type'; import { toLowerCaseAZ } from '../util/to-lower-case-a-z'; @@ -311,12 +311,15 @@ export class MediaQueryInvalid { } walk>(cb: (entry: { node: MediaQueryInvalidWalkerEntry, parent: MediaQueryInvalidWalkerParent, state?: T }, index: number | string) => boolean | void, state?: T): false | undefined { - let aborted = false; + if (this.media.length === 0) { + return; + } - this.media.forEach((child, index) => { - if (aborted) { - return; - } + const indexGenerator = walkerIndexGenerator(this.media); + + let index = 0; + while (index < this.media.length) { + const child = this.media[index]; let stateClone: T | undefined = undefined; if (state) { @@ -326,20 +329,19 @@ export class MediaQueryInvalid { } if (cb({ node: child, parent: this, state: stateClone }, index) === false) { - aborted = true; - return; + return false; } - if ('walk' in child) { + if ('walk' in child && this.media.includes(child)) { if (child.walk(cb, stateClone) === false) { - aborted = true; - return; + return false; } } - }); - if (aborted) { - return false; + index = indexGenerator(this.media, child, index); + if (index === -1) { + break; + } } }