Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions crates/oxc_ast/custom_types.d.ts

This file was deleted.

14 changes: 12 additions & 2 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ inherit_variants! {
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
#[estree(custom_ts_def)]
#[estree(no_ts_def)]
pub enum ArrayExpressionElement<'a> {
/// `...[3, 4]` in `const array = [1, 2, ...[3, 4], null];`
SpreadElement(Box<'a, SpreadElement<'a>>) = 64,
Expand Down Expand Up @@ -1626,7 +1626,17 @@ pub enum FunctionType {
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
#[estree(custom_serialize)]
#[estree(
custom_serialize,
add_ts_def = "
interface FormalParameterRest extends Span {
type: 'RestElement';
argument: BindingPatternKind;
typeAnnotation: TSTypeAnnotation | null;
optional: boolean;
}
"
)]
pub struct FormalParameters<'a> {
pub span: Span,
pub kind: FormalParameterKind,
Expand Down
12 changes: 10 additions & 2 deletions crates/oxc_ast/src/ast/jsx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ pub struct JSXClosingFragment {
/// JSX Element Name
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, GetAddress, ContentEq)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, GetAddress, ContentEq, ESTree)]
#[estree(
custom_serialize,
custom_ts_def = "type JSXElementName = JSXIdentifier | JSXNamespacedName | JSXMemberExpression"
)]
pub enum JSXElementName<'a> {
/// `<div />`
Identifier(Box<'a, JSXIdentifier<'a>>) = 0,
Expand Down Expand Up @@ -224,7 +228,11 @@ pub struct JSXMemberExpression<'a> {
/// ```
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, GetAddress, ContentEq)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, GetAddress, ContentEq, ESTree)]
#[estree(
custom_serialize,
custom_ts_def = "type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression"
)]
pub enum JSXMemberExpressionObject<'a> {
/// `<Apple.Orange />`
IdentifierReference(Box<'a, IdentifierReference<'a>>) = 0,
Expand Down
24 changes: 24 additions & 0 deletions crates/oxc_ast/src/ast/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,29 @@ bitflags! {

/// Dummy type to communicate the content of `RegExpFlags` to `oxc_ast_tools`.
#[ast(foreign = RegExpFlags)]
#[generate_derive(ESTree)]
#[estree(
custom_serialize,
custom_ts_def = "
type RegExpFlags = {
/** Global flag */
G: 1;
/** Ignore case flag */
I: 2;
/** Multiline flag */
M: 4;
/** DotAll flag */
S: 8;
/** Unicode flag */
U: 16;
/** Sticky flag */
Y: 32;
/** Indices flag */
D: 64;
/** Unicode sets flag */
V: 128;
}
"
)]
#[expect(dead_code)]
struct RegExpFlagsAlias(u8);
63 changes: 30 additions & 33 deletions npm/oxc-types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,13 @@ export interface FormalParameters extends Span {
items: Array<FormalParameter | FormalParameterRest>;
}

export interface FormalParameterRest extends Span {
type: 'RestElement';
argument: BindingPatternKind;
typeAnnotation: TSTypeAnnotation | null;
optional: boolean;
}

