Skip to content

Commit

Permalink
docs(ast): add documentation for all remaining JS AST methods (#8820)
Browse files Browse the repository at this point in the history
Finishes the remaining items that require documenting for the JS AST
implementations. Once again, I tried my best to ensure these are
accurate, but it might not be 100% correct.

I also renamed the `get_identifier` method to `get_identifier_name` to
make it clear that it returns an `Atom`/`str` and not an `Identifier`.
  • Loading branch information
camchenry authored Feb 1, 2025
1 parent 0bf2bcf commit 57b7ca8
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 67 deletions.
199 changes: 163 additions & 36 deletions crates/oxc_ast/src/ast_impl/js.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// FIXME: lots of methods are missing docs. If you have time, it would be a huge help to add some :)
#![warn(missing_docs)]
use std::{borrow::Cow, fmt};

Expand Down Expand Up @@ -265,7 +264,8 @@ impl<'a> Expression<'a> {
expr
}

#[allow(missing_docs)]
/// Turns any chainable expression such as `a.b` or `b()` into the chained equivalent
/// such as `a?.b` or `b?.()`.
pub fn into_chain_element(self) -> Option<ChainElement<'a>> {
match self {
Expression::StaticMemberExpression(e) => Some(ChainElement::StaticMemberExpression(e)),
Expand Down Expand Up @@ -751,33 +751,65 @@ impl Argument<'_> {
}

impl<'a> AssignmentTarget<'a> {
#[allow(missing_docs)]
pub fn get_identifier(&self) -> Option<&'a str> {
self.as_simple_assignment_target().and_then(SimpleAssignmentTarget::get_identifier)
/// Returns the identifier name of this assignment target when it is simple like `a = b`.
///
/// ## Example
///
/// - returns `a` when called on the left-hand side of `a = b`
/// - returns `b` when called on the left-hand side of `a.b = b`
/// - returns `None` when called on the left-hand side of `a[b] = b`
pub fn get_identifier_name(&self) -> Option<&'a str> {
self.as_simple_assignment_target().and_then(SimpleAssignmentTarget::get_identifier_name)
}

#[allow(missing_docs)]
/// Returns the expression inside of this assignment target, if applicable, and returns a reference to it.
///
/// For getting a mutable reference of the expression inside, use [`AssignmentTarget::get_expression_mut`].
///
/// ## Example
///
/// - returns `a` when called on `a!` in `a! = b`
/// - returns `None` when called on `a` in `a = b` because there is no inner expression to get
pub fn get_expression(&self) -> Option<&Expression<'a>> {
self.as_simple_assignment_target().and_then(SimpleAssignmentTarget::get_expression)
}

#[allow(missing_docs)]
/// Returns the expression inside of this assignment target, if applicable, and returns a mutable reference to it.
///
/// For getting an immutable reference of the expression inside, use [`AssignmentTarget::get_expression`].
///
/// ## Example
///
/// - returns `a` when called on `a!` in `a! = b`
/// - returns `None` when called on `a` in `a = b` because there is no inner expression to get
pub fn get_expression_mut(&mut self) -> Option<&mut Expression<'a>> {
self.as_simple_assignment_target_mut().and_then(SimpleAssignmentTarget::get_expression_mut)
}
}

impl<'a> SimpleAssignmentTarget<'a> {
#[allow(missing_docs)]
pub fn get_identifier(&self) -> Option<&'a str> {
/// Returns the identifier name of this assignment target if the target is an identifier or
/// a member expression, or `None` otherwise.
///
/// ## Example
///
/// - returns identifier `a` when called on the left-hand side of `a = b`
/// - returns identifier `b` when called on the left-hand side of `a.b = b`
/// - returns `None` when called on the left-hand side of `a[b] = b` because it is not an identifier
pub fn get_identifier_name(&self) -> Option<&'a str> {
match self {
Self::AssignmentTargetIdentifier(ident) => Some(ident.name.as_str()),
match_member_expression!(Self) => self.to_member_expression().static_property_name(),
_ => None,
}
}

