docs(ast): add doc comments to more AST nodes (#4413)

This commit is contained in:
Don Isaac 2024-07-26 21:21:35 -04:00 committed by GitHub
parent 868fc87885
commit f5f0ba8c33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 666 additions and 18 deletions

View file

@ -160,6 +160,8 @@ macro_rules! match_expression {
pub use match_expression;
/// Identifier Name
///
/// See: [13.1 Identifiers](https://tc39.es/ecma262/#sec-identifiers)
#[ast(visit)]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
@ -171,6 +173,8 @@ pub struct IdentifierName<'a> {
}
/// Identifier Reference
///
/// See: [13.1 Identifiers](https://tc39.es/ecma262/#sec-identifiers)
#[ast(visit)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
@ -178,14 +182,26 @@ pub struct IdentifierName<'a> {
pub struct IdentifierReference<'a> {
#[serde(flatten)]
pub span: Span,
/// The name of the identifier being referenced.
pub name: Atom<'a>,
/// Reference ID
///
/// Identifies what identifier this refers to, and how it is used. This is
/// set in the bind step of semantic analysis, and will always be [`None`]
/// immediately after parsing.
#[serde(skip)]
pub reference_id: Cell<Option<ReferenceId>>,
/// Flags indicating how the reference is used.
///
/// This gets set in the bind step of semantic analysis, and will always be
/// [`ReferenceFlag::None`] immediately after parsing.
#[serde(skip)]
pub reference_flag: ReferenceFlag,
}
/// Binding Identifier
///
/// See: [13.1 Identifiers](https://tc39.es/ecma262/#sec-identifiers)
#[ast(visit)]
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
@ -193,12 +209,21 @@ pub struct IdentifierReference<'a> {
pub struct BindingIdentifier<'a> {
#[serde(flatten)]
pub span: Span,
/// The identifier name being bound.
pub name: Atom<'a>,
/// Unique identifier for this binding.
///
/// This gets initialized during [`semantic analysis`] in the bind step. If
/// you choose to skip semantic analysis, this will always be [`None`].
///
/// [`semantic analysis`]: <https://docs.rs/oxc_semantic/latest/oxc_semantic/struct.SemanticBuilder.html>
#[serde(skip)]
pub symbol_id: Cell<Option<SymbolId>>,
}
/// Label Identifier
///
/// See: [13.1 Identifiers](https://tc39.es/ecma262/#sec-identifiers)
#[ast(visit)]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
@ -210,6 +235,8 @@ pub struct LabelIdentifier<'a> {
}
/// This Expression
///
/// Corresponds to the `this` keyword.
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -266,6 +293,12 @@ pub struct Elision {
}
/// Object Expression
///
/// ## Example
/// ```ts
/// const x = { foo: 'foo' }
/// // ^^^^^^^^^^^^^^
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -273,6 +306,7 @@ pub struct Elision {
pub struct ObjectExpression<'a> {
#[serde(flatten)]
pub span: Span,
/// Properties declared in the object
pub properties: Vec<'a, ObjectPropertyKind<'a>>,
#[serde(skip)]
pub trailing_comma: Option<Span>,
@ -283,7 +317,22 @@ pub struct ObjectExpression<'a> {
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
pub enum ObjectPropertyKind<'a> {
/// Object Property
///
/// ## Example
/// ```ts
/// const foo = 'foo'
/// const x = { foo, bar: 'bar' }
/// // ^^^ ^^^^^^^^^^
ObjectProperty(Box<'a, ObjectProperty<'a>>),
/// Object Spread Property
///
/// ## Example
/// ```ts
/// const obj = { foo: 'foo' }
/// const obj2 = { ...obj, bar: 'bar' }
/// // ^^^^^^
/// ```
SpreadProperty(Box<'a, SpreadElement<'a>>),
}
@ -438,6 +487,14 @@ pub struct StaticMemberExpression<'a> {
}
/// `MemberExpression[?Yield, ?Await] . PrivateIdentifier`
///
/// ## Example
/// ```ts
/// // _______ object
/// const foo.bar?.#baz
/// // ↑ ^^^^ field
/// // optional
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -451,6 +508,19 @@ pub struct PrivateFieldExpression<'a> {
}
/// Call Expression
///
/// ## Examples
/// ```ts
/// // ___ callee
/// const x = foo(1, 2)
///
/// // ^^^^ arguments
/// const y = foo.bar?.(1, 2)
/// // ^ optional
///
/// const z = foo<number, string>(1, 2)
/// // ^^^^^^^^^^^^^^ type_parameters
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -465,6 +535,15 @@ pub struct CallExpression<'a> {
}
/// New Expression
///
/// ## Example
/// ```ts
/// // callee arguments
/// // ↓↓↓ ↓↓↓↓
/// const foo = new Foo<number>(1, 2)
/// // ↑↑↑↑↑↑↑↑
/// // type_parameters
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -490,6 +569,16 @@ pub struct MetaProperty<'a> {
}
/// Spread Element
///
/// An array or object spread. Could be used in unpacking or a declaration.
///
/// ## Example
/// ```ts
/// const [first, ...rest] = arr
/// // ^^^^^^^
/// const obj = { foo: 'foo', ...obj2 }
/// // ^^^^^^^
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -497,6 +586,7 @@ pub struct MetaProperty<'a> {
pub struct SpreadElement<'a> {
#[serde(flatten)]
pub span: Span,
/// The expression being spread.
pub argument: Expression<'a>,
}
@ -1578,17 +1668,65 @@ pub struct Class<'a> {
pub r#type: ClassType,
#[serde(flatten)]
pub span: Span,
/// Decorators applied to the class.
///
/// Decorators are currently a stage 3 proposal. Oxc handles both TC39 and
/// legacy TypeScript decorators.
///
/// ## Example
/// ```ts
/// @Bar() // <-- Decorator
/// class Foo {}
/// ```
pub decorators: Vec<'a, Decorator<'a>>,
/// Class identifier, AKA the name
pub id: Option<BindingIdentifier<'a>>,
#[scope(enter_before)]
pub type_parameters: Option<Box<'a, TSTypeParameterDeclaration<'a>>>,
/// Super class. When present, this will usually be an [`IdentifierReference`].
///
/// ## Example
/// ```ts
/// class Foo extends Bar {}
/// // ^^^
/// ```
#[visit(as(ClassHeritage))]
pub super_class: Option<Expression<'a>>,
/// Type parameters passed to super class.
///
/// ## Example
/// ```ts
/// class Foo<T> extends Bar<T> {}
/// // ^
/// ```
pub super_type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
/// Interface implementation clause for TypeScript classes.
///
/// ## Example
/// ```ts
/// interface Bar {}
/// class Foo implements Bar {}
/// // ^^^
/// ```
pub implements: Option<Vec<'a, TSClassImplements<'a>>>,
pub body: Box<'a, ClassBody<'a>>,
/// Whether the class is abstract
///
/// ## Example
/// ```ts
/// class Foo {} // true
/// abstract class Bar {} // false
/// ```
pub r#abstract: bool,
/// Whether the class was `declare`ed
///
/// ## Example
/// ```ts
/// declare class Foo {}
/// ```
pub declare: bool,
/// Id of the scope created by the [`Class`], including type parameters and
/// statements within the [`ClassBody`].
pub scope_id: Cell<Option<ScopeId>>,
}
@ -1596,7 +1734,16 @@ pub struct Class<'a> {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
pub enum ClassType {
/// Class declaration statement
/// ```ts
/// class Foo { }
/// ```
ClassDeclaration,
/// Class expression
///
/// ```ts
/// const Foo = class {}
/// ```
ClassExpression,
}
@ -1610,15 +1757,44 @@ pub struct ClassBody<'a> {
pub body: Vec<'a, ClassElement<'a>>,
}
/// Class Body Element
///
/// ## Example
/// ```ts
/// class Foo {
/// [prop: string]: string // ClassElement::TSIndexSignature
///
/// public x: number // ClassElement::PropertyDefinition
///
/// accessor z() { return 5 } // ClassElement::AccessorProperty
///
/// // These are all ClassElement::MethodDefinitions
/// get y() { return 5 }
/// set y(value) { }
/// static foo() {}
/// bar() {}
/// }
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
pub enum ClassElement<'a> {
StaticBlock(Box<'a, StaticBlock<'a>>),
/// Class Methods
///
/// Includes static and non-static methods, constructors, getters, and setters.
MethodDefinition(Box<'a, MethodDefinition<'a>>),
PropertyDefinition(Box<'a, PropertyDefinition<'a>>),
AccessorProperty(Box<'a, AccessorProperty<'a>>),
/// Index Signature
///
/// ## Example
/// ```ts
/// class Foo {
/// [keys: string]: string
/// }
/// ```
TSIndexSignature(Box<'a, TSIndexSignature<'a>>),
}
@ -1627,6 +1803,9 @@ pub enum ClassElement<'a> {
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(rename_all = "camelCase")]
pub struct MethodDefinition<'a> {
/// Method definition type
///
/// This will always be true when an `abstract` modifier is used on the method.
pub r#type: MethodDefinitionType,
#[serde(flatten)]
pub span: Span,
@ -1663,17 +1842,76 @@ pub struct PropertyDefinition<'a> {
pub r#type: PropertyDefinitionType,
#[serde(flatten)]
pub span: Span,
/// Decorators applied to the property.
///
/// See [`Decorator`] for more information.
pub decorators: Vec<'a, Decorator<'a>>,
/// The expression used to declare the property.
pub key: PropertyKey<'a>,
/// Initialized value in the declaration.
///
/// ## Example
/// ```
/// class Foo {
/// x = 5 // Some(NumericLiteral)
/// y: string // None
///
/// constructor() {
/// this.y = "hello"
/// }
/// }
/// ```
pub value: Option<Expression<'a>>,
/// Property was declared with a computed key
///
/// ## Example
/// ```ts
/// class Foo {
/// ["a"]: string // true
/// b: number // false
/// }
/// ```
pub computed: bool,
/// Property was declared with a `static` modifier
pub r#static: bool,
/// Property is declared with a `declare` modifier.
///
/// ## Example
/// ```ts
/// class Foo {
/// x: number // false
/// declare y: string // true
/// }
///
/// declare class Bar {
/// x: number // false
/// }
/// ```
pub declare: bool,
pub r#override: bool,
/// `true` when created with an optional modifier (`?`)
pub optional: bool,
pub definite: bool,
/// `true` when declared with a `readonly` modifier
pub readonly: bool,
/// Type annotation on the property.
///
/// Will only ever be [`Some`] for TypeScript files.
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
/// Accessibility modifier.
///
/// Only ever [`Some`] for TypeScript files.
///
/// ## Example
///
/// ```ts
/// class Foo {
/// public w: number // Some(TSAccessibility::Public)
/// private x: string // Some(TSAccessibility::Private)
/// protected y: boolean // Some(TSAccessibility::Protected)
/// readonly z // None
/// }
/// ```
pub accessibility: Option<TSAccessibility>,
}
@ -1690,12 +1928,19 @@ pub enum PropertyDefinitionType {
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(rename_all = "camelCase")]
pub enum MethodDefinitionKind {
/// Class constructor
Constructor,
/// Static or instance method
Method,
/// Getter method
Get,
/// Setter method
Set,
}
/// An identifier for a private class member.
///
/// See: [MDN - Private class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
#[ast(visit)]
#[derive(Debug, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1706,6 +1951,19 @@ pub struct PrivateIdentifier<'a> {
pub name: Atom<'a>,
}
/// Class Static Block
///
/// See: [MDN - Static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks)
///
/// ## Example
///
/// ```ts
/// class Foo {
/// static {
/// this.someStaticProperty = 5;
/// }
/// }
/// ```
#[ast(visit)]
#[scope(flags(ScopeFlags::ClassStaticBlock))]
#[derive(Debug)]
@ -1718,6 +1976,29 @@ pub struct StaticBlock<'a> {
pub scope_id: Cell<Option<ScopeId>>,
}
/// ES6 Module Declaration
///
/// An ESM import or export statement.
///
/// ## Example
///
/// ```ts
/// // ImportDeclaration
/// import { foo } from 'foo';
/// import bar from 'bar';
/// import * as baz from 'baz';
///
/// // Not a ModuleDeclaration
/// export const a = 5;
///
/// const b = 6;
///
/// export { b }; // ExportNamedDeclaration
/// export default b; // ExportDefaultDeclaration
/// export * as c from './c'; // ExportAllDeclaration
/// export = b; // TSExportAssignment
/// export as namespace d; // TSNamespaceExportDeclaration
/// ```
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
@ -1763,6 +2044,14 @@ pub enum AccessorPropertyType {
TSAbstractAccessorProperty,
}
/// Class Accessor Property
///
/// ## Example
/// ```ts
/// class Foo {
/// accessor y: string
/// }
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1770,8 +2059,13 @@ pub struct AccessorProperty<'a> {
pub r#type: AccessorPropertyType,
#[serde(flatten)]
pub span: Span,
/// Decorators applied to the accessor property.
///
/// See [`Decorator`] for more information.
pub decorators: Vec<'a, Decorator<'a>>,
/// The expression used to declare the property.
pub key: PropertyKey<'a>,
/// Initialized value in the declaration, if present.
pub value: Option<Expression<'a>>,
pub computed: bool,
pub r#static: bool,
@ -1828,11 +2122,28 @@ pub struct ImportSpecifier<'a> {
#[serde(flatten)]
pub span: Span,
pub imported: ModuleExportName<'a>,
/// The name of the imported symbol.
///
/// ## Example
/// ```ts
/// // local and imported name are the same
/// import { Foo } from 'foo';
/// // ^^^
/// // imports can be renamed, changing the local name
/// import { Foo as Bar } from 'foo';
/// // ^^^
/// ```
pub local: BindingIdentifier<'a>,
pub import_kind: ImportOrExportKind,
}
// import local from "source"
/// Default Import Specifier
///
/// ## Example
/// ```ts
/// import local from "source";
/// ```
///
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1840,10 +2151,16 @@ pub struct ImportSpecifier<'a> {
pub struct ImportDefaultSpecifier<'a> {
#[serde(flatten)]
pub span: Span,
/// The name of the imported symbol.
pub local: BindingIdentifier<'a>,
}
// import * as local from "source"
/// Namespace import specifier
///
/// ## Example
/// ```ts
/// import * as local from "source";
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1885,6 +2202,17 @@ pub enum ImportAttributeKey<'a> {
StringLiteral(StringLiteral<'a>),
}
/// Named Export Declaration
///
/// ## Example
///
/// ```ts
/// // ________ specifiers
/// export { Foo, Bar };
/// export type { Baz } from 'baz';
/// // ^^^^ ^^^^^
/// // export_kind source
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1902,9 +2230,14 @@ pub struct ExportNamedDeclaration<'a> {
}
/// Export Default Declaration
///
/// ## Example
///
/// ```ts
/// export default HoistableDeclaration
/// export default ClassDeclaration
/// export default AssignmentExpression
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1916,6 +2249,15 @@ pub struct ExportDefaultDeclaration<'a> {
pub exported: ModuleExportName<'a>, // the `default` Keyword
}
/// Export All Declaration
///
/// ## Example
///
/// ```ts
/// // _______ exported
/// export * as numbers from '../numbers.js';
/// // ^^^^^^^^^^^^^^^ source
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1923,12 +2265,25 @@ pub struct ExportDefaultDeclaration<'a> {
pub struct ExportAllDeclaration<'a> {
#[serde(flatten)]
pub span: Span,
/// If this declaration is re-named
pub exported: Option<ModuleExportName<'a>>,
pub source: StringLiteral<'a>,
/// Will be `Some(vec![])` for empty assertion
pub with_clause: Option<WithClause<'a>>, // Some(vec![]) for empty assertion
pub export_kind: ImportOrExportKind, // `export type *`
pub export_kind: ImportOrExportKind, // `export type *`
}
/// Export Specifier
///
/// Each [`ExportSpecifier`] is one of the named exports in an [`ExportNamedDeclaration`].
///
/// ## Example
///
/// ```ts
/// // ____ export_kind
/// import { type Foo as Bar } from './foo';
/// // exported ^^^ ^^^ local
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1965,7 +2320,9 @@ pub enum ExportDefaultDeclarationKind<'a> {
}
}
/// Support:
/// Module Export Name
///
/// Supports:
/// * `import {"\0 any unicode" as foo} from ""`
/// * `export {foo as "\0 any unicode"}`
/// * es2022: <https://github.com/estree/estree/blob/master/es2022.md#modules>