export interface FormalParameter extends Span {
type: 'FormalParameter';
decorators: Array<Decorator>;
Expand Down Expand Up @@ -1032,6 +1039,25 @@ export interface RegExp {

export type RegExpPattern = string | string | Pattern;

export type RegExpFlags = {
/** Global flag */
G: 1;
/** Ignore case flag */
I: 2;
/** Multiline flag */
M: 4;
/** DotAll flag */
S: 8;
/** Unicode flag */
U: 16;
/** Sticky flag */
Y: 32;
/** Indices flag */
D: 64;
/** Unicode sets flag */
V: 128;
};

export interface JSXElement extends Span {
type: 'JSXElement';
openingElement: JSXOpeningElement;
Expand Down Expand Up @@ -1067,6 +1093,8 @@ export interface JSXClosingFragment extends Span {
type: 'JSXClosingFragment';
}

export type JSXElementName = JSXIdentifier | JSXNamespacedName | JSXMemberExpression;

export interface JSXNamespacedName extends Span {
type: 'JSXNamespacedName';
namespace: JSXIdentifier;
Expand All @@ -1079,6 +1107,8 @@ export interface JSXMemberExpression extends Span {
property: JSXIdentifier;
}

export type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression;

export interface JSXExpressionContainer extends Span {
type: 'JSXExpressionContainer';
expression: JSXExpression;
Expand Down Expand Up @@ -1941,36 +1971,3 @@ export interface NamedReference extends Span {
type: 'NamedReference';
name: string;
}

export interface FormalParameterRest extends Span {
type: 'RestElement';
argument: BindingPatternKind;
typeAnnotation: TSTypeAnnotation | null;
optional: boolean;
}

export type RegExpFlags = {
/** Global flag */
G: 1;
/** Ignore case flag */
I: 2;
/** Multiline flag */
M: 4;
/** DotAll flag */
S: 8;
/** Unicode flag */
U: 16;
/** Sticky flag */
Y: 32;
/** Indices flag */
D: 64;
/** Unicode sets flag */
V: 128;
};

export type JSXElementName =
| JSXIdentifier
| JSXNamespacedName
| JSXMemberExpression;

export type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression;
23 changes: 20 additions & 3 deletions tasks/ast_tools/src/derives/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ impl Derive for DeriveESTree {
}
generate_body_for_struct(struct_def, schema)
}
StructOrEnum::Enum(enum_def) => generate_body_for_enum(enum_def, schema),
StructOrEnum::Enum(enum_def) => {
if enum_def.estree.custom_serialize {
return quote!();
}
generate_body_for_enum(enum_def, schema)
}
};

let ty = type_def.ty_anon(schema);
Expand All @@ -92,16 +97,28 @@ fn parse_estree_attr(location: AttrLocation, part: AttrPart) -> Result<()> {
AttrPart::Tag("flatten") => struct_def.estree.flatten = true,
AttrPart::Tag("no_type") => struct_def.estree.no_type = true,
AttrPart::Tag("custom_serialize") => struct_def.estree.custom_serialize = true,
AttrPart::Tag("no_ts_def") => struct_def.estree.custom_ts_def = Some(String::new()),
AttrPart::String("add_ts", value) => struct_def.estree.add_ts = Some(value),
AttrPart::String("custom_ts_def", value) => {
struct_def.estree.custom_ts_def = Some(value);
}
AttrPart::String("add_ts_def", value) => {
struct_def.estree.add_ts_def = Some(value);
}
AttrPart::String("rename", value) => struct_def.estree.rename = Some(value),
AttrPart::String("via", value) => struct_def.estree.via = Some(value),
AttrPart::String("add_ts", value) => struct_def.estree.add_ts = Some(value),
_ => return Err(()),
},
// `#[estree]` attr on enum
AttrLocation::Enum(enum_def) => match part {
AttrPart::Tag("skip") => enum_def.estree.skip = true,
AttrPart::Tag("no_rename_variants") => enum_def.estree.no_rename_variants = true,
AttrPart::Tag("custom_ts_def") => enum_def.estree.custom_ts_def = true,
AttrPart::Tag("custom_serialize") => enum_def.estree.custom_serialize = true,
AttrPart::Tag("no_ts_def") => enum_def.estree.custom_ts_def = Some(String::new()),
AttrPart::String("custom_ts_def", value) => enum_def.estree.custom_ts_def = Some(value),
AttrPart::String("add_ts_def", value) => {
enum_def.estree.add_ts_def = Some(value);
}
_ => return Err(()),
},
// `#[estree]` attr on struct field
Expand Down
66 changes: 41 additions & 25 deletions tasks/ast_tools/src/generators/typescript.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Generator for TypeScript type definitions for all AST types.

use std::borrow::Cow;
use std::{borrow::Cow, fmt::Write};

use itertools::Itertools;

Expand All @@ -16,8 +16,6 @@ use crate::{

use super::{attr_positions, define_generator, AttrLocation, AttrPart, AttrPositions};

const CUSTOM_TYPESCRIPT: &str = include_str!("../../../../crates/oxc_ast/custom_types.d.ts");

/// Generator for TypeScript type definitions.
pub struct TypescriptGenerator;

Expand Down Expand Up @@ -56,27 +54,49 @@ impl Generator for TypescriptGenerator {

let mut code = String::new();
for type_def in &schema.types {
if !type_def.generates_derive(estree_derive_id) {
continue;
if type_def.generates_derive(estree_derive_id) {
generate_ts_type_def(type_def, &mut code, schema);
}
}

let ts_type_def = match type_def {
TypeDef::Struct(struct_def) => generate_ts_type_def_for_struct(struct_def, schema),
TypeDef::Enum(enum_def) => {
let ts_type_def = generate_ts_type_def_for_enum(enum_def, schema);
let Some(ts_type_def) = ts_type_def else { continue };
ts_type_def
}
_ => unreachable!(),
};
Output::Javascript { path: TYPESCRIPT_DEFINITIONS_PATH.to_string(), code }
}
}

code.push_str(&ts_type_def);
code.push_str("\n\n");
}
/// 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) {
// 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,
TypeDef::Enum(enum_def) => &enum_def.estree.custom_ts_def,
_ => unreachable!(),
};

code.push_str(CUSTOM_TYPESCRIPT);
if let Some(custom_ts_def) = custom_ts_def {
// Empty string means don't output any TS def at all for this type
if !custom_ts_def.is_empty() {
write!(code, "export {custom_ts_def};\n\n").unwrap();
}
} 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::Enum(enum_def) => generate_ts_type_def_for_enum(enum_def, schema),
_ => unreachable!(),
};
write!(code, "{ts_def};\n\n").unwrap();
};