#[allow(missing_docs)]
/// Returns the expression inside of this assignment target, if applicable, and returns a reference to it.
///
/// ## Example
///
/// - returns `a` when called on `a!` in `a! = b`
/// - returns `None` when called on `a` in `a = b` because there is no inner expression to get
pub fn get_expression(&self) -> Option<&Expression<'a>> {
match self {
Self::TSAsExpression(expr) => Some(&expr.expression),
Expand All @@ -788,7 +820,14 @@ impl<'a> SimpleAssignmentTarget<'a> {
}
}

#[allow(missing_docs)]
/// Returns the expression inside of this assignment target, if applicable, and returns a mutable reference to it.
///
/// For getting an immutable reference of the expression inside, use [`SimpleAssignmentTarget::get_expression`].
///
/// ## Example
///
/// - returns `a` when called on `a!` in `a! = b`
/// - returns `None` when called on `a` in `a = b` because there is no inner expression to get
pub fn get_expression_mut(&mut self) -> Option<&mut Expression<'a>> {
match self {
Self::TSAsExpression(expr) => Some(&mut expr.expression),
Expand All @@ -802,7 +841,8 @@ impl<'a> SimpleAssignmentTarget<'a> {
}

impl<'a> ArrayAssignmentTarget<'a> {
#[allow(missing_docs)]
/// Creates a new array assignment target (like `[a, b]` in the code `[a, b] = [1, 2]`)
/// using the given elements.
pub fn new_with_elements(
span: Span,
elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
Expand All @@ -812,27 +852,47 @@ impl<'a> ArrayAssignmentTarget<'a> {
}

impl<'a> ObjectAssignmentTarget<'a> {
#[allow(missing_docs)]
/// Creates a new object assignment target (like `{a, b}` in the code `({a, b} = obj)`) using
/// the given properties.
pub fn new_with_properties(
span: Span,
properties: Vec<'a, AssignmentTargetProperty<'a>>,
) -> Self {
Self { span, properties, rest: None }
}

#[allow(missing_docs)]
/// Returns `true` if this object assignment target is empty.
///
/// ## Example
///
/// - `{}` => `true`
/// - `{a}` => `false`
/// - `{...a}` => `false`
pub fn is_empty(&self) -> bool {
self.properties.is_empty() && self.rest.is_none()
}

#[allow(missing_docs)]
/// Returns the number of identifiers in this object assignment target.
///
/// ## Example
///
/// - `{}` => `0`
/// - `{a}` => `1`
/// - `{...a}` => `1`
/// - `{a, b}` => `2`
/// - `{a, b, ...c}` => `3`
pub fn len(&self) -> usize {
self.properties.len() + usize::from(self.rest.is_some())
}
}

impl AssignmentTargetMaybeDefault<'_> {
#[allow(missing_docs)]
/// Returns the identifier bound by this assignment target.
///
/// ## Example
///
/// - returns `b` when called on `a: b = 1` in `({a: b = 1} = obj)
/// - returns `b` when called on `a: b` in `({a: b} = obj)
pub fn identifier(&self) -> Option<&IdentifierReference<'_>> {
match self {
AssignmentTargetMaybeDefault::AssignmentTargetIdentifier(id) => Some(id),
Expand Down Expand Up @@ -883,7 +943,15 @@ impl Statement<'_> {
)
}

#[allow(missing_docs)]
/// Returns `true` if this statement affects control flow, such as `return`, `throw`, `break`, or `continue`.
///
/// ## Example
///
/// - `return true` => `true`
/// - `throw new Error()` => `true`
/// - `break` => `true`
/// - `continue` => `true`
/// - `if (true) { }` => `false`
pub fn is_jump_statement(&self) -> bool {
matches!(
self,
Expand Down Expand Up @@ -1049,33 +1117,67 @@ impl SwitchCase<'_> {
}

impl<'a> BindingPattern<'a> {
#[allow(missing_docs)]
pub fn get_identifier(&self) -> Option<Atom<'a>> {
self.kind.get_identifier()
/// Returns the name of the bound identifier in this binding pattern, if it has one, or `None` otherwise.
///
/// ## Example
///
/// - calling on `a = 1` in `let a = 1` would return `Some("a")`
/// - calling on `a = 1` in `let {a = 1} = c` would return `Some("a")`
/// - calling on `a: b` in `let {a: b} = c` would return `None`
pub fn get_identifier_name(&self) -> Option<Atom<'a>> {
self.kind.get_identifier_name()
}

#[allow(missing_docs)]
/// Returns the bound identifier in this binding pattern, if it has one, or `None` otherwise.
///
/// To just get the name of the bound identifier, use [`BindingPattern::get_identifier_name`].
///
/// ## Example
///
/// - calling on `a = 1` in `let a = 1` would return `Some(BindingIdentifier { name: "a", .. })`
/// - calling on `a = 1` in `let {a = 1} = c` would return `Some(BindingIdentifier { name: "a", .. })`
/// - calling on `a: b` in `let {a: b} = c` would return `None`
pub fn get_binding_identifier(&self) -> Option<&BindingIdentifier<'a>> {
self.kind.get_binding_identifier()
}

#[allow(missing_docs)]
/// Returns the bound identifiers in this binding pattern.
///
/// ## Example
///
/// - `let {} = obj` would return `[]`
/// - `let {a, b} = obj` would return `[a, b]`
/// - `let {a = 1, b: c} = obj` would return `[a, c]`
pub fn get_binding_identifiers(&self) -> std::vec::Vec<&BindingIdentifier<'a>> {
self.kind.get_binding_identifiers()
}
}

