import { ts, type tsc } from './typescript' /** * A lot of the extra information here only exists because TypeScript doesn't * export a union containing all the different node types, so you can't narrow * a node's type by its kind. Narrowing based on kind is very useful for plugins * since you can define a property using a kind name and the type of the 'node' * argument can be inferred instead of every plugin needing to cast it manually. * If you find yourself needing to parse any node kinds that aren't on this list, * please add them here. * * See: https://github.com/microsoft/TypeScript/issues/13634 */ export const SupportedKinds = { [ts.SyntaxKind.TypeAliasDeclaration]: { name: 'TypeAliasDeclaration', node: {} as ts.TypeAliasDeclaration, }, [ts.SyntaxKind.TypeReference]: { name: 'TypeReference', node: {} as ts.TypeReferenceNode, }, [ts.SyntaxKind.TypeLiteral]: { name: 'TypeLiteral', node: {} as ts.TypeLiteralNode, }, [ts.SyntaxKind.PropertySignature]: { name: 'PropertySignature', node: {} as ts.PropertySignature, }, [ts.SyntaxKind.TupleType]: { name: 'TupleType', node: {} as ts.TupleTypeNode, }, [ts.SyntaxKind.FunctionExpression]: { name: 'FunctionExpression', node: {} as ts.FunctionExpression, }, [ts.SyntaxKind.FunctionDeclaration]: { name: 'FunctionDeclaration', node: {} as ts.FunctionDeclaration, }, [ts.SyntaxKind.ArrayLiteralExpression]: { name: 'ArrayLiteralExpression', node: {} as ts.ArrayLiteralExpression, }, [ts.SyntaxKind.CallExpression]: { name: 'CallExpression', node: {} as ts.CallExpression, }, [ts.SyntaxKind.StringLiteral]: { name: 'StringLiteral', node: {} as ts.StringLiteral, }, [ts.SyntaxKind.NumericLiteral]: { name: 'NumericLiteral', node: {} as ts.NumericLiteral, }, [ts.SyntaxKind.TrueKeyword]: { name: 'TrueKeyword', node: {} as ts.TrueLiteral, }, [ts.SyntaxKind.FalseKeyword]: { name: 'FalseKeyword', node: {} as ts.FalseLiteral, }, [ts.SyntaxKind.Identifier]: { name: 'Identifier', node: {} as ts.Identifier, }, [ts.SyntaxKind.SourceFile]: { name: 'SourceFile', node: {} as ts.SourceFile, }, [ts.SyntaxKind.VariableDeclaration]: { name: 'VariableDeclaration', node: {} as ts.VariableDeclaration, }, [ts.SyntaxKind.ClassDeclaration]: { name: 'ClassDeclaration', node: {} as ts.ClassDeclaration, }, [ts.SyntaxKind.ExportDeclaration]: { name: 'ExportDeclaration', node: {} as ts.ExportDeclaration, }, [ts.SyntaxKind.ObjectLiteralExpression]: { name: 'ObjectLiteralExpression', node: {} as ts.ObjectLiteralExpression, }, [ts.SyntaxKind.AsExpression]: { name: 'AsExpression', node: {} as ts.AsExpression, }, [ts.SyntaxKind.ComputedPropertyName]: { name: 'ComputedPropertyName', node: {} as ts.ComputedPropertyName, }, [ts.SyntaxKind.PropertyAssignment]: { name: 'PropertyAssignment', node: {} as ts.PropertyAssignment, }, [ts.SyntaxKind.ShorthandPropertyAssignment]: { name: 'ShorthandPropertyAssignment', node: {} as ts.ShorthandPropertyAssignment, }, [ts.SyntaxKind.PropertyAccessExpression]: { name: 'PropertyAccessExpression', node: {} as ts.PropertyAccessExpression, }, [ts.SyntaxKind.NoSubstitutionTemplateLiteral]: { name: 'NoSubstitutionTemplateLiteral', node: {} as ts.NoSubstitutionTemplateLiteral, }, [ts.SyntaxKind.ExpressionStatement]: { name: 'ExpressionStatement', node: {} as ts.ExpressionStatement, }, [ts.SyntaxKind.TaggedTemplateExpression]: { name: 'TaggedTemplateExpression', node: {} as ts.TaggedTemplateExpression, }, [ts.SyntaxKind.ExportAssignment]: { name: 'ExportAssignment', node: {} as ts.ExportAssignment, }, [ts.SyntaxKind.ElementAccessExpression]: { name: 'ElementAccessExpression', node: {} as ts.ElementAccessExpression, }, [ts.SyntaxKind.TemplateExpression]: { name: 'TemplateExpression', node: {} as ts.TemplateExpression, }, [ts.SyntaxKind.ImportClause]: { name: 'ImportClause', node: {} as ts.ImportClause, }, [ts.SyntaxKind.ImportSpecifier]: { name: 'ImportSpecifier', node: {} as ts.ImportSpecifier, }, [ts.SyntaxKind.ImportDeclaration]: { name: 'ImportDeclaration', node: {} as ts.ImportDeclaration, }, [ts.SyntaxKind.NamedImports]: { name: 'NamedImports', node: {} as ts.NamedImports, }, [ts.SyntaxKind.VariableStatement]: { name: 'VariableStatement', node: {} as ts.VariableStatement, }, [ts.SyntaxKind.VariableDeclarationList]: { name: 'VariableDeclarationList', node: {} as ts.VariableDeclarationList, }, [ts.SyntaxKind.PlusToken]: { name: 'PlusToken', node: {} as ts.Node, }, [ts.SyntaxKind.EndOfFileToken]: { name: 'EndOfFileToken', node: {} as ts.Node, }, [ts.SyntaxKind.ExportKeyword]: { name: 'ExportKeyword', node: {} as ts.Node, }, [ts.SyntaxKind.AnyKeyword]: { name: 'AnyKeyword', node: {} as ts.Node>, }, [ts.SyntaxKind.ModuleDeclaration]: { name: 'ModuleDeclaration', node: {} as ts.ModuleDeclaration, }, [ts.SyntaxKind.ModuleBlock]: { name: 'ModuleBlock', node: {} as ts.ModuleBlock, }, [ts.SyntaxKind.Block]: { name: 'Block', node: {} as ts.Block, }, [ts.SyntaxKind.Parameter]: { name: 'Parameter', node: {} as ts.ParameterDeclaration, }, [ts.SyntaxKind.EqualsGreaterThanToken]: { name: 'EqualsGreaterThanToken', node: {} as ts.Node, }, [ts.SyntaxKind.ArrowFunction]: { name: 'ArrowFunction', node: {} as ts.ArrowFunction, }, [ts.SyntaxKind.TemplateHead]: { name: 'TemplateHead', node: {} as ts.TemplateHead, }, [ts.SyntaxKind.TemplateMiddle]: { name: 'TemplateMiddle', node: {} as ts.TemplateMiddle, }, [ts.SyntaxKind.TemplateSpan]: { name: 'TemplateSpan', node: {} as ts.TemplateSpan, }, [ts.SyntaxKind.TemplateTail]: { name: 'TemplateTail', node: {} as ts.TemplateTail, }, [ts.SyntaxKind.PrefixUnaryExpression]: { name: 'PrefixUnaryExpression', node: {} as ts.PrefixUnaryExpression, }, } satisfies { [K in ts.SyntaxKind]?: { name: keyof typeof ts.SyntaxKind node: ts.Node } } export type SupportedKind = keyof typeof SupportedKinds export type SupportedKindName = (typeof SupportedKinds)[SupportedKind]['name'] export type SupportedNode = (typeof SupportedKinds)[SupportedKind]['node'] export type SupportedNodeByKind = (typeof SupportedKinds)[K]['node'] export type SupportedNodeByKindName = Extract< (typeof SupportedKinds)[SupportedKind], { name: K } >['node'] export function isSupportedKind(kind: ts.SyntaxKind): kind is SupportedKind { return kind in SupportedKinds } export function isSupportedNode(node: ts.Node): node is SupportedNode { return isSupportedKind(node.getKind()) } export function getKind(node: SupportedNode): SupportedKind { return node.getKind() as SupportedKind } export function getKindName(nodeOrKind: SupportedNode | SupportedKind): SupportedKindName { const kind: SupportedKind = typeof nodeOrKind === 'object' ? getKind(nodeOrKind) : nodeOrKind return SupportedKinds[kind].name }