View file

@ -20,6 +20,22 @@ use super::{inherit_variants, js::*, literal::*, ts::*};
// 1.2 JSX Elements
/// JSX Element
///
/// Note that fragments (`<></>`) are represented as [`JSXFragment`], unless they are written as
/// members of React (e.g. `<React.Fragment></React.Fragment>`).
/// ## Examples
///
/// ```tsx
/// <Foo> // <- opening_element
/// some text // <- children
/// </Foo> // <- closing_element
/// ```
///
/// ```tsx
/// <Foo /> // <- opening_element, no closing_element
/// ```
///
/// See: [JSX Syntax](https://facebook.github.io/jsx/)
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -33,6 +49,20 @@ pub struct JSXElement<'a> {
}
/// JSX Opening Element
///
/// Opening tag in a [`JSXElement`].
///
/// ## Examples
/// ```tsx
/// // element with opening and closing tags (self_closing = false)
/// // ___ name
/// <Foo bar baz={4}>
/// // ^^^^^^^^^^^ attributes
///
/// // element with self-closing tag (self_closing = true)
/// <Component<T> />
/// // ^ type_parameters
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -40,13 +70,24 @@ pub struct JSXElement<'a> {
pub struct JSXOpeningElement<'a> {
#[serde(flatten)]
pub span: Span,
/// Is this tag self-closing?
///
/// ## Examples
/// ```tsx
/// <Foo /> // <- self_closing = true
/// <Foo> // <- self_closing = false
/// ```
pub self_closing: bool,
pub name: JSXElementName<'a>,
/// List of JSX attributes. In React-like applications, these become props.
pub attributes: Vec<'a, JSXAttributeItem<'a>>,
/// Type parameters for generic JSX elements.
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
}
/// JSX Closing Element
///
/// Closing tag in a [`JSXElement`]. Not all JSX elements have a closing tag.
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -58,6 +99,13 @@ pub struct JSXClosingElement<'a> {
}
/// JSX Fragment
///
/// A fragment written with the special `<></>` syntax. When written as a `<Fragment>` component,
/// fragments will be represented as [`JSXElement`]s.
///
/// Note that fragments cannot have attributes or type parameters.
///
/// See: [`React.Fragment`](https://react.dev/reference/react/Fragment)
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -70,6 +118,7 @@ pub struct JSXFragment<'a> {
pub children: Vec<'a, JSXChild<'a>>,
}
/// JSX Opening Fragment (`<>`)
#[ast]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -79,6 +128,7 @@ pub struct JSXOpeningFragment {
pub span: Span,
}
/// JSX Closing Fragment (`</>`)
#[ast]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -103,6 +153,12 @@ pub enum JSXElementName<'a> {
}
/// JSX Namespaced Name
///
/// ## Example
///
/// ```tsx
/// <Apple:Orange />
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -110,11 +166,27 @@ pub enum JSXElementName<'a> {
pub struct JSXNamespacedName<'a> {
#[serde(flatten)]
pub span: Span,
/// Namespace portion of the name, e.g. `Apple` in `<Apple:Orange />`
pub namespace: JSXIdentifier<'a>,
/// Name portion of the name, e.g. `Orange` in `<Apple:Orange />`
pub property: JSXIdentifier<'a>,
}
/// JSX Member Expression
///
/// Used in [`JSXElementName`]. Multiple member expressions may be chained together. In this case,
/// [`object`] will be a [`member expression`].
///
/// ## Example
///
/// ```tsx
/// // <object.property />
/// <Apple.Orange />
/// <Foo.Bar.Baz.Bang />
/// ```
///
/// [`object`]: JSXMemberExpression::object
/// [`member expression`]: JSXMemberExpressionObject::MemberExpression
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -122,7 +194,9 @@ pub struct JSXNamespacedName<'a> {
pub struct JSXMemberExpression<'a> {
#[serde(flatten)]
pub span: Span,
/// The object being accessed. This is everything before the last `.`.
pub object: JSXMemberExpressionObject<'a>,
/// The property being accessed. This is everything after the last `.`.
pub property: JSXIdentifier<'a>,
}
@ -135,6 +209,19 @@ pub enum JSXMemberExpressionObject<'a> {
MemberExpression(Box<'a, JSXMemberExpression<'a>>),
}
/// JSX Expression Container
///
/// Expression containers wrap [`JSXExpression`]s in JSX attributes and children using `{}`.
///
/// ## Example
///
/// ```tsx
/// // boolean-like and string-like expressions are not wrapped in containers.
/// // Here, only `container` is a JSXExpressionContainer.
/// <Foo bar baz="bang" container={4}/>
/// {4} // <- wrapped in container
/// </Foo>
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -148,7 +235,8 @@ pub struct JSXExpressionContainer<'a> {
inherit_variants! {
/// JSX Expression
///
/// Inherits variants from [`Expression`]. See [`ast` module docs] for explanation of inheritance.
/// Gets wrapped by a [`JSXExpressionContainer`]. Inherits variants from [`Expression`]. See [`ast`
/// module docs] for explanation of inheritance.
///
/// [`ast` module docs]: `super`
#[ast(visit)]
@ -163,6 +251,7 @@ pub enum JSXExpression<'a> {
}
}
/// An empty JSX expression (`{}`)
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -185,6 +274,12 @@ pub enum JSXAttributeItem<'a> {
}
/// JSX Attribute
///
/// ## Example
///
/// ```tsx
/// <Component has-no-value foo="foo" />
/// // name ^^^ ^^^^ value
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -197,6 +292,12 @@ pub struct JSXAttribute<'a> {
}
/// JSX Spread Attribute
///
/// ## Example
/// ```tsx
/// <Component {...props} />
/// // ^^^^^^^^ argument
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -208,6 +309,8 @@ pub struct JSXSpreadAttribute<'a> {
}
/// JSX Attribute Name
///
/// Part of a [`JSXAttribute`].
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -218,6 +321,8 @@ pub enum JSXAttributeName<'a> {
}
/// JSX Attribute Value
///
/// Part of a [`JSXAttribute`].
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -229,6 +334,11 @@ pub enum JSXAttributeValue<'a> {
Fragment(Box<'a, JSXFragment<'a>>),
}
/// JSX Identifier
///
/// Similar to [`IdentifierName`], but used in JSX elements.
///
/// [`IdentifierName`]: super::IdentifierName
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -242,18 +352,28 @@ pub struct JSXIdentifier<'a> {
// 1.4 JSX Children
/// JSX Child
///
/// Part of a [`JSXElement`].
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(untagged)]
pub enum JSXChild<'a> {
/// `<Foo>Some Text</Foo>`
Text(Box<'a, JSXText<'a>>),
/// `<Foo><Child /></Foo>`
Element(Box<'a, JSXElement<'a>>),
/// `<Foo><></></Foo>`
Fragment(Box<'a, JSXFragment<'a>>),
/// `<Foo>{expression}</Foo>`
ExpressionContainer(Box<'a, JSXExpressionContainer<'a>>),
/// `<Foo>{...spread}</Foo>`
Spread(Box<'a, JSXSpreadChild<'a>>),
}
/// JSX Spread Child.
///
/// Variant of [`JSXChild`] that represents an object spread (`{...expression}`).
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -264,6 +384,16 @@ pub struct JSXSpreadChild<'a> {
pub expression: Expression<'a>,
}
/// Text inside a JSX element.
///
/// Not to be confused with a [`StringLiteral`].
///
/// ## Example
///
/// ```tsx
/// <Foo>Some text</Foo> // `Some Text` is a JSXText,
/// <Foo>"Some string"</Foo> // but `"Some string"` is a StringLiteral.
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]

