From 1bb045c17e56f3d8707fb8dd286a6724e269398c Mon Sep 17 00:00:00 2001 From: Jon Webb Date: Mon, 3 Aug 2026 09:35:34 -0400 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75114=20css-tr?= =?UTF-8?q?ee:=20update=20types=20to=20v3=20by=20@jonathonwebb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- attw.json | 1 + types/css-tree/.npmignore | 1 + types/css-tree/css-tree-tests.ts | 270 +++++++- types/css-tree/index.d.ts | 511 ++++++++++++++-- types/css-tree/package.json | 2 +- types/css-tree/v2/.npmignore | 5 + types/css-tree/v2/css-tree-tests.ts | 753 +++++++++++++++++++++++ types/css-tree/v2/index.d.ts | 918 ++++++++++++++++++++++++++++ types/css-tree/v2/package.json | 21 + types/css-tree/v2/tsconfig.json | 19 + types/csso/package.json | 2 +- 11 files changed, 2436 insertions(+), 67 deletions(-) create mode 100644 types/css-tree/v2/.npmignore create mode 100644 types/css-tree/v2/css-tree-tests.ts create mode 100644 types/css-tree/v2/index.d.ts create mode 100644 types/css-tree/v2/package.json create mode 100644 types/css-tree/v2/tsconfig.json diff --git a/attw.json b/attw.json index e42a8c3aea9683..41bf9f33cc38a8 100644 --- a/attw.json +++ b/attw.json @@ -43,6 +43,7 @@ "crypto-ld", "css-declaration-sorter", "css-tree", + "css-tree/v2", "csso", "d3-array", "d3-axis", diff --git a/types/css-tree/.npmignore b/types/css-tree/.npmignore index 93e307400a5456..d73cba2e3a91b8 100644 --- a/types/css-tree/.npmignore +++ b/types/css-tree/.npmignore @@ -3,3 +3,4 @@ !**/*.d.cts !**/*.d.mts !**/*.d.*.ts +/v2/ diff --git a/types/css-tree/css-tree-tests.ts b/types/css-tree/css-tree-tests.ts index 31fe806d75fee1..bd6bb6a3f6e573 100644 --- a/types/css-tree/css-tree-tests.ts +++ b/types/css-tree/css-tree-tests.ts @@ -5,6 +5,8 @@ ast; // $ExpectType CssNode csstree.parse(".a { color: red; }", {}); // $ExpectType CssNode csstree.parse(".a { color: red; }", { context: "selector", positions: true }); // $ExpectType CssNode +csstree.parse(".a { color: red; }", { list: true }); // $ExpectType CssNode +csstree.parse(".a { color: red; }", { list: false }); // $ExpectType CssNodePlain csstree.walk(ast, (node, item, list) => { node; // $ExpectType CssNode @@ -73,21 +75,30 @@ csstree.generate(ast, {}); // $ExpectType string csstree.generate(ast, { sourceMap: true, decorator: handlers => ({ - children(node, delimiter) { - node; // $ExpectType CssNode - delimiter; // $ExpectType ((node: CssNode) => void) | undefined - handlers.children.call(handlers, node, delimiter); - }, node(node) { node; // $ExpectType CssNode handlers.node(node); }, - chunk(chunk) { - chunk; // $ExpectType string - handlers.chunk(chunk); + tokenBefore(prevCode, type, value) { + prevCode; // $ExpectType number + type; // $ExpectType number + value; // $ExpectType string + return handlers.tokenBefore(prevCode, type, value); + }, + token(type, value, suppressAutoWhiteSpace) { + type; // $ExpectType number + value; // $ExpectType string + suppressAutoWhiteSpace; // $ExpectType boolean | undefined + handlers.token(type, value, suppressAutoWhiteSpace); + }, + emit(value, type, auto) { + value; // $ExpectType string + type; // $ExpectType number + auto; // $ExpectType boolean + handlers.emit(value, type, auto); }, result() { - return handlers.result.call(handlers); + return handlers.result(); }, }), mode: "spec", @@ -120,6 +131,9 @@ const list = new csstree.List(); const anItem = list.createItem({ a: "c" }); anItem; // $ExpectType ListItem +const staticItem = csstree.List.createItem({ a: "c" }); +staticItem; // $ExpectType ListItem<{ a: string; }> + list.fromArray([{ a: "b" }]); list.toArray(); // $ExpectType Test[] list.size; // $ExpectType number @@ -262,18 +276,19 @@ list.prepend(anItem); // $ExpectType List list.prependData({ a: "b" }); // $ExpectType List list.append(anItem); // $ExpectType List list.appendData({ a: "b" }); // $ExpectType List +list.insert(anItem); // $ExpectType List list.insert(anItem, anItem); // $ExpectType List list.insertData({ a: "b" }, anItem); // $ExpectType List list.remove(anItem); // $ExpectType ListItem list.push({ a: "b" }); // $ExpectType void -list.pop(); // $ExpectType ListItem | undefined +list.pop(); // $ExpectType ListItem | null list.unshift({ a: "b" }); // $ExpectType void -list.shift(); // $ExpectType ListItem | undefined +list.shift(); // $ExpectType ListItem | null list.prependList(list); // $ExpectType List list.appendList(list); // $ExpectType List list.insertList(list, anItem); // $ExpectType List -list.replace(anItem, list); // $ExpectType List -list.replace(anItem, anItem); // $ExpectType List +list.replace(anItem, list); // $ExpectType void +list.replace(anItem, anItem); // $ExpectType void switch (ast.type) { case "AnPlusB": @@ -356,15 +371,48 @@ switch (ast.type) { ast.name; // $ExpectType string break; - case "MediaFeature": + case "Feature": + ast.kind; // $ExpectType string ast.name; // $ExpectType string - ast.value; // $ExpectType Dimension | Identifier | NumberNode | Ratio | null + ast.value; // $ExpectType Dimension | FunctionNode | Identifier | NumberNode | Ratio | null break; - case "MediaQuery": + case "FeatureRange": + ast.kind; // $ExpectType string + ast.left; // $ExpectType Dimension | FunctionNode | Identifier | NumberNode | Ratio + ast.leftComparison; // $ExpectType string + ast.middle; // $ExpectType Dimension | FunctionNode | Identifier | NumberNode | Ratio + ast.rightComparison; // $ExpectType string | null + ast.right; // $ExpectType Dimension | FunctionNode | Identifier | NumberNode | Ratio | null + break; + + case "FeatureFunction": + ast.kind; // $ExpectType string + ast.feature; // $ExpectType string + ast.value; // $ExpectType Declaration | Selector + break; + + case "GeneralEnclosed": + ast.kind; // $ExpectType string + ast.function; // $ExpectType string | null ast.children; // $ExpectType List break; + case "Condition": + ast.kind; // $ExpectType string + ast.children; // $ExpectType List + break; + + case "SupportsDeclaration": + ast.declaration; // $ExpectType Declaration + break; + + case "MediaQuery": + ast.modifier; // $ExpectType string | null + ast.mediaType; // $ExpectType string | null + ast.condition; // $ExpectType Condition | null + break; + case "MediaQueryList": ast.children; // $ExpectType List break; @@ -404,8 +452,8 @@ switch (ast.type) { break; case "Ratio": - ast.left; // $ExpectType string - ast.right; // $ExpectType string + ast.left; // $ExpectType FunctionNode | NumberNode + ast.right; // $ExpectType FunctionNode | NumberNode | null break; case "Raw": @@ -453,6 +501,19 @@ switch (ast.type) { ast.value; // $ExpectType string break; + case "Layer": + ast.name; // $ExpectType string + break; + + case "LayerList": + ast.children; // $ExpectType List + break; + + case "Scope": + ast.root; // $ExpectType Raw | SelectorList | null + ast.limit; // $ExpectType Raw | SelectorList | null + break; + default: ast; // $ExpectType never } @@ -538,15 +599,48 @@ switch (toPlain.type) { toPlain.name; // $ExpectType string break; - case "MediaFeature": + case "Feature": + toPlain.kind; // $ExpectType string toPlain.name; // $ExpectType string - toPlain.value; // $ExpectType Dimension | Identifier | NumberNode | Ratio | null + toPlain.value; // $ExpectType Dimension | FunctionNodePlain | Identifier | NumberNode | RatioPlain | null break; - case "MediaQuery": + case "FeatureRange": + toPlain.kind; // $ExpectType string + toPlain.left; // $ExpectType Dimension | FunctionNodePlain | Identifier | NumberNode | RatioPlain + toPlain.leftComparison; // $ExpectType string + toPlain.middle; // $ExpectType Dimension | FunctionNodePlain | Identifier | NumberNode | RatioPlain + toPlain.rightComparison; // $ExpectType string | null + toPlain.right; // $ExpectType Dimension | FunctionNodePlain | Identifier | NumberNode | RatioPlain | null + break; + + case "FeatureFunction": + toPlain.kind; // $ExpectType string + toPlain.feature; // $ExpectType string + toPlain.value; // $ExpectType DeclarationPlain | SelectorPlain + break; + + case "GeneralEnclosed": + toPlain.kind; // $ExpectType string + toPlain.function; // $ExpectType string | null + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Condition": + toPlain.kind; // $ExpectType string toPlain.children; // $ExpectType CssNodePlain[] break; + case "SupportsDeclaration": + toPlain.declaration; // $ExpectType DeclarationPlain + break; + + case "MediaQuery": + toPlain.modifier; // $ExpectType string | null + toPlain.mediaType; // $ExpectType string | null + toPlain.condition; // $ExpectType ConditionPlain | null + break; + case "MediaQueryList": toPlain.children; // $ExpectType CssNodePlain[] break; @@ -583,8 +677,8 @@ switch (toPlain.type) { break; case "Ratio": - toPlain.left; // $ExpectType string - toPlain.right; // $ExpectType string + toPlain.left; // $ExpectType FunctionNodePlain | NumberNode + toPlain.right; // $ExpectType FunctionNodePlain | NumberNode | null break; case "Raw": @@ -632,11 +726,27 @@ switch (toPlain.type) { toPlain.value; // $ExpectType string break; + case "Layer": + toPlain.name; // $ExpectType string + break; + + case "LayerList": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Scope": + toPlain.root; // $ExpectType Raw | SelectorListPlain | null + toPlain.limit; // $ExpectType Raw | SelectorListPlain | null + break; + default: toPlain; // $ExpectType never } -csstree.definitionSyntax.syntaxError; // $ExpectType SyntaxError +const dsError = csstree.definitionSyntax.SyntaxError("message", "input", 0); // $ExpectType DefinitionSyntaxError +dsError.input; // $ExpectType string +dsError.offset; // $ExpectType number +dsError.rawMessage; // $ExpectType string const syntax = csstree.definitionSyntax.parse("foo | bar"); // $ExpectType DSNodeGroup const node = syntax.terms[0]; // $ExpectType DSNode switch (node.type) { @@ -644,6 +754,10 @@ switch (node.type) { node; // $ExpectType DSNodeAtWord node.name; // $ExpectType string break; + case "Boolean": + node; // $ExpectType DSNodeBoolean + node.term; // $ExpectType DSNode + break; case "Comma": node; // $ExpectType DSNodeComma break; @@ -692,12 +806,18 @@ csstree.definitionSyntax.generate(syntax); // $ExpectType string csstree.definitionSyntax.generate(syntax, { forceBraces: true }); // $ExpectType string csstree.definitionSyntax.generate(syntax, { compact: true }); // $ExpectType string csstree.definitionSyntax.generate(syntax, { - decorate: (result: string, node) => { + decorate: (result, node) => { result; // $ExpectType string - node; // $ExpectType DSNode + node; // $ExpectType DSNode | DSNodeTypeOpts return result; }, }); +// $ExpectType string +csstree.definitionSyntax.generate(syntax, (result, node) => { + result; // $ExpectType string + node; // $ExpectType DSNode | DSNodeTypeOpts + return result; +}); csstree.definitionSyntax.walk(syntax, (node) => { node; // $ExpectType DSNode @@ -716,10 +836,26 @@ csstree.parse(".selector { /* comment */ }", { csstree.parse(".a { ::: invalid css ::: }", { onParseError(error, fallbackNode) { error; // $ExpectType SyntaxParseError + error.source; // $ExpectType string + error.line; // $ExpectType number + error.column; // $ExpectType number + error.formattedMessage; // $ExpectType string + error.sourceFragment(); // $ExpectType string fallbackNode; // $ExpectType CssNode }, }); +csstree.parse(".a {}", { + onToken(type, start, end, index) { + type; // $ExpectType number + start; // $ExpectType number + end; // $ExpectType number + index; // $ExpectType number + }, +}); +const tokenRecords: Array<{ type: number; start: number; end: number }> = []; +csstree.parse(".a {}", { onToken: tokenRecords, positions: true }); + csstree.ident.decode("foo"); // $ExpectType string csstree.ident.encode("foo"); // $ExpectType string csstree.string.decode("foo"); // $ExpectType string @@ -728,14 +864,39 @@ csstree.string.encode("foo", true); // $ExpectType string csstree.url.decode("foo"); // $ExpectType string csstree.url.encode("foo"); // $ExpectType string -csstree.fork({}); // $ExpectType { lexer: Lexer; } -const { lexer } = csstree.fork({ +csstree.fork({}); // $ExpectType Syntax +csstree.fork(config => config); // $ExpectType Syntax +const forked = csstree.fork({ atrules: {}, properties: {}, types: { foo: "" }, cssWideKeywords: ["initial"], }); +forked; // $ExpectType Syntax +const { lexer } = forked; lexer; // $ExpectType Lexer + +csstree.createSyntax({}); // $ExpectType Syntax +csstree.createLexer(); // $ExpectType Lexer +csstree.createLexer({}); // $ExpectType Lexer + +forked.parse(".a {}"); // $ExpectType CssNode +forked.parse(".a {}", { list: false }); // $ExpectType CssNodePlain +forked.generate(ast); // $ExpectType string +forked.walk(ast, () => {}); +forked.find(ast, () => true); // $ExpectType CssNode | null +forked.findLast(ast, () => true); // $ExpectType CssNode | null +forked.findAll(ast, () => true); // $ExpectType CssNode[] +forked.fromPlainObject(toPlain); // $ExpectType CssNode +forked.toPlainObject(ast); // $ExpectType CssNodePlain +forked.createLexer(); // $ExpectType Lexer +forked.fork({}); // $ExpectType Syntax +forked.tokenize(".a {}", (type, start, end) => { + type; // $ExpectType number + start; // $ExpectType number + end; // $ExpectType number +}); + lexer.matchAtruleDescriptor("foo", "bar", ast); // $ExpectType LexerMatchResult lexer.matchAtruleDescriptor("foo", "bar", "baz"); // $ExpectType LexerMatchResult lexer.matchAtrulePrelude("foo", ast); // $ExpectType LexerMatchResult @@ -750,4 +911,57 @@ lexer.match("foo", "bar"); // $ExpectType LexerMatchResult lexer.match(syntax, ast); // $ExpectType LexerMatchResult lexer.match(syntax, "bar"); // $ExpectType LexerMatchResult +const matchResult = lexer.matchProperty("color", ast); +matchResult.matched; // $ExpectType SyntaxMatchNode | null +matchResult.iterations; // $ExpectType number +matchResult.error; // $ExpectType Error | SyntaxMatchError | SyntaxReferenceError | null +matchResult.getTrace(ast); // $ExpectType SyntaxMatchNode[] | null +matchResult.isType(ast, "foo"); // $ExpectType boolean +matchResult.isProperty(ast, "color"); // $ExpectType boolean +matchResult.isKeyword(ast); // $ExpectType boolean + +lexer.checkStructure(ast); // $ExpectType false | StructureWarning[] +lexer.checkAtruleName("media"); // $ExpectType SyntaxReferenceError | undefined +lexer.checkAtrulePrelude("media", ast); // $ExpectType Error | SyntaxReferenceError | undefined +lexer.checkAtruleDescriptorName("media", "foo"); // $ExpectType SyntaxError | SyntaxReferenceError | undefined +lexer.checkPropertyName("color"); // $ExpectType SyntaxReferenceError | undefined + +lexer.findValueFragments("color", ast, "Type", "foo"); // $ExpectType LexerValueFragment[] +lexer.findAllFragments(ast, "Type", "foo"); // $ExpectType LexerValueFragment[] + +lexer.getAtrule("media"); // $ExpectType AtruleDescriptor | null +lexer.getAtrulePrelude("media"); // $ExpectType SyntaxDescriptor | null +lexer.getAtruleDescriptor("media", "foo"); // $ExpectType SyntaxDescriptor | null +lexer.getProperty("color"); // $ExpectType SyntaxDescriptor | null +lexer.getType("length"); // $ExpectType SyntaxDescriptor | null +lexer.validate(); // $ExpectType LexerValidationResult | null +lexer.dump(); // $ExpectType unknown +lexer.toString(); // $ExpectType string + csstree.lexer; // $ExpectType Lexer + +csstree.tokenize(".a {}"); // $ExpectType void +csstree.tokenize(".a {}", (type, start, end) => { + type; // $ExpectType number + start; // $ExpectType number + end; // $ExpectType number +}); +csstree.tokenTypes.Ident; // $ExpectType number +csstree.tokenNames; // $ExpectType string[] + +const tokenStream = new csstree.TokenStream(".a {}", csstree.tokenize); +tokenStream.source; // $ExpectType string +tokenStream.tokenType; // $ExpectType number +tokenStream.eof; // $ExpectType boolean +tokenStream.next(); // $ExpectType void +tokenStream.lookupType(1); // $ExpectType number +tokenStream.getTokenType(0); // $ExpectType number +tokenStream.dump(); // $ExpectType { idx: number; type: string; chunk: string; balance: number; }[] + +const offsetToLocation = new csstree.OffsetToLocation(".a {}"); +offsetToLocation.getLocation(0); // $ExpectType { source: string; offset: number; line: number; column: number; } +offsetToLocation.getLocationRange(0, 1); // $ExpectType CssLocation + +csstree.vendorPrefix("-webkit-foo"); // $ExpectType string +csstree.isCustomProperty("--foo"); // $ExpectType boolean +csstree.version; // $ExpectType string diff --git a/types/css-tree/index.d.ts b/types/css-tree/index.d.ts index c005ef349475c1..117788a9b9bf5b 100644 --- a/types/css-tree/index.d.ts +++ b/types/css-tree/index.d.ts @@ -34,6 +34,7 @@ export type ReduceFn> = (this: TContext, a export class List { constructor(); + static createItem(data: T): ListItem; get size(): number; get isEmpty(): boolean; get first(): TData | null; @@ -73,17 +74,17 @@ export class List { prependData(data: TData): List; append(item: ListItem): List; appendData(data: TData): List; - insert(item: ListItem, before: ListItem): List; + insert(item: ListItem, before?: ListItem | null): List; insertData(data: TData, before: ListItem): List; remove(item: ListItem): ListItem; push(item: TData): void; - pop(): ListItem | undefined; + pop(): ListItem | null; unshift(data: TData): void; - shift(): ListItem | undefined; + shift(): ListItem | null; prependList(list: List): List; appendList(list: List): List; insertList(list: List, before: ListItem): List; - replace(oldItem: ListItem, newItemOrList: List | ListItem): List; + replace(oldItem: ListItem, newItemOrList: List | ListItem): void; } export interface CssNodeCommon { @@ -229,20 +230,129 @@ export interface Identifier extends CssNodeCommon { name: string; } -export interface MediaFeature extends CssNodeCommon { - type: "MediaFeature"; +export interface Layer extends CssNodeCommon { + type: "Layer"; name: string; - value: Identifier | NumberNode | Dimension | Ratio | null; +} + +export interface LayerList extends CssNodeCommon { + type: "LayerList"; + children: List; +} + +export interface LayerListPlain extends CssNodeCommon { + type: "LayerList"; + children: CssNodePlain[]; +} + +export interface Feature extends CssNodeCommon { + type: "Feature"; + kind: string; + name: string; + value: Identifier | NumberNode | Dimension | Ratio | FunctionNode | null; +} + +export interface FeaturePlain extends CssNodeCommon { + type: "Feature"; + kind: string; + name: string; + value: Identifier | NumberNode | Dimension | RatioPlain | FunctionNodePlain | null; +} + +export interface FeatureRange extends CssNodeCommon { + type: "FeatureRange"; + kind: string; + left: Identifier | NumberNode | Dimension | Ratio | FunctionNode; + leftComparison: string; + middle: Identifier | NumberNode | Dimension | Ratio | FunctionNode; + rightComparison: string | null; + right: Identifier | NumberNode | Dimension | Ratio | FunctionNode | null; +} + +export interface FeatureRangePlain extends CssNodeCommon { + type: "FeatureRange"; + kind: string; + left: Identifier | NumberNode | Dimension | RatioPlain | FunctionNodePlain; + leftComparison: string; + middle: Identifier | NumberNode | Dimension | RatioPlain | FunctionNodePlain; + rightComparison: string | null; + right: Identifier | NumberNode | Dimension | RatioPlain | FunctionNodePlain | null; +} + +export interface FeatureFunction extends CssNodeCommon { + type: "FeatureFunction"; + kind: string; + feature: string; + value: Declaration | Selector; +} + +export interface FeatureFunctionPlain extends CssNodeCommon { + type: "FeatureFunction"; + kind: string; + feature: string; + value: DeclarationPlain | SelectorPlain; +} + +export interface GeneralEnclosed extends CssNodeCommon { + type: "GeneralEnclosed"; + kind: string; + function: string | null; + children: List; +} + +export interface GeneralEnclosedPlain extends CssNodeCommon { + type: "GeneralEnclosed"; + kind: string; + function: string | null; + children: CssNodePlain[]; +} + +export interface Condition extends CssNodeCommon { + type: "Condition"; + kind: string; + children: List; +} + +export interface ConditionPlain extends CssNodeCommon { + type: "Condition"; + kind: string; + children: CssNodePlain[]; +} + +export interface SupportsDeclaration extends CssNodeCommon { + type: "SupportsDeclaration"; + declaration: Declaration; +} + +export interface SupportsDeclarationPlain extends CssNodeCommon { + type: "SupportsDeclaration"; + declaration: DeclarationPlain; +} + +export interface Scope extends CssNodeCommon { + type: "Scope"; + root: SelectorList | Raw | null; + limit: SelectorList | Raw | null; +} + +export interface ScopePlain extends CssNodeCommon { + type: "Scope"; + root: SelectorListPlain | Raw | null; + limit: SelectorListPlain | Raw | null; } export interface MediaQuery extends CssNodeCommon { type: "MediaQuery"; - children: List; + modifier: string | null; + mediaType: string | null; + condition: Condition | null; } export interface MediaQueryPlain extends CssNodeCommon { type: "MediaQuery"; - children: CssNodePlain[]; + modifier: string | null; + mediaType: string | null; + condition: ConditionPlain | null; } export interface MediaQueryList extends CssNodeCommon { @@ -322,8 +432,14 @@ export interface PseudoElementSelectorPlain extends CssNodeCommon { export interface Ratio extends CssNodeCommon { type: "Ratio"; - left: string; - right: string; + left: NumberNode | FunctionNode; + right: NumberNode | FunctionNode | null; +} + +export interface RatioPlain extends CssNodeCommon { + type: "Ratio"; + left: NumberNode | FunctionNodePlain; + right: NumberNode | FunctionNodePlain | null; } export interface Raw extends CssNodeCommon { @@ -427,7 +543,12 @@ export type CssNode = | Hash | IdSelector | Identifier - | MediaFeature + | Feature + | FeatureRange + | FeatureFunction + | GeneralEnclosed + | Condition + | SupportsDeclaration | MediaQuery | MediaQueryList | NestingSelector @@ -449,7 +570,10 @@ export type CssNode = | UnicodeRange | Url | Value - | WhiteSpace; + | WhiteSpace + | Layer + | LayerList + | Scope; export type CssNodePlain = | AnPlusB @@ -470,7 +594,12 @@ export type CssNodePlain = | Hash | IdSelector | Identifier - | MediaFeature + | FeaturePlain + | FeatureRangePlain + | FeatureFunctionPlain + | GeneralEnclosedPlain + | ConditionPlain + | SupportsDeclarationPlain | MediaQueryPlain | MediaQueryListPlain | NthPlain @@ -480,7 +609,7 @@ export type CssNodePlain = | Percentage | PseudoClassSelectorPlain | PseudoElementSelectorPlain - | Ratio + | RatioPlain | Raw | RulePlain | SelectorPlain @@ -491,13 +620,18 @@ export type CssNodePlain = | UnicodeRange | Url | ValuePlain - | WhiteSpace; + | WhiteSpace + | Layer + | LayerListPlain + | ScopePlain; export interface SyntaxParseError extends SyntaxError { - input: string; + source: string; offset: number; - rawMessage: string; + line: number; + column: number; formattedMessage: string; + sourceFragment(extraLines?: number): string; } export interface ParseOptions { @@ -514,15 +648,22 @@ export interface ParseOptions { parseRulePrelude?: boolean | undefined; parseValue?: boolean | undefined; parseCustomProperty?: boolean | undefined; + onToken?: + | ((type: number, start: number, end: number, index: number) => void) + | Array<{ type: number; start: number; end: number }> + | undefined; + list?: boolean | undefined; } +export function parse(text: string, options: ParseOptions & { list: false }): CssNodePlain; export function parse(text: string, options?: ParseOptions): CssNode; export interface GenerateHandlers { - children: (node: CssNode, delimiter?: (node: CssNode) => void) => void; - node: (node: CssNode) => void; - chunk: (chunk: string) => void; - result: () => string; + node(node: CssNode): void; + tokenBefore(prevCode: number, type: number, value: string): number; + token(type: number, value: string, suppressAutoWhiteSpace?: boolean): void; + emit(value: string, type: number, auto: boolean): void; + result(): string; } export interface GenerateOptions { @@ -597,7 +738,12 @@ export type WalkOptions = | WalkOptionsVisit | WalkOptionsVisit | WalkOptionsVisit - | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit | WalkOptionsVisit | WalkOptionsVisit | WalkOptionsVisit @@ -619,6 +765,10 @@ export type WalkOptions = | WalkOptionsVisit | WalkOptionsVisit | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit | WalkOptionsNoVisit; export const walk: { @@ -675,6 +825,14 @@ export interface DSNodeAtWord { name: string; } +/** + * Definition syntax Boolean node + */ +export interface DSNodeBoolean { + type: "Boolean"; + term: DSNode; +} + /** * Definition syntax Comma node */ @@ -769,6 +927,7 @@ export interface DSNodeType { */ export type DSNode = | DSNodeAtWord + | DSNodeBoolean | DSNodeComma | DSNodeFunction | DSNodeGroup @@ -788,7 +947,15 @@ export type DSNodeMultiplied = | DSNodeKeyword | DSNodeProperty | DSNodeString - | DSNodeType; + | DSNodeType + | DSNodeToken + | DSNodeBoolean + | DSNodeMultiplier; + +export type DSGenerateDecorateFn = ( + result: string, + node: DSNode | DSNodeTypeOpts, +) => string; /** * Definition syntax generate options @@ -796,7 +963,7 @@ export type DSNodeMultiplied = export interface DSGenerateOptions { forceBraces?: boolean | undefined; compact?: boolean | undefined; - decorate?: ((result: string, node: DSNode) => void) | undefined; + decorate?: DSGenerateDecorateFn | undefined; } /** @@ -812,6 +979,12 @@ export interface DSWalkOptions { */ export type DSWalkEnterOrLeaveFn = (node: DSNode) => void; +export interface DefinitionSyntaxError extends SyntaxError { + input: string; + offset: number; + rawMessage: string; +} + /** * DefinitionSyntax */ @@ -825,7 +998,7 @@ export interface DefinitionSyntax { * @example * generate({type: 'Keyword', name: 'foo'}) => 'foo' */ - generate(node: DSNode, options?: DSGenerateOptions): string; + generate(node: DSNode, options?: DSGenerateOptions | DSGenerateDecorateFn): string; /** * Generates an AST from a CSS value syntax @@ -855,7 +1028,11 @@ export interface DefinitionSyntax { /** * Wrapper for syntax errors */ - syntaxError: SyntaxError; + SyntaxError: ( + message: string, + input: string, + offset?: number, + ) => DefinitionSyntaxError; } export const definitionSyntax: DefinitionSyntax; @@ -875,7 +1052,7 @@ export const url: { encode(input: string): string; }; -export class SyntaxMatchError extends SyntaxError { +export interface SyntaxMatchError extends SyntaxError { rawMessage: string; syntax: string; css: string; @@ -891,28 +1068,288 @@ export class SyntaxMatchError extends SyntaxError { }; } -export class SyntaxReferenceError extends SyntaxError { +export interface SyntaxReferenceError extends SyntaxError { reference: string; } +export interface SyntaxMatchNode { + syntax: { type: string; name: string } | null; + match?: SyntaxMatchNode[]; + node?: CssNode; +} + export interface LexerMatchResult { + matched: SyntaxMatchNode | null; + iterations: number; error: Error | SyntaxMatchError | SyntaxReferenceError | null; + getTrace(node: CssNode): SyntaxMatchNode[] | null; + isType(node: CssNode, type: string): boolean; + isProperty(node: CssNode, property: string): boolean; + isKeyword(node: CssNode): boolean; +} + +export interface LexerValueFragment { + parent: List; + nodes: List; +} + +export interface SyntaxDescriptor { + type: "Property" | "Type" | "AtrulePrelude" | "AtruleDescriptor"; + name: string; + parent: SyntaxDescriptor | null; + serializable: boolean; + syntax: DSNode | null; + match: ((...args: unknown[]) => unknown) | null; + matchRef?: ((...args: unknown[]) => unknown) | null; +} + +export interface AtruleDescriptor { + type: "Atrule"; + name: string; + prelude: SyntaxDescriptor | null; + descriptors: Record | null; +} + +export interface StructureWarning { + node: CssNode; + message: string; +} + +export interface LexerValidationResult { + errors: string[]; + types: string[]; + properties: string[]; } export class Lexer { - matchAtruleDescriptor(atruleName: string, descriptorName: string, value: CssNode | string): LexerMatchResult; - matchAtrulePrelude(atruleName: string, prelude: CssNode | string): LexerMatchResult; + checkStructure(ast: CssNode): StructureWarning[] | false; + checkAtruleName(atruleName: string): SyntaxReferenceError | undefined; + checkAtrulePrelude( + atruleName: string, + prelude: CssNode | string, + ): Error | SyntaxReferenceError | undefined; + checkAtruleDescriptorName( + atruleName: string, + descriptorName: string, + ): SyntaxReferenceError | SyntaxError | undefined; + checkPropertyName(propertyName: string): SyntaxReferenceError | undefined; + + matchAtruleDescriptor( + atruleName: string, + descriptorName: string, + value: CssNode | string, + ): LexerMatchResult; + matchAtrulePrelude( + atruleName: string, + prelude: CssNode | string, + ): LexerMatchResult; matchDeclaration(node: CssNode): LexerMatchResult; - matchProperty(propertyName: string, value: CssNode | string): LexerMatchResult; + matchProperty( + propertyName: string, + value: CssNode | string, + ): LexerMatchResult; matchType(typeName: string, value: CssNode | string): LexerMatchResult; match(syntax: DSNode | string, value: CssNode | string): LexerMatchResult; + findValueFragments( + propertyName: string, + value: CssNode, + type: string, + name: string, + ): LexerValueFragment[]; + findDeclarationValueFragments( + declaration: Declaration, + type: string, + name: string, + ): LexerValueFragment[]; + findAllFragments( + ast: CssNode, + type: string, + name: string, + ): LexerValueFragment[]; + + getAtrule( + atruleName: string, + fallbackBasename?: boolean, + ): AtruleDescriptor | null; + getAtrulePrelude( + atruleName: string, + fallbackBasename?: boolean, + ): SyntaxDescriptor | null; + getAtruleDescriptor( + atruleName: string, + name: string, + ): SyntaxDescriptor | null; + getProperty( + propertyName: string, + fallbackBasename?: boolean, + ): SyntaxDescriptor | null; + getType(name: string): SyntaxDescriptor | null; + + validate(): LexerValidationResult | null; + dump(syntaxAsAst?: boolean, pretty?: boolean): unknown; + toString(): string; } export const lexer: Lexer; -export function fork(extension: { - atrules?: Record | undefined; - properties?: Record | undefined; +export interface SyntaxConfig { + generic?: boolean | undefined; + cssWideKeywords?: string[] | undefined; + units?: Record | undefined; types?: Record | undefined; - cssWideKeywords?: Array | undefined; -}): { lexer: Lexer }; + atrules?: + | Record< + string, + | string + | { + prelude?: string | null; + descriptors?: Record | null; + } + > + | undefined; + properties?: Record | undefined; + node?: Record | undefined; +} + +export interface Syntax { + lexer: Lexer; + createLexer(config?: SyntaxConfig): Lexer; + tokenize( + source: string, + onToken?: (type: number, start: number, end: number) => void, + ): void; + parse(text: string, options: ParseOptions & { list: false }): CssNodePlain; + parse(text: string, options?: ParseOptions): CssNode; + generate(ast: CssNode, options?: GenerateOptions): string; + walk(ast: CssNode, options: EnterOrLeaveFn | WalkOptions): void; + find(ast: CssNode, fn: FindFn): CssNode | null; + findLast(ast: CssNode, fn: FindFn): CssNode | null; + findAll(ast: CssNode, fn: FindFn): CssNode[]; + fromPlainObject(node: CssNodePlain): CssNode; + toPlainObject(node: CssNode): CssNodePlain; + fork( + extension: SyntaxConfig | ((config: SyntaxConfig) => SyntaxConfig), + ): Syntax; +} + +export function createSyntax(config: SyntaxConfig): Syntax; + +export function fork( + extension: SyntaxConfig | ((config: SyntaxConfig) => SyntaxConfig), +): Syntax; + +export function createLexer(config?: SyntaxConfig): Lexer; + +export function tokenize( + source: string, + onToken?: (type: number, start: number, end: number) => void, +): void; + +export const tokenTypes: { + readonly EOF: number; + readonly Ident: number; + readonly Function: number; + readonly AtKeyword: number; + readonly Hash: number; + readonly String: number; + readonly BadString: number; + readonly Url: number; + readonly BadUrl: number; + readonly Delim: number; + readonly Number: number; + readonly Percentage: number; + readonly Dimension: number; + readonly WhiteSpace: number; + readonly CDO: number; + readonly CDC: number; + readonly Colon: number; + readonly Semicolon: number; + readonly Comma: number; + readonly LeftSquareBracket: number; + readonly RightSquareBracket: number; + readonly LeftParenthesis: number; + readonly RightParenthesis: number; + readonly LeftCurlyBracket: number; + readonly RightCurlyBracket: number; + readonly Comment: number; +}; + +export const tokenNames: string[]; + +export type TokenizeHandler = ( + source: string, + onToken: (type: number, start: number, end: number) => void, +) => void; + +export class TokenStream { + source: string; + firstCharOffset: number; + tokenCount: number; + eof: boolean; + tokenIndex: number; + tokenType: number; + tokenStart: number; + tokenEnd: number; + constructor(source: string, tokenize: TokenizeHandler); + reset(): void; + setSource(source?: string, tokenize?: TokenizeHandler): void; + lookupType(offset: number): number; + lookupTypeNonSC(idx: number): number; + lookupOffset(offset: number): number; + lookupOffsetNonSC(idx: number): number; + lookupValue(offset: number, referenceStr: string): boolean; + getTokenStart(tokenIndex: number): number; + getTokenEnd(tokenIndex: number): number; + getTokenType(tokenIndex: number): number; + substrToCursor(start: number): string; + isBlockOpenerTokenType(tokenType: number): boolean; + isBlockCloserTokenType(tokenType: number): boolean; + getBlockTokenPairIndex(tokenIndex: number): number; + isBalanceEdge(tokenIndex: number): boolean; + isDelim(code: number, offset?: number): boolean; + skip(tokenCount: number): void; + next(): void; + skipSC(): void; + skipUntilBalanced( + startToken: number, + stopConsume: (code: number) => number, + ): void; + forEachToken( + fn: (type: number, start: number, end: number, index: number) => void, + ): void; + dump(): Array<{ + idx: number; + type: string; + chunk: string; + balance: number; + }>; +} + +export class OffsetToLocation { + constructor( + source: string, + startOffset?: number, + startLine?: number, + startColumn?: number, + ); + setSource( + source?: string, + startOffset?: number, + startLine?: number, + startColumn?: number, + ): void; + getLocation( + offset: number, + filename?: string, + ): { source: string; offset: number; line: number; column: number }; + getLocationRange( + start: number, + end: number, + filename?: string, + ): CssLocation; +} + +export function vendorPrefix(str: string, offset?: number): string; +export function isCustomProperty(str: string, offset?: number): boolean; + +export const version: string; diff --git a/types/css-tree/package.json b/types/css-tree/package.json index 8efd493cfc26fc..1d5ebe0f6f0050 100644 --- a/types/css-tree/package.json +++ b/types/css-tree/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/css-tree", - "version": "2.3.9999", + "version": "3.2.9999", "projects": [ "https://github.com/csstree/csstree" ], diff --git a/types/css-tree/v2/.npmignore b/types/css-tree/v2/.npmignore new file mode 100644 index 00000000000000..93e307400a5456 --- /dev/null +++ b/types/css-tree/v2/.npmignore @@ -0,0 +1,5 @@ +* +!**/*.d.ts +!**/*.d.cts +!**/*.d.mts +!**/*.d.*.ts diff --git a/types/css-tree/v2/css-tree-tests.ts b/types/css-tree/v2/css-tree-tests.ts new file mode 100644 index 00000000000000..31fe806d75fee1 --- /dev/null +++ b/types/css-tree/v2/css-tree-tests.ts @@ -0,0 +1,753 @@ +import * as csstree from "css-tree"; + +const ast = csstree.parse(".a { color: red; }"); +ast; // $ExpectType CssNode + +csstree.parse(".a { color: red; }", {}); // $ExpectType CssNode +csstree.parse(".a { color: red; }", { context: "selector", positions: true }); // $ExpectType CssNode + +csstree.walk(ast, (node, item, list) => { + node; // $ExpectType CssNode + item; // $ExpectType ListItem + list; // $ExpectType List +}); + +csstree.walk(ast, {}); + +csstree.walk(ast, { + enter(node, item, list) { + this.break; // $ExpectType symbol + this.skip; // $ExpectType symbol + this.root; // $ExpectType CssNode + this.stylesheet; // $ExpectType StyleSheet | null + node; // $ExpectType ClassSelector + item; // $ExpectType ListItem + list; // $ExpectType List + this.atrule; // $ExpectType Atrule | null + }, + leave(node, item, list) { + this.break; // $ExpectType symbol + this.skip; // $ExpectType symbol + this.root; // $ExpectType CssNode + this.stylesheet; // $ExpectType StyleSheet | null + node; // $ExpectType ClassSelector + item; // $ExpectType ListItem + list; // $ExpectType List + this.atrule; // $ExpectType Atrule | null + }, + visit: "ClassSelector", + reverse: false, +}); + +csstree.walk.break; // $ExpectType symbol +csstree.walk.skip; // $ExpectType symbol + +const findResult = csstree.find(ast, (node, item, list) => { + node; // $ExpectType CssNode + item; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +findResult; // $ExpectType CssNode | null + +const findLastResult = csstree.findLast(ast, (node, item, list) => { + node; // $ExpectType CssNode + item; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +findLastResult; // $ExpectType CssNode | null + +const findAllResult = csstree.findAll(ast, (node, item, list) => { + node; // $ExpectType CssNode + item; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +findAllResult; // $ExpectType CssNode[] + +csstree.generate(ast); // $ExpectType string + +csstree.generate(ast, {}); // $ExpectType string + +csstree.generate(ast, { + sourceMap: true, + decorator: handlers => ({ + children(node, delimiter) { + node; // $ExpectType CssNode + delimiter; // $ExpectType ((node: CssNode) => void) | undefined + handlers.children.call(handlers, node, delimiter); + }, + node(node) { + node; // $ExpectType CssNode + handlers.node(node); + }, + chunk(chunk) { + chunk; // $ExpectType string + handlers.chunk(chunk); + }, + result() { + return handlers.result.call(handlers); + }, + }), + mode: "spec", +}); + +const property = csstree.property("*-vendor-property"); // $ExpectType Property + +const keyword = csstree.keyword("-vendor-keyword"); // $ExpectType Keyword + +csstree.clone(ast); // $ExpectType CssNode + +const fromPlain = csstree.fromPlainObject({ + type: "SelectorList", + children: [], +}); +fromPlain; // $ExpectType CssNode + +const toPlain = csstree.toPlainObject({ + type: "SelectorList", + children: new csstree.List(), +}); +toPlain; // $ExpectType CssNodePlain + +interface Test { + a: string; +} + +const list = new csstree.List(); + +const anItem = list.createItem({ a: "c" }); +anItem; // $ExpectType ListItem + +list.fromArray([{ a: "b" }]); +list.toArray(); // $ExpectType Test[] +list.size; // $ExpectType number +list.isEmpty; // $ExpectType boolean +list.first; // $ExpectType Test | null +list.last; // $ExpectType Test | null +list.forEach(function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List +}, { b: "c" }); +list.forEach(function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List +}); +list.forEachRight(function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List +}, { b: "c" }); +list.forEachRight(function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List +}); +list.nextUntil(anItem, function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}, { b: "c" }); +list.nextUntil(anItem, function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +list.prevUntil(anItem, function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}, { b: "c" }); +list.prevUntil(anItem, function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +list.some(function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}, { b: "c" }); +list.some(function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +list.reduce(function(accum, node) { + this; // $ExpectType List + accum; // $ExpectType number + node; // $ExpectType Test + return accum; +}, 0); // $ExpectType 0 +list.reduceRight(function(accum, node) { + this; // $ExpectType List + accum; // $ExpectType number + node; // $ExpectType Test + return accum; +}, 0); // $ExpectType 0 +const map1 = list.map(function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return { c: "d" }; +}, { b: "c" }); +map1; // $ExpectType List<{ c: string; }> +const map2 = list.map(function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test + node; // $ExpectType ListItem + list; // $ExpectType List + return { c: "d" }; +}); +map2; // $ExpectType List<{ c: string; }> + +const list2 = new csstree.List(); + +const filter1 = list2.filter(function(item, node, list): item is Test { + this.b; // $ExpectType string + item; // $ExpectType Test | null + node; // $ExpectType ListItem + list; // $ExpectType List + return !!item; +}, { b: "c" }); +filter1; // $ExpectType List +const filter2 = list2.filter(function(item, node, list): item is Test { + this; // $ExpectType List + item; // $ExpectType Test | null + node; // $ExpectType ListItem + list; // $ExpectType List + return !!item; +}); +filter2; // $ExpectType List +const filter3 = list2.filter(function(item, node, list) { + this.b; // $ExpectType string + item; // $ExpectType Test | null + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}, { b: "c" }); +filter3; // $ExpectType List +const filter4 = list2.filter(function(item, node, list) { + this; // $ExpectType List + item; // $ExpectType Test | null + node; // $ExpectType ListItem + list; // $ExpectType List + return true; +}); +filter4; // $ExpectType List + +list.clear(); +list.copy(); // $ExpectType List +list.prepend(anItem); // $ExpectType List +list.prependData({ a: "b" }); // $ExpectType List +list.append(anItem); // $ExpectType List +list.appendData({ a: "b" }); // $ExpectType List +list.insert(anItem, anItem); // $ExpectType List +list.insertData({ a: "b" }, anItem); // $ExpectType List +list.remove(anItem); // $ExpectType ListItem +list.push({ a: "b" }); // $ExpectType void +list.pop(); // $ExpectType ListItem | undefined +list.unshift({ a: "b" }); // $ExpectType void +list.shift(); // $ExpectType ListItem | undefined +list.prependList(list); // $ExpectType List +list.appendList(list); // $ExpectType List +list.insertList(list, anItem); // $ExpectType List +list.replace(anItem, list); // $ExpectType List +list.replace(anItem, anItem); // $ExpectType List + +switch (ast.type) { + case "AnPlusB": + ast.a; // $ExpectType string | null + ast.b; // $ExpectType string | null + break; + + case "Atrule": + ast.name; // $ExpectType string + ast.prelude; // $ExpectType AtrulePrelude | Raw | null + ast.block; // $ExpectType Block | null + break; + + case "AtrulePrelude": + ast.children; // $ExpectType List + break; + + case "AttributeSelector": + ast.name; // $ExpectType Identifier + ast.matcher; // $ExpectType string | null + ast.value; // $ExpectType Identifier | StringNode | null + ast.flags; // $ExpectType string | null + break; + + case "Block": + ast.children; // $ExpectType List + break; + + case "Brackets": + ast.children; // $ExpectType List + break; + + case "CDC": + break; + + case "CDO": + break; + + case "ClassSelector": + ast.name; // $ExpectType string + break; + + case "Combinator": + ast.name; // $ExpectType string + break; + + case "Comment": + ast.value; // $ExpectType string + break; + + case "Declaration": + ast.important; // $ExpectType string | boolean + ast.property; // $ExpectType string + ast.value; // $ExpectType Raw | Value + break; + + case "DeclarationList": + ast.children; // $ExpectType List + break; + + case "Dimension": + ast.value; // $ExpectType string + ast.unit; // $ExpectType string + break; + + case "Function": + ast.name; // $ExpectType string + ast.children; // $ExpectType List + break; + + case "Hash": + ast.value; // $ExpectType string + break; + + case "IdSelector": + ast.name; // $ExpectType string + break; + + case "Identifier": + ast.name; // $ExpectType string + break; + + case "MediaFeature": + ast.name; // $ExpectType string + ast.value; // $ExpectType Dimension | Identifier | NumberNode | Ratio | null + break; + + case "MediaQuery": + ast.children; // $ExpectType List + break; + + case "MediaQueryList": + ast.children; // $ExpectType List + break; + + case "NestingSelector": + break; + + case "Nth": + ast.nth; // $ExpectType AnPlusB | Identifier + ast.selector; // $ExpectType SelectorList | null + break; + + case "Number": + ast.value; // $ExpectType string + break; + + case "Operator": + ast.value; // $ExpectType string + break; + + case "Parentheses": + ast.children; // $ExpectType List + break; + + case "Percentage": + ast.value; // $ExpectType string + break; + + case "PseudoClassSelector": + ast.name; // $ExpectType string + ast.children; // $ExpectType List | null + break; + + case "PseudoElementSelector": + ast.name; // $ExpectType string + ast.children; // $ExpectType List | null + break; + + case "Ratio": + ast.left; // $ExpectType string + ast.right; // $ExpectType string + break; + + case "Raw": + ast.value; // $ExpectType string + break; + + case "Rule": + ast.prelude; // $ExpectType Raw | SelectorList + ast.block; // $ExpectType Block + break; + + case "Selector": + ast.children; // $ExpectType List + break; + + case "SelectorList": + ast.children; // $ExpectType List + break; + + case "String": + ast.value; // $ExpectType string + break; + + case "StyleSheet": + ast.children; // $ExpectType List + break; + + case "TypeSelector": + ast.name; // $ExpectType string + break; + + case "UnicodeRange": + ast.value; // $ExpectType string + break; + + case "Url": + ast.value; // $ExpectType string + break; + + case "Value": + ast.children; // $ExpectType List + break; + + case "WhiteSpace": + ast.value; // $ExpectType string + break; + + default: + ast; // $ExpectType never +} + +switch (toPlain.type) { + case "AnPlusB": + toPlain.a; // $ExpectType string | null + toPlain.b; // $ExpectType string | null + break; + + case "Atrule": + toPlain.name; // $ExpectType string + toPlain.prelude; // $ExpectType Raw | AtrulePreludePlain | null + toPlain.block; // $ExpectType BlockPlain | null + break; + + case "AtrulePrelude": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "AttributeSelector": + toPlain.name; // $ExpectType Identifier + toPlain.matcher; // $ExpectType string | null + toPlain.value; // $ExpectType Identifier | StringNode | null + toPlain.flags; // $ExpectType string | null + break; + + case "Block": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Brackets": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "CDC": + break; + + case "CDO": + break; + + case "ClassSelector": + toPlain.name; // $ExpectType string + break; + + case "Combinator": + toPlain.name; // $ExpectType string + break; + + case "Comment": + toPlain.value; // $ExpectType string + break; + + case "Declaration": + toPlain.important; // $ExpectType string | boolean + toPlain.property; // $ExpectType string + toPlain.value; // $ExpectType Raw | ValuePlain + break; + + case "DeclarationList": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Dimension": + toPlain.value; // $ExpectType string + toPlain.unit; // $ExpectType string + break; + + case "Function": + toPlain.name; // $ExpectType string + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Hash": + toPlain.value; // $ExpectType string + break; + + case "IdSelector": + toPlain.name; // $ExpectType string + break; + + case "Identifier": + toPlain.name; // $ExpectType string + break; + + case "MediaFeature": + toPlain.name; // $ExpectType string + toPlain.value; // $ExpectType Dimension | Identifier | NumberNode | Ratio | null + break; + + case "MediaQuery": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "MediaQueryList": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Nth": + toPlain.nth; // $ExpectType AnPlusB | Identifier + toPlain.selector; // $ExpectType SelectorListPlain | null + break; + + case "Number": + toPlain.value; // $ExpectType string + break; + + case "Operator": + toPlain.value; // $ExpectType string + break; + + case "Parentheses": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "Percentage": + toPlain.value; // $ExpectType string + break; + + case "PseudoClassSelector": + toPlain.name; // $ExpectType string + toPlain.children; // $ExpectType CssNodePlain[] | null + break; + + case "PseudoElementSelector": + toPlain.name; // $ExpectType string + toPlain.children; // $ExpectType CssNodePlain[] | null + break; + + case "Ratio": + toPlain.left; // $ExpectType string + toPlain.right; // $ExpectType string + break; + + case "Raw": + toPlain.value; // $ExpectType string + break; + + case "Rule": + toPlain.prelude; // $ExpectType Raw | SelectorListPlain + toPlain.block; // $ExpectType BlockPlain + break; + + case "Selector": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "SelectorList": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "String": + toPlain.value; // $ExpectType string + break; + + case "StyleSheet": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "TypeSelector": + toPlain.name; // $ExpectType string + break; + + case "UnicodeRange": + toPlain.value; // $ExpectType string + break; + + case "Url": + toPlain.value; // $ExpectType string + break; + + case "Value": + toPlain.children; // $ExpectType CssNodePlain[] + break; + + case "WhiteSpace": + toPlain.value; // $ExpectType string + break; + + default: + toPlain; // $ExpectType never +} + +csstree.definitionSyntax.syntaxError; // $ExpectType SyntaxError +const syntax = csstree.definitionSyntax.parse("foo | bar"); // $ExpectType DSNodeGroup +const node = syntax.terms[0]; // $ExpectType DSNode +switch (node.type) { + case "AtKeyword": + node; // $ExpectType DSNodeAtWord + node.name; // $ExpectType string + break; + case "Comma": + node; // $ExpectType DSNodeComma + break; + case "Function": + node; // $ExpectType DSNodeFunction + node.name; // $ExpectType string + break; + case "Group": + node; // $ExpectType DSNodeGroup + node.terms; // $ExpectType DSNode[] + node.combinator; // $ExpectType DSNodeCombinator + node.disallowEmpty; // $ExpectType boolean + node.explicit; // $ExpectType boolean + break; + case "Keyword": + node; // $ExpectType DSNodeKeyword + node.name; // $ExpectType string + break; + case "Multiplier": + node; // $ExpectType DSNodeMultiplier + node.comma; // $ExpectType boolean + node.min; // $ExpectType number + node.max; // $ExpectType number + node.term; // $ExpectType DSNodeMultiplied + break; + case "Property": + node; // $ExpectType DSNodeProperty + node.name; // $ExpectType string + break; + case "String": + node; // $ExpectType DSNodeString + node.value; // $ExpectType string + break; + case "Token": + node; // $ExpectType DSNodeToken + node.value; // $ExpectType string + break; + case "Type": + node; // $ExpectType DSNodeType + node.name; // $ExpectType string + node.opts; // $ExpectType DSNodeTypeOpts | null + break; +} + +csstree.definitionSyntax.generate(syntax); // $ExpectType string +csstree.definitionSyntax.generate(syntax, { forceBraces: true }); // $ExpectType string +csstree.definitionSyntax.generate(syntax, { compact: true }); // $ExpectType string +csstree.definitionSyntax.generate(syntax, { + decorate: (result: string, node) => { + result; // $ExpectType string + node; // $ExpectType DSNode + return result; + }, +}); + +csstree.definitionSyntax.walk(syntax, (node) => { + node; // $ExpectType DSNode +}); +csstree.definitionSyntax.walk(syntax, (node) => { + node; // $ExpectType DSNode +}, undefined); + +csstree.parse(".selector { /* comment */ }", { + onComment(value, loc) { + value; // $ExpectType string + loc; // $ExpectType CssLocation + }, +}); + +csstree.parse(".a { ::: invalid css ::: }", { + onParseError(error, fallbackNode) { + error; // $ExpectType SyntaxParseError + fallbackNode; // $ExpectType CssNode + }, +}); + +csstree.ident.decode("foo"); // $ExpectType string +csstree.ident.encode("foo"); // $ExpectType string +csstree.string.decode("foo"); // $ExpectType string +csstree.string.encode("foo"); // $ExpectType string +csstree.string.encode("foo", true); // $ExpectType string +csstree.url.decode("foo"); // $ExpectType string +csstree.url.encode("foo"); // $ExpectType string + +csstree.fork({}); // $ExpectType { lexer: Lexer; } +const { lexer } = csstree.fork({ + atrules: {}, + properties: {}, + types: { foo: "" }, + cssWideKeywords: ["initial"], +}); +lexer; // $ExpectType Lexer +lexer.matchAtruleDescriptor("foo", "bar", ast); // $ExpectType LexerMatchResult +lexer.matchAtruleDescriptor("foo", "bar", "baz"); // $ExpectType LexerMatchResult +lexer.matchAtrulePrelude("foo", ast); // $ExpectType LexerMatchResult +lexer.matchAtrulePrelude("foo", "bar"); // $ExpectType LexerMatchResult +lexer.matchDeclaration(ast); // $ExpectType LexerMatchResult +lexer.matchProperty("foo", ast); // $ExpectType LexerMatchResult +lexer.matchProperty("foo", "bar"); // $ExpectType LexerMatchResult +lexer.matchType("foo", ast); // $ExpectType LexerMatchResult +lexer.matchType("foo", "bar"); // $ExpectType LexerMatchResult +lexer.match("foo", ast); // $ExpectType LexerMatchResult +lexer.match("foo", "bar"); // $ExpectType LexerMatchResult +lexer.match(syntax, ast); // $ExpectType LexerMatchResult +lexer.match(syntax, "bar"); // $ExpectType LexerMatchResult + +csstree.lexer; // $ExpectType Lexer diff --git a/types/css-tree/v2/index.d.ts b/types/css-tree/v2/index.d.ts new file mode 100644 index 00000000000000..c005ef349475c1 --- /dev/null +++ b/types/css-tree/v2/index.d.ts @@ -0,0 +1,918 @@ +export interface CssLocation { + source: string; + start: { + offset: number; + line: number; + column: number; + }; + end: { + offset: number; + line: number; + column: number; + }; +} + +export interface ListItem { + prev: ListItem | null; + next: ListItem | null; + data: TData; +} + +export type IteratorFn> = ( + this: TContext, + item: TData, + node: ListItem, + list: List, +) => TResult; +export type FilterFn> = ( + this: TContext, + item: TData, + node: ListItem, + list: List, +) => item is TResult; +export type ReduceFn> = (this: TContext, accum: TValue, data: TData) => TValue; + +export class List { + constructor(); + get size(): number; + get isEmpty(): boolean; + get first(): TData | null; + get last(): TData | null; + [Symbol.iterator](): IterableIterator; + fromArray(array: TData[]): List; + createItem(data: TData): ListItem; + toArray(): TData[]; + toJSON(): TData[]; + forEach(fn: IteratorFn, context: TContext): void; + forEach(fn: IteratorFn): void; + forEachRight(fn: IteratorFn, context: TContext): void; + forEachRight(fn: IteratorFn): void; + nextUntil(start: ListItem, fn: IteratorFn, context: TContext): void; + nextUntil(start: ListItem, fn: IteratorFn): void; + prevUntil(start: ListItem, fn: IteratorFn, context: TContext): void; + prevUntil(start: ListItem, fn: IteratorFn): void; + reduce(fn: ReduceFn, initialValue: TValue, context: TContext): TValue; + reduce(fn: ReduceFn, initialValue: TValue): TValue; + reduceRight( + fn: ReduceFn, + initialValue: TValue, + context: TContext, + ): TValue; + reduceRight(fn: ReduceFn, initialValue: TValue): TValue; + some(fn: IteratorFn, context: TContext): boolean; + some(fn: IteratorFn): boolean; + map(fn: IteratorFn, context: TContext): List; + map(fn: IteratorFn): List; + filter(fn: FilterFn, context: TContext): List; + filter(fn: FilterFn): List; + filter(fn: IteratorFn, context: TContext): List; + filter(fn: IteratorFn): List; + clear(): void; + copy(): List; + prepend(item: ListItem): List; + prependData(data: TData): List; + append(item: ListItem): List; + appendData(data: TData): List; + insert(item: ListItem, before: ListItem): List; + insertData(data: TData, before: ListItem): List; + remove(item: ListItem): ListItem; + push(item: TData): void; + pop(): ListItem | undefined; + unshift(data: TData): void; + shift(): ListItem | undefined; + prependList(list: List): List; + appendList(list: List): List; + insertList(list: List, before: ListItem): List; + replace(oldItem: ListItem, newItemOrList: List | ListItem): List; +} + +export interface CssNodeCommon { + type: string; + loc?: CssLocation | undefined; +} + +export interface AnPlusB extends CssNodeCommon { + type: "AnPlusB"; + a: string | null; + b: string | null; +} + +export interface Atrule extends CssNodeCommon { + type: "Atrule"; + name: string; + prelude: AtrulePrelude | Raw | null; + block: Block | null; +} + +export interface AtrulePlain extends CssNodeCommon { + type: "Atrule"; + name: string; + prelude: AtrulePreludePlain | Raw | null; + block: BlockPlain | null; +} + +export interface AtrulePrelude extends CssNodeCommon { + type: "AtrulePrelude"; + children: List; +} + +export interface AtrulePreludePlain extends CssNodeCommon { + type: "AtrulePrelude"; + children: CssNodePlain[]; +} + +export interface AttributeSelector extends CssNodeCommon { + type: "AttributeSelector"; + name: Identifier; + matcher: string | null; + value: StringNode | Identifier | null; + flags: string | null; +} + +export interface Block extends CssNodeCommon { + type: "Block"; + children: List; +} + +export interface BlockPlain extends CssNodeCommon { + type: "Block"; + children: CssNodePlain[]; +} + +export interface Brackets extends CssNodeCommon { + type: "Brackets"; + children: List; +} + +export interface BracketsPlain extends CssNodeCommon { + type: "Brackets"; + children: CssNodePlain[]; +} + +export interface CDC extends CssNodeCommon { + type: "CDC"; +} + +export interface CDO extends CssNodeCommon { + type: "CDO"; +} + +export interface ClassSelector extends CssNodeCommon { + type: "ClassSelector"; + name: string; +} + +export interface Combinator extends CssNodeCommon { + type: "Combinator"; + name: string; +} + +export interface Comment extends CssNodeCommon { + type: "Comment"; + value: string; +} + +export interface Declaration extends CssNodeCommon { + type: "Declaration"; + important: boolean | string; + property: string; + value: Value | Raw; +} + +export interface DeclarationPlain extends CssNodeCommon { + type: "Declaration"; + important: boolean | string; + property: string; + value: ValuePlain | Raw; +} + +export interface DeclarationList extends CssNodeCommon { + type: "DeclarationList"; + children: List; +} + +export interface DeclarationListPlain extends CssNodeCommon { + type: "DeclarationList"; + children: CssNodePlain[]; +} + +export interface Dimension extends CssNodeCommon { + type: "Dimension"; + value: string; + unit: string; +} + +export interface FunctionNode extends CssNodeCommon { + type: "Function"; + name: string; + children: List; +} + +export interface FunctionNodePlain extends CssNodeCommon { + type: "Function"; + name: string; + children: CssNodePlain[]; +} + +export interface Hash extends CssNodeCommon { + type: "Hash"; + value: string; +} + +export interface IdSelector extends CssNodeCommon { + type: "IdSelector"; + name: string; +} + +export interface Identifier extends CssNodeCommon { + type: "Identifier"; + name: string; +} + +export interface MediaFeature extends CssNodeCommon { + type: "MediaFeature"; + name: string; + value: Identifier | NumberNode | Dimension | Ratio | null; +} + +export interface MediaQuery extends CssNodeCommon { + type: "MediaQuery"; + children: List; +} + +export interface MediaQueryPlain extends CssNodeCommon { + type: "MediaQuery"; + children: CssNodePlain[]; +} + +export interface MediaQueryList extends CssNodeCommon { + type: "MediaQueryList"; + children: List; +} + +export interface MediaQueryListPlain extends CssNodeCommon { + type: "MediaQueryList"; + children: CssNodePlain[]; +} + +export interface NestingSelector extends CssNodeCommon { + type: "NestingSelector"; +} + +export interface Nth extends CssNodeCommon { + type: "Nth"; + nth: AnPlusB | Identifier; + selector: SelectorList | null; +} + +export interface NthPlain extends CssNodeCommon { + type: "Nth"; + nth: AnPlusB | Identifier; + selector: SelectorListPlain | null; +} + +export interface NumberNode extends CssNodeCommon { + type: "Number"; + value: string; +} + +export interface Operator extends CssNodeCommon { + type: "Operator"; + value: string; +} + +export interface Parentheses extends CssNodeCommon { + type: "Parentheses"; + children: List; +} + +export interface ParenthesesPlain extends CssNodeCommon { + type: "Parentheses"; + children: CssNodePlain[]; +} + +export interface Percentage extends CssNodeCommon { + type: "Percentage"; + value: string; +} + +export interface PseudoClassSelector extends CssNodeCommon { + type: "PseudoClassSelector"; + name: string; + children: List | null; +} + +export interface PseudoClassSelectorPlain extends CssNodeCommon { + type: "PseudoClassSelector"; + name: string; + children: CssNodePlain[] | null; +} + +export interface PseudoElementSelector extends CssNodeCommon { + type: "PseudoElementSelector"; + name: string; + children: List | null; +} + +export interface PseudoElementSelectorPlain extends CssNodeCommon { + type: "PseudoElementSelector"; + name: string; + children: CssNodePlain[] | null; +} + +export interface Ratio extends CssNodeCommon { + type: "Ratio"; + left: string; + right: string; +} + +export interface Raw extends CssNodeCommon { + type: "Raw"; + value: string; +} + +export interface Rule extends CssNodeCommon { + type: "Rule"; + prelude: SelectorList | Raw; + block: Block; +} + +export interface RulePlain extends CssNodeCommon { + type: "Rule"; + prelude: SelectorListPlain | Raw; + block: BlockPlain; +} + +export interface Selector extends CssNodeCommon { + type: "Selector"; + children: List; +} + +export interface SelectorPlain extends CssNodeCommon { + type: "Selector"; + children: CssNodePlain[]; +} + +export interface SelectorList extends CssNodeCommon { + type: "SelectorList"; + children: List; +} + +export interface SelectorListPlain extends CssNodeCommon { + type: "SelectorList"; + children: CssNodePlain[]; +} + +export interface StringNode extends CssNodeCommon { + type: "String"; + value: string; +} + +export interface StyleSheet extends CssNodeCommon { + type: "StyleSheet"; + children: List; +} + +export interface StyleSheetPlain extends CssNodeCommon { + type: "StyleSheet"; + children: CssNodePlain[]; +} + +export interface TypeSelector extends CssNodeCommon { + type: "TypeSelector"; + name: string; +} + +export interface UnicodeRange extends CssNodeCommon { + type: "UnicodeRange"; + value: string; +} + +export interface Url extends CssNodeCommon { + type: "Url"; + value: string; +} + +export interface Value extends CssNodeCommon { + type: "Value"; + children: List; +} + +export interface ValuePlain extends CssNodeCommon { + type: "Value"; + children: CssNodePlain[]; +} + +export interface WhiteSpace extends CssNodeCommon { + type: "WhiteSpace"; + value: string; +} + +export type CssNode = + | AnPlusB + | Atrule + | AtrulePrelude + | AttributeSelector + | Block + | Brackets + | CDC + | CDO + | ClassSelector + | Combinator + | Comment + | Declaration + | DeclarationList + | Dimension + | FunctionNode + | Hash + | IdSelector + | Identifier + | MediaFeature + | MediaQuery + | MediaQueryList + | NestingSelector + | Nth + | NumberNode + | Operator + | Parentheses + | Percentage + | PseudoClassSelector + | PseudoElementSelector + | Ratio + | Raw + | Rule + | Selector + | SelectorList + | StringNode + | StyleSheet + | TypeSelector + | UnicodeRange + | Url + | Value + | WhiteSpace; + +export type CssNodePlain = + | AnPlusB + | AtrulePlain + | AtrulePreludePlain + | AttributeSelector + | BlockPlain + | BracketsPlain + | CDC + | CDO + | ClassSelector + | Combinator + | Comment + | DeclarationPlain + | DeclarationListPlain + | Dimension + | FunctionNodePlain + | Hash + | IdSelector + | Identifier + | MediaFeature + | MediaQueryPlain + | MediaQueryListPlain + | NthPlain + | NumberNode + | Operator + | ParenthesesPlain + | Percentage + | PseudoClassSelectorPlain + | PseudoElementSelectorPlain + | Ratio + | Raw + | RulePlain + | SelectorPlain + | SelectorListPlain + | StringNode + | StyleSheetPlain + | TypeSelector + | UnicodeRange + | Url + | ValuePlain + | WhiteSpace; + +export interface SyntaxParseError extends SyntaxError { + input: string; + offset: number; + rawMessage: string; + formattedMessage: string; +} + +export interface ParseOptions { + context?: string | undefined; + atrule?: string | undefined; + positions?: boolean | undefined; + onComment?: (value: string, loc: CssLocation) => void; + onParseError?: ((error: SyntaxParseError, fallbackNode: CssNode) => void) | undefined; + filename?: string | undefined; + offset?: number | undefined; + line?: number | undefined; + column?: number | undefined; + parseAtrulePrelude?: boolean | undefined; + parseRulePrelude?: boolean | undefined; + parseValue?: boolean | undefined; + parseCustomProperty?: boolean | undefined; +} + +export function parse(text: string, options?: ParseOptions): CssNode; + +export interface GenerateHandlers { + children: (node: CssNode, delimiter?: (node: CssNode) => void) => void; + node: (node: CssNode) => void; + chunk: (chunk: string) => void; + result: () => string; +} + +export interface GenerateOptions { + sourceMap?: boolean | undefined; + decorator?: ((handlers: GenerateHandlers) => GenerateHandlers) | undefined; + mode?: "safe" | "spec" | undefined; +} + +export function generate(ast: CssNode, options?: GenerateOptions): string; + +export interface WalkContext { + /** + * Stops traversal. No visitor function will be invoked once this value is + * returned by a visitor. + */ + break: symbol; + /** + * Prevent the current node from being iterated. No visitor function will be + * invoked for its properties or children nodes; note that this value only + * has an effect for enter visitor as leave visitor invokes after iterating + * over all node's properties and children. + */ + skip: symbol; + root: CssNode; + stylesheet: StyleSheet | null; + atrule: Atrule | null; + atrulePrelude: AtrulePrelude | null; + rule: Rule | null; + selector: SelectorList | null; + block: Block | null; + declaration: Declaration | null; + function: FunctionNode | PseudoClassSelector | PseudoElementSelector | null; +} + +export type EnterOrLeaveFn = ( + this: WalkContext, + node: NodeType, + item: ListItem, + list: List, +) => void; + +export interface WalkOptionsNoVisit { + visit?: never; + enter?: EnterOrLeaveFn | undefined; + leave?: EnterOrLeaveFn | undefined; + reverse?: boolean | undefined; +} + +export interface WalkOptionsVisit { + visit: NodeType["type"]; + enter?: EnterOrLeaveFn | undefined; + leave?: EnterOrLeaveFn | undefined; + reverse?: boolean | undefined; +} + +export type WalkOptions = + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsVisit + | WalkOptionsNoVisit; + +export const walk: { + (ast: CssNode, options: EnterOrLeaveFn | WalkOptions): void; + /** + * Stops traversal. No visitor function will be invoked once this value is returned by a visitor. + */ + readonly break: symbol; + /** + * Prevent the current node from being iterated. No visitor function will be invoked for its properties or children + * nodes; note that this value only has an effect for enter visitor as leave visitor invokes after iterating over + * all node's properties and children. + */ + readonly skip: symbol; +}; + +export type FindFn = (this: WalkContext, node: CssNode, item: ListItem, list: List) => boolean; + +export function find(ast: CssNode, fn: FindFn): CssNode | null; +export function findLast(ast: CssNode, fn: FindFn): CssNode | null; +export function findAll(ast: CssNode, fn: FindFn): CssNode[]; + +export interface Property { + readonly basename: string; + readonly name: string; + readonly hack: string; + readonly vendor: string; + readonly prefix: string; + readonly custom: boolean; +} + +export function property(value: string): Property; + +export interface Keyword { + readonly basename: string; + readonly name: string; + readonly vendor: string; + readonly prefix: string; + readonly custom: boolean; +} + +export function keyword(value: string): Keyword; + +export function clone(node: CssNode): CssNode; + +export function fromPlainObject(node: CssNodePlain): CssNode; +export function toPlainObject(node: CssNode): CssNodePlain; + +/** + * Definition syntax AtWord node + */ +export interface DSNodeAtWord { + type: "AtKeyword"; + name: string; +} + +/** + * Definition syntax Comma node + */ +export interface DSNodeComma { + type: "Comma"; +} + +/** + * Definition syntax Function node + */ +export interface DSNodeFunction { + type: "Function"; + name: string; +} + +export type DSNodeCombinator = "|" | "||" | "&&" | " "; + +/** + * Definition syntax Group node + */ +export interface DSNodeGroup { + type: "Group"; + terms: DSNode[]; + combinator: DSNodeCombinator; + disallowEmpty: boolean; + explicit: boolean; +} + +/** + * Definition syntax Keyword node + */ +export interface DSNodeKeyword { + type: "Keyword"; + name: string; +} + +/** + * Definition syntax Multiplier node + */ +export interface DSNodeMultiplier { + type: "Multiplier"; + comma: boolean; + min: number; + max: number; + term: DSNodeMultiplied; +} + +/** + * Definition syntax Property node + */ +export interface DSNodeProperty { + type: "Property"; + name: string; +} + +/** + * Definition syntax String node + */ +export interface DSNodeString { + type: "String"; + value: string; +} + +/** + * Definition syntax Token node + */ +export interface DSNodeToken { + type: "Token"; + value: string; +} + +/** + * Definition syntax Type node options + */ +export interface DSNodeTypeOpts { + type: "Range"; + min: number | null; + max: number | null; +} + +/** + * Definition syntax Type node + */ +export interface DSNodeType { + type: "Type"; + name: string; + opts: DSNodeTypeOpts | null; +} + +/** + * Definition syntax node + */ +export type DSNode = + | DSNodeAtWord + | DSNodeComma + | DSNodeFunction + | DSNodeGroup + | DSNodeKeyword + | DSNodeMultiplier + | DSNodeProperty + | DSNodeString + | DSNodeToken + | DSNodeType; + +/** + * Definition syntax node compatible with a multiplier + */ +export type DSNodeMultiplied = + | DSNodeFunction + | DSNodeGroup + | DSNodeKeyword + | DSNodeProperty + | DSNodeString + | DSNodeType; + +/** + * Definition syntax generate options + */ +export interface DSGenerateOptions { + forceBraces?: boolean | undefined; + compact?: boolean | undefined; + decorate?: ((result: string, node: DSNode) => void) | undefined; +} + +/** + * Definition syntax walk options + */ +export interface DSWalkOptions { + enter?: DSWalkEnterOrLeaveFn | undefined; + leave?: DSWalkEnterOrLeaveFn | undefined; +} + +/** + * Definition syntax walk callback + */ +export type DSWalkEnterOrLeaveFn = (node: DSNode) => void; + +/** + * DefinitionSyntax + */ +export interface DefinitionSyntax { + /** + * Generates CSS value definition syntax from an AST + * + * @param node - The AST + * @param options - Options that affect generation + * + * @example + * generate({type: 'Keyword', name: 'foo'}) => 'foo' + */ + generate(node: DSNode, options?: DSGenerateOptions): string; + + /** + * Generates an AST from a CSS value syntax + * + * @param source - The CSS value syntax to parse + * + * @example + * parse('foo | bar') => + * { + * type: 'Group', + * terms: [ + * { type: 'Keyword', name: 'foo' }, + * { type: 'Keyword', name: 'bar' } + * ], + * combinator: '|', + * disallowEmpty: false, + * explicit: false + * } + */ + parse(source: string): DSNodeGroup; + + /** + * Walks definition syntax AST + */ + walk(node: DSNode, options: DSWalkEnterOrLeaveFn | DSWalkOptions, context?: any): void; + + /** + * Wrapper for syntax errors + */ + syntaxError: SyntaxError; +} + +export const definitionSyntax: DefinitionSyntax; + +export const ident: { + decode(input: string): string; + encode(input: string): string; +}; + +export const string: { + encode(input: string, apostrophe?: boolean): string; + decode(input: string): string; +}; + +export const url: { + decode(input: string): string; + encode(input: string): string; +}; + +export class SyntaxMatchError extends SyntaxError { + rawMessage: string; + syntax: string; + css: string; + mismatchOffset: number; + mismatchLength: number; + offset: number; + line: number; + column: number; + loc: { + source: string; + start: { offset: number; line: number; column: number }; + end: { offset: number; line: number; column: number }; + }; +} + +export class SyntaxReferenceError extends SyntaxError { + reference: string; +} + +export interface LexerMatchResult { + error: Error | SyntaxMatchError | SyntaxReferenceError | null; +} + +export class Lexer { + matchAtruleDescriptor(atruleName: string, descriptorName: string, value: CssNode | string): LexerMatchResult; + matchAtrulePrelude(atruleName: string, prelude: CssNode | string): LexerMatchResult; + matchDeclaration(node: CssNode): LexerMatchResult; + matchProperty(propertyName: string, value: CssNode | string): LexerMatchResult; + matchType(typeName: string, value: CssNode | string): LexerMatchResult; + match(syntax: DSNode | string, value: CssNode | string): LexerMatchResult; +} + +export const lexer: Lexer; + +export function fork(extension: { + atrules?: Record | undefined; + properties?: Record | undefined; + types?: Record | undefined; + cssWideKeywords?: Array | undefined; +}): { lexer: Lexer }; diff --git a/types/css-tree/v2/package.json b/types/css-tree/v2/package.json new file mode 100644 index 00000000000000..8efd493cfc26fc --- /dev/null +++ b/types/css-tree/v2/package.json @@ -0,0 +1,21 @@ +{ + "private": true, + "name": "@types/css-tree", + "version": "2.3.9999", + "projects": [ + "https://github.com/csstree/csstree" + ], + "devDependencies": { + "@types/css-tree": "workspace:." + }, + "owners": [ + { + "name": "Erik Källén", + "githubUsername": "erik-kallen" + }, + { + "name": "Jason Kratzer", + "githubUsername": "pyoor" + } + ] +} diff --git a/types/css-tree/v2/tsconfig.json b/types/css-tree/v2/tsconfig.json new file mode 100644 index 00000000000000..7646db44b43fc8 --- /dev/null +++ b/types/css-tree/v2/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "node16", + "lib": [ + "es6" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "css-tree-tests.ts" + ] +} diff --git a/types/csso/package.json b/types/csso/package.json index 6709fb6b8c4472..1af585d8487ccb 100644 --- a/types/csso/package.json +++ b/types/csso/package.json @@ -6,7 +6,7 @@ "https://github.com/css/csso" ], "dependencies": { - "@types/css-tree": "*" + "@types/css-tree": "^2" }, "devDependencies": { "@types/csso": "workspace:." From 0e741bfcf3c6104a22811f639cc004abb759bec9 Mon Sep 17 00:00:00 2001 From: thromer Date: Mon, 3 Aug 2026 08:23:32 -0700 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#75171=20google?= =?UTF-8?q?-apps-scripts:=20Add=20support=20for=20Tables=20to=20Sheets=20A?= =?UTF-8?q?PI.=20by=20@thromer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/google-apps-script/apis/sheets_v4.d.ts | 64 +++++++++ .../test/google-apps-script-apis-tests.ts | 126 ++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/types/google-apps-script/apis/sheets_v4.d.ts b/types/google-apps-script/apis/sheets_v4.d.ts index fd63eb79b2c081..c7a0b85106e418 100644 --- a/types/google-apps-script/apis/sheets_v4.d.ts +++ b/types/google-apps-script/apis/sheets_v4.d.ts @@ -226,6 +226,11 @@ declare namespace GoogleAppsScript { resource: Schema.GetSpreadsheetByDataFilterRequest, spreadsheetId: string, ): Sheets.Schema.Spreadsheet; + getByDataFilter( + resource: Schema.GetSpreadsheetByDataFilterRequest, + spreadsheetId: string, + optionalArgs: object, + ): Sheets.Schema.Spreadsheet; } } namespace Schema { @@ -275,10 +280,17 @@ declare namespace GoogleAppsScript { interface AddSheetResponse { properties?: Sheets.Schema.SheetProperties | undefined; } + interface AddTableRequest { + table?: Sheets.Schema.Table | undefined; + } + interface AddTableResponse { + table?: Sheets.Schema.Table | undefined; + } interface AppendCellsRequest { fields?: string | undefined; rows?: Sheets.Schema.RowData[] | undefined; sheetId?: number | undefined; + tableId?: string | undefined; } interface AppendDimensionRequest { dimension?: string | undefined; @@ -352,6 +364,7 @@ declare namespace GoogleAppsScript { criteria?: object | undefined; range?: Sheets.Schema.GridRange | undefined; sortSpecs?: Sheets.Schema.SortSpec[] | undefined; + tableId?: string | undefined; } interface BatchClearValuesByDataFilterRequest { dataFilters?: Sheets.Schema.DataFilter[] | undefined; @@ -637,6 +650,9 @@ declare namespace GoogleAppsScript { interface DeleteSheetRequest { sheetId?: number | undefined; } + interface DeleteTableRequest { + tableId?: string | undefined; + } interface DeveloperMetadata { location?: Sheets.Schema.DeveloperMetadataLocation | undefined; metadataId?: number | undefined; @@ -729,6 +745,7 @@ declare namespace GoogleAppsScript { namedRangeId?: string | undefined; range?: Sheets.Schema.GridRange | undefined; sortSpecs?: Sheets.Schema.SortSpec[] | undefined; + tableId?: string | undefined; title?: string | undefined; } interface FindReplaceRequest { @@ -751,6 +768,7 @@ declare namespace GoogleAppsScript { } interface GetSpreadsheetByDataFilterRequest { dataFilters?: Sheets.Schema.DataFilter[] | undefined; + excludeTablesInBandedRanges?: boolean | undefined; includeGridData?: boolean | undefined; } interface GradientRule { @@ -940,6 +958,7 @@ declare namespace GoogleAppsScript { protectedRangeId?: number | undefined; range?: Sheets.Schema.GridRange | undefined; requestingUserCanEdit?: boolean | undefined; + tableId?: string | undefined; unprotectedRanges?: Sheets.Schema.GridRange[] | undefined; warningOnly?: boolean | undefined; } @@ -960,6 +979,7 @@ declare namespace GoogleAppsScript { addNamedRange?: Sheets.Schema.AddNamedRangeRequest | undefined; addProtectedRange?: Sheets.Schema.AddProtectedRangeRequest | undefined; addSheet?: Sheets.Schema.AddSheetRequest | undefined; + addTable?: Sheets.Schema.AddTableRequest | undefined; appendCells?: Sheets.Schema.AppendCellsRequest | undefined; appendDimension?: Sheets.Schema.AppendDimensionRequest | undefined; autoFill?: Sheets.Schema.AutoFillRequest | undefined; @@ -979,6 +999,7 @@ declare namespace GoogleAppsScript { deleteProtectedRange?: Sheets.Schema.DeleteProtectedRangeRequest | undefined; deleteRange?: Sheets.Schema.DeleteRangeRequest | undefined; deleteSheet?: Sheets.Schema.DeleteSheetRequest | undefined; + deleteTable?: Sheets.Schema.DeleteTableRequest | undefined; duplicateFilterView?: Sheets.Schema.DuplicateFilterViewRequest | undefined; duplicateSheet?: Sheets.Schema.DuplicateSheetRequest | undefined; findReplace?: Sheets.Schema.FindReplaceRequest | undefined; @@ -1008,6 +1029,7 @@ declare namespace GoogleAppsScript { updateProtectedRange?: Sheets.Schema.UpdateProtectedRangeRequest | undefined; updateSheetProperties?: Sheets.Schema.UpdateSheetPropertiesRequest | undefined; updateSpreadsheetProperties?: Sheets.Schema.UpdateSpreadsheetPropertiesRequest | undefined; + updateTable?: Sheets.Schema.UpdateTableRequest | undefined; } interface Response { addBanding?: Sheets.Schema.AddBandingResponse | undefined; @@ -1017,6 +1039,7 @@ declare namespace GoogleAppsScript { addNamedRange?: Sheets.Schema.AddNamedRangeResponse | undefined; addProtectedRange?: Sheets.Schema.AddProtectedRangeResponse | undefined; addSheet?: Sheets.Schema.AddSheetResponse | undefined; + addTable?: Sheets.Schema.AddTableResponse | undefined; createDeveloperMetadata?: Sheets.Schema.CreateDeveloperMetadataResponse | undefined; deleteConditionalFormatRule?: Sheets.Schema.DeleteConditionalFormatRuleResponse | undefined; deleteDeveloperMetadata?: Sheets.Schema.DeleteDeveloperMetadataResponse | undefined; @@ -1057,6 +1080,7 @@ declare namespace GoogleAppsScript { properties?: Sheets.Schema.SheetProperties | undefined; protectedRanges?: Sheets.Schema.ProtectedRange[] | undefined; rowGroups?: Sheets.Schema.DimensionGroup[] | undefined; + tables?: Sheets.Schema.Table[] | undefined; } interface SheetProperties { gridProperties?: Sheets.Schema.GridProperties | undefined; @@ -1101,6 +1125,28 @@ declare namespace GoogleAppsScript { timeZone?: string | undefined; title?: string | undefined; } + interface Table { + columnProperties?: Sheets.Schema.TableColumnProperties[] | undefined; + name?: string | undefined; + range?: Sheets.Schema.GridRange | undefined; + rowsProperties?: Sheets.Schema.TableRowsProperties | undefined; + tableId?: string | undefined; + } + interface TableColumnDataValidationRule { + condition?: Sheets.Schema.BooleanCondition | undefined; + } + interface TableColumnProperties { + columnIndex?: number | undefined; + columnName?: string | undefined; + columnType?: string | undefined; + dataValidationRule?: Sheets.Schema.TableColumnDataValidationRule | undefined; + } + interface TableRowsProperties { + firstBandColorStyle?: Sheets.Schema.ColorStyle | undefined; + footerColorStyle?: Sheets.Schema.ColorStyle | undefined; + headerColorStyle?: Sheets.Schema.ColorStyle | undefined; + secondBandColorStyle?: Sheets.Schema.ColorStyle | undefined; + } interface TextFormat { bold?: boolean | undefined; fontFamily?: string | undefined; @@ -1235,6 +1281,10 @@ declare namespace GoogleAppsScript { fields?: string | undefined; properties?: Sheets.Schema.SpreadsheetProperties | undefined; } + interface UpdateTableRequest { + fields?: string | undefined; + table?: Sheets.Schema.Table | undefined; + } interface UpdateValuesByDataFilterResponse { dataFilter?: Sheets.Schema.DataFilter | undefined; updatedCells?: number | undefined; @@ -1305,6 +1355,8 @@ declare namespace GoogleAppsScript { newAddProtectedRangeRequest(): Sheets.Schema.AddProtectedRangeRequest; // Create a new instance of AddSheetRequest newAddSheetRequest(): Sheets.Schema.AddSheetRequest; + // Create a new instance of AddTableRequest + newAddTableRequest(): Sheets.Schema.AddTableRequest; // Create a new instance of AppendCellsRequest newAppendCellsRequest(): Sheets.Schema.AppendCellsRequest; // Create a new instance of AppendDimensionRequest @@ -1417,6 +1469,8 @@ declare namespace GoogleAppsScript { newDeleteRangeRequest(): Sheets.Schema.DeleteRangeRequest; // Create a new instance of DeleteSheetRequest newDeleteSheetRequest(): Sheets.Schema.DeleteSheetRequest; + // Create a new instance of DeleteTableRequest + newDeleteTableRequest(): Sheets.Schema.DeleteTableRequest; // Create a new instance of DeveloperMetadata newDeveloperMetadata(): Sheets.Schema.DeveloperMetadata; // Create a new instance of DeveloperMetadataLocation @@ -1539,6 +1593,14 @@ declare namespace GoogleAppsScript { newSpreadsheet(): Sheets.Schema.Spreadsheet; // Create a new instance of SpreadsheetProperties newSpreadsheetProperties(): Sheets.Schema.SpreadsheetProperties; + // Create a new instance of Table + newTable(): Sheets.Schema.Table; + // Create a new instance of TableColumnDataValidationRule + newTableColumnDataValidationRule(): Sheets.Schema.TableColumnDataValidationRule; + // Create a new instance of TableColumnProperties + newTableColumnProperties(): Sheets.Schema.TableColumnProperties; + // Create a new instance of TableRowsProperties + newTableRowsProperties(): Sheets.Schema.TableRowsProperties; // Create a new instance of TextFormat newTextFormat(): Sheets.Schema.TextFormat; // Create a new instance of TextFormatRun @@ -1583,6 +1645,8 @@ declare namespace GoogleAppsScript { newUpdateSheetPropertiesRequest(): Sheets.Schema.UpdateSheetPropertiesRequest; // Create a new instance of UpdateSpreadsheetPropertiesRequest newUpdateSpreadsheetPropertiesRequest(): Sheets.Schema.UpdateSpreadsheetPropertiesRequest; + // Create a new instance of UpdateTableRequest + newUpdateTableRequest(): Sheets.Schema.UpdateTableRequest; // Create a new instance of ValueRange newValueRange(): Sheets.Schema.ValueRange; // Create a new instance of WaterfallChartColumnStyle diff --git a/types/google-apps-script/test/google-apps-script-apis-tests.ts b/types/google-apps-script/test/google-apps-script-apis-tests.ts index 024f123e351815..d490ce2b9f0f6f 100644 --- a/types/google-apps-script/test/google-apps-script-apis-tests.ts +++ b/types/google-apps-script/test/google-apps-script-apis-tests.ts @@ -60,6 +60,132 @@ function testSheets() { const spreadsheets = sheets.Spreadsheets; // $ExpectType Spreadsheet const create = spreadsheets.create({}); + // $ExpectType Spreadsheet + const get1 = Sheets.Spreadsheets.get("spreeadsheet_id"); + // $ExpectType Spreadsheet + const get2 = Sheets.Spreadsheets.get("spreeadsheet_id", {}); + // $ExpectType Spreadsheet + const getByDataFilter1 = Sheets.Spreadsheets.getByDataFilter( + Sheets.newGetSpreadsheetByDataFilterRequest(), + "spreeadsheet_id", + ); + // $ExpectType Spreadsheet + const getByDataFilter2 = Sheets.Spreadsheets.getByDataFilter( + Sheets.newGetSpreadsheetByDataFilterRequest(), + "spreeadsheet_id", + {}, + ); +} + +function testSheetShallow() { + if (!Sheets) return; + // $ExpectType Spreadsheet + const spreadsheet = Sheets.Spreadsheets.get("spreeadsheet_id"); + // $ExpectType Sheet + const sheet = spreadsheet.sheets![0]!; + // $ExpectType BandedRange[]; + const bandedRanges = sheet.bandedRanges!; + // $ExpectType BasicFilter; + const basicFilter = sheet.basicFilter!; + // $ExpectType EmbeddedChart[] + const charts = sheet.charts!; + // $ExpectType DimensionGroup[] + const columnGroups = sheet.columnGroups!; + // $ExpectType ConditionalFormatRule[] + const conditionalFormats = sheet.conditionalFormats!; + // $ExpectType GridData[] + const data = sheet.data!; + // $ExpectType DeveloperMetadata[] + const developerMetadata = sheet.developerMetadata!; + // $ExpectType FilterView[] + const filterViews = sheet.filterViews!; + // $ExpectType GridRange[] + const merges = sheet.merges!; + // $ExpectType SheetProperties + const properties = sheet.properties!; + // $ExpectType ProtectedRange[] + const protectedRanges = sheet.protectedRanges!; + // $ExpectType DimensionGroup[] + const rowGroups = sheet.rowGroups!; + // TODO: ExpectType Slicer[] const slicers = sheet.slicers!; + // $ExpectType Table[] + const tables = sheet.tables!; +} + +function testSheetsTables() { + if (!Sheets) return; + // $ExpectType AddTableRequest + const addTableReq = Sheets.newAddTableRequest(); + // $ExpectType DeleteTableRequest + const deleteTableReq = Sheets.newDeleteTableRequest(); + // $ExpectType Table + const table = Sheets.newTable(); + // $ExpectType TableColumnDataValidationRule + const tableColumnDataValidationRule = Sheets.newTableColumnDataValidationRule(); + // $ExpectType TableColumnProperties + const tableColumnProperties = Sheets.newTableColumnProperties(); + // $ExpectType TableRowsProperties + const tableRowsProperties = Sheets.newTableRowsProperties(); + // $ExpectType UpdateTableRequest + const updateTableReq = Sheets.newUpdateTableRequest(); + + // Test Table interface + tableColumnDataValidationRule.condition = { "values": [{ "userEnteredValue": "option1" }] }; + tableColumnProperties.columnIndex = 1; + tableColumnProperties.columnName = "Col1"; + tableColumnProperties.columnType = "ONE_OF_LIST"; + tableColumnProperties.dataValidationRule = tableColumnDataValidationRule; + tableRowsProperties.firstBandColorStyle = { themeColor: "blue" }; + tableRowsProperties.footerColorStyle = { themeColor: "cyan" }; + tableRowsProperties.headerColorStyle = { themeColor: "magenta" }; + tableRowsProperties.secondBandColorStyle = { themeColor: "mauve" }; + table.columnProperties = [tableColumnProperties]; + table.name = "Table1"; + table.range = { + endColumnIndex: 3, + endRowIndex: 5, + sheetId: 1234, + startColumnIndex: 1, + startRowIndex: 1, + }; + table.rowsProperties = tableRowsProperties; + table.tableId = "1729"; + + // Test table batch requests and response + const batchResp = Sheets.Spreadsheets.batchUpdate( + { + requests: [ + { + addTable: addTableReq, + }, + { + deleteTable: deleteTableReq, + }, + { + updateTable: updateTableReq, + }, + ], + }, + "spreadsheet_id", + ); + // $ExpectType AddTableResponse + const addTableResp = batchResp.replies![0].addTable!; + + // Test tableId in various types + // $ExpectType string + const tableId1 = Sheets.newAppendCellsRequest().tableId!; + // $ExpectType string + const tableId2 = Sheets.newBasicFilter().tableId!; + // $ExpectType string + const tableId3 = Sheets.newFilterView().tableId!; + // $ExpectType string + const tableId4 = Sheets.newProtectedRange().tableId!; + // $ExpectType string + const tableId5 = Sheets.newFilterView().tableId!; + + // Test excludeTablesInBandedRanges field in one type + // $ExpectType boolean + const excludeTablesInBandedRanges = Sheets.newGetSpreadsheetByDataFilterRequest().excludeTablesInBandedRanges!; } function testSlides() {