From d62a51468cae150e502c7904419b8f4024cc20f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Mon, 24 Aug 2026 01:02:34 +0200 Subject: [PATCH 1/5] Fix kind field for ImportDeclaration/TypeAliasDeclaration --- packages/typescript/src/ast/ast.generated.ts | 4 ++-- tools/scripts/tsc/generate-ts-ast.ts | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/typescript/src/ast/ast.generated.ts b/packages/typescript/src/ast/ast.generated.ts index 76ddfe362ae96..816961424b141 100644 --- a/packages/typescript/src/ast/ast.generated.ts +++ b/packages/typescript/src/ast/ast.generated.ts @@ -656,7 +656,7 @@ export interface InterfaceDeclaration extends StatementBase, DeclarationBase, Mo readonly members: NodeArray; } export interface TypeAliasDeclaration extends StatementBase, DeclarationBase, ModifiersBase { - readonly kind: SyntaxKind.TypeAliasDeclaration; + readonly kind: SyntaxKind.TypeAliasDeclaration | SyntaxKind.JSTypeAliasDeclaration; readonly name: Identifier; readonly typeParameters?: NodeArray; readonly type: TypeNode; @@ -681,7 +681,7 @@ export interface NotEmittedTypeElement extends NodeBase, TypeElementBase { readonly kind: SyntaxKind.NotEmittedTypeElement; } export interface ImportDeclaration extends StatementBase, ModifiersBase, DeclarationBase { - readonly kind: SyntaxKind.ImportDeclaration; + readonly kind: SyntaxKind.ImportDeclaration | SyntaxKind.JSImportDeclaration; readonly importClause?: ImportClause; readonly moduleSpecifier: Expression; readonly attributes?: ImportAttributes; diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index 753c7286ae094..2e8c0c0564064 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -339,8 +339,11 @@ function generateAstGenerated(): string { typeParamStr = `<${tps.join(", ")}>`; } - // Kind line: use type param name if available, otherwise SyntaxKind constant - const kindLine = `\n readonly kind: ${node.kindType.formatTypeScript()};`; + const kindType = [ + node.kindType.formatTypeScript(), + ...node.kindAliases.map(kind => `SyntaxKind.${kind}`), + ].join(" | "); + const kindLine = `\n readonly kind: ${kindType};`; let memberLines = ""; for (const m of tsInterfaceMembers(node)) { From 3f070519bea4572dff2b3bb51e4ed7e31607310c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Mon, 24 Aug 2026 01:04:31 +0200 Subject: [PATCH 2/5] Define Expression/Statement/... as unions --- packages/typescript/src/ast/ast.generated.ts | 123 +++++++++++++++++-- tools/scripts/tsc/generate-ts-ast.ts | 14 ++- 2 files changed, 126 insertions(+), 11 deletions(-) diff --git a/packages/typescript/src/ast/ast.generated.ts b/packages/typescript/src/ast/ast.generated.ts index 816961424b141..4cea3117dd63e 100644 --- a/packages/typescript/src/ast/ast.generated.ts +++ b/packages/typescript/src/ast/ast.generated.ts @@ -8,6 +8,7 @@ import type { JsxTagNamePropertyAccess, Node, NodeArray, + SourceFile, } from "./ast.ts"; export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ConflictMarkerTrivia; export type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -1335,9 +1336,59 @@ export interface JSDocTypeLiteral extends JSDocTypeBase, DeclarationBase { readonly isArrayType: boolean; } -export type Expression = ExpressionBase; -export type Statement = StatementBase; -export type TypeNode = TypeNodeBase; +export type Expression = + | Identifier + | PrivateIdentifier + | ClassExpression + | OmittedExpression + | KeywordExpression + | StringLiteral + | NumericLiteral + | BigIntLiteral + | RegularExpressionLiteral + | NoSubstitutionTemplateLiteral + | BinaryExpression + | PrefixUnaryExpression + | PostfixUnaryExpression + | YieldExpression + | ArrowFunction + | FunctionExpression + | AsExpression + | SatisfiesExpression + | ConditionalExpression + | PropertyAccessExpression + | ElementAccessExpression + | CallExpression + | NewExpression + | MetaProperty + | NonNullExpression + | SpreadElement + | TemplateExpression + | TaggedTemplateExpression + | ParenthesizedExpression + | ArrayLiteralExpression + | ObjectLiteralExpression + | DeleteExpression + | TypeOfExpression + | VoidExpression + | AwaitExpression + | TypeAssertion + | ExpressionWithTypeArguments + | SyntheticExpression + | PartiallyEmittedExpression + | JsxElement + | JsxAttributes + | JsxNamespacedName + | JsxOpeningElement + | JsxSelfClosingElement + | JsxFragment + | JsxOpeningFragment + | JsxClosingFragment + | JsxExpression + | JsxText + | SyntheticReferenceExpression; +export type Statement = EmptyStatement | IfStatement | DoStatement | WhileStatement | ForStatement | ForInOrOfStatement | BreakStatement | ContinueStatement | ReturnStatement | WithStatement | SwitchStatement | ThrowStatement | TryStatement | DebuggerStatement | LabeledStatement | ExpressionStatement | Block | VariableStatement | MissingDeclaration | FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumDeclaration | ModuleBlock | NotEmittedStatement | ImportDeclaration | ExportAssignment | NamespaceExportDeclaration | ModuleDeclaration | ImportEqualsDeclaration | ExportDeclaration; +export type TypeNode = KeywordTypeNode | UnionTypeNode | IntersectionTypeNode | ConditionalTypeNode | TypeOperatorNode | InferTypeNode | ArrayTypeNode | IndexedAccessTypeNode | TypeReferenceNode | LiteralTypeNode | ThisTypeNode | TypePredicateNode | TypeQueryNode | MappedTypeNode | TypeLiteralNode | TupleTypeNode | NamedTupleMember | OptionalTypeNode | RestTypeNode | ParenthesizedTypeNode | FunctionTypeNode | ConstructorTypeNode | TemplateLiteralTypeNode | TemplateLiteralTypeSpan | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocAllType | JSDocVariadicType | JSDocOptionalType | JSDocSignature | JSDocNameReference | ImportTypeNode | JSDocTypeLiteral; export type HeritageClauseElement = ExpressionWithTypeArguments | TypeReferenceNode; export type BlockOrExpression = Block | Expression; export type NodeBody = Block | Expression | ModuleBlock | ModuleDeclaration; @@ -1371,7 +1422,7 @@ export type TemplateMiddleOrTail = TemplateMiddle | TemplateTail; export type TemplateLiteral = TemplateExpression | NoSubstitutionTemplateLiteral; export type TypePredicateParameterName = Identifier | ThisTypeNode; export type ImportAttributeName = Identifier | StringLiteral; -export type LeftHandSideExpression = LeftHandSideExpressionBase; +export type LeftHandSideExpression = Identifier | PrivateIdentifier | ClassExpression | StringLiteral | NumericLiteral | BigIntLiteral | RegularExpressionLiteral | FunctionExpression | PropertyAccessExpression | ElementAccessExpression | CallExpression | NewExpression | MetaProperty | NonNullExpression | TemplateExpression | TaggedTemplateExpression | ParenthesizedExpression | ArrayLiteralExpression | ObjectLiteralExpression | ExpressionWithTypeArguments | PartiallyEmittedExpression | JsxElement | JsxAttributes | JsxSelfClosingElement | JsxFragment; export type JSDocComment = JSDocText | JSDocLink | JSDocLinkCode | JSDocLinkPlain; export type SignatureDeclaration = CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignatureDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | AccessorDeclaration | FunctionExpression | ArrowFunction; export type StringLiteralLikeNode = StringLiteral | NoSubstitutionTemplateLiteral; @@ -1388,11 +1439,65 @@ export type VariableOrPropertyDeclaration = VariableDeclaration | PropertyDeclar export type CallOrNewExpression = CallExpression | NewExpression; export type ImportClauseOrBindingPattern = ImportClause | BindingPattern; export type AnyImportSyntax = ImportDeclaration | ImportEqualsDeclaration; -export type Declaration = DeclarationBase; -export type ClassElement = ClassElementBase; -export type TypeElement = TypeElementBase; -export type ObjectLiteralElement = ObjectLiteralElementBase; -export type JSDocTag = JSDocTagBase; +export type Declaration = + | VariableDeclaration + | ParameterDeclaration + | BindingElement + | MissingDeclaration + | FunctionDeclaration + | ClassDeclaration + | ClassExpression + | InterfaceDeclaration + | TypeAliasDeclaration + | EnumMember + | EnumDeclaration + | ImportDeclaration + | NamespaceImport + | ExportAssignment + | NamespaceExportDeclaration + | NamespaceExport + | ExportSpecifier + | CallSignatureDeclaration + | ConstructSignatureDeclaration + | ConstructorDeclaration + | GetAccessorDeclaration + | SetAccessorDeclaration + | IndexSignatureDeclaration + | MethodSignatureDeclaration + | MethodDeclaration + | PropertySignatureDeclaration + | PropertyDeclaration + | SemicolonClassElement + | ClassStaticBlockDeclaration + | NoSubstitutionTemplateLiteral + | BinaryExpression + | ArrowFunction + | FunctionExpression + | CallExpression + | ObjectLiteralExpression + | SpreadAssignment + | PropertyAssignment + | ShorthandPropertyAssignment + | MappedTypeNode + | TypeLiteralNode + | NamedTupleMember + | FunctionTypeNode + | ConstructorTypeNode + | JsxAttributes + | JsxAttribute + | JSDocSignature + | SourceFile + | ModuleDeclaration + | ImportEqualsDeclaration + | ExportDeclaration + | ImportClause + | ImportSpecifier + | TypeParameterDeclaration + | JSDocTypeLiteral; +export type ClassElement = ConstructorDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | MethodDeclaration | PropertyDeclaration | SemicolonClassElement | ClassStaticBlockDeclaration; +export type TypeElement = NotEmittedTypeElement | CallSignatureDeclaration | ConstructSignatureDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | IndexSignatureDeclaration | MethodSignatureDeclaration | PropertySignatureDeclaration; +export type ObjectLiteralElement = GetAccessorDeclaration | SetAccessorDeclaration | MethodDeclaration | SpreadAssignment | PropertyAssignment | ShorthandPropertyAssignment | JsxSpreadAttribute; +export type JSDocTag = JSDocTypeTag | JSDocUnknownTag | JSDocTemplateTag | JSDocReturnTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocOverrideTag | JSDocDeprecatedTag | JSDocSeeTag | JSDocImplementsTag | JSDocAugmentsTag | JSDocSatisfiesTag | JSDocThrowsTag | JSDocThisTag | JSDocImportTag | JSDocCallbackTag | JSDocOverloadTag | JSDocTypedefTag | JSDocParameterOrPropertyTag; export type ArrayBindingElement = BindingElement | OmittedExpression; export type AssertionExpression = TypeAssertion | AsExpression; export type BooleanLiteral = TrueLiteral | FalseLiteral; diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index 2e8c0c0564064..96b448908fac0 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -289,6 +289,14 @@ function visitorEntries(): VisitorEntry[] { return entries; } +function nodeExtends(node: NodeType, base: NodeType): boolean { + return node.extends.some(parent => parent === base || nodeExtends(parent, base)); +} + +function concreteNodesForBase(base: NodeType): NodeType[] { + return api.nodes().filter(node => nodeExtends(node, base)); +} + // ──────────────────────────────────────────────────────────────────────────── // Code generation: ast.generated.ts // ──────────────────────────────────────────────────────────────────────────── @@ -372,7 +380,7 @@ function generateAstGenerated(): string { parts.push(`export type ${alias.name} = ${members};`); } else if (alias.base) { - parts.push(`export type ${alias.name} = ${baseTsName(alias.base)};`); + parts.push(`export type ${alias.name} = ${concreteNodesForBase(alias.base).map(a => a.name).join(" | ")};`); } } @@ -532,7 +540,9 @@ function unresolvedAstImports(): string[] { for (const member of alias.unionMemberTypes) collectTypeReferences(member, referenced); } else if (alias.base) { - collectTypeReferences(alias.base, referenced); + for (const node of concreteNodesForBase(alias.base)) { + collectTypeReferences(node, referenced); + } } } for (const variant of tsVariants) { From c331a91ddb55976e06fa1dd0fe1e219ecb215250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Wed, 26 Aug 2026 23:05:58 +0200 Subject: [PATCH 3/5] Node type as union --- packages/typescript/src/ast/ast.generated.ts | 214 +++++++++++++++++-- packages/typescript/src/ast/ast.ts | 7 +- tools/scripts/tsc/generate-ts-ast.ts | 15 +- 3 files changed, 217 insertions(+), 19 deletions(-) diff --git a/packages/typescript/src/ast/ast.generated.ts b/packages/typescript/src/ast/ast.generated.ts index 4cea3117dd63e..2f82dad4cb322 100644 --- a/packages/typescript/src/ast/ast.generated.ts +++ b/packages/typescript/src/ast/ast.generated.ts @@ -6,8 +6,8 @@ import { SyntaxKind } from "#enums/syntaxKind"; import { TokenFlags } from "#enums/tokenFlags"; import type { JsxTagNamePropertyAccess, - Node, NodeArray, + NodeBase, SourceFile, } from "./ast.ts"; export type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ConflictMarkerTrivia; @@ -394,9 +394,6 @@ export type CompoundAssignmentOperator = SyntaxKind.PlusEqualsToken | SyntaxKind export type AssignmentOperatorOrHigher = SyntaxKind.QuestionQuestionToken | LogicalOperatorOrHigher | AssignmentOperator; export type LogicalOrCoalescingAssignmentOperator = SyntaxKind.AmpersandAmpersandEqualsToken | SyntaxKind.BarBarEqualsToken | SyntaxKind.QuestionQuestionEqualsToken; -export interface NodeBase extends Node { - readonly flags: NodeFlags; -} export interface StatementBase extends NodeBase { readonly _statementBrand: any; } @@ -430,21 +427,21 @@ export interface NodeWithTypeArgumentsBase extends TypeNodeBase { export interface JSDocTypeBase extends TypeNodeBase { readonly _jsDocTypeBrand: any; } -export interface DeclarationBase extends Node { +export interface DeclarationBase extends NodeBase { readonly _declarationBrand: any; } -export interface ModifiersBase extends Node { +export interface ModifiersBase extends NodeBase { readonly modifiers?: NodeArray; readonly modifierFlags: ModifierFlags; } -export interface FunctionLikeBase extends Node { +export interface FunctionLikeBase extends NodeBase { readonly _declarationBrand: any; readonly typeParameters?: NodeArray; readonly parameters: NodeArray; readonly type?: TypeNode; readonly fullSignature?: TypeNode; } -export interface BodyBase extends Node { +export interface BodyBase extends NodeBase { readonly asteriskToken?: AsteriskToken; readonly body?: NodeBody; } @@ -459,7 +456,7 @@ export interface ClassLikeBase extends ModifiersBase { readonly heritageClauses?: NodeArray; readonly members: NodeArray; } -export interface LiteralLikeNodeBase extends Node { +export interface LiteralLikeNodeBase extends NodeBase { readonly text: string; readonly tokenFlags: TokenFlags; } @@ -470,10 +467,10 @@ export interface TemplateLiteralLikeNodeBase extends LiteralLikeNodeBase { readonly rawText: string; readonly templateFlags: TokenFlags; } -export interface TypeElementBase extends Node { +export interface TypeElementBase extends NodeBase { readonly _typeElementBrand: any; } -export interface ClassElementBase extends Node { +export interface ClassElementBase extends NodeBase { readonly _classElementBrand: any; } export interface NamedMemberBase extends ModifiersBase { @@ -481,7 +478,7 @@ export interface NamedMemberBase extends ModifiersBase { readonly name: PropertyName; readonly postfixToken?: QuestionToken | ExclamationToken; } -export interface ObjectLiteralElementBase extends Node { +export interface ObjectLiteralElementBase extends NodeBase { readonly _objectLiteralBrand: any; } export interface UnionOrIntersectionTypeNodeBase extends TypeNodeBase { @@ -1513,6 +1510,199 @@ export type ArrayDestructuringAssignment = BinaryExpression; export type ObjectDestructuringAssignment = BinaryExpression; export type FunctionBody = Block; export type IncrementExpression = UpdateExpressionBase; +export type Node = + | ArrayLiteralExpression + | ArrayTypeNode + | ArrowFunction + | AsExpression + | AwaitExpression + | BigIntLiteral + | BinaryExpression + | BindingElement + | BindingPattern + | Block + | BreakStatement + | CallExpression + | CallSignatureDeclaration + | CaseBlock + | CaseOrDefaultClause + | CatchClause + | ClassDeclaration + | ClassExpression + | ClassStaticBlockDeclaration + | ComputedPropertyName + | ConditionalExpression + | ConditionalTypeNode + | ConstructorDeclaration + | ConstructorTypeNode + | ConstructSignatureDeclaration + | ContinueStatement + | DebuggerStatement + | Decorator + | DeleteExpression + | DoStatement + | ElementAccessExpression + | EmptyStatement + | EnumDeclaration + | EnumMember + | ExportAssignment + | ExportDeclaration + | ExportSpecifier + | ExpressionStatement + | ExpressionWithTypeArguments + | ExternalModuleReference + | ForInOrOfStatement + | ForStatement + | FunctionDeclaration + | FunctionExpression + | FunctionTypeNode + | GetAccessorDeclaration + | HeritageClause + | Identifier + | IfStatement + | ImportAttribute + | ImportAttributes + | ImportClause + | ImportDeclaration + | ImportEqualsDeclaration + | ImportSpecifier + | ImportTypeNode + | IndexedAccessTypeNode + | IndexSignatureDeclaration + | InferTypeNode + | InterfaceDeclaration + | IntersectionTypeNode + | JSDoc + | JSDocAllType + | JSDocAugmentsTag + | JSDocCallbackTag + | JSDocDeprecatedTag + | JSDocImplementsTag + | JSDocImportTag + | JSDocLink + | JSDocLinkCode + | JSDocLinkPlain + | JSDocNameReference + | JSDocNonNullableType + | JSDocNullableType + | JSDocOptionalType + | JSDocOverloadTag + | JSDocOverrideTag + | JSDocParameterOrPropertyTag + | JSDocPrivateTag + | JSDocProtectedTag + | JSDocPublicTag + | JSDocReadonlyTag + | JSDocReturnTag + | JSDocSatisfiesTag + | JSDocSeeTag + | JSDocSignature + | JSDocTemplateTag + | JSDocText + | JSDocThisTag + | JSDocThrowsTag + | JSDocTypedefTag + | JSDocTypeExpression + | JSDocTypeLiteral + | JSDocTypeTag + | JSDocUnknownTag + | JSDocVariadicType + | JsxAttribute + | JsxAttributes + | JsxClosingElement + | JsxClosingFragment + | JsxElement + | JsxExpression + | JsxFragment + | JsxNamespacedName + | JsxOpeningElement + | JsxOpeningFragment + | JsxSelfClosingElement + | JsxSpreadAttribute + | JsxText + | KeywordExpression + | KeywordTypeNode + | LabeledStatement + | LiteralTypeNode + | MappedTypeNode + | MetaProperty + | MethodDeclaration + | MethodSignatureDeclaration + | MissingDeclaration + | ModuleBlock + | ModuleDeclaration + | NamedExports + | NamedImports + | NamedTupleMember + | NamespaceExport + | NamespaceExportDeclaration + | NamespaceImport + | NewExpression + | NonNullExpression + | NoSubstitutionTemplateLiteral + | NotEmittedStatement + | NotEmittedTypeElement + | NumericLiteral + | ObjectLiteralExpression + | OmittedExpression + | OptionalTypeNode + | ParameterDeclaration + | ParenthesizedExpression + | ParenthesizedTypeNode + | PartiallyEmittedExpression + | PostfixUnaryExpression + | PrefixUnaryExpression + | PrivateIdentifier + | PropertyAccessExpression + | PropertyAssignment + | PropertyDeclaration + | PropertySignatureDeclaration + | QualifiedName + | RegularExpressionLiteral + | RestTypeNode + | ReturnStatement + | SatisfiesExpression + | SemicolonClassElement + | SetAccessorDeclaration + | ShorthandPropertyAssignment + | SourceFile + | SpreadAssignment + | SpreadElement + | StringLiteral + | SwitchStatement + | SyntaxList + | SyntheticExpression + | SyntheticReferenceExpression + | TaggedTemplateExpression + | TemplateExpression + | TemplateHead + | TemplateLiteralTypeNode + | TemplateLiteralTypeSpan + | TemplateMiddle + | TemplateSpan + | TemplateTail + | ThisTypeNode + | ThrowStatement + | Token + | TryStatement + | TupleTypeNode + | TypeAliasDeclaration + | TypeAssertion + | TypeLiteralNode + | TypeOfExpression + | TypeOperatorNode + | TypeParameterDeclaration + | TypePredicateNode + | TypeQueryNode + | TypeReferenceNode + | UnionTypeNode + | VariableDeclaration + | VariableDeclarationList + | VariableStatement + | VoidExpression + | WhileStatement + | WithStatement + | YieldExpression; export interface ForInStatement extends StatementBase { readonly kind: SyntaxKind.ForInStatement; diff --git a/packages/typescript/src/ast/ast.ts b/packages/typescript/src/ast/ast.ts index 804f0c0c6a33d..04e988ab17492 100644 --- a/packages/typescript/src/ast/ast.ts +++ b/packages/typescript/src/ast/ast.ts @@ -30,6 +30,7 @@ import type { JsxSpreadAttribute, KeywordSyntaxKind, ModifierSyntaxKind, + Node, ParameterDeclaration, PropertyAccessExpression, PropertyAssignment, @@ -80,12 +81,12 @@ export interface ReadonlyTextRange { readonly end: number; } -export interface NodeArray extends ReadonlyArray, ReadonlyTextRange { +export interface NodeArray extends ReadonlyArray, ReadonlyTextRange { hasTrailingComma?: boolean; transformFlags: number; } -export interface Node extends ReadonlyTextRange { +export interface NodeBase extends ReadonlyTextRange { readonly kind: SyntaxKind; readonly flags: NodeFlags; readonly parent: Node; @@ -122,7 +123,7 @@ export interface MappedDiagnosticDirective { readonly unusedCode: number; } -export interface SourceFile extends Node { +export interface SourceFile extends NodeBase { readonly kind: SyntaxKind.SourceFile; readonly statements: NodeArray; readonly endOfFileToken: EndOfFile; diff --git a/tools/scripts/tsc/generate-ts-ast.ts b/tools/scripts/tsc/generate-ts-ast.ts index 96b448908fac0..05420b5dff792 100644 --- a/tools/scripts/tsc/generate-ts-ast.ts +++ b/tools/scripts/tsc/generate-ts-ast.ts @@ -145,7 +145,7 @@ function resolveBaseExtends(base: NodeType): string { .map(e => baseTsName(e)); if (tsExts.length > 0) return tsExts.join(", "); } - return "Node"; + return "NodeBase"; } function deriveNodeTsExtends(node: NodeType): string { @@ -319,6 +319,7 @@ function generateAstGenerated(): string { // ── Base interfaces from schema ── parts.push(""); for (const base of api.bases()) { + if (base.key === "NodeBase") continue; if (goOnlyBases.has(base.key)) continue; const name = baseTsName(base); const extendsClause = resolveBaseExtends(base); @@ -384,6 +385,12 @@ function generateAstGenerated(): string { } } + const allNodesNames = api + .nodes() + .map(node => node.name) + .sort((a, b) => a.localeCompare(b)); + parts.push(`export type Node = ${allNodesNames.join(" | ")};`); + // ── Variant interfaces (from multi-kind nodes with enum Kind) ── parts.push(""); for (const v of tsVariants) { @@ -430,7 +437,7 @@ function generateAstGenerated(): string { // ── Header (with imports resolved from the schema model) ── // Types referenced by the generated declarations but not declared here are // hand-written in ast.ts; import them so the module type-checks. - const astImports = ["Node", "NodeArray", ...unresolvedAstImports()]; + const astImports = ["NodeBase", "NodeArray", ...unresolvedAstImports()]; astImports.sort((a, b) => a.localeCompare(b)); const header = `// Code generated by tools/scripts/tsc/generate-ts-ast.ts. DO NOT EDIT. @@ -459,7 +466,7 @@ const astBuiltinTypeNames = new Set([ "NodeFlags", "TokenFlags", "SyntaxKind", - "Node", + "NodeBase", "NodeArray", ]); @@ -497,7 +504,7 @@ function collectTypeReferences(type: Type, into: Set): void { // declarations emitted by generateAstGenerated so references to them are not // mistaken for hand-written ast.ts types. function declaredAstNames(): Set { - const declared = new Set(); + const declared = new Set(["Node"]); for (const { name } of api.kindAliases()) declared.add(name); for (const base of api.bases()) { if (!goOnlyBases.has(base.key)) declared.add(baseTsName(base)); From 21c4bcaab191a032b5bd0d714b5dc60bd775e668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Thu, 27 Aug 2026 00:17:59 +0200 Subject: [PATCH 4/5] AI review: update encoder --- .../typescript/src/api/node/node.generated.ts | 18 ++++++++++-------- packages/typescript/src/ast/ast.ts | 3 ++- tools/scripts/tsc/generate-encoder.ts | 18 ++++++++++-------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/packages/typescript/src/api/node/node.generated.ts b/packages/typescript/src/api/node/node.generated.ts index 035c8d308e737..4117e3e4cbd21 100644 --- a/packages/typescript/src/api/node/node.generated.ts +++ b/packages/typescript/src/api/node/node.generated.ts @@ -2,9 +2,11 @@ import { getTokenPosOfNode, + type JSDoc, ModifierFlags, type Node, type NodeArray, + type NodeBase, type SourceFile, SyntaxKind, } from "../../ast/index.ts"; @@ -153,13 +155,13 @@ export class RemoteNodeList extends Array implements NodeArray(visitNode: (node: RemoteNode) => T | undefined): T | undefined { + forEachNode(visitNode: (node: Node) => T | undefined): T | undefined { if (!this.length) return; let next = this.index + 1; while (next) { const child = this.getOrCreateChildAtNodeIndex(next); next = child.next; - const result = visitNode(child as RemoteNode); + const result = visitNode(child as Node); if (result) return result; } } @@ -222,7 +224,7 @@ export class RemoteNodeList extends Array implements NodeArray); if (result) { return result; } @@ -257,7 +259,7 @@ export class RemoteNode extends RemoteNodeBase implements Node { } } else if (child.kind !== SyntaxKind.JSDoc) { - const result = visitNode(child); + const result = visitNode(child as Node); if (result) { return result; } @@ -268,16 +270,16 @@ export class RemoteNode extends RemoteNodeBase implements Node { } } - get jsDoc(): readonly Node[] | undefined { + get jsDoc(): readonly JSDoc[] | undefined { if (!this.hasChildren()) { return undefined; } - let result: Node[] | undefined; + let result: JSDoc[] | undefined; let next = this.index + 1; do { const child = this.getOrCreateChildAtNodeIndex(next); if (!(child instanceof RemoteNodeList) && child.kind === SyntaxKind.JSDoc) { - (result ??= []).push(child); + (result ??= []).push(child as unknown as JSDoc); } next = child.next; } diff --git a/packages/typescript/src/ast/ast.ts b/packages/typescript/src/ast/ast.ts index 04e988ab17492..29e0f2d96f16a 100644 --- a/packages/typescript/src/ast/ast.ts +++ b/packages/typescript/src/ast/ast.ts @@ -25,6 +25,7 @@ import type { ForStatement, Identifier, IfStatement, + JSDoc, JsxAttribute, JsxExpression, JsxSpreadAttribute, @@ -90,7 +91,7 @@ export interface NodeBase extends ReadonlyTextRange { readonly kind: SyntaxKind; readonly flags: NodeFlags; readonly parent: Node; - readonly jsDoc?: readonly Node[] | undefined; + readonly jsDoc?: readonly JSDoc[] | undefined; forEachChild(visitor: (node: Node) => T, visitArray?: (nodes: NodeArray) => T): T | undefined; getSourceFile(): SourceFile; getStart(sourceFile?: SourceFile, includeJsDocComment?: boolean): number; diff --git a/tools/scripts/tsc/generate-encoder.ts b/tools/scripts/tsc/generate-encoder.ts index fc1a67022a39d..78104e45b7d4f 100644 --- a/tools/scripts/tsc/generate-encoder.ts +++ b/tools/scripts/tsc/generate-encoder.ts @@ -1475,9 +1475,11 @@ function generateTSNodeGenerated(): string { function emitNodeGeneratedImports(w: CodeWriter) { w.write(`import {`); w.write(` getTokenPosOfNode,`); + w.write(` type JSDoc,`); w.write(` ModifierFlags,`); w.write(` type Node,`); w.write(` type NodeArray,`); + w.write(` type NodeBase,`); w.write(` type SourceFile,`); w.write(` SyntaxKind,`); w.write(`} from "../../ast/index.ts";`); @@ -1588,13 +1590,13 @@ function emitRemoteNodeList(w: CodeWriter) { w.write(` }`); w.write(` }`); w.write(``); - w.write(` forEachNode(visitNode: (node: RemoteNode) => T | undefined): T | undefined {`); + w.write(` forEachNode(visitNode: (node: Node) => T | undefined): T | undefined {`); w.write(` if (!this.length) return;`); w.write(` let next = this.index + 1;`); w.write(` while (next) {`); w.write(` const child = this.getOrCreateChildAtNodeIndex(next);`); w.write(` next = child.next;`); - w.write(` const result = visitNode(child as RemoteNode);`); + w.write(` const result = visitNode(child as Node);`); w.write(` if (result) return result;`); w.write(` }`); w.write(` }`); @@ -1659,7 +1661,7 @@ function emitRemoteNodeList(w: CodeWriter) { } function emitRemoteNodeClassOpen(w: CodeWriter) { - w.write(`export class RemoteNode extends RemoteNodeBase implements Node {`); + w.write(`export class RemoteNode extends RemoteNodeBase implements NodeBase {`); w.write(` protected static NODE_LEN: number = NODE_LEN;`); w.write(` protected override get sourceFile(): SourceFileInfo {`); w.write(` return this._sourceFile;`); @@ -1681,7 +1683,7 @@ function emitRemoteNodeClassOpen(w: CodeWriter) { w.write(` const child = this.getOrCreateChildAtNodeIndex(next);`); w.write(` if (child instanceof RemoteNodeList) {`); w.write(` if (visitList) {`); - w.write(` const result = visitList(child);`); + w.write(` const result = visitList(child as NodeArray);`); w.write(` if (result) {`); w.write(` return result;`); w.write(` }`); @@ -1694,7 +1696,7 @@ function emitRemoteNodeClassOpen(w: CodeWriter) { w.write(` }`); w.write(` }`); w.write(` else if (child.kind !== SyntaxKind.JSDoc) {`); - w.write(` const result = visitNode(child);`); + w.write(` const result = visitNode(child as Node);`); w.write(` if (result) {`); w.write(` return result;`); w.write(` }`); @@ -1705,16 +1707,16 @@ function emitRemoteNodeClassOpen(w: CodeWriter) { w.write(` }`); w.write(` }`); w.write(``); - w.write(` get jsDoc(): readonly Node[] | undefined {`); + w.write(` get jsDoc(): readonly JSDoc[] | undefined {`); w.write(` if (!this.hasChildren()) {`); w.write(` return undefined;`); w.write(` }`); - w.write(` let result: Node[] | undefined;`); + w.write(` let result: JSDoc[] | undefined;`); w.write(` let next = this.index + 1;`); w.write(` do {`); w.write(` const child = this.getOrCreateChildAtNodeIndex(next);`); w.write(` if (!(child instanceof RemoteNodeList) && child.kind === SyntaxKind.JSDoc) {`); - w.write(` (result ??= []).push(child);`); + w.write(` (result ??= []).push(child as unknown as JSDoc);`); w.write(` }`); w.write(` next = child.next;`); w.write(` }`); From 2865838ab089241767210f0da1bbc9406bc4d353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Thu, 27 Aug 2026 01:09:26 +0200 Subject: [PATCH 5/5] Fix type errors in is.ts --- packages/typescript/src/ast/astnav.ts | 2 +- packages/typescript/src/ast/is.ts | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/packages/typescript/src/ast/astnav.ts b/packages/typescript/src/ast/astnav.ts index 96e4edecaed74..77124f7257bd5 100644 --- a/packages/typescript/src/ast/astnav.ts +++ b/packages/typescript/src/ast/astnav.ts @@ -164,7 +164,7 @@ function getTokenAtPositionImpl( while (true) { // Visit each child of current to find the one containing the position. - state.next = undefined; + state.next = undefined as Node | undefined; nodeAfterLeft = undefined as Node | undefined; // In Strada, JSDoc nodes with a single comment represent that comment as a string diff --git a/packages/typescript/src/ast/is.ts b/packages/typescript/src/ast/is.ts index ecf91f4c74f3b..32dd399713f82 100644 --- a/packages/typescript/src/ast/is.ts +++ b/packages/typescript/src/ast/is.ts @@ -8,11 +8,13 @@ import { ScriptKind } from "#enums/scriptKind"; import { SyntaxKind } from "#enums/syntaxKind"; import type { AsExpression, + AwaitExpression, BindingPattern, BlockOrExpression, BooleanLiteral, ComputedPropertyName, ConciseBody, + DeleteExpression, ExclamationToken, Expression, ExpressionWithTypeArguments, @@ -34,6 +36,7 @@ import type { ParenthesizedExpression, PartiallyEmittedExpression, PlusToken, + PostfixUnaryExpression, PrefixUnaryExpression, QuestionToken, ReadonlyKeyword, @@ -44,7 +47,9 @@ import type { ThisTypeNode, TypeAssertion, TypeNode, + TypeOfExpression, UnaryExpressionBase, + VoidExpression, } from "./ast.ts"; import { isBinaryExpression, @@ -304,11 +309,11 @@ function isExpressionNode(node: Node): boolean { } function isImportCall(node: Node): node is Node & { readonly expression: MetaProperty; } { - if (node.kind !== SyntaxKind.CallExpression || !hasExpression(node) || !node.expression) { + if (node.kind !== SyntaxKind.CallExpression) { return false; } return node.expression.kind === SyntaxKind.MetaProperty - && (node.expression as MetaProperty).keywordToken === SyntaxKind.ImportKeyword; + && node.expression.keywordToken === SyntaxKind.ImportKeyword; } function isJSDocLinkLike(node: Node): boolean { @@ -456,12 +461,9 @@ function isLeftHandSideExpressionKind(kind: SyntaxKind): boolean { } } -export function isUnaryExpression(node: Node): node is UnaryExpressionBase { - return isUnaryExpressionKind(skipPartiallyEmittedExpressions(node).kind); -} - -function isUnaryExpressionKind(kind: SyntaxKind): boolean { - switch (kind) { +export function isUnaryExpression(node: Node): node is PrefixUnaryExpression | PostfixUnaryExpression | DeleteExpression | TypeOfExpression | VoidExpression | AwaitExpression | TypeAssertion | LeftHandSideExpression { + const expression = skipPartiallyEmittedExpressions(node); + switch (expression.kind) { case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: case SyntaxKind.DeleteExpression: @@ -471,7 +473,7 @@ function isUnaryExpressionKind(kind: SyntaxKind): boolean { case SyntaxKind.TypeAssertionExpression: return true; default: - return isLeftHandSideExpressionKind(kind); + return isLeftHandSideExpression(expression); } } @@ -506,10 +508,11 @@ export function skipOuterExpressions(node: Expression, kinds?: OuterExpressionKi export function skipOuterExpressions(node: Node, kinds?: OuterExpressionKinds): Node; /** @internal */ export function skipOuterExpressions(node: Node, kinds = OuterExpressionKinds.All) { + let innerNode: Expression | undefined; while (isOuterExpression(node, kinds)) { - node = node.expression; + innerNode = node.expression; } - return node; + return innerNode ?? node; } function isJSDocTypeAssertion(node: ParenthesizedExpression): boolean {