View file

@ -47,6 +47,20 @@ pub struct TSThisParameter<'a> {
/// Enum Declaration
///
/// `const_opt`enum`BindingIdentifier`{`EnumBody_opt`}
///
/// ## Examples
///
/// ```ts
/// enum Foo {
/// A,
/// B
/// }
/// // `Bar` has `r#const` set to `true`
/// const enum Bar {
/// A,
/// B
/// }
/// ```
#[ast(visit)]
#[scope]
#[derive(Debug)]
@ -63,6 +77,19 @@ pub struct TSEnumDeclaration<'a> {
pub scope_id: Cell<Option<ScopeId>>,
}
/// Enum Member
///
/// ## Example
///
/// ```ts
/// enum Foo {
/// // _ id
/// A = 1,
/// // ^ initializer
/// B // initializer will be `None`
///
/// }
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -96,16 +123,43 @@ pub enum TSEnumMemberName<'a> {
}
}
/// TypeScript Type Annotation
///
/// An annotation on a variable declaration, parameter, etc.
///
/// ## Example
/// ```ts
/// const x: number = 1;
/// // ^^^^^^^^
///
/// function foo(x: number): number { return x; }
/// // ^^^^^^^^ ^^^^^^^^
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(tag = "type", rename_all = "camelCase")]
pub struct TSTypeAnnotation<'a> {
#[serde(flatten)]
/// starts at the `:` token and ends at the end of the type annotation
pub span: Span,
pub type_annotation: TSType<'a>,
}
/// TypeScript Literal Type
///
/// A type that is a literal value. Wraps a [`TSLiteral`].
///
/// ## Example
/// ```ts
/// const x: 'foo' = 'foo';
/// // ^^^^^
///
/// type NonZero<N> = N extends 0 ? never : N;
/// // ^
/// type Three = NonZero<3>;
/// // ^
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -131,6 +185,10 @@ pub enum TSLiteral<'a> {
UnaryExpression(Box<'a, UnaryExpression<'a>>),
}
/// TypeScript Type
///
/// This is the root-level type for TypeScript types, kind of like [`Expression`] is for
/// expressions.
#[ast(visit)]
#[repr(C, u8)]
#[derive(Debug, Hash)]
@ -226,7 +284,13 @@ macro_rules! match_ts_type {
}
pub use match_ts_type;
/// `SomeType extends OtherType ? TrueType : FalseType;`
/// TypeScript Conditional Type
///
/// ## Example
///
/// ```ts
/// SomeType extends OtherType ? TrueType : FalseType;
/// ```
///
/// <https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#handbook-content>
#[ast(visit)]
@ -244,7 +308,13 @@ pub struct TSConditionalType<'a> {
pub scope_id: Cell<Option<ScopeId>>,
}
/// string | string[] | (() => string) | { s: string }
/// TypeScript Union Type
///
/// ## Example
///
/// ```ts
/// string | string[] | (() => string) | { s: string }
/// ```
///
/// <https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#unions>
#[ast(visit)]
@ -280,7 +350,12 @@ pub struct TSParenthesizedType<'a> {
pub type_annotation: TSType<'a>,
}
/// keyof unique readonly
/// TypeScript Type Operators
///
/// Includes
/// - `keyof`
/// - `unique`
/// - `readonly`
///
/// <https://www.typescriptlang.org/docs/handbook/2/keyof-types.html>
#[ast(visit)]
@ -304,7 +379,15 @@ pub enum TSTypeOperatorOperator {
Readonly,
}
/// `let myArray: string[] = ["hello", "world"];`
/// TypeScript Array Type
///
/// Does not include tuple types, which are stored as [`TSTupleType`].
///
/// ## Example
///
/// ```ts
/// let myArray: string[] = ["hello", "world"];
/// ```
///
/// <https://www.typescriptlang.org/docs/handbook/2/objects.html#the-array-type>
#[ast(visit)]
@ -317,7 +400,15 @@ pub struct TSArrayType<'a> {
pub element_type: TSType<'a>,
}
/// `type I1 = Person["age" | "name"];`
/// TypeScript Index Access Type
///
/// This is the type equivalent to expression member access.
///
/// ## Example
///
/// ```ts
/// type I1 = Person["age" | "name"];
/// ```
///
/// <https://www.typescriptlang.org/docs/handbook/2/indexed-access-types.html#handbook-content>
#[ast(visit)]
@ -331,7 +422,13 @@ pub struct TSIndexedAccessType<'a> {
pub index_type: TSType<'a>,
}
/// TypeScript Tuple Type
///
/// ## Example
///
/// ```ts
/// type `StringNumberPair` = [string, number];
/// ```
///
/// <https://www.typescriptlang.org/docs/handbook/2/objects.html#tuple-types>
#[ast(visit)]
@ -381,6 +478,8 @@ inherit_variants! {
///
/// Inherits variants from [`TSType`]. See [`ast` module docs] for explanation of inheritance.
///
/// See [`TSNamedTupleMember`] for named tuple elements.
///
/// [`ast` module docs]: `super`
#[ast(visit)]
#[repr(C, u8)]
@ -654,6 +753,7 @@ pub struct TSClassImplements<'a> {
pub struct TSInterfaceDeclaration<'a> {
#[serde(flatten)]
pub span: Span,
/// The identifier (name) of the interface.
pub id: BindingIdentifier<'a>,
#[scope(enter_before)]
pub extends: Option<Vec<'a, TSInterfaceHeritage<'a>>>,
@ -699,6 +799,17 @@ pub enum TSSignature<'a> {
TSMethodSignature(Box<'a, TSMethodSignature<'a>>),
}
/// An index signature within a class, type alias, etc.
///
/// ## Example
/// [playground link](https://oxc-project.github.io/oxc/playground/?code=3YCAAIC9gICAgICAgIC6nsrEgtem3AB/pQsrWlLnujiFhkHVtfeFMq5RMD7X5AzJnZ5R/ecQ5KG1FUFjzXvrxFXH0m6HpS+Ob3TC8gQXeRQygA%3D%3D)
/// ```ts
/// type MapOf<T> = {
/// // _________ parameters (vec with 1 element)
/// [K: string]: T
/// // - type_annotation
/// }
/// ```
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1127,6 +1238,30 @@ pub struct TSNonNullExpression<'a> {
pub expression: Expression<'a>,
}
/// Decorator
///
/// Decorators are annotations on classes, methods, properties, and parameters.
/// They are usually either an [`IdentifierReference`] or an [`CallExpression`].
///
/// ## Example
/// ```ts
/// @Foo // class decorator
/// @Bar() // class decorator factory
/// class SomeClass {
/// @Freeze // property decorator
/// public x: number;
///
/// @MethodDecorator // method decorator
/// public method(
/// @LogParam x: number // parameter decorator
/// ) {
/// // ...
/// }
/// }
/// ```
///
/// [`IdentifierReference`]: crate::ast::js::IdentifierReference
/// [`CallExpression`]: crate::ast::js::CallExpression
#[ast(visit)]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
@ -1174,12 +1309,15 @@ pub struct TSInstantiationExpression<'a> {
pub type_parameters: Box<'a, TSTypeParameterInstantiation<'a>>,
}
/// See [TypeScript - Type-Only Imports and Exports](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html)
#[ast]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[serde(rename_all = "camelCase")]
pub enum ImportOrExportKind {
/// `import { foo } from './foo'`;
Value,
/// `import type { foo } from './foo'`;
Type,
}
@ -1194,6 +1332,7 @@ pub struct JSDocNullableType<'a> {
#[serde(flatten)]
pub span: Span,
pub type_annotation: TSType<'a>,
/// Was `?` after the type annotation?
pub postfix: bool,
}