impl<'a> BindingPatternKind<'a> {
#[allow(missing_docs)]
pub fn get_identifier(&self) -> Option<Atom<'a>> {
/// Returns the name of the bound identifier in this binding pattern, if it has one, or `None` otherwise.
///
/// ## Example
///
/// - calling on `a = 1` in `let a = 1` would return `Some("a")`
/// - calling on `a = 1` in `let {a = 1} = c` would return `Some("a")`
/// - calling on `a: b` in `let {a: b} = c` would return `None`
pub fn get_identifier_name(&self) -> Option<Atom<'a>> {
match self {
Self::BindingIdentifier(ident) => Some(ident.name),
Self::AssignmentPattern(assign) => assign.left.get_identifier(),
Self::AssignmentPattern(assign) => assign.left.get_identifier_name(),
_ => None,
}
}

#[allow(missing_docs)]
/// Returns the bound identifier in this binding pattern, if it has one, or `None` otherwise.
///
/// To just get the name of the bound identifier, use [`BindingPatternKind::get_identifier_name`].
///
/// ## Example
///
/// - calling on `a = 1` in `let a = 1` would return `Some(BindingIdentifier { name: "a", .. })`
/// - calling on `a = 1` in `let {a = 1} = c` would return `Some(BindingIdentifier { name: "a", .. })`
/// - calling on `a: b` in `let {a: b} = c` would return `None`
pub fn get_binding_identifier(&self) -> Option<&BindingIdentifier<'a>> {
match self {
Self::BindingIdentifier(ident) => Some(ident),
Expand All @@ -1102,14 +1204,27 @@ impl<'a> BindingPatternKind<'a> {
}
}

#[allow(missing_docs)]
/// Returns the bound identifiers in this binding pattern.
///
/// ## Example
///
/// - `let {} = obj` would return `[]`
/// - `let {a, b} = obj` would return `[a, b]`
/// - `let {a = 1, b: c} = obj` would return `[a, c]`
pub fn get_binding_identifiers(&self) -> std::vec::Vec<&BindingIdentifier<'a>> {
let mut idents = vec![];
self.append_binding_identifiers(&mut idents);
idents
}

#[allow(missing_docs)]
/// Returns `true` if this binding pattern is destructuring.
///
/// ## Example
///
/// - `{a, b}` in `let {a, b} = obj` would return `true`
/// - `[a, b]` in `let [a, b] = arr` would return `true`
/// - `a = 1` in `let {a = 1} = obj` would return `true`
/// - `a` in `let {a = 1} = obj` would return `false`
pub fn is_destructuring_pattern(&self) -> bool {
match self {
Self::ObjectPattern(_) | Self::ArrayPattern(_) => true,
Expand All @@ -1118,22 +1233,22 @@ impl<'a> BindingPatternKind<'a> {
}
}

#[allow(missing_docs)]
/// Returns `true` if this binding pattern is a binding identifier like `a` in `let a = 1`.
pub fn is_binding_identifier(&self) -> bool {
matches!(self, Self::BindingIdentifier(_))
}

#[allow(missing_docs)]
/// Returns `true` if this binding pattern is an object pattern like `{a}` in `let {a} = obj`.
pub fn is_object_pattern(&self) -> bool {
matches!(self, Self::ObjectPattern(_))
}

#[allow(missing_docs)]
/// Returns `true` if this binding pattern is an array pattern like `[a]` in `let [a] = arr`.
pub fn is_array_pattern(&self) -> bool {
matches!(self, Self::ArrayPattern(_))
}

#[allow(missing_docs)]
/// Returns `true` if this binding pattern is an assignment pattern like `a = 1` in `let {a = 1} = obj`.
pub fn is_assignment_pattern(&self) -> bool {
matches!(self, Self::AssignmentPattern(_))
}
Expand Down Expand Up @@ -1379,7 +1494,16 @@ impl<'a> ClassElement<'a> {
}
}

