diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 75c39ef2d449c..6e01ef983ea4e 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1725,6 +1725,15 @@ pub struct ArrayPattern<'a> { pub rest: Option>>, } +/// A `...rest` binding in an [array](ArrayPattern) or [object](ObjectPattern) destructure. +/// +/// ## Examples +/// ```ts +/// const [a, ...rest] = [1, 2, 3]; +/// // ^^^^ argument +/// const { x, y, ...others} = foo.bar(); +/// // ^^^^^^ argument +/// ``` #[ast(visit)] #[derive(Debug)] #[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ContentHash)] @@ -1736,7 +1745,41 @@ pub struct BindingRestElement<'a> { pub argument: BindingPattern<'a>, } -/// Function Definitions +/// Function Statement or Expression +/// +/// Includes generator functions and function-valued class properties. +/// Arrow functions are represented by [`ArrowFunctionExpression`]. +/// +/// # Examples +/// ```ts +/// // id ___ ____ return_type +/// function foo(a: number): void { +/// // ^^^^^^^^^ params +/// console.log(a); +/// } +/// ``` +/// +/// ```ts +/// // `async` and `generator` are true +/// async function* foo() { +/// yield 1; +/// } +/// ``` +/// +/// ```js +/// // function.id is None +/// // use function.r#type to check if a node is a function expression. +/// const foo = function() { } +/// ``` +/// +/// ```ts +/// // Function overloads will not have a body +/// function add(a: number, b: number): number; // <-- No body +/// function add(a: string, b: string): string; // <-- No body +/// function add(a: any, b: any): any { // <-- Body is between `{}`, inclusive. +/// return a + b; +/// } +/// ``` #[ast(visit)] #[scope( // `flags` passed in to visitor via parameter defined by `#[visit(args(flags = ...))]` on parents @@ -1751,7 +1794,14 @@ pub struct Function<'a> { pub r#type: FunctionType, #[serde(flatten)] pub span: Span, + /// The function identifier. [`None`] for anonymous function expressions. pub id: Option>, + /// Is this a generator function? + /// + /// ```ts + /// function* foo() { } // <- generator: true + /// function bar() { } // <- generator: false + /// ``` pub generator: bool, pub r#async: bool, pub declare: bool, @@ -1761,19 +1811,36 @@ pub struct Function<'a> { /// The JavaScript specification states that you cannot have a parameter called `this`, /// and so TypeScript uses that syntax space to let you declare the type for `this` in the function body. /// - /// ```TypeScript + /// ```ts /// interface DB { - /// filterUsers(filter: (this: User) => boolean): User[]; + /// filterUsers(filter: (this: User) => boolean): User[]; + /// // ^^^^ /// } /// /// const db = getDB(); /// const admins = db.filterUsers(function (this: User) { - /// return this.admin; + /// return this.admin; /// }); /// ``` pub this_param: Option>>, + /// Function parameters. + /// + /// Does not include `this` parameters used by some TypeScript functions. pub params: Box<'a, FormalParameters<'a>>, + /// The TypeScript return type annotation. pub return_type: Option>>, + /// The function body. + /// + /// [`None`] for function declarations, e.g. + /// ```ts + /// // TypeScript function declarations have no body + /// declare function foo(a: number): number; + /// + /// function bar(a: number): number; // <- overloads have no body + /// function bar(a: number): number { + /// return a; + /// } + /// ``` pub body: Option>>, #[serde(skip)] #[clone_in(default)] diff --git a/crates/oxc_ast/src/generated/ast_builder.rs b/crates/oxc_ast/src/generated/ast_builder.rs index bcb649f6a8ff1..a372c5cecd536 100644 --- a/crates/oxc_ast/src/generated/ast_builder.rs +++ b/crates/oxc_ast/src/generated/ast_builder.rs @@ -832,15 +832,15 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// - r#type /// - span: The [`Span`] covering this node - /// - id - /// - generator + /// - id: The function identifier. [`None`] for anonymous function expressions. + /// - generator: Is this a generator function? /// - r#async /// - declare /// - type_parameters /// - this_param: Declaring `this` in a Function - /// - params - /// - return_type - /// - body + /// - params: Function parameters. + /// - return_type: The TypeScript return type annotation. + /// - body: The function body. #[inline] pub fn expression_function( self, @@ -4179,15 +4179,15 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// - r#type /// - span: The [`Span`] covering this node - /// - id - /// - generator + /// - id: The function identifier. [`None`] for anonymous function expressions. + /// - generator: Is this a generator function? /// - r#async /// - declare /// - type_parameters /// - this_param: Declaring `this` in a Function - /// - params - /// - return_type - /// - body + /// - params: Function parameters. + /// - return_type: The TypeScript return type annotation. + /// - body: The function body. #[inline] pub fn declaration_function( self, @@ -5719,15 +5719,15 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// - r#type /// - span: The [`Span`] covering this node - /// - id - /// - generator + /// - id: The function identifier. [`None`] for anonymous function expressions. + /// - generator: Is this a generator function? /// - r#async /// - declare /// - type_parameters /// - this_param: Declaring `this` in a Function - /// - params - /// - return_type - /// - body + /// - params: Function parameters. + /// - return_type: The TypeScript return type annotation. + /// - body: The function body. #[inline] pub fn function( self, @@ -5773,15 +5773,15 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// - r#type /// - span: The [`Span`] covering this node - /// - id - /// - generator + /// - id: The function identifier. [`None`] for anonymous function expressions. + /// - generator: Is this a generator function? /// - r#async /// - declare /// - type_parameters /// - this_param: Declaring `this` in a Function - /// - params - /// - return_type - /// - body + /// - params: Function parameters. + /// - return_type: The TypeScript return type annotation. + /// - body: The function body. #[inline] pub fn alloc_function( self, @@ -7677,15 +7677,15 @@ impl<'a> AstBuilder<'a> { /// ## Parameters /// - r#type /// - span: The [`Span`] covering this node - /// - id - /// - generator + /// - id: The function identifier. [`None`] for anonymous function expressions. + /// - generator: Is this a generator function? /// - r#async /// - declare /// - type_parameters /// - this_param: Declaring `this` in a Function - /// - params - /// - return_type - /// - body + /// - params: Function parameters. + /// - return_type: The TypeScript return type annotation. + /// - body: The function body. #[inline] pub fn export_default_declaration_kind_function( self, diff --git a/crates/oxc_semantic/src/node.rs b/crates/oxc_semantic/src/node.rs index c24bba2fe6fe8..89439410dcd06 100644 --- a/crates/oxc_semantic/src/node.rs +++ b/crates/oxc_semantic/src/node.rs @@ -110,6 +110,7 @@ pub struct AstNodes<'a> { } impl<'a> AstNodes<'a> { + /// Iterate over all [`AstNode`]s in this AST. pub fn iter(&self) -> impl Iterator> + '_ { self.nodes.iter() } diff --git a/crates/oxc_semantic/src/symbol.rs b/crates/oxc_semantic/src/symbol.rs index 2170dc7fc1183..1042ce9527a31 100644 --- a/crates/oxc_semantic/src/symbol.rs +++ b/crates/oxc_semantic/src/symbol.rs @@ -49,16 +49,40 @@ pub struct SymbolTable { } impl SymbolTable { + /// Returns the number of symbols in this table. #[inline] pub fn len(&self) -> usize { self.spans.len() } + /// Returns `true` if this table contains no symbols. #[inline] pub fn is_empty(&self) -> bool { self.spans.is_empty() } + /// Iterate over all symbol IDs in this table. + /// + /// Use [`ScopeTree::iter_bindings_in`] to only iterate over symbols declared in a specific + /// scope. + /// + /// [`ScopeTree::iter_bindings_in`]: crate::scope::ScopeTree::iter_bindings_in + /// + /// ## Example + /// + /// ``` + /// use oxc_semantic::Semantic; + /// let semantic: Semantic<'_> = parse_and_analyze("./foo.js"); + /// + /// let classes = semantic + /// .scopes() + /// .symbol_ids() + /// .filter(|symbol_id| { + /// let flags = semantic.symbols().get_flags(*symbol_id); + /// flags.is_class() + /// }) + /// .collect::>(); + /// ``` pub fn symbol_ids(&self) -> impl Iterator + '_ { self.spans.iter_enumerated().map(|(symbol_id, _)| symbol_id) } @@ -69,11 +93,15 @@ impl SymbolTable { .find_map(|(symbol, &inner_span)| if inner_span == span { Some(symbol) } else { None }) } + /// Get the [`Span`] of the [`AstNode`] declaring a symbol. + /// + /// [`AstNode`]: crate::node::AstNode #[inline] pub fn get_span(&self, symbol_id: SymbolId) -> Span { self.spans[symbol_id] } + /// Get the identifier name a symbol is bound to. #[inline] pub fn get_name(&self, symbol_id: SymbolId) -> &str { &self.names[symbol_id] @@ -84,11 +112,15 @@ impl SymbolTable { self.names[symbol_id] = name; } + /// Get the [`SymbolFlags`] for a symbol, which describe how the symbol is declared. + /// + /// To find how a symbol is used, use [`SymbolTable::get_resolved_references`]. #[inline] pub fn get_flags(&self, symbol_id: SymbolId) -> SymbolFlags { self.flags[symbol_id] } + /// Get a mutable reference to a symbol's [flags](SymbolFlags). #[inline] pub fn get_flags_mut(&mut self, symbol_id: SymbolId) -> &mut SymbolFlags { &mut self.flags[symbol_id] @@ -123,6 +155,16 @@ impl SymbolTable { self.get_symbol_id_from_span(span).map(|symbol_id| self.get_scope_id(symbol_id)) } + /// Get the ID of the AST node declaring a symbol. + /// + /// This node will be a [`VariableDeclaration`], [`Function`], or some other AST node + /// that _has_ a [`BindingIdentifier`] or a [`BindingPattern`]. It will not point to the + /// binding pattern or identifier node itself. + /// + /// [`VariableDeclaration`]: oxc_ast::ast::VariableDeclaration + /// [`Function`]: oxc_ast::ast::Function + /// [`BindingIdentifier`]: oxc_ast::ast::BindingIdentifier + /// [`BindingPattern`]: oxc_ast::ast::BindingPattern #[inline] pub fn get_declaration(&self, symbol_id: SymbolId) -> NodeId { self.declarations[symbol_id] @@ -158,6 +200,9 @@ impl SymbolTable { self.references.push(reference) } + /// Get a resolved or unresolved reference. + /// + /// [`ReferenceId`]s can be found in [`IdentifierReference`] and similar nodes. #[inline] pub fn get_reference(&self, reference_id: ReferenceId) -> &Reference { &self.references[reference_id] @@ -168,16 +213,25 @@ impl SymbolTable { &mut self.references[reference_id] } + /// Returns `true` if the corresponding [`Reference`] is resolved to a symbol. + /// + /// When `false`, this could either be a reference to a global value or an identifier that does + /// not exist. #[inline] pub fn has_binding(&self, reference_id: ReferenceId) -> bool { self.references[reference_id].symbol_id().is_some() } + /// Find [`Reference`] ids resolved to a symbol. + /// + /// If you want direct access to a symbol's [`Reference`]s, use + /// [`SymbolTable::get_resolved_references`]. #[inline] pub fn get_resolved_reference_ids(&self, symbol_id: SymbolId) -> &Vec { &self.resolved_references[symbol_id] } + /// Find [`Reference`]s resolved to a symbol. pub fn get_resolved_references( &self, symbol_id: SymbolId,