View file

@ -84,6 +84,12 @@ impl<'a> Expression<'a> {
)
}
/// `true` if this [`Expression`] is a literal expression for a primitive value.
///
/// Does not include [`TemplateLiteral`]s, [`object literals`], or [`array literals`].
///
/// [`object literals`]: ObjectExpression
/// [`array literals`]: ArrayExpression
pub fn is_literal(&self) -> bool {
// Note: TemplateLiteral is not `Literal`
matches!(
@ -157,6 +163,8 @@ impl<'a> Expression<'a> {
}
/// Determines whether the given expr is a `null` or `undefined` or `void 0`
///
/// Corresponds to a [nullish value check](https://developer.mozilla.org/en-US/docs/Glossary/Nullish).
pub fn is_null_or_undefined(&self) -> bool {
self.is_null() || self.evaluate_to_undefined()
}
@ -330,6 +338,7 @@ impl<'a> ArrayExpressionElement<'a> {
}
impl<'a> ObjectExpression<'a> {
/// Returns `true` if this object has a property named `__proto__`
pub fn has_proto(&self) -> bool {
use crate::syntax_directed_operations::PropName;
self.properties.iter().any(|p| p.prop_name().is_some_and(|name| name.0 == "__proto__"))
@ -345,12 +354,9 @@ impl<'a> PropertyKey<'a> {
Self::NumericLiteral(lit) => Some(Cow::Owned(lit.value.to_string())),
Self::BigIntLiteral(lit) => Some(Cow::Borrowed(lit.raw.as_str())),
Self::NullLiteral(_) => Some(Cow::Borrowed("null")),
Self::TemplateLiteral(lit) => lit
.expressions
.is_empty()
.then(|| lit.quasi())
.flatten()
.map(std::convert::Into::into),
Self::TemplateLiteral(lit) => {
lit.expressions.is_empty().then(|| lit.quasi()).flatten().map(Into::into)
}
_ => None,
}
}
@ -1197,6 +1203,8 @@ impl<'a> Hash for Class<'a> {
}
impl<'a> ClassElement<'a> {
/// Returns `true` if this [`ClassElement`] is a static block or has a
/// static modifier.
pub fn r#static(&self) -> bool {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => false,
@ -1251,6 +1259,7 @@ impl<'a> ClassElement<'a> {
}
}
/// Returns `true` if this [`ClassElement`] is a property or accessor
pub fn is_property(&self) -> bool {
matches!(self, Self::PropertyDefinition(_) | Self::AccessorProperty(_))
}

View file

@ -5,12 +5,25 @@
//! # Oxc AST
//!
//! Abstract Syntax Tree nodes for Oxc. Supports both TypeScript and JavaScript.
//!
//! This is almost similar to [estree](https://github.com/estree/estree) except a few places:
//! * `Identifier` is replaced with explicit `BindingIdentifier`, `IdentifierReference`, `IdentifierName` per spec
//! * `AssignmentExpression`.`left` `Pattern` is replaced with `AssignmentTarget`
//! * `Identifier` is replaced with explicit [`BindingIdentifier`], [`IdentifierReference`], [`IdentifierName`] per spec
//! * `AssignmentExpression`.`left` `Pattern` is replaced with [`AssignmentTarget`]
//!
//! ## Parsing
//!
//! You can obtain an AST by parsing source code with a [`Parser`] from [`oxc_parser`].
//!
//! ## Cargo Features
//! * `"serde"` enables support for serde serialization
//!
//! [`BindingIdentifier`]: ast::BindingIdentifier
//! [`IdentifierReference`]: ast::IdentifierReference
//! [`IdentifierName`]: ast::IdentifierName
//! [`AssignmentTarget`]: ast::AssignmentTarget
//! [`oxc_parser`]: <https://docs.rs/oxc_parser>
//! [`Parser`]: <https://docs.rs/oxc_parser/latest/oxc_parser/struct.Parser.html>
#[cfg(feature = "serialize")]
mod serialize;