#[allow(missing_docs)]
/// Returns `true` if this [`ClassElement`] is computed.
///
/// The following all return `true`:
/// ```ts
/// class C {
/// [a] = 1;
/// [b]() {}
/// accessor [c] = 2;
/// }
/// ```
pub fn computed(&self) -> bool {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => false,
Expand All @@ -1389,7 +1513,7 @@ impl<'a> ClassElement<'a> {
}
}

#[allow(missing_docs)]
/// Returns the [accessibility][`TSAccessibility`] of this [`ClassElement`], if any is indicated.
pub fn accessibility(&self) -> Option<TSAccessibility> {
match self {
Self::StaticBlock(_) | Self::TSIndexSignature(_) | Self::AccessorProperty(_) => None,
Expand All @@ -1398,7 +1522,8 @@ impl<'a> ClassElement<'a> {
}
}

#[allow(missing_docs)]
/// Returns whether this [`ClassElement`] method is a constructor, method, getter, or setter,
/// or `None` otherwise if it is not a method definition.
pub fn method_definition_kind(&self) -> Option<MethodDefinitionKind> {
match self {
Self::TSIndexSignature(_)
Expand All @@ -1409,7 +1534,9 @@ impl<'a> ClassElement<'a> {
}
}

#[allow(missing_docs)]
/// Returns the [`PropertyKey`] of this [`ClassElement`], if any.
///
/// This is either the name of the method, property name, or accessor name.
pub fn property_key(&self) -> Option<&PropertyKey<'a>> {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
Expand Down
7 changes: 4 additions & 3 deletions crates/oxc_ast/src/ast_kind_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ impl AstKind<'_> {
Self::VariableDeclaration(_) => "VariableDeclaration".into(),
Self::VariableDeclarator(v) => format!(
"VariableDeclarator({})",
v.id.get_identifier().unwrap_or(Atom::from(DESTRUCTURE.as_ref()))
v.id.get_identifier_name().unwrap_or(Atom::from(DESTRUCTURE.as_ref()))
)
.into(),

Expand Down Expand Up @@ -290,7 +290,8 @@ impl AstKind<'_> {
Self::ArrayExpressionElement(_) => "ArrayExpressionElement".into(),
Self::AssignmentTarget(_) => "AssignmentTarget".into(),
Self::SimpleAssignmentTarget(a) => {
format!("SimpleAssignmentTarget({})", a.get_identifier().unwrap_or(&UNKNOWN)).into()
format!("SimpleAssignmentTarget({})", a.get_identifier_name().unwrap_or(&UNKNOWN))
.into()
}
Self::AssignmentTargetPattern(_) => "AssignmentTargetPattern".into(),
Self::ArrayAssignmentTarget(_) => "ArrayAssignmentTarget".into(),
Expand All @@ -305,7 +306,7 @@ impl AstKind<'_> {
Self::FormalParameters(_) => "FormalParameters".into(),
Self::FormalParameter(p) => format!(
"FormalParameter({})",
p.pattern.get_identifier().unwrap_or(Atom::from(DESTRUCTURE.as_ref()))
p.pattern.get_identifier_name().unwrap_or(Atom::from(DESTRUCTURE.as_ref()))
)
.into(),
Self::CatchParameter(_) => "CatchParameter".into(),
Expand Down
Loading

0 comments on commit 57b7ca8

Please sign in to comment.