mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
docs(ast): enforce doc comments on AST node methods (#6714)
Part of https://github.com/oxc-project/backlog/issues/130
This commit is contained in:
parent
8d27e2daab
commit
a7dd5aa3ee
4 changed files with 295 additions and 4 deletions
|
|
@ -1,3 +1,5 @@
|
|||
// 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, cell::Cell, fmt};
|
||||
|
||||
use oxc_allocator::{Box, FromIn, Vec};
|
||||
|
|
@ -12,16 +14,20 @@ use oxc_syntax::{
|
|||
use crate::ast::*;
|
||||
|
||||
impl<'a> Program<'a> {
|
||||
/// Returns `true` if this program has no statements or directives.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.body.is_empty() && self.directives.is_empty()
|
||||
}
|
||||
|
||||
/// Returns `true` if this program uses strict mode semantics. Both source
|
||||
/// type and `"use strict"` directives are considered.
|
||||
pub fn is_strict(&self) -> bool {
|
||||
self.source_type.is_strict() || self.directives.iter().any(Directive::is_use_strict)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Expression<'a> {
|
||||
/// Returns `true` if this expression is TypeScript-specific syntax.
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
|
@ -33,6 +39,7 @@ impl<'a> Expression<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a [primary expression](https://tc39.es/ecma262/#sec-primary-expression).
|
||||
pub fn is_primary_expression(&self) -> bool {
|
||||
self.is_literal()
|
||||
|| matches!(
|
||||
|
|
@ -66,18 +73,24 @@ impl<'a> Expression<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns `true` for [string](StringLiteral) and [template](TemplateLiteral) literals.
|
||||
pub fn is_string_literal(&self) -> bool {
|
||||
matches!(self, Self::StringLiteral(_) | Self::TemplateLiteral(_))
|
||||
}
|
||||
|
||||
/// Returns `true` for [numeric](NumericLiteral) and [big int](BigIntLiteral) literals.
|
||||
pub fn is_number_literal(&self) -> bool {
|
||||
matches!(self, Self::NumericLiteral(_) | Self::BigIntLiteral(_))
|
||||
}
|
||||
|
||||
/// Returns `true` for [bigint literals](BigIntLiteral).
|
||||
pub fn is_big_int_literal(&self) -> bool {
|
||||
matches!(self, Self::BigIntLiteral(_))
|
||||
}
|
||||
|
||||
/// Returns `true` for [string literals](StringLiteral) matching the
|
||||
/// expected value. Note that [non-substitution template
|
||||
/// literals](TemplateLiteral) are not considered.
|
||||
pub fn is_specific_string_literal(&self, string: &str) -> bool {
|
||||
match self {
|
||||
Self::StringLiteral(s) => s.value == string,
|
||||
|
|
@ -110,6 +123,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` for [numeric literals](NumericLiteral)
|
||||
pub fn is_number(&self) -> bool {
|
||||
matches!(self, Self::NumericLiteral(_))
|
||||
}
|
||||
|
|
@ -119,6 +133,7 @@ impl<'a> Expression<'a> {
|
|||
matches!(self, Self::NumericLiteral(lit) if lit.value == 0.0)
|
||||
}
|
||||
|
||||
/// Determines whether the given expr is a specific [number](NumericLiteral) literal.
|
||||
pub fn is_number_value(&self, val: f64) -> bool {
|
||||
matches!(self, Self::NumericLiteral(lit) if (lit.value - val).abs() < f64::EPSILON)
|
||||
}
|
||||
|
|
@ -154,6 +169,7 @@ impl<'a> Expression<'a> {
|
|||
expr
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_specific_id(&self, name: &str) -> bool {
|
||||
match self.get_inner_expression() {
|
||||
Expression::Identifier(ident) => ident.name == name,
|
||||
|
|
@ -161,6 +177,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool {
|
||||
match self.get_inner_expression() {
|
||||
expr if expr.is_member_expression() => {
|
||||
|
|
@ -176,6 +193,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_inner_expression(&self) -> &Expression<'a> {
|
||||
let mut expr = self;
|
||||
loop {
|
||||
|
|
@ -192,6 +210,7 @@ impl<'a> Expression<'a> {
|
|||
expr
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_inner_expression_mut(&mut self) -> &mut Expression<'a> {
|
||||
let mut expr = self;
|
||||
loop {
|
||||
|
|
@ -208,10 +227,12 @@ impl<'a> Expression<'a> {
|
|||
expr
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_identifier_reference(&self) -> bool {
|
||||
matches!(self, Expression::Identifier(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_identifier_reference(&self) -> Option<&IdentifierReference<'a>> {
|
||||
match self.get_inner_expression() {
|
||||
Expression::Identifier(ident) => Some(ident),
|
||||
|
|
@ -219,27 +240,33 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_function(&self) -> bool {
|
||||
matches!(self, Expression::FunctionExpression(_) | Expression::ArrowFunctionExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_call_expression(&self) -> bool {
|
||||
matches!(self, Expression::CallExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_super_call_expression(&self) -> bool {
|
||||
matches!(self, Expression::CallExpression(expr) if matches!(&expr.callee, Expression::Super(_)))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_call_like_expression(&self) -> bool {
|
||||
self.is_call_expression()
|
||||
&& matches!(self, Expression::NewExpression(_) | Expression::ImportExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_binaryish(&self) -> bool {
|
||||
matches!(self, Expression::BinaryExpression(_) | Expression::LogicalExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_member_expr(&self) -> Option<&MemberExpression<'a>> {
|
||||
match self.get_inner_expression() {
|
||||
Expression::ChainExpression(chain_expr) => chain_expr.expression.as_member_expression(),
|
||||
|
|
@ -247,6 +274,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_immutable_value(&self) -> bool {
|
||||
match self {
|
||||
Self::BooleanLiteral(_)
|
||||
|
|
@ -264,6 +292,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_require_call(&self) -> bool {
|
||||
if let Self::CallExpression(call_expr) = self {
|
||||
call_expr.is_require_call()
|
||||
|
|
@ -274,6 +303,7 @@ impl<'a> Expression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> IdentifierName<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, name: Atom<'a>) -> Self {
|
||||
Self { span, name }
|
||||
}
|
||||
|
|
@ -287,12 +317,14 @@ impl<'a> fmt::Display for IdentifierName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> IdentifierReference<'a> {
|
||||
#[allow(missing_docs)]
|
||||
#[inline]
|
||||
pub fn new(span: Span, name: Atom<'a>) -> Self {
|
||||
Self { span, name, reference_id: Cell::default() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn new_with_reference_id(
|
||||
span: Span,
|
||||
name: Atom<'a>,
|
||||
|
|
@ -302,6 +334,7 @@ impl<'a> IdentifierReference<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(missing_docs)]
|
||||
pub fn reference_id(&self) -> Option<ReferenceId> {
|
||||
self.reference_id.get()
|
||||
}
|
||||
|
|
@ -314,10 +347,12 @@ impl<'a> fmt::Display for IdentifierReference<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BindingIdentifier<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, name: Atom<'a>) -> Self {
|
||||
Self { span, name, symbol_id: Cell::default() }
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn new_with_symbol_id(span: Span, name: Atom<'a>, symbol_id: SymbolId) -> Self {
|
||||
Self { span, name, symbol_id: Cell::new(Some(symbol_id)) }
|
||||
}
|
||||
|
|
@ -331,12 +366,14 @@ impl<'a> fmt::Display for BindingIdentifier<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ArrayExpressionElement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_elision(&self) -> bool {
|
||||
matches!(self, Self::Elision(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PropertyKey<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn static_name(&self) -> Option<Cow<'a, str>> {
|
||||
match self {
|
||||
Self::StaticIdentifier(ident) => Some(Cow::Borrowed(ident.name.as_str())),
|
||||
|
|
@ -352,18 +389,22 @@ impl<'a> PropertyKey<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_specific_static_name(&self, name: &str) -> bool {
|
||||
self.static_name().is_some_and(|n| n == name)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_identifier(&self) -> bool {
|
||||
matches!(self, Self::PrivateIdentifier(_) | Self::StaticIdentifier(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_private_identifier(&self) -> bool {
|
||||
matches!(self, Self::PrivateIdentifier(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn private_name(&self) -> Option<Atom<'a>> {
|
||||
match self {
|
||||
Self::PrivateIdentifier(ident) => Some(ident.name.clone()),
|
||||
|
|
@ -371,6 +412,7 @@ impl<'a> PropertyKey<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn name(&self) -> Option<Cow<'a, str>> {
|
||||
if self.is_private_identifier() {
|
||||
self.private_name().map(|name| Cow::Borrowed(name.as_str()))
|
||||
|
|
@ -379,6 +421,7 @@ impl<'a> PropertyKey<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_specific_id(&self, name: &str) -> bool {
|
||||
match self {
|
||||
PropertyKey::StaticIdentifier(ident) => ident.name == name,
|
||||
|
|
@ -386,6 +429,7 @@ impl<'a> PropertyKey<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_specific_string_literal(&self, string: &str) -> bool {
|
||||
matches!(self, Self::StringLiteral(s) if s.value == string)
|
||||
}
|
||||
|
|
@ -401,6 +445,7 @@ impl PropertyKind {
|
|||
}
|
||||
|
||||
impl<'a> TemplateLiteral<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_no_substitution_template(&self) -> bool {
|
||||
self.expressions.is_empty() && self.quasis.len() == 1
|
||||
}
|
||||
|
|
@ -412,10 +457,12 @@ impl<'a> TemplateLiteral<'a> {
|
|||
}
|
||||
|
||||
impl<'a> MemberExpression<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_computed(&self) -> bool {
|
||||
matches!(self, MemberExpression::ComputedMemberExpression(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn optional(&self) -> bool {
|
||||
match self {
|
||||
MemberExpression::ComputedMemberExpression(expr) => expr.optional,
|
||||
|
|
@ -424,6 +471,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn object(&self) -> &Expression<'a> {
|
||||
match self {
|
||||
MemberExpression::ComputedMemberExpression(expr) => &expr.object,
|
||||
|
|
@ -432,6 +480,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn static_property_name(&self) -> Option<&'a str> {
|
||||
match self {
|
||||
MemberExpression::ComputedMemberExpression(expr) => {
|
||||
|
|
@ -442,6 +491,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn static_property_info(&self) -> Option<(Span, &'a str)> {
|
||||
match self {
|
||||
MemberExpression::ComputedMemberExpression(expr) => match &expr.expression {
|
||||
|
|
@ -462,6 +512,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn through_optional_is_specific_member_access(&self, object: &str, property: &str) -> bool {
|
||||
let object_matches = match self.object().without_parentheses() {
|
||||
Expression::ChainExpression(x) => match &x.expression {
|
||||
|
|
@ -487,6 +538,7 @@ impl<'a> MemberExpression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ComputedMemberExpression<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn static_property_name(&self) -> Option<Atom<'a>> {
|
||||
match &self.expression {
|
||||
Expression::StringLiteral(lit) => Some(lit.value.clone()),
|
||||
|
|
@ -501,6 +553,7 @@ impl<'a> ComputedMemberExpression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> StaticMemberExpression<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_first_object(&self) -> &Expression<'a> {
|
||||
match &self.object {
|
||||
Expression::StaticMemberExpression(member) => {
|
||||
|
|
@ -523,6 +576,7 @@ impl<'a> StaticMemberExpression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> CallExpression<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn callee_name(&self) -> Option<&str> {
|
||||
match &self.callee {
|
||||
Expression::Identifier(ident) => Some(ident.name.as_str()),
|
||||
|
|
@ -530,6 +584,7 @@ impl<'a> CallExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_require_call(&self) -> bool {
|
||||
if self.arguments.len() != 1 {
|
||||
return false;
|
||||
|
|
@ -545,6 +600,7 @@ impl<'a> CallExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_symbol_or_symbol_for_call(&self) -> bool {
|
||||
// TODO: is 'Symbol' reference to global object
|
||||
match &self.callee {
|
||||
|
|
@ -559,6 +615,7 @@ impl<'a> CallExpression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn common_js_require(&self) -> Option<&StringLiteral> {
|
||||
if !(self.callee.is_specific_id("require") && self.arguments.len() == 1) {
|
||||
return None;
|
||||
|
|
@ -571,26 +628,31 @@ impl<'a> CallExpression<'a> {
|
|||
}
|
||||
|
||||
impl Argument<'_> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_spread(&self) -> bool {
|
||||
matches!(self, Self::SpreadElement(_))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_expression(&self) -> Option<&Expression<'a>> {
|
||||
self.as_simple_assignment_target().and_then(SimpleAssignmentTarget::get_expression)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
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> {
|
||||
match self {
|
||||
Self::AssignmentTargetIdentifier(ident) => Some(ident.name.as_str()),
|
||||
|
|
@ -599,6 +661,7 @@ impl<'a> SimpleAssignmentTarget<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_expression(&self) -> Option<&Expression<'a>> {
|
||||
match self {
|
||||
Self::TSAsExpression(expr) => Some(&expr.expression),
|
||||
|
|
@ -609,6 +672,7 @@ impl<'a> SimpleAssignmentTarget<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_expression_mut(&mut self) -> Option<&mut Expression<'a>> {
|
||||
match self {
|
||||
Self::TSAsExpression(expr) => Some(&mut expr.expression),
|
||||
|
|
@ -622,6 +686,7 @@ impl<'a> SimpleAssignmentTarget<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ArrayAssignmentTarget<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new_with_elements(
|
||||
span: Span,
|
||||
elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
|
||||
|
|
@ -631,6 +696,7 @@ impl<'a> ArrayAssignmentTarget<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ObjectAssignmentTarget<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new_with_properties(
|
||||
span: Span,
|
||||
properties: Vec<'a, AssignmentTargetProperty<'a>>,
|
||||
|
|
@ -638,16 +704,19 @@ impl<'a> ObjectAssignmentTarget<'a> {
|
|||
Self { span, properties, rest: None }
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.properties.is_empty() && self.rest.is_none()
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn len(&self) -> usize {
|
||||
self.properties.len() + usize::from(self.rest.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AssignmentTargetMaybeDefault<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn name(&self) -> Option<Atom> {
|
||||
match self {
|
||||
AssignmentTargetMaybeDefault::AssignmentTargetIdentifier(id) => Some(id.name.clone()),
|
||||
|
|
@ -664,6 +733,7 @@ impl<'a> AssignmentTargetMaybeDefault<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Statement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
match self {
|
||||
match_declaration!(Self) => {
|
||||
|
|
@ -676,6 +746,7 @@ impl<'a> Statement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_iteration_statement(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
|
@ -707,16 +778,19 @@ impl<'a> Directive<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BlockStatement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, body: Vec<'a, Statement<'a>>) -> Self {
|
||||
Self { span, body, scope_id: Cell::default() }
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn new_with_scope_id(span: Span, body: Vec<'a, Statement<'a>>, scope_id: ScopeId) -> Self {
|
||||
Self { span, body, scope_id: Cell::new(Some(scope_id)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Declaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
match self {
|
||||
Self::VariableDeclaration(decl) => decl.is_typescript_syntax(),
|
||||
|
|
@ -725,7 +799,14 @@ impl<'a> Declaration<'a> {
|
|||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the identifier bound by this declaration.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ts
|
||||
/// const x = 1; // None. may change in the future.
|
||||
/// class Foo {} // Some(IdentifierReference { name: "Foo", .. })
|
||||
/// enum Bar {} // Some(IdentifierReference { name: "Bar", .. })
|
||||
/// ```
|
||||
pub fn id(&self) -> Option<&BindingIdentifier<'a>> {
|
||||
match self {
|
||||
Declaration::FunctionDeclaration(decl) => decl.id.as_ref(),
|
||||
|
|
@ -738,6 +819,7 @@ impl<'a> Declaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn declare(&self) -> bool {
|
||||
match self {
|
||||
Declaration::VariableDeclaration(decl) => decl.declare,
|
||||
|
|
@ -753,32 +835,39 @@ impl<'a> Declaration<'a> {
|
|||
}
|
||||
|
||||
impl<'a> VariableDeclaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
self.declare
|
||||
}
|
||||
|
||||
/// Returns `true` if any of this declaration's variables have an initializer.
|
||||
pub fn has_init(&self) -> bool {
|
||||
self.declarations.iter().any(|decl| decl.init.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
impl VariableDeclarationKind {
|
||||
/// `var x`
|
||||
pub fn is_var(&self) -> bool {
|
||||
matches!(self, Self::Var)
|
||||
}
|
||||
|
||||
/// `const x`
|
||||
pub fn is_const(&self) -> bool {
|
||||
matches!(self, Self::Const)
|
||||
}
|
||||
|
||||
/// `let x` or `const x`
|
||||
pub fn is_lexical(&self) -> bool {
|
||||
matches!(self, Self::Const | Self::Let)
|
||||
}
|
||||
|
||||
/// `await using x`
|
||||
pub fn is_await(&self) -> bool {
|
||||
matches!(self, Self::AwaitUsing)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Var => "var",
|
||||
|
|
@ -798,6 +887,7 @@ impl fmt::Display for VariableDeclarationKind {
|
|||
}
|
||||
|
||||
impl<'a> ForStatement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(
|
||||
span: Span,
|
||||
init: Option<ForStatementInit<'a>>,
|
||||
|
|
@ -818,6 +908,7 @@ impl<'a> ForStatementInit<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ForInStatement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(
|
||||
span: Span,
|
||||
left: ForStatementLeft<'a>,
|
||||
|
|
@ -829,6 +920,7 @@ impl<'a> ForInStatement<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ForOfStatement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(
|
||||
span: Span,
|
||||
r#await: bool,
|
||||
|
|
@ -849,18 +941,21 @@ impl<'a> ForStatementLeft<'a> {
|
|||
}
|
||||
|
||||
impl<'a> SwitchStatement<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, discriminant: Expression<'a>, cases: Vec<'a, SwitchCase<'a>>) -> Self {
|
||||
Self { span, discriminant, cases, scope_id: Cell::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> SwitchCase<'a> {
|
||||
/// `true` for `default:` cases.
|
||||
pub fn is_default_case(&self) -> bool {
|
||||
self.test.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CatchClause<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(
|
||||
span: Span,
|
||||
param: Option<CatchParameter<'a>>,
|
||||
|
|
@ -871,16 +966,19 @@ impl<'a> CatchClause<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BindingPattern<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_identifier(&self) -> Option<Atom<'a>> {
|
||||
self.kind.get_identifier()
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_binding_identifier(&self) -> Option<&BindingIdentifier<'a>> {
|
||||
self.kind.get_binding_identifier()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BindingPatternKind<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_identifier(&self) -> Option<Atom<'a>> {
|
||||
match self {
|
||||
Self::BindingIdentifier(ident) => Some(ident.name.clone()),
|
||||
|
|
@ -889,6 +987,7 @@ impl<'a> BindingPatternKind<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_binding_identifier(&self) -> Option<&BindingIdentifier<'a>> {
|
||||
match self {
|
||||
Self::BindingIdentifier(ident) => Some(ident),
|
||||
|
|
@ -897,6 +996,7 @@ impl<'a> BindingPatternKind<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_destructuring_pattern(&self) -> bool {
|
||||
match self {
|
||||
Self::ObjectPattern(_) | Self::ArrayPattern(_) => true,
|
||||
|
|
@ -905,37 +1005,43 @@ impl<'a> BindingPatternKind<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_binding_identifier(&self) -> bool {
|
||||
matches!(self, Self::BindingIdentifier(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_assignment_pattern(&self) -> bool {
|
||||
matches!(self, Self::AssignmentPattern(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ObjectPattern<'a> {
|
||||
/// `true` for empty object patterns (`{}`).
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.properties.is_empty() && self.rest.is_none()
|
||||
}
|
||||
|
||||
/// The number of properties, including rest properties, in this object pattern.
|
||||
pub fn len(&self) -> usize {
|
||||
self.properties.len() + usize::from(self.rest.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArrayPattern<'a> {
|
||||
/// `true` for empty array patterns (`[]`).
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.elements.is_empty() && self.rest.is_none()
|
||||
}
|
||||
|
||||
/// The number of elements, including rest elements, in this array pattern.
|
||||
pub fn len(&self) -> usize {
|
||||
self.elements.len() + usize::from(self.rest.is_some())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Function<'a> {
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
#![allow(clippy::too_many_arguments, missing_docs)]
|
||||
pub fn new(
|
||||
r#type: FunctionType,
|
||||
span: Span,
|
||||
|
|
@ -979,6 +1085,7 @@ impl<'a> Function<'a> {
|
|||
self.id.as_ref().and_then(|id| id.symbol_id.get())
|
||||
}
|
||||
|
||||
/// `true` for overload signatures and `declare function` statements.
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
matches!(
|
||||
self.r#type,
|
||||
|
|
@ -987,28 +1094,34 @@ impl<'a> Function<'a> {
|
|||
|| self.declare
|
||||
}
|
||||
|
||||
/// `true` for function expressions
|
||||
pub fn is_expression(&self) -> bool {
|
||||
self.r#type == FunctionType::FunctionExpression
|
||||
}
|
||||
|
||||
/// `true` for function declarations
|
||||
pub fn is_function_declaration(&self) -> bool {
|
||||
matches!(self.r#type, FunctionType::FunctionDeclaration)
|
||||
}
|
||||
|
||||
/// `true` for `declare function` statements
|
||||
pub fn is_ts_declare_function(&self) -> bool {
|
||||
matches!(self.r#type, FunctionType::TSDeclareFunction)
|
||||
}
|
||||
|
||||
/// `true` for non-expression functions
|
||||
pub fn is_declaration(&self) -> bool {
|
||||
matches!(self.r#type, FunctionType::FunctionDeclaration | FunctionType::TSDeclareFunction)
|
||||
}
|
||||
|
||||
/// `true` if this function's body has a `"use strict"` directive.
|
||||
pub fn is_strict(&self) -> bool {
|
||||
self.body.as_ref().is_some_and(|body| body.has_use_strict_directive())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FormalParameters<'a> {
|
||||
/// Number of parameters bound in this parameter list.
|
||||
pub fn parameters_count(&self) -> usize {
|
||||
self.items.len() + self.rest.as_ref().map_or(0, |_| 1)
|
||||
}
|
||||
|
|
@ -1023,10 +1136,36 @@ impl<'a> FormalParameters<'a> {
|
|||
}
|
||||
|
||||
impl<'a> FormalParameter<'a> {
|
||||
/// `true` if a `public` accessibility modifier is present. Use
|
||||
/// [`has_modifier`](FormalParameter::has_modifier) if you want to check for
|
||||
/// _any_ modifier, including `readonly` and `override`.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ts
|
||||
/// class Foo {
|
||||
/// constructor(
|
||||
/// public x: number, // <- true
|
||||
/// private y: string, // <- false
|
||||
/// z: string // <- false
|
||||
/// ) {}
|
||||
/// }
|
||||
pub fn is_public(&self) -> bool {
|
||||
matches!(self.accessibility, Some(TSAccessibility::Public))
|
||||
}
|
||||
|
||||
/// `true` if any modifier, accessibility or otherwise, is present.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ts
|
||||
/// class Foo {
|
||||
/// constructor(
|
||||
/// public a: number, // <- true
|
||||
/// readonly b: string, // <- true
|
||||
/// override c: string, // <- true
|
||||
/// d: string // <- false
|
||||
/// ) {}
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn has_modifier(&self) -> bool {
|
||||
self.accessibility.is_some() || self.readonly || self.r#override
|
||||
|
|
@ -1034,32 +1173,39 @@ impl<'a> FormalParameter<'a> {
|
|||
}
|
||||
|
||||
impl FormalParameterKind {
|
||||
/// `true` when part of a TypeScript method or function signature.
|
||||
pub fn is_signature(&self) -> bool {
|
||||
matches!(self, Self::Signature)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FormalParameters<'a> {
|
||||
/// `true` if no parameters are bound.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.items.is_empty()
|
||||
}
|
||||
|
||||
/// `true` if at least one parameter is bound, including [rest bindings](BindingRestElement).
|
||||
pub fn has_parameter(&self) -> bool {
|
||||
!self.is_empty() || self.rest.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> FunctionBody<'a> {
|
||||
/// `true` if this function body contains no statements or directives.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.directives.is_empty() && self.statements.is_empty()
|
||||
}
|
||||
|
||||
/// `true` if this function body contains a `"use strict"` directive.
|
||||
#[allow(missing_docs)]
|
||||
pub fn has_use_strict_directive(&self) -> bool {
|
||||
self.directives.iter().any(Directive::is_use_strict)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ArrowFunctionExpression<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(
|
||||
span: Span,
|
||||
expression: bool,
|
||||
|
|
@ -1093,7 +1239,7 @@ impl<'a> ArrowFunctionExpression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Class<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::too_many_arguments, missing_docs)]
|
||||
pub fn new(
|
||||
r#type: ClassType,
|
||||
span: Span,
|
||||
|
|
@ -1145,6 +1291,7 @@ impl<'a> Class<'a> {
|
|||
self.r#type == ClassType::ClassDeclaration
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
self.declare || self.r#abstract
|
||||
}
|
||||
|
|
@ -1167,6 +1314,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn computed(&self) -> bool {
|
||||
match self {
|
||||
Self::TSIndexSignature(_) | Self::StaticBlock(_) => false,
|
||||
|
|
@ -1176,6 +1324,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn accessibility(&self) -> Option<TSAccessibility> {
|
||||
match self {
|
||||
Self::StaticBlock(_) | Self::TSIndexSignature(_) | Self::AccessorProperty(_) => None,
|
||||
|
|
@ -1184,6 +1333,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn method_definition_kind(&self) -> Option<MethodDefinitionKind> {
|
||||
match self {
|
||||
Self::TSIndexSignature(_)
|
||||
|
|
@ -1194,6 +1344,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn property_key(&self) -> Option<&PropertyKey<'a>> {
|
||||
match self {
|
||||
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
|
||||
|
|
@ -1203,6 +1354,8 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Try to get the statically known name of this [`ClassElement`]. Handles
|
||||
/// computed members that use literals.
|
||||
pub fn static_name(&self) -> Option<Cow<'a, str>> {
|
||||
match self {
|
||||
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
|
||||
|
|
@ -1217,6 +1370,8 @@ impl<'a> ClassElement<'a> {
|
|||
matches!(self, Self::PropertyDefinition(_) | Self::AccessorProperty(_))
|
||||
}
|
||||
|
||||
/// `true` for overloads, declarations, index signatures, and abstract
|
||||
/// methods, etc. That is, any non-concrete implementation.
|
||||
pub fn is_ts_empty_body_function(&self) -> bool {
|
||||
match self {
|
||||
Self::PropertyDefinition(_)
|
||||
|
|
@ -1227,6 +1382,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
match self {
|
||||
Self::TSIndexSignature(_) => true,
|
||||
|
|
@ -1239,6 +1395,7 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// `true` for [decorated](Decorator) class elements.
|
||||
pub fn has_decorator(&self) -> bool {
|
||||
match self {
|
||||
Self::MethodDefinition(method) => !method.decorators.is_empty(),
|
||||
|
|
@ -1267,24 +1424,29 @@ impl<'a> ClassElement<'a> {
|
|||
}
|
||||
|
||||
impl PropertyDefinitionType {
|
||||
/// `true` for abstract properties and methods.
|
||||
pub fn is_abstract(&self) -> bool {
|
||||
matches!(self, Self::TSAbstractPropertyDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
impl MethodDefinitionKind {
|
||||
/// `true` for constructors.
|
||||
pub fn is_constructor(&self) -> bool {
|
||||
matches!(self, Self::Constructor)
|
||||
}
|
||||
|
||||
/// `true` for regular methods.
|
||||
pub fn is_method(&self) -> bool {
|
||||
matches!(self, Self::Method)
|
||||
}
|
||||
|
||||
/// `true` for setter methods.
|
||||
pub fn is_set(&self) -> bool {
|
||||
matches!(self, Self::Set)
|
||||
}
|
||||
|
||||
/// `true` for getter methods.
|
||||
pub fn is_get(&self) -> bool {
|
||||
matches!(self, Self::Get)
|
||||
}
|
||||
|
|
@ -1296,6 +1458,7 @@ impl MethodDefinitionKind {
|
|||
matches!(self, Self::Get | Self::Set)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn scope_flags(self) -> ScopeFlags {
|
||||
match self {
|
||||
Self::Constructor => ScopeFlags::Constructor | ScopeFlags::Function,
|
||||
|
|
@ -1307,24 +1470,28 @@ impl MethodDefinitionKind {
|
|||
}
|
||||
|
||||
impl MethodDefinitionType {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_abstract(&self) -> bool {
|
||||
matches!(self, Self::TSAbstractMethodDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PrivateIdentifier<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, name: Atom<'a>) -> Self {
|
||||
Self { span, name }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> StaticBlock<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, body: Vec<'a, Statement<'a>>) -> Self {
|
||||
Self { span, body, scope_id: Cell::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ModuleDeclaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
match self {
|
||||
ModuleDeclaration::ImportDeclaration(_) => false,
|
||||
|
|
@ -1336,10 +1503,12 @@ impl<'a> ModuleDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_import(&self) -> bool {
|
||||
matches!(self, Self::ImportDeclaration(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_export(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
|
|
@ -1351,10 +1520,12 @@ impl<'a> ModuleDeclaration<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_default_export(&self) -> bool {
|
||||
matches!(self, Self::ExportDefaultDeclaration(_))
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn source(&self) -> Option<&StringLiteral<'a>> {
|
||||
match self {
|
||||
Self::ImportDeclaration(decl) => Some(&decl.source),
|
||||
|
|
@ -1366,6 +1537,7 @@ impl<'a> ModuleDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn with_clause(&self) -> Option<&Box<'a, WithClause<'a>>> {
|
||||
match self {
|
||||
Self::ImportDeclaration(decl) => decl.with_clause.as_ref(),
|
||||
|
|
@ -1379,12 +1551,14 @@ impl<'a> ModuleDeclaration<'a> {
|
|||
}
|
||||
|
||||
impl AccessorPropertyType {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_abstract(&self) -> bool {
|
||||
matches!(self, Self::TSAbstractAccessorProperty)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ImportDeclarationSpecifier<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn local(&self) -> &BindingIdentifier<'a> {
|
||||
match self {
|
||||
ImportDeclarationSpecifier::ImportSpecifier(specifier) => &specifier.local,
|
||||
|
|
@ -1393,12 +1567,14 @@ impl<'a> ImportDeclarationSpecifier<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn name(&self) -> Cow<'a, str> {
|
||||
Cow::Borrowed(self.local().name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ImportAttributeKey<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn as_atom(&self) -> Atom<'a> {
|
||||
match self {
|
||||
Self::Identifier(identifier) => identifier.name.clone(),
|
||||
|
|
@ -1408,6 +1584,7 @@ impl<'a> ImportAttributeKey<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ExportNamedDeclaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
self.export_kind == ImportOrExportKind::Type
|
||||
|| self.declaration.as_ref().map_or(false, Declaration::is_typescript_syntax)
|
||||
|
|
@ -1415,24 +1592,28 @@ impl<'a> ExportNamedDeclaration<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ExportDefaultDeclaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
self.declaration.is_typescript_syntax()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExportAllDeclaration<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
self.export_kind.is_type()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExportSpecifier<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn new(span: Span, local: ModuleExportName<'a>, exported: ModuleExportName<'a>) -> Self {
|
||||
Self { span, local, exported, export_kind: ImportOrExportKind::Value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExportDefaultDeclarationKind<'a> {
|
||||
#[allow(missing_docs)]
|
||||
#[inline]
|
||||
pub fn is_typescript_syntax(&self) -> bool {
|
||||
match self {
|
||||
|
|
@ -1456,6 +1637,7 @@ impl<'a> fmt::Display for ModuleExportName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ModuleExportName<'a> {
|
||||
#[allow(missing_docs)]
|
||||
pub fn name(&self) -> Atom<'a> {
|
||||
match self {
|
||||
Self::IdentifierName(identifier) => identifier.name.clone(),
|
||||
|
|
@ -1464,6 +1646,7 @@ impl<'a> ModuleExportName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn identifier_name(&self) -> Option<Atom<'a>> {
|
||||
match self {
|
||||
Self::IdentifierName(identifier) => Some(identifier.name.clone()),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//! [JSX](https://facebook.github.io/jsx)
|
||||
|
||||
#![warn(missing_docs)]
|
||||
use std::fmt;
|
||||
|
||||
use oxc_span::{Atom, Span};
|
||||
|
|
@ -16,6 +16,7 @@ export type JSXMemberExpressionObject = JSXIdentifier | JSXMemberExpression;
|
|||
// 1.2 JSX Elements
|
||||
|
||||
impl<'a> JSXIdentifier<'a> {
|
||||
/// Create a new JSX identifier with the given `name`.
|
||||
pub fn new(span: Span, name: Atom<'a>) -> Self {
|
||||
Self { span, name }
|
||||
}
|
||||
|
|
@ -35,6 +36,9 @@ impl<'a> fmt::Display for JSXNamespacedName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> JSXElementName<'a> {
|
||||
/// Get this name's contained identifier reference, returning [`None`] if it
|
||||
/// is some other variant. Note that [namespaced
|
||||
/// identifiers](JSXElementName::NamespacedName) are not included.
|
||||
pub fn get_identifier(&self) -> Option<&IdentifierReference<'a>> {
|
||||
match self {
|
||||
JSXElementName::Identifier(_)
|
||||
|
|
@ -45,6 +49,7 @@ impl<'a> JSXElementName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
pub fn get_identifier_name(&self) -> Option<Atom<'a>> {
|
||||
match self {
|
||||
Self::Identifier(id) => Some(id.as_ref().name.clone()),
|
||||
|
|
@ -55,12 +60,17 @@ impl<'a> JSXElementName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> JSXMemberExpression<'a> {
|
||||
/// Get the identifier being referenced, if there is one. Will return
|
||||
/// [`None`] for `this` expressions or if semantic analysis was skipped.
|
||||
pub fn get_identifier(&self) -> Option<&IdentifierReference<'a>> {
|
||||
self.object.get_identifier()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> JSXMemberExpressionObject<'a> {
|
||||
/// Get the identifier being referenced, if there is one. Will return
|
||||
/// [`None`] for [`this`](JSXMemberExpressionObject::ThisExpression)
|
||||
/// expressions or if semantic analysis was skipped.
|
||||
pub fn get_identifier(&self) -> Option<&IdentifierReference<'a>> {
|
||||
let mut object = self;
|
||||
loop {
|
||||
|
|
@ -111,20 +121,35 @@ impl<'a> JSXExpression<'a> {
|
|||
}
|
||||
|
||||
impl<'a> JSXAttribute<'a> {
|
||||
/// Returns `true` if this attribute's name is the expected `name`.
|
||||
///
|
||||
/// Use [`JSXAttribute::is_identifier_ignore_case`] if you want to ignore
|
||||
/// upper/lower case differences.
|
||||
pub fn is_identifier(&self, name: &str) -> bool {
|
||||
matches!(&self.name, JSXAttributeName::Identifier(ident) if ident.name == name)
|
||||
}
|
||||
|
||||
/// Returns `true` if this attribute's name is the expected `name`, ignoring
|
||||
/// casing.
|
||||
pub fn is_identifier_ignore_case(&self, name: &str) -> bool {
|
||||
matches!(&self.name, JSXAttributeName::Identifier(ident) if ident.name.eq_ignore_ascii_case(name))
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a React `key`.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```tsx
|
||||
/// <Foo key="value" /> // -> `true`
|
||||
/// <Foo bar="value" /> // -> `false`
|
||||
/// ```
|
||||
pub fn is_key(&self) -> bool {
|
||||
self.is_identifier("key")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> JSXAttributeName<'a> {
|
||||
/// Try to convert this attribute name into an [identifier](JSXIdentifier).
|
||||
/// Returns [`None`] for [namespaced names](JSXAttributeName::NamespacedName).
|
||||
pub fn as_identifier(&self) -> Option<&JSXIdentifier<'a>> {
|
||||
match self {
|
||||
Self::Identifier(ident) => Some(ident.as_ref()),
|
||||
|
|
@ -132,6 +157,14 @@ impl<'a> JSXAttributeName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the rightmost identifier in the attribute name.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```tsx
|
||||
/// <Foo /> // -> `Foo`
|
||||
/// <Foo.Bar /> // -> `Bar`
|
||||
/// <Foo.Bar.Baz /> // -> `Baz`
|
||||
/// ```
|
||||
pub fn get_identifier(&self) -> &JSXIdentifier<'a> {
|
||||
match self {
|
||||
Self::Identifier(ident) => ident.as_ref(),
|
||||
|
|
@ -140,6 +173,8 @@ impl<'a> JSXAttributeName<'a> {
|
|||
}
|
||||
}
|
||||
impl<'a> JSXAttributeValue<'a> {
|
||||
/// Get the contained [`StringLiteral`], or [`None`] if this is some other
|
||||
/// kind of value.
|
||||
pub fn as_string_literal(&self) -> Option<&StringLiteral<'a>> {
|
||||
match self {
|
||||
Self::StringLiteral(lit) => Some(lit.as_ref()),
|
||||
|
|
@ -173,6 +208,7 @@ impl<'a> JSXAttributeItem<'a> {
|
|||
}
|
||||
|
||||
impl<'a> JSXChild<'a> {
|
||||
/// Returns `true` if this an [expression container](JSXChild::ExpressionContainer).
|
||||
pub const fn is_expression_container(&self) -> bool {
|
||||
matches!(self, Self::ExpressionContainer(_))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
//! Literals
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
|
|
@ -14,10 +15,12 @@ use oxc_syntax::number::NumberBase;
|
|||
use crate::ast::*;
|
||||
|
||||
impl BooleanLiteral {
|
||||
/// Create a new boolean literal representing the given `value`.
|
||||
pub fn new(span: Span, value: bool) -> Self {
|
||||
Self { span, value }
|
||||
}
|
||||
|
||||
/// `"true"` or `"false"` depending on this boolean's value.
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
if self.value {
|
||||
"true"
|
||||
|
|
@ -42,6 +45,7 @@ impl ContentHash for NullLiteral {
|
|||
}
|
||||
|
||||
impl NullLiteral {
|
||||
/// Create a new `null` literal at the given location.
|
||||
pub fn new(span: Span) -> Self {
|
||||
Self { span }
|
||||
}
|
||||
|
|
@ -55,6 +59,7 @@ impl fmt::Display for NullLiteral {
|
|||
}
|
||||
|
||||
impl<'a> NumericLiteral<'a> {
|
||||
/// Create a numeric literal representing the given `value`.
|
||||
pub fn new(span: Span, value: f64, raw: &'a str, base: NumberBase) -> Self {
|
||||
Self { span, value, raw, base }
|
||||
}
|
||||
|
|
@ -101,6 +106,7 @@ impl<'a> fmt::Display for NumericLiteral<'a> {
|
|||
}
|
||||
|
||||
impl<'a> BigIntLiteral<'a> {
|
||||
/// Is this BigInt literal zero? (`0n`).
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.raw == "0n"
|
||||
}
|
||||
|
|
@ -119,6 +125,7 @@ impl<'a> fmt::Display for RegExp<'a> {
|
|||
}
|
||||
|
||||
impl<'a> RegExpPattern<'a> {
|
||||
/// Returns the number of characters in the pattern.
|
||||
pub fn len(&self) -> usize {
|
||||
match self {
|
||||
Self::Raw(it) | Self::Invalid(it) => it.len(),
|
||||
|
|
@ -126,10 +133,13 @@ impl<'a> RegExpPattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the pattern is empty (i.e. has a
|
||||
/// [len](RegExpPattern::len) of `0`).
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns the string as this regular expression would appear in source code.
|
||||
pub fn source_text(&self, source_text: &'a str) -> Cow<str> {
|
||||
match self {
|
||||
Self::Raw(raw) | Self::Invalid(raw) => Cow::Borrowed(raw),
|
||||
|
|
@ -152,6 +162,8 @@ impl<'a> RegExpPattern<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Flatten this regular expression into a compiled [`Pattern`], returning
|
||||
/// [`None`] if the pattern is invalid or not parsed.
|
||||
pub fn as_pattern(&self) -> Option<&Pattern<'a>> {
|
||||
if let Self::Pattern(it) = self {
|
||||
Some(it.as_ref())
|
||||
|
|
@ -257,6 +269,7 @@ impl fmt::Display for RegExpFlags {
|
|||
}
|
||||
|
||||
impl<'a> StringLiteral<'a> {
|
||||
/// Create a new string literal representing the given `value`.
|
||||
pub fn new(span: Span, value: Atom<'a>) -> Self {
|
||||
Self { span, value }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
//!
|
||||
//! [AST Spec](https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/ast-spec)
|
||||
//! [Archived TypeScript spec](https://github.com/microsoft/TypeScript/blob/3c99d50da5a579d9fa92d02664b1b66d4ff55944/doc/spec-ARCHIVED.md)
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{cell::Cell, fmt};
|
||||
|
||||
|
|
@ -11,6 +12,7 @@ use oxc_span::{Atom, Span};
|
|||
use crate::ast::*;
|
||||
|
||||
impl<'a> TSEnumDeclaration<'a> {
|
||||
/// Create a new enum declaration.
|
||||
pub fn new(
|
||||
span: Span,
|
||||
id: BindingIdentifier<'a>,
|
||||
|
|
@ -22,6 +24,7 @@ impl<'a> TSEnumDeclaration<'a> {
|
|||
}
|
||||
}
|
||||
impl<'a> TSEnumMemberName<'a> {
|
||||
/// Get the name of this enum member if it can be determined statically.
|
||||
pub fn static_name(&self) -> Option<&'a str> {
|
||||
match self {
|
||||
Self::StaticIdentifier(ident) => Some(ident.name.as_str()),
|
||||
|
|
@ -34,6 +37,15 @@ impl<'a> TSEnumMemberName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> TSType<'a> {
|
||||
/// Get the first identifier reference in this type.
|
||||
///
|
||||
/// For qualified (i.e. namespaced) types, the left-most identifier is
|
||||
/// returned.
|
||||
///
|
||||
/// ```
|
||||
/// let ty = get_type_for("foo.bar.Baz"); // TSType::TSQualifiedName
|
||||
/// get_identifier_reference(&ty); // Some(IdentifierReference { name: "foo", .. })
|
||||
/// ```
|
||||
pub fn get_identifier_reference(&self) -> Option<IdentifierReference<'a>> {
|
||||
match self {
|
||||
TSType::TSTypeReference(reference) => {
|
||||
|
|
@ -48,6 +60,7 @@ impl<'a> TSType<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this type is a type reference to `const`.
|
||||
pub fn is_const_type_reference(&self) -> bool {
|
||||
matches!(self, TSType::TSTypeReference(reference) if reference.type_name.is_const())
|
||||
}
|
||||
|
|
@ -63,6 +76,7 @@ impl<'a> TSType<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a keyword type (e.g. `number`, `any`, `string`).
|
||||
#[rustfmt::skip]
|
||||
pub fn is_keyword(&self) -> bool {
|
||||
matches!(self, TSType::TSAnyKeyword(_) | TSType::TSBigIntKeyword(_) | TSType::TSBooleanKeyword(_)
|
||||
|
|
@ -73,12 +87,22 @@ impl<'a> TSType<'a> {
|
|||
)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a [keyword] or literal type.
|
||||
///
|
||||
/// [keyword]: Self::is_keyword
|
||||
pub fn is_keyword_or_literal(&self) -> bool {
|
||||
self.is_keyword() || matches!(self, TSType::TSLiteralType(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TSTypeName<'a> {
|
||||
/// Get the "leftmost" identifier in a dot-separated type name.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ts
|
||||
/// type Foo = Bar; // -> Bar
|
||||
/// type Foo = Bar.Baz; // -> Bar
|
||||
/// ```
|
||||
pub fn get_first_name(name: &TSTypeName<'a>) -> IdentifierReference<'a> {
|
||||
match name {
|
||||
TSTypeName::IdentifierReference(name) => (*name).clone(),
|
||||
|
|
@ -86,6 +110,7 @@ impl<'a> TSTypeName<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a reference to `const`.
|
||||
pub fn is_const(&self) -> bool {
|
||||
if let TSTypeName::IdentifierReference(ident) = self {
|
||||
if ident.name == "const" {
|
||||
|
|
@ -95,10 +120,13 @@ impl<'a> TSTypeName<'a> {
|
|||
false
|
||||
}
|
||||
|
||||
/// Returns `true` if this is an [`TSTypeName::IdentifierReference`].
|
||||
pub fn is_identifier(&self) -> bool {
|
||||
matches!(self, Self::IdentifierReference(_))
|
||||
}
|
||||
|
||||
/// Returns `true` if this is a [qualified name](TSTypeName::QualifiedName)
|
||||
/// (i.e. a dot-separated name).
|
||||
pub fn is_qualified_name(&self) -> bool {
|
||||
matches!(self, Self::QualifiedName(_))
|
||||
}
|
||||
|
|
@ -130,11 +158,13 @@ impl<'a> TSType<'a> {
|
|||
}
|
||||
|
||||
impl TSAccessibility {
|
||||
/// Returns `true` for `private` accessibility modifiers.
|
||||
#[inline]
|
||||
pub fn is_private(self) -> bool {
|
||||
matches!(self, Self::Private)
|
||||
}
|
||||
|
||||
/// Converts this modifier into a string as it would appear in the source code.
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Public => "public",
|
||||
|
|
@ -157,6 +187,7 @@ impl fmt::Display for TSAccessibility {
|
|||
}
|
||||
|
||||
impl<'a> TSModuleDeclaration<'a> {
|
||||
/// Create a new module declaration with no bound scope.
|
||||
pub fn new(
|
||||
span: Span,
|
||||
id: TSModuleDeclarationName<'a>,
|
||||
|
|
@ -167,16 +198,21 @@ impl<'a> TSModuleDeclaration<'a> {
|
|||
Self { span, id, body, kind, declare, scope_id: Cell::default() }
|
||||
}
|
||||
|
||||
/// Returns `true` if this module's body exists and uses strict mode
|
||||
/// semantics (as determined by [`TSModuleDeclarationBody::is_strict`]).
|
||||
pub fn is_strict(&self) -> bool {
|
||||
self.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict)
|
||||
}
|
||||
}
|
||||
|
||||
impl TSModuleDeclarationKind {
|
||||
/// Returns `true` for `declare global { ... }`
|
||||
pub fn is_global(self) -> bool {
|
||||
matches!(self, TSModuleDeclarationKind::Global)
|
||||
}
|
||||
|
||||
/// Declaration keyword as a string, identical to how it would appear in the
|
||||
/// source code.
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Global => "global",
|
||||
|
|
@ -187,10 +223,25 @@ impl TSModuleDeclarationKind {
|
|||
}
|
||||
|
||||
impl<'a> TSModuleDeclarationName<'a> {
|
||||
/// Returns `true` if this name is a string literal.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```ts
|
||||
/// // true
|
||||
/// module "*.less" {
|
||||
/// const styles: { [key: string]: string };
|
||||
/// export default styles;
|
||||
/// }
|
||||
///
|
||||
/// // false
|
||||
/// module bar {}
|
||||
/// namespace bang {}
|
||||
/// ```
|
||||
pub fn is_string_literal(&self) -> bool {
|
||||
matches!(self, Self::StringLiteral(_))
|
||||
}
|
||||
|
||||
/// Get the static name of this module declaration name.
|
||||
pub fn name(&self) -> Atom<'a> {
|
||||
match self {
|
||||
Self::Identifier(ident) => ident.name.clone(),
|
||||
|
|
@ -209,10 +260,12 @@ impl<'a> fmt::Display for TSModuleDeclarationName<'a> {
|
|||
}
|
||||
|
||||
impl<'a> TSModuleDeclarationBody<'a> {
|
||||
/// Does the body of this module use strict mode semantics?
|
||||
pub fn is_strict(&self) -> bool {
|
||||
matches!(self, Self::TSModuleBlock(block) if block.is_strict())
|
||||
}
|
||||
|
||||
/// Returns `true` if this module contains no statements.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
match self {
|
||||
TSModuleDeclarationBody::TSModuleDeclaration(declaration) => declaration.body.is_none(),
|
||||
|
|
@ -220,6 +273,8 @@ impl<'a> TSModuleDeclarationBody<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to `self` as a [`TSModuleBlock`]. Returns
|
||||
/// [`None`] if the body is something other than a block.
|
||||
pub fn as_module_block_mut(&mut self) -> Option<&mut TSModuleBlock<'a>> {
|
||||
match self {
|
||||
TSModuleDeclarationBody::TSModuleBlock(block) => Some(block.as_mut()),
|
||||
|
|
@ -231,6 +286,7 @@ impl<'a> TSModuleDeclarationBody<'a> {
|
|||
}
|
||||
|
||||
impl<'a> TSModuleBlock<'a> {
|
||||
/// Returns `true` if this module contains a `"use strict"` directive.
|
||||
pub fn is_strict(&self) -> bool {
|
||||
self.directives.iter().any(Directive::is_use_strict)
|
||||
}
|
||||
|
|
@ -267,16 +323,19 @@ impl<'a> Decorator<'a> {
|
|||
}
|
||||
|
||||
impl ImportOrExportKind {
|
||||
/// Returns `true` for "regular" imports and exports.
|
||||
pub fn is_value(&self) -> bool {
|
||||
matches!(self, Self::Value)
|
||||
}
|
||||
|
||||
/// Returns `true` if this is an `import type` or `export type` statement.
|
||||
pub fn is_type(&self) -> bool {
|
||||
matches!(self, Self::Type)
|
||||
}
|
||||
}
|
||||
|
||||
impl TSTypeOperatorOperator {
|
||||
/// Get the operator string as it would appear in the source code.
|
||||
pub fn to_str(self) -> &'static str {
|
||||
match self {
|
||||
TSTypeOperatorOperator::Keyof => "keyof",
|
||||
|
|
|
|||
Loading…
Reference in a new issue