Skip to content

Commit

Permalink
feat(ast/estree): export Node union type
Browse files Browse the repository at this point in the history
  • Loading branch information
hi-ogawa committed Mar 7, 2025
1 parent 85d49e3 commit d669e6a
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 5 deletions.
22 changes: 21 additions & 1 deletion napi/parser/test/parser.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assertType, describe, it } from 'vitest';

import type { Statement } from '../index';
import type { Node, Statement } from '../index';
import { parseSync } from '../index';

describe('parse', () => {
Expand All @@ -10,4 +10,24 @@ describe('parse', () => {
const ret = parseSync('test.js', code);
assertType<Statement>(ret.program.body[0]);
});

it('Node type', () => {
function example(node: Node) {
node.type satisfies string;
switch (node.type) {
case 'FunctionDeclaration': {
example(node.body);
break;
}
case 'BlockStatement': {
for (const child of node.body) {
example(child);
}
break;
}
}
}
const ret = parseSync('test.js', code);
example(ret.program);
});
});
204 changes: 204 additions & 0 deletions npm/oxc-types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1626,3 +1626,207 @@ export interface NamedReference extends Span {
type: 'NamedReference';
name: string;
}

export type Node =
| Program
| IdentifierName
| IdentifierReference
| BindingIdentifier
| LabelIdentifier
| ThisExpression
| ArrayExpression
| ObjectExpression
| ObjectProperty
| TemplateLiteral
| TaggedTemplateExpression
| TemplateElement
| ComputedMemberExpression
| StaticMemberExpression
| PrivateFieldExpression
| CallExpression
| NewExpression
| MetaProperty
| SpreadElement
| UpdateExpression
| UnaryExpression
| BinaryExpression
| PrivateInExpression
| LogicalExpression
| ConditionalExpression
| AssignmentExpression
| ArrayAssignmentTarget
| ObjectAssignmentTarget
| AssignmentTargetRest
| AssignmentTargetWithDefault
| AssignmentTargetPropertyIdentifier
| AssignmentTargetPropertyProperty
| SequenceExpression
| Super
| AwaitExpression
| ChainExpression
| ParenthesizedExpression
| Directive
| Hashbang
| BlockStatement
| VariableDeclaration
| VariableDeclarator
| EmptyStatement
| ExpressionStatement
| IfStatement
| DoWhileStatement
| WhileStatement
| ForStatement
| ForInStatement
| ForOfStatement
| ContinueStatement
| BreakStatement
| ReturnStatement
| WithStatement
| SwitchStatement
| SwitchCase
| LabeledStatement
| ThrowStatement
| TryStatement
| CatchClause
| DebuggerStatement
| AssignmentPattern
| ObjectPattern
| BindingProperty
| ArrayPattern
| BindingRestElement
| Function
| FunctionBody
| ArrowFunctionExpression
| YieldExpression
| Class
| ClassBody
| MethodDefinition
| PropertyDefinition
| PrivateIdentifier
| StaticBlock
| AccessorProperty
| ImportExpression
| ImportDeclaration
| ImportSpecifier
| ImportDefaultSpecifier
| ImportNamespaceSpecifier
| ImportAttribute
| ExportNamedDeclaration
| ExportDefaultDeclaration
| ExportAllDeclaration
| ExportSpecifier
| V8IntrinsicExpression
| BooleanLiteral
| NullLiteral
| NumericLiteral
| StringLiteral
| BigIntLiteral
| RegExpLiteral
| JSXElement
| JSXOpeningElement
| JSXClosingElement
| JSXFragment
| JSXOpeningFragment
| JSXClosingFragment
| JSXNamespacedName
| JSXMemberExpression
| JSXExpressionContainer
| JSXEmptyExpression
| JSXAttribute
| JSXSpreadAttribute
| JSXIdentifier
| JSXSpreadChild
| JSXText
| TSThisParameter
| TSEnumDeclaration
| TSEnumMember
| TSTypeAnnotation
| TSLiteralType
| TSConditionalType
| TSUnionType
| TSIntersectionType
| TSParenthesizedType
| TSTypeOperator
| TSArrayType
| TSIndexedAccessType
| TSTupleType
| TSNamedTupleMember
| TSOptionalType
| TSRestType
| TSAnyKeyword
| TSStringKeyword
| TSBooleanKeyword
| TSNumberKeyword
| TSNeverKeyword
| TSIntrinsicKeyword
| TSUnknownKeyword
| TSNullKeyword
| TSUndefinedKeyword
| TSVoidKeyword
| TSSymbolKeyword
| TSThisType
| TSObjectKeyword
| TSBigIntKeyword
| TSTypeReference
| TSQualifiedName
| TSTypeParameterInstantiation
| TSTypeParameter
| TSTypeParameterDeclaration
| TSTypeAliasDeclaration
| TSClassImplements
| TSInterfaceDeclaration
| TSInterfaceBody
| TSPropertySignature
| TSIndexSignature
| TSCallSignatureDeclaration
| TSMethodSignature
| TSConstructSignatureDeclaration
| TSIndexSignatureName
| TSInterfaceHeritage
| TSTypePredicate
| TSModuleDeclaration
| TSModuleBlock
| TSTypeLiteral
| TSInferType
| TSTypeQuery
| TSImportType
| TSImportAttributes
| TSImportAttribute
| TSFunctionType
| TSConstructorType
| TSMappedType
| TSTemplateLiteralType
| TSAsExpression
| TSSatisfiesExpression
| TSTypeAssertion
| TSImportEqualsDeclaration
| TSExternalModuleReference
| TSNonNullExpression
| Decorator
| TSExportAssignment
| TSNamespaceExportDeclaration
| TSInstantiationExpression
| JSDocNullableType
| JSDocNonNullableType
| JSDocUnknownType
| Pattern
| Disjunction
| Alternative
| BoundaryAssertion
| LookAroundAssertion
| Quantifier
| Character
| CharacterClassEscape
| UnicodePropertyEscape
| Dot
| CharacterClass
| CharacterClassRange
| ClassStringDisjunction
| ClassString
| CapturingGroup
| IgnoreGroup
| Modifiers
| Modifier
| IndexedReference
| NamedReference
| FormalParameterRest;
30 changes: 26 additions & 4 deletions tasks/ast_tools/src/generators/typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,31 @@ impl Generator for TypescriptGenerator {
let estree_derive_id = codegen.get_derive_id_by_name("ESTree");

let mut code = String::new();
let mut ast_node_names: Vec<String> = vec![];
for type_def in &schema.types {
if type_def.generates_derive(estree_derive_id) {
generate_ts_type_def(type_def, &mut code, schema);
generate_ts_type_def(type_def, &mut code, &mut ast_node_names, schema);
}
}

// Manually append `FormalParameterRest`, which is generated via `add_ts_def`.
// TODO: Should not be hard-coded here.
let ast_node_union = ast_node_names.join(" | ");
write_it!(code, "export type Node = {ast_node_union} | FormalParameterRest;\n\n");

Output::Javascript { path: TYPESCRIPT_DEFINITIONS_PATH.to_string(), code }
}
}