Output::Javascript { path: TYPESCRIPT_DEFINITIONS_PATH.to_string(), code }
// Add additional custom TS def if provided via `#[estree(add_ts_def = "...")]` attribute
let add_ts_def = match type_def {
TypeDef::Struct(struct_def) => &struct_def.estree.add_ts_def,
TypeDef::Enum(enum_def) => &enum_def.estree.add_ts_def,
_ => unreachable!(),
};
if let Some(add_ts_def) = add_ts_def {
write!(code, "export {add_ts_def};\n\n").unwrap();
}
}

Expand Down Expand Up @@ -163,11 +183,7 @@ fn generate_ts_type_def_for_struct(struct_def: &StructDef, schema: &Schema) -> S
}

/// Generate Typescript type definition for an enum.
fn generate_ts_type_def_for_enum(enum_def: &EnumDef, schema: &Schema) -> Option<String> {
if enum_def.estree.custom_ts_def {
return None;
}

fn generate_ts_type_def_for_enum(enum_def: &EnumDef, schema: &Schema) -> String {
let union = if enum_def.is_fieldless() {
enum_def
.all_variants(schema)
Expand All @@ -181,7 +197,7 @@ fn generate_ts_type_def_for_enum(enum_def: &EnumDef, schema: &Schema) -> Option<
};

let enum_name = enum_def.name();
Some(format!("export type {enum_name} = {union};"))
format!("export type {enum_name} = {union};")
}

/// Get TS type name for a type.
Expand Down
19 changes: 17 additions & 2 deletions tasks/ast_tools/src/schema/extensions/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,34 @@
pub struct ESTreeStruct {
pub rename: Option<String>,
pub via: Option<String>,
pub add_ts: Option<String>,
pub skip: bool,
pub flatten: bool,
pub no_type: bool,
/// `true` if serializer is implemented manually and should not be generated
pub custom_serialize: bool,
/// Additional fields to add to TS type definition
pub add_ts: Option<String>,
/// Custom TS type definition. Does not include `export`.
/// Empty string if type should not have a TS type definition.
pub custom_ts_def: Option<String>,
/// Additional custom TS type definition to add along with the generated one.
/// Does not include `export`.
pub add_ts_def: Option<String>,
}

/// Configuration for ESTree generator on an enum.
#[derive(Default, Debug)]
pub struct ESTreeEnum {
pub skip: bool,
pub no_rename_variants: bool,
pub custom_ts_def: bool,
/// `true` if serializer is implemented manually and should not be generated
pub custom_serialize: bool,
/// Custom TS type definition. Does not include `export`.
/// Empty string if type should not have a TS type definition.
pub custom_ts_def: Option<String>,
/// Additional custom TS type definition to add along with the generated one.
/// Does not include `export`.
pub add_ts_def: Option<String>,
}

/// Configuration for ESTree generator on a struct field.
Expand Down
Loading