/// Generate Typescript type definition for a struct or enum.
///
/// Push type defs to `code`.
fn generate_ts_type_def(type_def: &TypeDef, code: &mut String, schema: &Schema) {
fn generate_ts_type_def(
type_def: &TypeDef,
code: &mut String,
ast_node_names: &mut Vec<String>,
schema: &Schema,
) {
// Use custom TS def if provided via `#[estree(custom_ts_def = "...")]` attribute
let custom_ts_def = match type_def {
TypeDef::Struct(struct_def) => &struct_def.estree.custom_ts_def,
Expand All @@ -52,11 +63,14 @@ fn generate_ts_type_def(type_def: &TypeDef, code: &mut String, schema: &Schema)
// Empty string means don't output any TS def at all for this type
if !custom_ts_def.is_empty() {
write_it!(code, "export {custom_ts_def};\n\n");
unreachable!();
}
} else {
// No custom definition. Generate one.
let ts_def = match type_def {
TypeDef::Struct(struct_def) => generate_ts_type_def_for_struct(struct_def, schema),
TypeDef::Struct(struct_def) => {
generate_ts_type_def_for_struct(struct_def, ast_node_names, schema)
}
TypeDef::Enum(enum_def) => generate_ts_type_def_for_enum(enum_def, schema),
_ => unreachable!(),
};
Expand All @@ -78,7 +92,11 @@ fn generate_ts_type_def(type_def: &TypeDef, code: &mut String, schema: &Schema)
}

/// Generate Typescript type definition for a struct.
fn generate_ts_type_def_for_struct(struct_def: &StructDef, schema: &Schema) -> Option<String> {
fn generate_ts_type_def_for_struct(
struct_def: &StructDef,
ast_node_names: &mut Vec<String>,
schema: &Schema,
) -> Option<String> {
// If struct marked with `#[estree(ts_alias = "...")]`, then it needs no type def
if struct_def.estree.ts_alias.is_some() {
return None;
Expand Down Expand Up @@ -108,6 +126,10 @@ fn generate_ts_type_def_for_struct(struct_def: &StructDef, schema: &Schema) -> O
fields_str.push_str(&format!("\n\ttype: '{type_name}';"));
}

if !struct_def.estree.no_type {
ast_node_names.push(type_name.to_string());
}

let mut output_as_type = false;

if let Some(field_indices) = &struct_def.estree.field_indices {
Expand Down

0 comments on commit d669e6a

Please sign in to comment.