feat(ast)!: introduce ExportDeclaration, ExportFromDeclaration (#25095)

## Summary

Split the overloaded Rust `ExportNamedDeclaration` into syntax-specific AST nodes:

- `ExportDeclaration` for exported declarations
- `ExportNamedDeclaration` for local exports
- `ExportFromDeclaration` for re-exports

## Breaking Change

The Rust AST changes from:

```rust
pub struct ExportNamedDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub declaration: Option<Declaration<'a>>,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub source: Option<StringLiteral<'a>>,
    pub export_kind: ImportOrExportKind,
    pub with_clause: Option<Box<'a, WithClause<'a>>>,
}

pub enum ModuleDeclaration<'a> {
    // ...
    ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>),
    // ...
}
```

to:

```rust
pub struct ExportDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub declaration: Declaration<'a>,
}

pub struct ExportNamedDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub export_kind: ImportOrExportKind,
}

pub struct ExportFromDeclaration<'a> {
    pub node_id: Cell<NodeId>,
    pub span: Span,
    pub specifiers: Vec<'a, ExportSpecifier<'a>>,
    pub source: StringLiteral<'a>,
    pub export_kind: ImportOrExportKind,
    pub with_clause: Option<Box<'a, WithClause<'a>>>,
}

pub enum ModuleDeclaration<'a> {
    // ...
    ExportDeclaration(Box<'a, ExportDeclaration<'a>>),
    ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>),
    ExportFromDeclaration(Box<'a, ExportFromDeclaration<'a>>),
    // ...
}
```

## Why?

The previous node represented three distinct syntax forms through optional and mutually exclusive fields:

```text
export const value = 1;       -> ExportDeclaration
export { value };             -> ExportNamedDeclaration
export { value } from "mod";  -> ExportFromDeclaration
```

This allowed invalid combinations such as declarations with specifiers or sources, and import attributes without a source. The new nodes make these states unrepresentable and remove repeated `declaration`/`source` branching from consumers.

## How to migrate

Match the syntax-specific `ModuleDeclaration`, `Statement`, or `AstKind` variant instead of inspecting optional fields. Generated builders, visitors, traversal ancestors, and formatter wrappers now expose corresponding APIs for all three nodes.

Common field migrations:

| Previous representation | New representation |
| --- | --- |
| `declaration: Some(declaration)` | `ExportDeclaration { declaration }` |
| `declaration.as_ref()` | `&export.declaration` |
| `source.is_none()` for local exports | Match `ExportNamedDeclaration` |
| `source: Some(source)` | `ExportFromDeclaration { source }` |
| `source.as_ref().unwrap()` | `&export.source` |
| `with_clause` | Only available on `ExportFromDeclaration` |
| Stored `export_kind` on exported declarations | `ExportDeclaration::export_kind()` |
| `ExportNamedDeclaration::boxed_plain_declaration(...)` | `ExportDeclaration::boxed(...)` |
| `ExportNamedDeclaration::boxed(..., None, specifiers, None, ...)` | `ExportNamedDeclaration::boxed(..., specifiers, ...)` |
| `ExportNamedDeclaration::boxed(..., None, specifiers, Some(source), ...)` | `ExportFromDeclaration::boxed(..., specifiers, source, ...)` |

closes https://github.com/oxc-project/backlog/issues/219
This commit is contained in:
camc314 committed 2026-07-31 10:25:47 +00:00
1 parent dda5636004
commit 1bdedd11ca
146 files changed
+4991 -3437

No files matched your search

+68 -14
View File
@@ -1524,10 +1524,14 @@ function deserializeStatement(pos) {
case 66:
return deserializeBoxExportDefaultDeclaration(pos + 8);
case 67:
return deserializeBoxExportNamedDeclaration(pos + 8);
return deserializeBoxExportDeclaration(pos + 8);
case 68:
return deserializeBoxTSExportAssignment(pos + 8);
return deserializeBoxExportNamedDeclaration(pos + 8);
case 69:
return deserializeBoxExportFromDeclaration(pos + 8);
case 70:
return deserializeBoxTSExportAssignment(pos + 8);
case 71:
return deserializeBoxTSNamespaceExportDeclaration(pos + 8);
default:
throw Error(`Unexpected discriminant ${uint8[pos]} for Statement`);
@@ -3099,7 +3103,58 @@ function deserializeImportAttributeKey(pos) {
}
}
function deserializeExportDeclaration(pos) {
let start,
end,
previousParent = parent,
node = (parent = {
__proto__: NodeProto,
type: "ExportNamedDeclaration",
declaration: null,
specifiers: [],
source: null,
exportKind: null,
attributes: [],
start: (start = deserializeI32(pos)),
end: (end = deserializeI32(pos + 4)),
range: [start, end],
parent,
}),
declaration = deserializeDeclaration(pos + 16);
node.declaration = declaration;
node.exportKind =
declaration.declare === true ||
declaration.type === "TSTypeAliasDeclaration" ||
declaration.type === "TSInterfaceDeclaration"
? "type"
: "value";
parent = previousParent;
return node;
}
function deserializeExportNamedDeclaration(pos) {
let start,
end,
previousParent = parent,
node = (parent = {
__proto__: NodeProto,
type: "ExportNamedDeclaration",
declaration: null,
specifiers: null,
source: null,
exportKind: deserializeImportOrExportKind(pos + 12),
attributes: [],
start: (start = deserializeI32(pos)),
end: (end = deserializeI32(pos + 4)),
range: [start, end],
parent,
});
node.specifiers = deserializeVecExportSpecifier(pos + 16);
parent = previousParent;
return node;
}
function deserializeExportFromDeclaration(pos) {
let start,
end,
previousParent = parent,
@@ -3116,10 +3171,9 @@ function deserializeExportNamedDeclaration(pos) {
range: [start, end],
parent,
}),
withClause = deserializeOptionBoxWithClause(pos + 104);
node.declaration = deserializeOptionDeclaration(pos + 16);
node.specifiers = deserializeVecExportSpecifier(pos + 32);
node.source = deserializeOptionStringLiteral(pos + 56);
withClause = deserializeOptionBoxWithClause(pos + 88);
node.specifiers = deserializeVecExportSpecifier(pos + 16);
node.source = deserializeStringLiteral(pos + 40);
node.attributes = withClause === null ? [] : withClause.attributes;
parent = previousParent;
return node;
@@ -6727,10 +6781,18 @@ function deserializeBoxExportDefaultDeclaration(pos) {
return deserializeExportDefaultDeclaration(int32[pos >> 2]);
}
function deserializeBoxExportDeclaration(pos) {
return deserializeExportDeclaration(int32[pos >> 2]);
}
function deserializeBoxExportNamedDeclaration(pos) {
return deserializeExportNamedDeclaration(int32[pos >> 2]);
}
function deserializeBoxExportFromDeclaration(pos) {
return deserializeExportFromDeclaration(int32[pos >> 2]);
}
function deserializeBoxTSExportAssignment(pos) {
return deserializeTSExportAssignment(int32[pos >> 2]);
}
@@ -6795,10 +6857,6 @@ function deserializeVecImportAttribute(pos) {
return arr;
}
function deserializeOptionDeclaration(pos) {
return uint8[pos] === 31 ? null : deserializeDeclaration(pos);
}
function deserializeVecExportSpecifier(pos) {
let arr = [],
pos32 = pos >> 2;
@@ -6811,10 +6869,6 @@ function deserializeVecExportSpecifier(pos) {
return arr;
}
function deserializeOptionStringLiteral(pos) {
return uint8[pos + 12] === 2 ? null : deserializeStringLiteral(pos);
}
function deserializeOptionModuleExportName(pos) {
return uint8[pos] === 255 ? null : deserializeModuleExportName(pos);
}
+87 -13
View File
@@ -2401,8 +2401,7 @@ pub struct StaticBlock<'a> {
/// import bar from 'bar';
/// import * as baz from 'baz';
///
/// // Not a ModuleDeclaration
/// export const a = 5;
/// export const a = 5; // ExportDeclaration
///
/// const b = 6;
///
@@ -2424,14 +2423,17 @@ pub enum ModuleDeclaration<'a> {
ExportAllDeclaration(Box<'a, ExportAllDeclaration<'a>>) = 65,
/// `export default 5;`
ExportDefaultDeclaration(Box<'a, ExportDefaultDeclaration<'a>>) = 66,
/// `export {five} from './numbers.js';`
/// `export const five = 5;`
ExportDeclaration(Box<'a, ExportDeclaration<'a>>) = 67,
/// `export {six, seven};`
ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>) = 67,
ExportNamedDeclaration(Box<'a, ExportNamedDeclaration<'a>>) = 68,
/// `export {five} from './numbers.js';`
ExportFromDeclaration(Box<'a, ExportFromDeclaration<'a>>) = 69,
/// `export = 5;`
TSExportAssignment(Box<'a, TSExportAssignment<'a>>) = 68,
TSExportAssignment(Box<'a, TSExportAssignment<'a>>) = 70,
/// `export as namespace React;`
TSNamespaceExportDeclaration(Box<'a, TSNamespaceExportDeclaration<'a>>) = 69,
TSNamespaceExportDeclaration(Box<'a, TSNamespaceExportDeclaration<'a>>) = 71,
}
#[ast]
@@ -2669,32 +2671,104 @@ pub enum ImportAttributeKey<'a> {
StringLiteral(StringLiteral<'a>) = 1,
}
/// Named Export Declaration
/// Exported declaration.
///
/// ## Example
///
/// ```ts
/// export const foo = 1;
/// export interface Bar {}
/// ```
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, Dummy, ReplaceWith, TakeIn)]
#[generate_derive(ContentEq, ESTree, GetSpan, GetSpanMut, UnstableAddress)]
#[estree(
rename = "ExportNamedDeclaration",
ts_alias = "ExportNamedDeclaration",
add_ts_def = "
interface ExportNamedDeclaration extends Span {
type: 'ExportNamedDeclaration';
declaration: Declaration | null;
specifiers: Array<ExportSpecifier>;
source: StringLiteral | null;
exportKind?: ImportOrExportKind;
attributes: Array<ImportAttribute>;
parent/* IF !LINTER */?/* END IF */: Node;
}
",
add_fields(
specifiers = EmptyArray,
source = Null,
exportKind = ExportDeclarationExportKind,
attributes = EmptyArray,
),
field_order(declaration, specifiers, source, exportKind, attributes, span),
)]
pub struct ExportDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub declaration: Declaration<'a>,
}
/// Local named export declaration.
///
/// ## Example
///
/// ```ts
/// // ________ specifiers
/// export { Foo, Bar };
/// export type { Baz } from 'baz';
/// // ^^^^ ^^^^^
/// // export_kind source
/// export type { Baz };
/// // ^^^^
/// // export_kind
/// ```
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, Dummy, ReplaceWith, TakeIn)]
#[generate_derive(ContentEq, ESTree, GetSpan, GetSpanMut, UnstableAddress)]
#[estree(
rename = "ExportNamedDeclaration",
ts_alias = "ExportNamedDeclaration",
add_fields(declaration = Null, source = Null, attributes = EmptyArray),
field_order(declaration, specifiers, source, export_kind, attributes, span),
)]
pub struct ExportNamedDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub declaration: Option<Declaration<'a>>,
pub specifiers: Vec<'a, ExportSpecifier<'a>>,
pub source: Option<StringLiteral<'a>>,
/// `export type { foo }`
#[ts]
pub export_kind: ImportOrExportKind,
}
/// Named re-export declaration.
///
/// ## Example
///
/// ```ts
/// export { Foo, Bar } from 'module';
/// export type { Baz } from 'baz';
/// ```
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, Dummy, ReplaceWith, TakeIn)]
#[generate_derive(ContentEq, ESTree, GetSpan, GetSpanMut, UnstableAddress)]
#[estree(
rename = "ExportNamedDeclaration",
ts_alias = "ExportNamedDeclaration",
add_fields(declaration = Null),
field_order(declaration, specifiers, source, export_kind, with_clause, span),
)]
pub struct ExportFromDeclaration<'a> {
pub node_id: Cell<NodeId>,
pub span: Span,
pub specifiers: Vec<'a, ExportSpecifier<'a>>,
pub source: StringLiteral<'a>,
/// `export type { foo } from 'module'`
#[ts]
pub export_kind: ImportOrExportKind,
/// Some(vec![]) for empty assertion
#[estree(rename = "attributes", via = ExportNamedDeclarationWithClause)]
#[estree(rename = "attributes", via = ExportFromDeclarationWithClause)]
pub with_clause: Option<Box<'a, WithClause<'a>>>,
}
+37 -6
View File
@@ -1902,7 +1902,9 @@ impl<'a> ModuleDeclaration<'a> {
match self {
ModuleDeclaration::ImportDeclaration(_) => false,
ModuleDeclaration::ExportDefaultDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportNamedDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportFromDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::ExportAllDeclaration(decl) => decl.is_typescript_syntax(),
ModuleDeclaration::TSNamespaceExportDeclaration(_)
| ModuleDeclaration::TSExportAssignment(_) => true,
@@ -1920,7 +1922,9 @@ impl<'a> ModuleDeclaration<'a> {
self,
Self::ExportAllDeclaration(_)
| Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::ExportFromDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_)
)
@@ -1942,8 +1946,10 @@ impl<'a> ModuleDeclaration<'a> {
match self {
Self::ImportDeclaration(decl) => Some(&decl.source),
Self::ExportAllDeclaration(decl) => Some(&decl.source),
Self::ExportNamedDeclaration(decl) => decl.source.as_ref(),
Self::ExportFromDeclaration(decl) => Some(&decl.source),
Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => None,
}
@@ -1960,8 +1966,10 @@ impl<'a> ModuleDeclaration<'a> {
match self {
Self::ImportDeclaration(decl) => decl.with_clause.as_deref(),
Self::ExportAllDeclaration(decl) => decl.with_clause.as_deref(),
Self::ExportNamedDeclaration(decl) => decl.with_clause.as_deref(),
Self::ExportFromDeclaration(decl) => decl.with_clause.as_deref(),
Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => None,
}
@@ -2009,11 +2017,34 @@ impl<'a> ImportAttributeKey<'a> {
}
}
impl ExportNamedDeclaration<'_> {
/// Returns `true` if this export declaration uses any TypeScript syntax (such as `type` or `declare`).
impl ExportDeclaration<'_> {
/// Returns the export kind derived from the wrapped declaration.
#[inline]
pub fn export_kind(&self) -> ImportOrExportKind {
if self.declaration.declare() || self.declaration.is_type() {
ImportOrExportKind::Type
} else {
ImportOrExportKind::Value
}
}
/// Returns `true` if this export declaration uses any TypeScript syntax.
pub fn is_typescript_syntax(&self) -> bool {
self.export_kind == ImportOrExportKind::Type
|| self.declaration.as_ref().is_some_and(Declaration::is_typescript_syntax)
self.declaration.is_typescript_syntax()
}
}
impl ExportNamedDeclaration<'_> {
/// Returns `true` if this is a TypeScript type-only export.
pub fn is_typescript_syntax(&self) -> bool {
self.export_kind.is_type()
}
}
impl ExportFromDeclaration<'_> {
/// Returns `true` if this is a TypeScript type-only re-export.
pub fn is_typescript_syntax(&self) -> bool {
self.export_kind.is_type()
}
}
+14
View File
@@ -65,7 +65,9 @@ impl<'a> AstKind<'a> {
match self {
Self::ImportDeclaration(decl) => Some(ModuleDeclarationKind::Import(decl)),
Self::ExportAllDeclaration(decl) => Some(ModuleDeclarationKind::ExportAll(decl)),
Self::ExportDeclaration(decl) => Some(ModuleDeclarationKind::Export(decl)),
Self::ExportNamedDeclaration(decl) => Some(ModuleDeclarationKind::ExportNamed(decl)),
Self::ExportFromDeclaration(decl) => Some(ModuleDeclarationKind::ExportFrom(decl)),
Self::ExportDefaultDeclaration(decl) => {
Some(ModuleDeclarationKind::ExportDefault(decl))
}
@@ -515,7 +517,9 @@ impl AstKind<'_> {
Self::ImportNamespaceSpecifier(_) => "ImportNamespaceSpecifier".into(),
Self::ImportAttribute(_) => "ImportAttribute".into(),
Self::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration".into(),
Self::ExportDeclaration(_) => "ExportDeclaration".into(),
Self::ExportNamedDeclaration(_) => "ExportNamedDeclaration".into(),
Self::ExportFromDeclaration(_) => "ExportFromDeclaration".into(),
Self::ExportAllDeclaration(_) => "ExportAllDeclaration".into(),
Self::WithClause(_) => "WithClause".into(),
Self::JSXOpeningElement(_) => "JSXOpeningElement".into(),
@@ -773,8 +777,12 @@ pub enum ModuleDeclarationKind<'a> {
Import(&'a ImportDeclaration<'a>),
/// An export all declaration like `export * from 'foo'`
ExportAll(&'a ExportAllDeclaration<'a>),
/// An exported declaration like `export const foo = 1`
Export(&'a ExportDeclaration<'a>),
/// A named export declaration like `export { foo, bar }`
ExportNamed(&'a ExportNamedDeclaration<'a>),
/// A named re-export declaration like `export { foo } from 'bar'`
ExportFrom(&'a ExportFromDeclaration<'a>),
/// A default export declaration like `export default foo`
ExportDefault(&'a ExportDefaultDeclaration<'a>),
/// A TypeScript export assignment like `export = foo`
@@ -789,7 +797,9 @@ impl ModuleDeclarationKind<'_> {
matches!(
self,
Self::ExportAll(_)
| Self::Export(_)
| Self::ExportNamed(_)
| Self::ExportFrom(_)
| Self::ExportDefault(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExport(_)
@@ -802,7 +812,9 @@ impl GetSpan for ModuleDeclarationKind<'_> {
match self {
Self::Import(decl) => decl.span,
Self::ExportAll(decl) => decl.span,
Self::Export(decl) => decl.span,
Self::ExportNamed(decl) => decl.span,
Self::ExportFrom(decl) => decl.span,
Self::ExportDefault(decl) => decl.span,
Self::TSExportAssignment(decl) => decl.span,
Self::TSNamespaceExport(decl) => decl.span,
@@ -816,7 +828,9 @@ impl GetAddress for ModuleDeclarationKind<'_> {
match *self {
Self::Import(decl) => decl.unstable_address(),
Self::ExportAll(decl) => decl.unstable_address(),
Self::Export(decl) => decl.unstable_address(),
Self::ExportNamed(decl) => decl.unstable_address(),
Self::ExportFrom(decl) => decl.unstable_address(),
Self::ExportDefault(decl) => decl.unstable_address(),
Self::TSExportAssignment(decl) => decl.unstable_address(),
Self::TSNamespaceExport(decl) => decl.unstable_address(),
+1 -56
View File
@@ -11,7 +11,7 @@
use std::{alloc::Layout, mem::MaybeUninit, slice, str};
use oxc_allocator::{Allocator, ArenaBox, ArenaVec, GetAllocator, IntoIn};
use oxc_allocator::{Allocator, ArenaBox, GetAllocator};
use oxc_span::{SPAN, Span};
use oxc_str::Str;
use oxc_syntax::{number::NumberBase, operator::UnaryOperator, scope::ScopeId};
@@ -177,61 +177,6 @@ impl<'a> Function<'a> {
}
}
impl<'a> ExportNamedDeclaration<'a> {
/// Build an [`ExportNamedDeclaration`] with no modifiers, containing a set of
/// [exported symbol names](ExportSpecifier), and store it in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `specifiers`
/// * `source`
#[inline]
pub fn boxed_plain<B: GetAstBuilder<'a>, V1>(
span: Span,
specifiers: V1,
source: Option<StringLiteral<'a>>,
builder: &B,
) -> ArenaBox<'a, Self>
where
V1: IntoIn<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
{
let builder = builder.builder();
ExportNamedDeclaration::boxed(
span,
None,
specifiers,
source,
ImportOrExportKind::Value,
None,
builder,
)
}
/// Build an [`ExportNamedDeclaration`] with no modifiers, wrapping a [`Declaration`],
/// and store it in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
#[inline]
pub fn boxed_plain_declaration<B: GetAstBuilder<'a>>(
span: Span,
declaration: Declaration<'a>,
builder: &B,
) -> ArenaBox<'a, Self> {
let builder = builder.builder();
ExportNamedDeclaration::boxed(
span,
Some(declaration),
[],
None,
ImportOrExportKind::Value,
None,
builder,
)
}
}
impl<'a> TemplateElement<'a> {
/// Build a [`TemplateElement`], escaping special characters in the raw value.
///
+38 -10
View File
@@ -909,16 +909,30 @@ const _: () = {
assert!(size_of::<ImportAttributeKey>() == 56);
assert!(align_of::<ImportAttributeKey>() == 8);
// Padding: 4 bytes
assert!(size_of::<ExportDeclaration>() == 32);
assert!(align_of::<ExportDeclaration>() == 8);
assert!(offset_of!(ExportDeclaration, span) == 0);
assert!(offset_of!(ExportDeclaration, node_id) == 8);
assert!(offset_of!(ExportDeclaration, declaration) == 16);
// Padding: 3 bytes
assert!(size_of::<ExportNamedDeclaration>() == 112);
assert!(size_of::<ExportNamedDeclaration>() == 40);
assert!(align_of::<ExportNamedDeclaration>() == 8);
assert!(offset_of!(ExportNamedDeclaration, span) == 0);
assert!(offset_of!(ExportNamedDeclaration, node_id) == 8);
assert!(offset_of!(ExportNamedDeclaration, export_kind) == 12);
assert!(offset_of!(ExportNamedDeclaration, declaration) == 16);
assert!(offset_of!(ExportNamedDeclaration, specifiers) == 32);
assert!(offset_of!(ExportNamedDeclaration, source) == 56);
assert!(offset_of!(ExportNamedDeclaration, with_clause) == 104);
assert!(offset_of!(ExportNamedDeclaration, specifiers) == 16);
// Padding: 3 bytes
assert!(size_of::<ExportFromDeclaration>() == 96);
assert!(align_of::<ExportFromDeclaration>() == 8);
assert!(offset_of!(ExportFromDeclaration, span) == 0);
assert!(offset_of!(ExportFromDeclaration, node_id) == 8);
assert!(offset_of!(ExportFromDeclaration, export_kind) == 12);
assert!(offset_of!(ExportFromDeclaration, specifiers) == 16);
assert!(offset_of!(ExportFromDeclaration, source) == 40);
assert!(offset_of!(ExportFromDeclaration, with_clause) == 88);
// Padding: 4 bytes
assert!(size_of::<ExportDefaultDeclaration>() == 32);
@@ -2726,16 +2740,30 @@ const _: () = if cfg!(target_family = "wasm") || align_of::<u64>() == 8 {
assert!(size_of::<ImportAttributeKey>() == 36);
assert!(align_of::<ImportAttributeKey>() == 4);
// Padding: 0 bytes
assert!(size_of::<ExportDeclaration>() == 20);
assert!(align_of::<ExportDeclaration>() == 4);
assert!(offset_of!(ExportDeclaration, span) == 0);
assert!(offset_of!(ExportDeclaration, node_id) == 8);
assert!(offset_of!(ExportDeclaration, declaration) == 12);
// Padding: 3 bytes
assert!(size_of::<ExportNamedDeclaration>() == 76);
assert!(size_of::<ExportNamedDeclaration>() == 32);
assert!(align_of::<ExportNamedDeclaration>() == 4);
assert!(offset_of!(ExportNamedDeclaration, span) == 0);
assert!(offset_of!(ExportNamedDeclaration, node_id) == 8);
assert!(offset_of!(ExportNamedDeclaration, export_kind) == 12);
assert!(offset_of!(ExportNamedDeclaration, declaration) == 16);
assert!(offset_of!(ExportNamedDeclaration, specifiers) == 24);
assert!(offset_of!(ExportNamedDeclaration, source) == 40);
assert!(offset_of!(ExportNamedDeclaration, with_clause) == 72);
assert!(offset_of!(ExportNamedDeclaration, specifiers) == 16);
// Padding: 3 bytes
assert!(size_of::<ExportFromDeclaration>() == 68);
assert!(align_of::<ExportFromDeclaration>() == 4);
assert!(offset_of!(ExportFromDeclaration, span) == 0);
assert!(offset_of!(ExportFromDeclaration, node_id) == 8);
assert!(offset_of!(ExportFromDeclaration, export_kind) == 12);
assert!(offset_of!(ExportFromDeclaration, specifiers) == 16);
assert!(offset_of!(ExportFromDeclaration, source) == 32);
assert!(offset_of!(ExportFromDeclaration, with_clause) == 64);
// Padding: 0 bytes
assert!(size_of::<ExportDefaultDeclaration>() == 20);
+192 -28
View File
@@ -9452,25 +9452,35 @@ impl<'a> Statement<'a> {
))
}
/// Build a [`Statement::ExportDeclaration`].
///
/// This node contains an [`ExportDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
#[inline]
pub fn new_export_declaration<B: GetAstBuilder<'a>>(
span: Span,
declaration: Declaration<'a>,
builder: &B,
) -> Self {
Self::ExportDeclaration(ExportDeclaration::boxed(span, declaration, builder.builder()))
}
/// Build a [`Statement::ExportNamedDeclaration`].
///
/// This node contains an [`ExportNamedDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo }`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new_export_named_declaration<B: GetAstBuilder<'a>, V1>(
span: Span,
declaration: Option<Declaration<'a>>,
specifiers: V1,
source: Option<StringLiteral<'a>>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
@@ -9478,7 +9488,36 @@ impl<'a> Statement<'a> {
{
Self::ExportNamedDeclaration(ExportNamedDeclaration::boxed(
span,
declaration,
specifiers,
export_kind,
builder.builder(),
))
}
/// Build a [`Statement::ExportFromDeclaration`].
///
/// This node contains an [`ExportFromDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo } from 'module'`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new_export_from_declaration<B: GetAstBuilder<'a>, V1>(
span: Span,
specifiers: V1,
source: StringLiteral<'a>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
V1: IntoIn<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
{
Self::ExportFromDeclaration(ExportFromDeclaration::boxed(
span,
specifiers,
source,
export_kind,
@@ -16264,25 +16303,35 @@ impl<'a> ModuleDeclaration<'a> {
))
}
/// Build a [`ModuleDeclaration::ExportDeclaration`].
///
/// This node contains an [`ExportDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
#[inline]
pub fn new_export_declaration<B: GetAstBuilder<'a>>(
span: Span,
declaration: Declaration<'a>,
builder: &B,
) -> Self {
Self::ExportDeclaration(ExportDeclaration::boxed(span, declaration, builder.builder()))
}
/// Build a [`ModuleDeclaration::ExportNamedDeclaration`].
///
/// This node contains an [`ExportNamedDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo }`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new_export_named_declaration<B: GetAstBuilder<'a>, V1>(
span: Span,
declaration: Option<Declaration<'a>>,
specifiers: V1,
source: Option<StringLiteral<'a>>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
@@ -16290,7 +16339,36 @@ impl<'a> ModuleDeclaration<'a> {
{
Self::ExportNamedDeclaration(ExportNamedDeclaration::boxed(
span,
declaration,
specifiers,
export_kind,
builder.builder(),
))
}
/// Build a [`ModuleDeclaration::ExportFromDeclaration`].
///
/// This node contains an [`ExportFromDeclaration`] that will be stored in the memory arena.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo } from 'module'`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new_export_from_declaration<B: GetAstBuilder<'a>, V1>(
span: Span,
specifiers: V1,
source: StringLiteral<'a>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
V1: IntoIn<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
{
Self::ExportFromDeclaration(ExportFromDeclaration::boxed(
span,
specifiers,
source,
export_kind,
@@ -16884,6 +16962,44 @@ impl<'a> ImportAttributeKey<'a> {
}
}
impl<'a> ExportDeclaration<'a> {
/// Build an [`ExportDeclaration`].
///
/// If you want the built node to be allocated in the memory arena,
/// use [`ExportDeclaration::boxed`] instead.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
#[inline]
pub fn new<B: GetAstBuilder<'a>>(
span: Span,
declaration: Declaration<'a>,
builder: &B,
) -> Self {
let builder = builder.builder();
ExportDeclaration { node_id: Cell::new(builder.node_id()), span, declaration }
}
/// Build an [`ExportDeclaration`], and store it in the memory arena.
///
/// Returns a [`Box`](ArenaBox) containing the newly-allocated node.
/// If you want a stack-allocated node, use [`ExportDeclaration::new`] instead.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
#[inline]
pub fn boxed<B: GetAstBuilder<'a>>(
span: Span,
declaration: Declaration<'a>,
builder: &B,
) -> ArenaBox<'a, Self> {
let builder = builder.builder();
ArenaBox::new_in(Self::new(span, declaration, builder), &builder.allocator())
}
}
impl<'a> ExportNamedDeclaration<'a> {
/// Build an [`ExportNamedDeclaration`].
///
@@ -16892,19 +17008,13 @@ impl<'a> ExportNamedDeclaration<'a> {
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo }`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new<B: GetAstBuilder<'a>, V1>(
span: Span,
declaration: Option<Declaration<'a>>,
specifiers: V1,
source: Option<StringLiteral<'a>>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
@@ -16914,11 +17024,8 @@ impl<'a> ExportNamedDeclaration<'a> {
ExportNamedDeclaration {
node_id: Cell::new(builder.node_id()),
span,
declaration,
specifiers: specifiers.into_in(builder.allocator()),
source,
export_kind,
with_clause,
}
}
@@ -16929,17 +17036,74 @@ impl<'a> ExportNamedDeclaration<'a> {
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `declaration`
/// * `specifiers`
/// * `export_kind`: `export type { foo }`
#[inline]
pub fn boxed<B: GetAstBuilder<'a>, V1>(
span: Span,
specifiers: V1,
export_kind: ImportOrExportKind,
builder: &B,
) -> ArenaBox<'a, Self>
where
V1: IntoIn<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
{
let builder = builder.builder();
ArenaBox::new_in(Self::new(span, specifiers, export_kind, builder), &builder.allocator())
}
}
impl<'a> ExportFromDeclaration<'a> {
/// Build an [`ExportFromDeclaration`].
///
/// If you want the built node to be allocated in the memory arena,
/// use [`ExportFromDeclaration::boxed`] instead.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo }`
/// * `export_kind`: `export type { foo } from 'module'`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn new<B: GetAstBuilder<'a>, V1>(
span: Span,
specifiers: V1,
source: StringLiteral<'a>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
) -> Self
where
V1: IntoIn<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
{
let builder = builder.builder();
ExportFromDeclaration {
node_id: Cell::new(builder.node_id()),
span,
specifiers: specifiers.into_in(builder.allocator()),
source,
export_kind,
with_clause,
}
}
/// Build an [`ExportFromDeclaration`], and store it in the memory arena.
///
/// Returns a [`Box`](ArenaBox) containing the newly-allocated node.
/// If you want a stack-allocated node, use [`ExportFromDeclaration::new`] instead.
///
/// ## Parameters
/// * `span`: The [`Span`] covering this node
/// * `specifiers`
/// * `source`
/// * `export_kind`: `export type { foo } from 'module'`
/// * `with_clause`: Some(vec![]) for empty assertion
#[inline]
pub fn boxed<B: GetAstBuilder<'a>, V1>(
span: Span,
declaration: Option<Declaration<'a>>,
specifiers: V1,
source: Option<StringLiteral<'a>>,
source: StringLiteral<'a>,
export_kind: ImportOrExportKind,
with_clause: Option<ArenaBox<'a, WithClause<'a>>>,
builder: &B,
@@ -16949,7 +17113,7 @@ impl<'a> ExportNamedDeclaration<'a> {
{
let builder = builder.builder();
ArenaBox::new_in(
Self::new(span, declaration, specifiers, source, export_kind, with_clause, builder),
Self::new(span, specifiers, source, export_kind, with_clause, builder),
&builder.allocator(),
)
}
+122 -100
View File
@@ -8,7 +8,7 @@ use oxc_syntax::node::NodeId;
use crate::ast::*;
/// The largest integer value that can be mapped to an `AstType`/`AstKind` enum variant.
pub const AST_TYPE_MAX: u8 = 188;
pub const AST_TYPE_MAX: u8 = 190;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(u8)]
@@ -103,105 +103,107 @@ pub enum AstType {
ImportNamespaceSpecifier = 87,
WithClause = 88,
ImportAttribute = 89,
ExportNamedDeclaration = 90,
ExportDefaultDeclaration = 91,
ExportAllDeclaration = 92,
ExportSpecifier = 93,
V8IntrinsicExpression = 94,
BooleanLiteral = 95,
NullLiteral = 96,
NumericLiteral = 97,
StringLiteral = 98,
BigIntLiteral = 99,
RegExpLiteral = 100,
JSXElement = 101,
JSXOpeningElement = 102,
JSXClosingElement = 103,
JSXFragment = 104,
JSXOpeningFragment = 105,
JSXClosingFragment = 106,
JSXNamespacedName = 107,
JSXMemberExpression = 108,
JSXExpressionContainer = 109,
JSXEmptyExpression = 110,
JSXAttribute = 111,
JSXSpreadAttribute = 112,
JSXIdentifier = 113,
JSXSpreadChild = 114,
JSXText = 115,
TSThisParameter = 116,
TSEnumDeclaration = 117,
TSEnumBody = 118,
TSEnumMember = 119,
TSTypeAnnotation = 120,
TSLiteralType = 121,
TSConditionalType = 122,
TSUnionType = 123,
TSIntersectionType = 124,
TSParenthesizedType = 125,
TSTypeOperator = 126,
TSArrayType = 127,
TSIndexedAccessType = 128,
TSTupleType = 129,
TSNamedTupleMember = 130,
TSOptionalType = 131,
TSRestType = 132,
TSAnyKeyword = 133,
TSStringKeyword = 134,
TSBooleanKeyword = 135,
TSNumberKeyword = 136,
TSNeverKeyword = 137,
TSIntrinsicKeyword = 138,
TSUnknownKeyword = 139,
TSNullKeyword = 140,
TSUndefinedKeyword = 141,
TSVoidKeyword = 142,
TSSymbolKeyword = 143,
TSThisType = 144,
TSObjectKeyword = 145,
TSBigIntKeyword = 146,
TSTypeReference = 147,
TSQualifiedName = 148,
TSTypeParameterInstantiation = 149,
TSTypeParameter = 150,
TSTypeParameterDeclaration = 151,
TSTypeAliasDeclaration = 152,
TSClassImplements = 153,
TSInterfaceDeclaration = 154,
TSInterfaceBody = 155,
TSPropertySignature = 156,
TSIndexSignature = 157,
TSCallSignatureDeclaration = 158,
TSMethodSignature = 159,
TSConstructSignatureDeclaration = 160,
TSIndexSignatureName = 161,
TSInterfaceHeritage = 162,
TSTypePredicate = 163,
TSModuleDeclaration = 164,
TSGlobalDeclaration = 165,
TSModuleBlock = 166,
TSTypeLiteral = 167,
TSInferType = 168,
TSTypeQuery = 169,
TSImportType = 170,
TSImportTypeQualifiedName = 171,
TSFunctionType = 172,
TSConstructorType = 173,
TSMappedType = 174,
TSTemplateLiteralType = 175,
TSAsExpression = 176,
TSSatisfiesExpression = 177,
TSTypeAssertion = 178,
TSImportEqualsDeclaration = 179,
TSExternalModuleReference = 180,
TSNonNullExpression = 181,
Decorator = 182,
TSExportAssignment = 183,
TSNamespaceExportDeclaration = 184,
TSInstantiationExpression = 185,
JSDocNullableType = 186,
JSDocNonNullableType = 187,
JSDocUnknownType = 188,
ExportDeclaration = 90,
ExportNamedDeclaration = 91,
ExportFromDeclaration = 92,
ExportDefaultDeclaration = 93,
ExportAllDeclaration = 94,
ExportSpecifier = 95,
V8IntrinsicExpression = 96,
BooleanLiteral = 97,
NullLiteral = 98,
NumericLiteral = 99,
StringLiteral = 100,
BigIntLiteral = 101,
RegExpLiteral = 102,
JSXElement = 103,
JSXOpeningElement = 104,
JSXClosingElement = 105,
JSXFragment = 106,
JSXOpeningFragment = 107,
JSXClosingFragment = 108,
JSXNamespacedName = 109,
JSXMemberExpression = 110,
JSXExpressionContainer = 111,
JSXEmptyExpression = 112,
JSXAttribute = 113,
JSXSpreadAttribute = 114,
JSXIdentifier = 115,
JSXSpreadChild = 116,
JSXText = 117,
TSThisParameter = 118,
TSEnumDeclaration = 119,
TSEnumBody = 120,
TSEnumMember = 121,
TSTypeAnnotation = 122,
TSLiteralType = 123,
TSConditionalType = 124,
TSUnionType = 125,
TSIntersectionType = 126,
TSParenthesizedType = 127,
TSTypeOperator = 128,
TSArrayType = 129,
TSIndexedAccessType = 130,
TSTupleType = 131,
TSNamedTupleMember = 132,
TSOptionalType = 133,
TSRestType = 134,
TSAnyKeyword = 135,
TSStringKeyword = 136,
TSBooleanKeyword = 137,
TSNumberKeyword = 138,
TSNeverKeyword = 139,
TSIntrinsicKeyword = 140,
TSUnknownKeyword = 141,
TSNullKeyword = 142,
TSUndefinedKeyword = 143,
TSVoidKeyword = 144,
TSSymbolKeyword = 145,
TSThisType = 146,
TSObjectKeyword = 147,
TSBigIntKeyword = 148,
TSTypeReference = 149,
TSQualifiedName = 150,
TSTypeParameterInstantiation = 151,
TSTypeParameter = 152,
TSTypeParameterDeclaration = 153,
TSTypeAliasDeclaration = 154,
TSClassImplements = 155,
TSInterfaceDeclaration = 156,
TSInterfaceBody = 157,
TSPropertySignature = 158,
TSIndexSignature = 159,
TSCallSignatureDeclaration = 160,
TSMethodSignature = 161,
TSConstructSignatureDeclaration = 162,
TSIndexSignatureName = 163,
TSInterfaceHeritage = 164,
TSTypePredicate = 165,
TSModuleDeclaration = 166,
TSGlobalDeclaration = 167,
TSModuleBlock = 168,
TSTypeLiteral = 169,
TSInferType = 170,
TSTypeQuery = 171,
TSImportType = 172,
TSImportTypeQualifiedName = 173,
TSFunctionType = 174,
TSConstructorType = 175,
TSMappedType = 176,
TSTemplateLiteralType = 177,
TSAsExpression = 178,
TSSatisfiesExpression = 179,
TSTypeAssertion = 180,
TSImportEqualsDeclaration = 181,
TSExternalModuleReference = 182,
TSNonNullExpression = 183,
Decorator = 184,
TSExportAssignment = 185,
TSNamespaceExportDeclaration = 186,
TSInstantiationExpression = 187,
JSDocNullableType = 188,
JSDocNonNullableType = 189,
JSDocUnknownType = 190,
}
/// Untyped AST Node Kind
@@ -306,7 +308,9 @@ pub enum AstKind<'a> {
AstType::ImportNamespaceSpecifier as u8,
WithClause(&'a WithClause<'a>) = AstType::WithClause as u8,
ImportAttribute(&'a ImportAttribute<'a>) = AstType::ImportAttribute as u8,
ExportDeclaration(&'a ExportDeclaration<'a>) = AstType::ExportDeclaration as u8,
ExportNamedDeclaration(&'a ExportNamedDeclaration<'a>) = AstType::ExportNamedDeclaration as u8,
ExportFromDeclaration(&'a ExportFromDeclaration<'a>) = AstType::ExportFromDeclaration as u8,
ExportDefaultDeclaration(&'a ExportDefaultDeclaration<'a>) =
AstType::ExportDefaultDeclaration as u8,
ExportAllDeclaration(&'a ExportAllDeclaration<'a>) = AstType::ExportAllDeclaration as u8,
@@ -513,7 +517,9 @@ impl AstKind<'_> {
Self::ImportNamespaceSpecifier(it) => it.node_id(),
Self::WithClause(it) => it.node_id(),
Self::ImportAttribute(it) => it.node_id(),
Self::ExportDeclaration(it) => it.node_id(),
Self::ExportNamedDeclaration(it) => it.node_id(),
Self::ExportFromDeclaration(it) => it.node_id(),
Self::ExportDefaultDeclaration(it) => it.node_id(),
Self::ExportAllDeclaration(it) => it.node_id(),
Self::ExportSpecifier(it) => it.node_id(),
@@ -710,7 +716,9 @@ impl AstKind<'_> {
Self::ImportNamespaceSpecifier(it) => it.set_node_id(node_id),
Self::WithClause(it) => it.set_node_id(node_id),
Self::ImportAttribute(it) => it.set_node_id(node_id),
Self::ExportDeclaration(it) => it.set_node_id(node_id),
Self::ExportNamedDeclaration(it) => it.set_node_id(node_id),
Self::ExportFromDeclaration(it) => it.set_node_id(node_id),
Self::ExportDefaultDeclaration(it) => it.set_node_id(node_id),
Self::ExportAllDeclaration(it) => it.set_node_id(node_id),
Self::ExportSpecifier(it) => it.set_node_id(node_id),
@@ -909,7 +917,9 @@ impl GetSpan for AstKind<'_> {
Self::ImportNamespaceSpecifier(it) => it.span(),
Self::WithClause(it) => it.span(),
Self::ImportAttribute(it) => it.span(),
Self::ExportDeclaration(it) => it.span(),
Self::ExportNamedDeclaration(it) => it.span(),
Self::ExportFromDeclaration(it) => it.span(),
Self::ExportDefaultDeclaration(it) => it.span(),
Self::ExportAllDeclaration(it) => it.span(),
Self::ExportSpecifier(it) => it.span(),
@@ -1109,7 +1119,9 @@ impl GetAddress for AstKind<'_> {
Self::ImportNamespaceSpecifier(it) => it.unstable_address(),
Self::WithClause(it) => it.unstable_address(),
Self::ImportAttribute(it) => it.unstable_address(),
Self::ExportDeclaration(it) => it.unstable_address(),
Self::ExportNamedDeclaration(it) => it.unstable_address(),
Self::ExportFromDeclaration(it) => it.unstable_address(),
Self::ExportDefaultDeclaration(it) => it.unstable_address(),
Self::ExportAllDeclaration(it) => it.unstable_address(),
Self::ExportSpecifier(it) => it.unstable_address(),
@@ -1667,11 +1679,21 @@ impl<'a> AstKind<'a> {
if let Self::ImportAttribute(v) = self { Some(v) } else { None }
}
#[inline]
pub fn as_export_declaration(self) -> Option<&'a ExportDeclaration<'a>> {
if let Self::ExportDeclaration(v) = self { Some(v) } else { None }
}
#[inline]
pub fn as_export_named_declaration(self) -> Option<&'a ExportNamedDeclaration<'a>> {
if let Self::ExportNamedDeclaration(v) = self { Some(v) } else { None }
}
#[inline]
pub fn as_export_from_declaration(self) -> Option<&'a ExportFromDeclaration<'a>> {
if let Self::ExportFromDeclaration(v) = self { Some(v) } else { None }
}
#[inline]
pub fn as_export_default_declaration(self) -> Option<&'a ExportDefaultDeclaration<'a>> {
if let Self::ExportDefaultDeclaration(v) = self { Some(v) } else { None }
@@ -1414,7 +1414,9 @@ impl<'new_alloc> CloneIn<'new_alloc> for Statement<'_> {
Self::ImportDeclaration(_)
| Self::ExportAllDeclaration(_)
| Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::ExportFromDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => Statement::from(CloneIn::clone_in_impl(
self.to_module_declaration(),
@@ -2672,9 +2674,15 @@ impl<'new_alloc> CloneIn<'new_alloc> for ModuleDeclaration<'_> {
Self::ExportDefaultDeclaration(it) => ModuleDeclaration::ExportDefaultDeclaration(
CloneIn::clone_in_impl(it, with_semantic_ids, allocator),
),
Self::ExportDeclaration(it) => ModuleDeclaration::ExportDeclaration(
CloneIn::clone_in_impl(it, with_semantic_ids, allocator),
),
Self::ExportNamedDeclaration(it) => ModuleDeclaration::ExportNamedDeclaration(
CloneIn::clone_in_impl(it, with_semantic_ids, allocator),
),
Self::ExportFromDeclaration(it) => ModuleDeclaration::ExportFromDeclaration(
CloneIn::clone_in_impl(it, with_semantic_ids, allocator),
),
Self::TSExportAssignment(it) => ModuleDeclaration::TSExportAssignment(
CloneIn::clone_in_impl(it, with_semantic_ids, allocator),
),
@@ -2932,6 +2940,22 @@ impl<'new_alloc> CloneIn<'new_alloc> for ImportAttributeKey<'_> {
}
}
impl<'new_alloc> CloneIn<'new_alloc> for ExportDeclaration<'_> {
type Cloned = ExportDeclaration<'new_alloc>;
fn clone_in_impl(
&self,
with_semantic_ids: CloneInSemanticIds,
allocator: &'new_alloc Allocator,
) -> Self::Cloned {
ExportDeclaration {
node_id: CloneIn::clone_in_impl(&self.node_id, with_semantic_ids, allocator),
span: CloneIn::clone_in_impl(&self.span, with_semantic_ids, allocator),
declaration: CloneIn::clone_in_impl(&self.declaration, with_semantic_ids, allocator),
}
}
}
impl<'new_alloc> CloneIn<'new_alloc> for ExportNamedDeclaration<'_> {
type Cloned = ExportNamedDeclaration<'new_alloc>;
@@ -2943,7 +2967,23 @@ impl<'new_alloc> CloneIn<'new_alloc> for ExportNamedDeclaration<'_> {
ExportNamedDeclaration {
node_id: CloneIn::clone_in_impl(&self.node_id, with_semantic_ids, allocator),
span: CloneIn::clone_in_impl(&self.span, with_semantic_ids, allocator),
declaration: CloneIn::clone_in_impl(&self.declaration, with_semantic_ids, allocator),
specifiers: CloneIn::clone_in_impl(&self.specifiers, with_semantic_ids, allocator),
export_kind: CloneIn::clone_in_impl(&self.export_kind, with_semantic_ids, allocator),
}
}
}
impl<'new_alloc> CloneIn<'new_alloc> for ExportFromDeclaration<'_> {
type Cloned = ExportFromDeclaration<'new_alloc>;
fn clone_in_impl(
&self,
with_semantic_ids: CloneInSemanticIds,
allocator: &'new_alloc Allocator,
) -> Self::Cloned {
ExportFromDeclaration {
node_id: CloneIn::clone_in_impl(&self.node_id, with_semantic_ids, allocator),
span: CloneIn::clone_in_impl(&self.span, with_semantic_ids, allocator),
specifiers: CloneIn::clone_in_impl(&self.specifiers, with_semantic_ids, allocator),
source: CloneIn::clone_in_impl(&self.source, with_semantic_ids, allocator),
export_kind: CloneIn::clone_in_impl(&self.export_kind, with_semantic_ids, allocator),
@@ -707,7 +707,9 @@ impl ContentEq for Statement<'_> {
(Self::ExportDefaultDeclaration(a), Self::ExportDefaultDeclaration(b)) => {
a.content_eq(b)
}
(Self::ExportDeclaration(a), Self::ExportDeclaration(b)) => a.content_eq(b),
(Self::ExportNamedDeclaration(a), Self::ExportNamedDeclaration(b)) => a.content_eq(b),
(Self::ExportFromDeclaration(a), Self::ExportFromDeclaration(b)) => a.content_eq(b),
(Self::TSExportAssignment(a), Self::TSExportAssignment(b)) => a.content_eq(b),
(Self::TSNamespaceExportDeclaration(a), Self::TSNamespaceExportDeclaration(b)) => {
a.content_eq(b)
@@ -1303,7 +1305,9 @@ impl ContentEq for ModuleDeclaration<'_> {
(Self::ExportDefaultDeclaration(a), Self::ExportDefaultDeclaration(b)) => {
a.content_eq(b)
}
(Self::ExportDeclaration(a), Self::ExportDeclaration(b)) => a.content_eq(b),
(Self::ExportNamedDeclaration(a), Self::ExportNamedDeclaration(b)) => a.content_eq(b),
(Self::ExportFromDeclaration(a), Self::ExportFromDeclaration(b)) => a.content_eq(b),
(Self::TSExportAssignment(a), Self::TSExportAssignment(b)) => a.content_eq(b),
(Self::TSNamespaceExportDeclaration(a), Self::TSNamespaceExportDeclaration(b)) => {
a.content_eq(b)
@@ -1421,10 +1425,22 @@ impl ContentEq for ImportAttributeKey<'_> {
}
}
impl ContentEq for ExportNamedDeclaration<'_> {
impl ContentEq for ExportDeclaration<'_> {
fn content_eq(&self, other: &Self) -> bool {
ContentEq::content_eq(&self.declaration, &other.declaration)
&& ContentEq::content_eq(&self.specifiers, &other.specifiers)
}
}
impl ContentEq for ExportNamedDeclaration<'_> {
fn content_eq(&self, other: &Self) -> bool {
ContentEq::content_eq(&self.specifiers, &other.specifiers)
&& ContentEq::content_eq(&self.export_kind, &other.export_kind)
}
}
impl ContentEq for ExportFromDeclaration<'_> {
fn content_eq(&self, other: &Self) -> bool {
ContentEq::content_eq(&self.specifiers, &other.specifiers)
&& ContentEq::content_eq(&self.source, &other.source)
&& ContentEq::content_eq(&self.export_kind, &other.export_kind)
&& ContentEq::content_eq(&self.with_clause, &other.with_clause)
+29 -3
View File
@@ -1466,9 +1466,9 @@ impl<'a> Dummy<'a> for StaticBlock<'a> {
impl<'a> Dummy<'a> for ModuleDeclaration<'a> {
/// Create a dummy [`ModuleDeclaration`].
///
/// Has cost of making 2 allocations (48 bytes).
/// Has cost of making 1 allocation (40 bytes).
fn dummy(allocator: &'a Allocator) -> Self {
Self::ExportDefaultDeclaration(Dummy::dummy(allocator))
Self::ExportNamedDeclaration(Dummy::dummy(allocator))
}
}
@@ -1643,6 +1643,19 @@ impl<'a> Dummy<'a> for ImportAttributeKey<'a> {
}
}
impl<'a> Dummy<'a> for ExportDeclaration<'a> {
/// Create a dummy [`ExportDeclaration`].
///
/// Has cost of making 1 allocation (40 bytes).
fn dummy(allocator: &'a Allocator) -> Self {
Self {
node_id: Dummy::dummy(allocator),
span: Dummy::dummy(allocator),
declaration: Dummy::dummy(allocator),
}
}
}
impl<'a> Dummy<'a> for ExportNamedDeclaration<'a> {
/// Create a dummy [`ExportNamedDeclaration`].
///
@@ -1651,7 +1664,20 @@ impl<'a> Dummy<'a> for ExportNamedDeclaration<'a> {
Self {
node_id: Dummy::dummy(allocator),
span: Dummy::dummy(allocator),
declaration: Dummy::dummy(allocator),
specifiers: Dummy::dummy(allocator),
export_kind: Dummy::dummy(allocator),
}
}
}
impl<'a> Dummy<'a> for ExportFromDeclaration<'a> {
/// Create a dummy [`ExportFromDeclaration`].
///
/// Does not allocate any data into arena.
fn dummy(allocator: &'a Allocator) -> Self {
Self {
node_id: Dummy::dummy(allocator),
span: Dummy::dummy(allocator),
specifiers: Dummy::dummy(allocator),
source: Dummy::dummy(allocator),
export_kind: Dummy::dummy(allocator),
+37 -2
View File
@@ -831,7 +831,9 @@ impl ESTree for Statement<'_> {
Self::ImportDeclaration(_)
| Self::ExportAllDeclaration(_)
| Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::ExportFromDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_) => {
self.to_module_declaration().serialize(serializer)
@@ -1600,7 +1602,9 @@ impl ESTree for ModuleDeclaration<'_> {
Self::ImportDeclaration(it) => it.serialize(serializer),
Self::ExportAllDeclaration(it) => it.serialize(serializer),
Self::ExportDefaultDeclaration(it) => it.serialize(serializer),
Self::ExportDeclaration(it) => it.serialize(serializer),
Self::ExportNamedDeclaration(it) => it.serialize(serializer),
Self::ExportFromDeclaration(it) => it.serialize(serializer),
Self::TSExportAssignment(it) => it.serialize(serializer),
Self::TSNamespaceExportDeclaration(it) => it.serialize(serializer),
}
@@ -1750,17 +1754,48 @@ impl ESTree for ImportAttributeKey<'_> {
}
}
impl ESTree for ExportNamedDeclaration<'_> {
impl ESTree for ExportDeclaration<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("ExportNamedDeclaration"));
state.serialize_field("declaration", &self.declaration);
state.serialize_field("specifiers", &crate::serialize::basic::EmptyArray(self));
state.serialize_field("source", &crate::serialize::basic::Null(self));
state.serialize_ts_field(
"exportKind",
&crate::serialize::js::ExportDeclarationExportKind(self),
);
state.serialize_field("attributes", &crate::serialize::basic::EmptyArray(self));
state.serialize_span(self.span);
state.end();
}
}
impl ESTree for ExportNamedDeclaration<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("ExportNamedDeclaration"));
state.serialize_field("declaration", &crate::serialize::basic::Null(self));
state.serialize_field("specifiers", &self.specifiers);
state.serialize_field("source", &crate::serialize::basic::Null(self));
state.serialize_ts_field("exportKind", &self.export_kind);
state.serialize_field("attributes", &crate::serialize::basic::EmptyArray(self));
state.serialize_span(self.span);
state.end();
}
}
impl ESTree for ExportFromDeclaration<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
let mut state = serializer.serialize_struct();
state.serialize_field("type", &JsonSafeString("ExportNamedDeclaration"));
state.serialize_field("declaration", &crate::serialize::basic::Null(self));
state.serialize_field("specifiers", &self.specifiers);
state.serialize_field("source", &self.source);
state.serialize_ts_field("exportKind", &self.export_kind);
state.serialize_field(
"attributes",
&crate::serialize::js::ExportNamedDeclarationWithClause(self),
&crate::serialize::js::ExportFromDeclarationWithClause(self),
);
state.serialize_span(self.span);
state.end();
@@ -321,7 +321,9 @@ impl GetAddress for Statement<'_> {
Self::ImportDeclaration(it) => GetAddress::address(it),
Self::ExportAllDeclaration(it) => GetAddress::address(it),
Self::ExportDefaultDeclaration(it) => GetAddress::address(it),
Self::ExportDeclaration(it) => GetAddress::address(it),
Self::ExportNamedDeclaration(it) => GetAddress::address(it),
Self::ExportFromDeclaration(it) => GetAddress::address(it),
Self::TSExportAssignment(it) => GetAddress::address(it),
Self::TSNamespaceExportDeclaration(it) => GetAddress::address(it),
}
@@ -509,7 +511,9 @@ impl GetAddress for ModuleDeclaration<'_> {
Self::ImportDeclaration(it) => GetAddress::address(it),
Self::ExportAllDeclaration(it) => GetAddress::address(it),
Self::ExportDefaultDeclaration(it) => GetAddress::address(it),
Self::ExportDeclaration(it) => GetAddress::address(it),
Self::ExportNamedDeclaration(it) => GetAddress::address(it),
Self::ExportFromDeclaration(it) => GetAddress::address(it),
Self::TSExportAssignment(it) => GetAddress::address(it),
Self::TSNamespaceExportDeclaration(it) => GetAddress::address(it),
}
@@ -625,7 +625,9 @@ impl GetSpan for Statement<'_> {
Self::ImportDeclaration(it) => GetSpan::span(&**it),
Self::ExportAllDeclaration(it) => GetSpan::span(&**it),
Self::ExportDefaultDeclaration(it) => GetSpan::span(&**it),
Self::ExportDeclaration(it) => GetSpan::span(&**it),
Self::ExportNamedDeclaration(it) => GetSpan::span(&**it),
Self::ExportFromDeclaration(it) => GetSpan::span(&**it),
Self::TSExportAssignment(it) => GetSpan::span(&**it),
Self::TSNamespaceExportDeclaration(it) => GetSpan::span(&**it),
}
@@ -1100,7 +1102,9 @@ impl GetSpan for ModuleDeclaration<'_> {
Self::ImportDeclaration(it) => GetSpan::span(&**it),
Self::ExportAllDeclaration(it) => GetSpan::span(&**it),
Self::ExportDefaultDeclaration(it) => GetSpan::span(&**it),
Self::ExportDeclaration(it) => GetSpan::span(&**it),
Self::ExportNamedDeclaration(it) => GetSpan::span(&**it),
Self::ExportFromDeclaration(it) => GetSpan::span(&**it),
Self::TSExportAssignment(it) => GetSpan::span(&**it),
Self::TSNamespaceExportDeclaration(it) => GetSpan::span(&**it),
}
@@ -1182,6 +1186,13 @@ impl GetSpan for ImportAttributeKey<'_> {
}
}
impl GetSpan for ExportDeclaration<'_> {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl GetSpan for ExportNamedDeclaration<'_> {
#[inline]
fn span(&self) -> Span {
@@ -1189,6 +1200,13 @@ impl GetSpan for ExportNamedDeclaration<'_> {
}
}
impl GetSpan for ExportFromDeclaration<'_> {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl GetSpan for ExportDefaultDeclaration<'_> {
#[inline]
fn span(&self) -> Span {
@@ -624,7 +624,9 @@ impl GetSpanMut for Statement<'_> {
Self::ImportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportAllDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportDefaultDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportNamedDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportFromDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::TSExportAssignment(it) => GetSpanMut::span_mut(&mut **it),
Self::TSNamespaceExportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
}
@@ -1099,7 +1101,9 @@ impl GetSpanMut for ModuleDeclaration<'_> {
Self::ImportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportAllDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportDefaultDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportNamedDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::ExportFromDeclaration(it) => GetSpanMut::span_mut(&mut **it),
Self::TSExportAssignment(it) => GetSpanMut::span_mut(&mut **it),
Self::TSNamespaceExportDeclaration(it) => GetSpanMut::span_mut(&mut **it),
}
@@ -1181,6 +1185,13 @@ impl GetSpanMut for ImportAttributeKey<'_> {
}
}
impl GetSpanMut for ExportDeclaration<'_> {
#[inline]
fn span_mut(&mut self) -> &mut Span {
&mut self.span
}
}
impl GetSpanMut for ExportNamedDeclaration<'_> {
#[inline]
fn span_mut(&mut self) -> &mut Span {
@@ -1188,6 +1199,13 @@ impl GetSpanMut for ExportNamedDeclaration<'_> {
}
}
impl GetSpanMut for ExportFromDeclaration<'_> {
#[inline]
fn span_mut(&mut self) -> &mut Span {
&mut self.span
}
}
impl GetSpanMut for ExportDefaultDeclaration<'_> {
#[inline]
fn span_mut(&mut self) -> &mut Span {
@@ -234,8 +234,12 @@ impl<'a> ReplaceWith<'a> for ImportAttribute<'a> {}
impl<'a> ReplaceWith<'a> for ImportAttributeKey<'a> {}
impl<'a> ReplaceWith<'a> for ExportDeclaration<'a> {}
impl<'a> ReplaceWith<'a> for ExportNamedDeclaration<'a> {}
impl<'a> ReplaceWith<'a> for ExportFromDeclaration<'a> {}
impl<'a> ReplaceWith<'a> for ExportDefaultDeclaration<'a> {}
impl<'a> ReplaceWith<'a> for ExportAllDeclaration<'a> {}
@@ -236,8 +236,12 @@ impl<'a> TakeIn<'a> for ImportAttribute<'a> {}
impl<'a> TakeIn<'a> for ImportAttributeKey<'a> {}
impl<'a> TakeIn<'a> for ExportDeclaration<'a> {}
impl<'a> TakeIn<'a> for ExportNamedDeclaration<'a> {}
impl<'a> TakeIn<'a> for ExportFromDeclaration<'a> {}
impl<'a> TakeIn<'a> for ExportDefaultDeclaration<'a> {}
impl<'a> TakeIn<'a> for ExportAllDeclaration<'a> {}
@@ -188,8 +188,12 @@ impl UnstableAddress for WithClause<'_> {}
impl UnstableAddress for ImportAttribute<'_> {}
impl UnstableAddress for ExportDeclaration<'_> {}
impl UnstableAddress for ExportNamedDeclaration<'_> {}
impl UnstableAddress for ExportFromDeclaration<'_> {}
impl UnstableAddress for ExportDefaultDeclaration<'_> {}
impl UnstableAddress for ExportAllDeclaration<'_> {}
+36
View File
@@ -1685,6 +1685,22 @@ impl ImportAttribute<'_> {
}
}
impl ExportDeclaration<'_> {
/// Get [`NodeId`] of [`ExportDeclaration`].
///
/// Only use this method on a post-semantic AST where [`NodeId`]s are always defined.
#[inline]
pub fn node_id(&self) -> NodeId {
self.node_id.get()
}
/// Set [`NodeId`] of [`ExportDeclaration`].
#[inline]
pub fn set_node_id(&self, node_id: NodeId) {
self.node_id.set(node_id);
}
}
impl ExportNamedDeclaration<'_> {
/// Get [`NodeId`] of [`ExportNamedDeclaration`].
///
@@ -1701,6 +1717,22 @@ impl ExportNamedDeclaration<'_> {
}
}
impl ExportFromDeclaration<'_> {
/// Get [`NodeId`] of [`ExportFromDeclaration`].
///
/// Only use this method on a post-semantic AST where [`NodeId`]s are always defined.
#[inline]
pub fn node_id(&self) -> NodeId {
self.node_id.get()
}
/// Set [`NodeId`] of [`ExportFromDeclaration`].
#[inline]
pub fn set_node_id(&self, node_id: NodeId) {
self.node_id.set(node_id);
}
}
impl ExportDefaultDeclaration<'_> {
/// Get [`NodeId`] of [`ExportDefaultDeclaration`].
///
@@ -3853,7 +3885,9 @@ impl Statement<'_> {
Self::ImportDeclaration(it) => it.node_id(),
Self::ExportAllDeclaration(it) => it.node_id(),
Self::ExportDefaultDeclaration(it) => it.node_id(),
Self::ExportDeclaration(it) => it.node_id(),
Self::ExportNamedDeclaration(it) => it.node_id(),
Self::ExportFromDeclaration(it) => it.node_id(),
Self::TSExportAssignment(it) => it.node_id(),
Self::TSNamespaceExportDeclaration(it) => it.node_id(),
}
@@ -4048,7 +4082,9 @@ impl ModuleDeclaration<'_> {
Self::ImportDeclaration(it) => it.node_id(),
Self::ExportAllDeclaration(it) => it.node_id(),
Self::ExportDefaultDeclaration(it) => it.node_id(),
Self::ExportDeclaration(it) => it.node_id(),
Self::ExportNamedDeclaration(it) => it.node_id(),
Self::ExportFromDeclaration(it) => it.node_id(),
Self::TSExportAssignment(it) => it.node_id(),
Self::TSNamespaceExportDeclaration(it) => it.node_id(),
}
@@ -2766,7 +2766,9 @@ impl<'a> Statement<'a> {
Self::ImportDeclaration(_)
| Self::ExportAllDeclaration(_)
| Self::ExportDefaultDeclaration(_)
| Self::ExportDeclaration(_)
| Self::ExportNamedDeclaration(_)
| Self::ExportFromDeclaration(_)
| Self::TSExportAssignment(_)
| Self::TSNamespaceExportDeclaration(_)
)
@@ -2866,9 +2868,11 @@ impl<'a> TryFrom<Statement<'a>> for ModuleDeclaration<'a> {
Statement::ExportDefaultDeclaration(o) => {
Ok(ModuleDeclaration::ExportDefaultDeclaration(o))
}
Statement::ExportDeclaration(o) => Ok(ModuleDeclaration::ExportDeclaration(o)),
Statement::ExportNamedDeclaration(o) => {
Ok(ModuleDeclaration::ExportNamedDeclaration(o))
}
Statement::ExportFromDeclaration(o) => Ok(ModuleDeclaration::ExportFromDeclaration(o)),
Statement::TSExportAssignment(o) => Ok(ModuleDeclaration::TSExportAssignment(o)),
Statement::TSNamespaceExportDeclaration(o) => {
Ok(ModuleDeclaration::TSNamespaceExportDeclaration(o))
@@ -2890,7 +2894,9 @@ impl<'a> From<ModuleDeclaration<'a>> for Statement<'a> {
ModuleDeclaration::ExportDefaultDeclaration(o) => {
Statement::ExportDefaultDeclaration(o)
}
ModuleDeclaration::ExportDeclaration(o) => Statement::ExportDeclaration(o),
ModuleDeclaration::ExportNamedDeclaration(o) => Statement::ExportNamedDeclaration(o),
ModuleDeclaration::ExportFromDeclaration(o) => Statement::ExportFromDeclaration(o),
ModuleDeclaration::TSExportAssignment(o) => Statement::TSExportAssignment(o),
ModuleDeclaration::TSNamespaceExportDeclaration(o) => {
Statement::TSNamespaceExportDeclaration(o)
@@ -5612,7 +5618,9 @@ macro_rules! match_module_declaration {
$ty::ImportDeclaration(_)
| $ty::ExportAllDeclaration(_)
| $ty::ExportDefaultDeclaration(_)
| $ty::ExportDeclaration(_)
| $ty::ExportNamedDeclaration(_)
| $ty::ExportFromDeclaration(_)
| $ty::TSExportAssignment(_)
| $ty::TSNamespaceExportDeclaration(_)
};
+18 -3
View File
@@ -739,7 +739,7 @@ impl ESTree for ImportDeclarationSpecifiers<'_, '_> {
}
}
// Serializers for `with_clause` field of `ImportDeclaration`, `ExportNamedDeclaration`,
// Serializers for `with_clause` field of `ImportDeclaration`, `ExportFromDeclaration`,
// and `ExportAllDeclaration` (which are renamed to `attributes` in ESTree AST).
//
// Serialize only the `with_entries` field of `WithClause`, and serialize `None` as empty array (`[]`).
@@ -775,9 +775,9 @@ impl ESTree for ImportDeclarationWithClause<'_, '_> {
withClause === null ? [] : withClause.attributes
"
)]
pub struct ExportNamedDeclarationWithClause<'a, 'b>(pub &'b ExportNamedDeclaration<'a>);
pub struct ExportFromDeclarationWithClause<'a, 'b>(pub &'b ExportFromDeclaration<'a>);
impl ESTree for ExportNamedDeclarationWithClause<'_, '_> {
impl ESTree for ExportFromDeclarationWithClause<'_, '_> {
fn serialize<S: Serializer>(&self, serializer: S) {
if let Some(with_clause) = &self.0.with_clause {
with_clause.with_entries.serialize(serializer);
@@ -787,6 +787,21 @@ impl ESTree for ExportNamedDeclarationWithClause<'_, '_> {
}
}
/// Serializer for the derived `exportKind` field of [`ExportDeclaration`].
#[ast_meta]
#[estree(
ts_type = "ImportOrExportKind",
raw_deser = "(THIS.declaration.declare === true || THIS.declaration.type === 'TSTypeAliasDeclaration' || THIS.declaration.type === 'TSInterfaceDeclaration') ? 'type' : 'value'"
)]
#[ts]
pub struct ExportDeclarationExportKind<'a, 'b>(pub &'b ExportDeclaration<'a>);
impl ESTree for ExportDeclarationExportKind<'_, '_> {
fn serialize<S: Serializer>(&self, serializer: S) {
self.0.export_kind().serialize(serializer);
}
}
#[ast_meta]
#[estree(
ts_type = "Array<ImportAttribute>",
+4 -4
View File
@@ -86,10 +86,10 @@ impl Program<'_> {
/// from the `Program` start span.
/// See <https://github.com/oxc-project/oxc/pull/10134> for more info.
///
/// Special case where first statement is an `ExportNamedDeclaration` or `ExportDefaultDeclaration`
/// Special case where first statement is an `ExportDeclaration` or `ExportDefaultDeclaration`
/// exporting a class with decorators, where one of the decorators is before `export`.
/// In these cases, the span of the statement starts after the span of the decorators.
/// e.g. `@dec export class C {}` - `ExportNamedDeclaration` span start is 5, `Decorator` span start is 0.
/// e.g. `@dec export class C {}` - `ExportDeclaration` span start is 5, `Decorator` span start is 0.
/// `Program` span start is 0 (not 5).
#[ast_meta]
#[estree(raw_deser = "
@@ -189,8 +189,8 @@ fn get_ts_start_span(program: &Program<'_>) -> u32 {
let start = first_stmt.span().start;
match first_stmt {
Statement::ExportNamedDeclaration(decl) => {
if let Some(Declaration::ClassDeclaration(class)) = &decl.declaration
Statement::ExportDeclaration(decl) => {
if let Declaration::ClassDeclaration(class) = &decl.declaration
&& let Some(decorator) = class.decorators.first()
{
return cmp::min(start, decorator.span.start);
+17 -3
View File
@@ -727,26 +727,40 @@ pub static INHERITED_ENUMS: [InheritedEnum; 9] = [
is_boxed: true,
discriminant: 66,
},
EnumVariant {
name: "ExportDeclaration",
inner_name: "ExportDeclaration",
inner_has_lifetime: true,
is_boxed: true,
discriminant: 67,
},
EnumVariant {
name: "ExportNamedDeclaration",
inner_name: "ExportNamedDeclaration",
inner_has_lifetime: true,
is_boxed: true,
discriminant: 67,
discriminant: 68,
},
EnumVariant {
name: "ExportFromDeclaration",
inner_name: "ExportFromDeclaration",
inner_has_lifetime: true,
is_boxed: true,
discriminant: 69,
},
EnumVariant {
name: "TSExportAssignment",
inner_name: "TSExportAssignment",
inner_has_lifetime: true,
is_boxed: true,
discriminant: 68,
discriminant: 70,
},
EnumVariant {
name: "TSNamespaceExportDeclaration",
inner_name: "TSNamespaceExportDeclaration",
inner_has_lifetime: true,
is_boxed: true,
discriminant: 69,
discriminant: 71,
},
],
},
File diff suppressed because it is too large. Load diff
@@ -542,9 +542,21 @@ impl<'a> VisitMut<'a> for Utf8ToUtf16Converter<'_> {
self.convert_offset(&mut it.span.end);
}
fn visit_export_named_declaration(&mut self, it: &mut ExportNamedDeclaration<'a>) {
fn visit_export_declaration(&mut self, it: &mut ExportDeclaration<'a>) {
// Custom implementation
self.convert_export_named_declaration(it);
self.convert_export_declaration(it);
}
fn visit_export_named_declaration(&mut self, it: &mut ExportNamedDeclaration<'a>) {
self.convert_offset(&mut it.span.start);
walk_mut::walk_export_named_declaration(self, it);
self.convert_offset(&mut it.span.end);
}
fn visit_export_from_declaration(&mut self, it: &mut ExportFromDeclaration<'a>) {
self.convert_offset(&mut it.span.start);
walk_mut::walk_export_from_declaration(self, it);
self.convert_offset(&mut it.span.end);
}
fn visit_export_default_declaration(&mut self, it: &mut ExportDefaultDeclaration<'a>) {
+36 -6
View File
@@ -606,11 +606,21 @@ pub trait Visit<'a>: Sized {
walk_import_attribute_key(self, it);
}
#[inline]
fn visit_export_declaration(&mut self, it: &ExportDeclaration<'a>) {
walk_export_declaration(self, it);
}
#[inline]
fn visit_export_named_declaration(&mut self, it: &ExportNamedDeclaration<'a>) {
walk_export_named_declaration(self, it);
}
#[inline]
fn visit_export_from_declaration(&mut self, it: &ExportFromDeclaration<'a>) {
walk_export_from_declaration(self, it);
}
#[inline]
fn visit_export_default_declaration(&mut self, it: &ExportDefaultDeclaration<'a>) {
walk_export_default_declaration(self, it);
@@ -2698,9 +2708,13 @@ pub mod walk {
ModuleDeclaration::ExportDefaultDeclaration(it) => {
visitor.visit_export_default_declaration(it)
}
ModuleDeclaration::ExportDeclaration(it) => visitor.visit_export_declaration(it),
ModuleDeclaration::ExportNamedDeclaration(it) => {
visitor.visit_export_named_declaration(it)
}
ModuleDeclaration::ExportFromDeclaration(it) => {
visitor.visit_export_from_declaration(it)
}
ModuleDeclaration::TSExportAssignment(it) => visitor.visit_ts_export_assignment(it),
ModuleDeclaration::TSNamespaceExportDeclaration(it) => {
visitor.visit_ts_namespace_export_declaration(it)
@@ -2833,6 +2847,15 @@ pub mod walk {
}
}
#[inline]
pub fn walk_export_declaration<'a, V: Visit<'a>>(visitor: &mut V, it: &ExportDeclaration<'a>) {
let kind = AstKind::ExportDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
visitor.visit_declaration(&it.declaration);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_named_declaration<'a, V: Visit<'a>>(
visitor: &mut V,
@@ -2841,13 +2864,20 @@ pub mod walk {
let kind = AstKind::ExportNamedDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
if let Some(declaration) = &it.declaration {
visitor.visit_declaration(declaration);
}
visitor.visit_export_specifiers(&it.specifiers);
if let Some(source) = &it.source {
visitor.visit_string_literal(source);
}
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_from_declaration<'a, V: Visit<'a>>(
visitor: &mut V,
it: &ExportFromDeclaration<'a>,
) {
let kind = AstKind::ExportFromDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
visitor.visit_export_specifiers(&it.specifiers);
visitor.visit_string_literal(&it.source);
if let Some(with_clause) = &it.with_clause {
visitor.visit_with_clause(with_clause);
}
+39 -7
View File
@@ -633,11 +633,21 @@ pub trait VisitJs<'a>: Sized {
walk_import_attribute_key(self, it);
}
#[inline]
fn visit_export_declaration(&mut self, it: &ExportDeclaration<'a>) {
walk_export_declaration(self, it);
}
#[inline]
fn visit_export_named_declaration(&mut self, it: &ExportNamedDeclaration<'a>) {
walk_export_named_declaration(self, it);
}
#[inline]
fn visit_export_from_declaration(&mut self, it: &ExportFromDeclaration<'a>) {
walk_export_from_declaration(self, it);
}
#[inline]
fn visit_export_default_declaration(&mut self, it: &ExportDefaultDeclaration<'a>) {
walk_export_default_declaration(self, it);
@@ -2336,7 +2346,6 @@ pub mod walk_js {
visitor.leave_node(kind);
}
#[inline]
pub fn walk_module_declaration<'a, V: VisitJs<'a>>(
visitor: &mut V,
it: &ModuleDeclaration<'a>,
@@ -2348,9 +2357,13 @@ pub mod walk_js {
ModuleDeclaration::ExportDefaultDeclaration(it) => {
visitor.visit_export_default_declaration(it)
}
ModuleDeclaration::ExportDeclaration(it) => visitor.visit_export_declaration(it),
ModuleDeclaration::ExportNamedDeclaration(it) => {
visitor.visit_export_named_declaration(it)
}
ModuleDeclaration::ExportFromDeclaration(it) => {
visitor.visit_export_from_declaration(it)
}
ModuleDeclaration::TSExportAssignment(it) => visitor.visit_ts_export_assignment(it),
_ => {}
}
@@ -2481,6 +2494,18 @@ pub mod walk_js {
}
}
#[inline]
pub fn walk_export_declaration<'a, V: VisitJs<'a>>(
visitor: &mut V,
it: &ExportDeclaration<'a>,
) {
let kind = AstKind::ExportDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
visitor.visit_declaration(&it.declaration);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_named_declaration<'a, V: VisitJs<'a>>(
visitor: &mut V,
@@ -2489,13 +2514,20 @@ pub mod walk_js {
let kind = AstKind::ExportNamedDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
if let Some(declaration) = &it.declaration {
visitor.visit_declaration(declaration);
}
visitor.visit_export_specifiers(&it.specifiers);
if let Some(source) = &it.source {
visitor.visit_string_literal(source);
}
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_from_declaration<'a, V: VisitJs<'a>>(
visitor: &mut V,
it: &ExportFromDeclaration<'a>,
) {
let kind = AstKind::ExportFromDeclaration(visitor.alloc(it));
visitor.enter_node(kind);
visitor.visit_span(&it.span);
visitor.visit_export_specifiers(&it.specifiers);
visitor.visit_string_literal(&it.source);
if let Some(with_clause) = &it.with_clause {
visitor.visit_with_clause(with_clause);
}
@@ -625,11 +625,21 @@ pub trait VisitJsMut<'a>: Sized {
walk_import_attribute_key(self, it);
}
#[inline]
fn visit_export_declaration(&mut self, it: &mut ExportDeclaration<'a>) {
walk_export_declaration(self, it);
}
#[inline]
fn visit_export_named_declaration(&mut self, it: &mut ExportNamedDeclaration<'a>) {
walk_export_named_declaration(self, it);
}
#[inline]
fn visit_export_from_declaration(&mut self, it: &mut ExportFromDeclaration<'a>) {
walk_export_from_declaration(self, it);
}
#[inline]
fn visit_export_default_declaration(&mut self, it: &mut ExportDefaultDeclaration<'a>) {
walk_export_default_declaration(self, it);
@@ -2438,7 +2448,6 @@ pub mod walk_js_mut {
visitor.leave_node(kind);
}
#[inline]
pub fn walk_module_declaration<'a, V: VisitJsMut<'a>>(
visitor: &mut V,
it: &mut ModuleDeclaration<'a>,
@@ -2450,9 +2459,13 @@ pub mod walk_js_mut {
ModuleDeclaration::ExportDefaultDeclaration(it) => {
visitor.visit_export_default_declaration(it)
}
ModuleDeclaration::ExportDeclaration(it) => visitor.visit_export_declaration(it),
ModuleDeclaration::ExportNamedDeclaration(it) => {
visitor.visit_export_named_declaration(it)
}
ModuleDeclaration::ExportFromDeclaration(it) => {
visitor.visit_export_from_declaration(it)
}
ModuleDeclaration::TSExportAssignment(it) => visitor.visit_ts_export_assignment(it),
_ => {}
}
@@ -2595,6 +2608,18 @@ pub mod walk_js_mut {
}
}
#[inline]
pub fn walk_export_declaration<'a, V: VisitJsMut<'a>>(
visitor: &mut V,
it: &mut ExportDeclaration<'a>,
) {
let kind = AstType::ExportDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
visitor.visit_declaration(&mut it.declaration);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_named_declaration<'a, V: VisitJsMut<'a>>(
visitor: &mut V,
@@ -2603,13 +2628,20 @@ pub mod walk_js_mut {
let kind = AstType::ExportNamedDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
if let Some(declaration) = &mut it.declaration {
visitor.visit_declaration(declaration);
}
visitor.visit_export_specifiers(&mut it.specifiers);
if let Some(source) = &mut it.source {
visitor.visit_string_literal(source);
}
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_from_declaration<'a, V: VisitJsMut<'a>>(
visitor: &mut V,
it: &mut ExportFromDeclaration<'a>,
) {
let kind = AstType::ExportFromDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
visitor.visit_export_specifiers(&mut it.specifiers);
visitor.visit_string_literal(&mut it.source);
if let Some(with_clause) = &mut it.with_clause {
visitor.visit_with_clause(with_clause);
}
@@ -598,11 +598,21 @@ pub trait VisitMut<'a>: Sized {
walk_import_attribute_key(self, it);
}
#[inline]
fn visit_export_declaration(&mut self, it: &mut ExportDeclaration<'a>) {
walk_export_declaration(self, it);
}
#[inline]
fn visit_export_named_declaration(&mut self, it: &mut ExportNamedDeclaration<'a>) {
walk_export_named_declaration(self, it);
}
#[inline]
fn visit_export_from_declaration(&mut self, it: &mut ExportFromDeclaration<'a>) {
walk_export_from_declaration(self, it);
}
#[inline]
fn visit_export_default_declaration(&mut self, it: &mut ExportDefaultDeclaration<'a>) {
walk_export_default_declaration(self, it);
@@ -2798,9 +2808,13 @@ pub mod walk_mut {
ModuleDeclaration::ExportDefaultDeclaration(it) => {
visitor.visit_export_default_declaration(it)
}
ModuleDeclaration::ExportDeclaration(it) => visitor.visit_export_declaration(it),
ModuleDeclaration::ExportNamedDeclaration(it) => {
visitor.visit_export_named_declaration(it)
}
ModuleDeclaration::ExportFromDeclaration(it) => {
visitor.visit_export_from_declaration(it)
}
ModuleDeclaration::TSExportAssignment(it) => visitor.visit_ts_export_assignment(it),
ModuleDeclaration::TSNamespaceExportDeclaration(it) => {
visitor.visit_ts_namespace_export_declaration(it)
@@ -2948,6 +2962,18 @@ pub mod walk_mut {
}
}
#[inline]
pub fn walk_export_declaration<'a, V: VisitMut<'a>>(
visitor: &mut V,
it: &mut ExportDeclaration<'a>,
) {
let kind = AstType::ExportDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
visitor.visit_declaration(&mut it.declaration);
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_named_declaration<'a, V: VisitMut<'a>>(
visitor: &mut V,
@@ -2956,13 +2982,20 @@ pub mod walk_mut {
let kind = AstType::ExportNamedDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
if let Some(declaration) = &mut it.declaration {
visitor.visit_declaration(declaration);
}
visitor.visit_export_specifiers(&mut it.specifiers);
if let Some(source) = &mut it.source {
visitor.visit_string_literal(source);
}
visitor.leave_node(kind);
}
#[inline]
pub fn walk_export_from_declaration<'a, V: VisitMut<'a>>(
visitor: &mut V,
it: &mut ExportFromDeclaration<'a>,
) {
let kind = AstType::ExportFromDeclaration;
visitor.enter_node(kind);
visitor.visit_span(&mut it.span);
visitor.visit_export_specifiers(&mut it.specifiers);
visitor.visit_string_literal(&mut it.source);
if let Some(with_clause) = &mut it.with_clause {
visitor.visit_with_clause(with_clause);
}
@@ -78,16 +78,13 @@ impl Utf8ToUtf16Converter<'_> {
self.convert_offset(&mut prop.span.end);
}
pub(crate) fn convert_export_named_declaration(
&mut self,
decl: &mut ExportNamedDeclaration<'_>,
) {
pub(crate) fn convert_export_declaration(&mut self, decl: &mut ExportDeclaration<'_>) {
// Special case logic for `@dec export class C {}`
if let Some(Declaration::ClassDeclaration(class)) = &mut decl.declaration {
if let Declaration::ClassDeclaration(class) = &mut decl.declaration {
self.convert_exported_class(class, &mut decl.span);
} else {
self.convert_offset(&mut decl.span.start);
walk_mut::walk_export_named_declaration(self, decl);
walk_mut::walk_export_declaration(self, decl);
self.convert_offset(&mut decl.span.end);
}
}
@@ -106,7 +103,7 @@ impl Utf8ToUtf16Converter<'_> {
}
}
/// Visit `ExportNamedDeclaration` or `ExportDefaultDeclaration` containing a `Class`.
/// Visit `ExportDeclaration` or `ExportDefaultDeclaration` containing a `Class`.
/// e.g. `export class C {}`, `export default class {}`
///
/// These need special handing because decorators before the `export` keyword
+79 -55
View File
@@ -3,7 +3,7 @@ use std::ops::Not;
use cow_utils::CowUtils;
use oxc_ast::ast::*;
use oxc_span::GetSpan;
use oxc_span::{GetSpan, Span};
use oxc_syntax::{
operator::UnaryOperator,
precedence::{GetPrecedence, Precedence},
@@ -152,7 +152,9 @@ impl Gen for Statement<'_> {
Self::LabeledStatement(stmt) => stmt.print(p, ctx),
Self::EmptyStatement(stmt) => stmt.print(p, ctx),
Self::ImportDeclaration(decl) => decl.print(p, ctx),
Self::ExportDeclaration(decl) => decl.print(p, ctx),
Self::ExportNamedDeclaration(decl) => decl.print(p, ctx),
Self::ExportFromDeclaration(decl) => decl.print(p, ctx),
Self::ExportDefaultDeclaration(decl) => decl.print(p, ctx),
Self::ExportAllDeclaration(decl) => decl.print(p, ctx),
Self::WithStatement(stmt) => stmt.print(p, ctx),
@@ -1042,10 +1044,10 @@ impl Gen for ImportAttribute<'_> {
}
}
impl Gen for ExportNamedDeclaration<'_> {
impl Gen for ExportDeclaration<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
p.print_comments_at(self.span.start);
if let Some(Declaration::FunctionDeclaration(func)) = &self.declaration
if let Declaration::FunctionDeclaration(func) = &self.declaration
&& func.pure
&& p.options.print_annotation_comment()
{
@@ -1057,63 +1059,85 @@ impl Gen for ExportNamedDeclaration<'_> {
p.print_indent();
p.add_source_mapping(self.span);
p.print_str("export");
if let Some(decl) = &self.declaration {
// A decorated class starts with `@`, so no space is needed after `export`.
if matches!(decl, Declaration::ClassDeclaration(c) if !c.decorators.is_empty()) {
p.print_soft_space();
} else {
p.print_hard_space();
}
match decl {
Declaration::VariableDeclaration(decl) => decl.print(p, ctx),
Declaration::FunctionDeclaration(decl) => decl.print(p, ctx),
Declaration::ClassDeclaration(decl) => decl.print(p, ctx),
Declaration::TSModuleDeclaration(decl) => decl.print(p, ctx),
Declaration::TSGlobalDeclaration(decl) => decl.print(p, ctx),
Declaration::TSTypeAliasDeclaration(decl) => decl.print(p, ctx),
Declaration::TSInterfaceDeclaration(decl) => decl.print(p, ctx),
Declaration::TSEnumDeclaration(decl) => decl.print(p, ctx),
Declaration::TSImportEqualsDeclaration(decl) => decl.print(p, ctx),
}
if matches!(
decl,
Declaration::VariableDeclaration(_)
| Declaration::TSTypeAliasDeclaration(_)
| Declaration::TSImportEqualsDeclaration(_)
) {
p.print_semicolon_after_statement();
} else {
p.print_soft_newline();
p.needs_semicolon = false;
}
} else {
if self.export_kind.is_type() {
p.print_hard_space();
p.print_str("type");
}
let decl = &self.declaration;
// A decorated class starts with `@`, so no space is needed after `export`.
if matches!(decl, Declaration::ClassDeclaration(c) if !c.decorators.is_empty()) {
p.print_soft_space();
p.print_ascii_byte(b'{');
if !self.specifiers.is_empty() {
p.print_soft_space();
p.print_list(&self.specifiers, ctx);
p.print_soft_space();
}
p.print_ascii_byte(b'}');
if let Some(source) = &self.source {
p.print_soft_space();
p.print_str("from");
p.print_soft_space();
p.print_string_literal(source, false);
if let Some(with_clause) = &self.with_clause {
p.print_soft_space();
with_clause.print(p, ctx);
}
}
} else {
p.print_hard_space();
}
match decl {
Declaration::VariableDeclaration(decl) => decl.print(p, ctx),
Declaration::FunctionDeclaration(decl) => decl.print(p, ctx),
Declaration::ClassDeclaration(decl) => decl.print(p, ctx),
Declaration::TSModuleDeclaration(decl) => decl.print(p, ctx),
Declaration::TSGlobalDeclaration(decl) => decl.print(p, ctx),
Declaration::TSTypeAliasDeclaration(decl) => decl.print(p, ctx),
Declaration::TSInterfaceDeclaration(decl) => decl.print(p, ctx),
Declaration::TSEnumDeclaration(decl) => decl.print(p, ctx),
Declaration::TSImportEqualsDeclaration(decl) => decl.print(p, ctx),
}
if matches!(
decl,
Declaration::VariableDeclaration(_)
| Declaration::TSTypeAliasDeclaration(_)
| Declaration::TSImportEqualsDeclaration(_)
) {
p.print_semicolon_after_statement();
} else {
p.print_soft_newline();
p.needs_semicolon = false;
}
}
}
impl Gen for ExportNamedDeclaration<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
gen_export_specifiers(p, ctx, self.span, self.export_kind, &self.specifiers);
p.print_semicolon_after_statement();
}
}
impl Gen for ExportFromDeclaration<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
gen_export_specifiers(p, ctx, self.span, self.export_kind, &self.specifiers);
p.print_soft_space();
p.print_str("from");
p.print_soft_space();
p.print_string_literal(&self.source, false);
if let Some(with_clause) = &self.with_clause {
p.print_soft_space();
with_clause.print(p, ctx);
}
p.print_semicolon_after_statement();
}
}
fn gen_export_specifiers(
p: &mut Codegen,
ctx: Context,
span: Span,
export_kind: ImportOrExportKind,
specifiers: &[ExportSpecifier<'_>],
) {
p.print_comments_at(span.start);
p.print_indent();
p.add_source_mapping(span);
p.print_str("export");
if export_kind.is_type() {
p.print_hard_space();
p.print_str("type");
}
p.print_soft_space();
p.print_ascii_byte(b'{');
if !specifiers.is_empty() {
p.print_soft_space();
p.print_list(specifiers, ctx);
p.print_soft_space();
}
p.print_ascii_byte(b'}');
}
impl Gen for TSExportAssignment<'_> {
fn r#gen(&self, p: &mut Codegen, ctx: Context) {
p.print_indent();
@@ -1223,7 +1247,7 @@ impl Gen for ExportDefaultDeclaration<'_> {
&& func.pure
&& p.options.print_annotation_comment()
{
// See [`ExportNamedDeclaration`] for the rationale.
// See [`ExportDeclaration`] for the rationale.
p.print_annotation_comment(self.span.start, AnnotationKind::NoSideEffects, true);
}
p.print_indent();
+5 -8
View File
@@ -1,8 +1,7 @@
use oxc_ast::ast::{
ArrayPattern, AssignmentPattern, BindingIdentifier, BindingPattern, BindingRestElement, Class,
Declaration, ExportNamedDeclaration, FormalParameter, FormalParameters, Function,
ImportDeclaration, ImportDeclarationSpecifier, ModuleDeclaration, ObjectPattern,
VariableDeclaration,
Declaration, ExportDeclaration, FormalParameter, FormalParameters, Function, ImportDeclaration,
ImportDeclarationSpecifier, ModuleDeclaration, ObjectPattern, VariableDeclaration,
};
/// [`BoundName`](https://tc39.es/ecma262/#sec-static-semantics-boundnames)
@@ -133,7 +132,7 @@ impl<'a> BoundNames<'a> for ModuleDeclaration<'a> {
fn bound_names<F: FnMut(&BindingIdentifier<'a>)>(&self, f: &mut F) {
match self {
ModuleDeclaration::ImportDeclaration(decl) => decl.bound_names(f),
ModuleDeclaration::ExportNamedDeclaration(decl) => decl.bound_names(f),
ModuleDeclaration::ExportDeclaration(decl) => decl.bound_names(f),
_ => {}
}
}
@@ -159,10 +158,8 @@ impl<'a> BoundNames<'a> for ImportDeclaration<'a> {
}
}
impl<'a> BoundNames<'a> for ExportNamedDeclaration<'a> {
impl<'a> BoundNames<'a> for ExportDeclaration<'a> {
fn bound_names<F: FnMut(&BindingIdentifier<'a>)>(&self, f: &mut F) {
if let Some(decl) = &self.declaration {
decl.bound_names(f);
}
self.declaration.bound_names(f);
}
}
@@ -117,7 +117,9 @@ pub enum AstNodes<'a> {
ImportNamespaceSpecifier(&'a AstNode<'a, ImportNamespaceSpecifier<'a>>),
WithClause(&'a AstNode<'a, WithClause<'a>>),
ImportAttribute(&'a AstNode<'a, ImportAttribute<'a>>),
ExportDeclaration(&'a AstNode<'a, ExportDeclaration<'a>>),
ExportNamedDeclaration(&'a AstNode<'a, ExportNamedDeclaration<'a>>),
ExportFromDeclaration(&'a AstNode<'a, ExportFromDeclaration<'a>>),
ExportDefaultDeclaration(&'a AstNode<'a, ExportDefaultDeclaration<'a>>),
ExportAllDeclaration(&'a AstNode<'a, ExportAllDeclaration<'a>>),
ExportSpecifier(&'a AstNode<'a, ExportSpecifier<'a>>),
@@ -317,7 +319,9 @@ impl AstNodes<'_> {
Self::ImportNamespaceSpecifier(n) => n.span(),
Self::WithClause(n) => n.span(),
Self::ImportAttribute(n) => n.span(),
Self::ExportDeclaration(n) => n.span(),
Self::ExportNamedDeclaration(n) => n.span(),
Self::ExportFromDeclaration(n) => n.span(),
Self::ExportDefaultDeclaration(n) => n.span(),
Self::ExportAllDeclaration(n) => n.span(),
Self::ExportSpecifier(n) => n.span(),
@@ -517,7 +521,9 @@ impl AstNodes<'_> {
Self::ImportNamespaceSpecifier(n) => n.parent(),
Self::WithClause(n) => n.parent(),
Self::ImportAttribute(n) => n.parent(),
Self::ExportDeclaration(n) => n.parent(),
Self::ExportNamedDeclaration(n) => n.parent(),
Self::ExportFromDeclaration(n) => n.parent(),
Self::ExportDefaultDeclaration(n) => n.parent(),
Self::ExportAllDeclaration(n) => n.parent(),
Self::ExportSpecifier(n) => n.parent(),
@@ -712,7 +718,9 @@ impl AstNodes<'_> {
Self::ImportNamespaceSpecifier(_) => "ImportNamespaceSpecifier",
Self::WithClause(_) => "WithClause",
Self::ImportAttribute(_) => "ImportAttribute",
Self::ExportDeclaration(_) => "ExportDeclaration",
Self::ExportNamedDeclaration(_) => "ExportNamedDeclaration",
Self::ExportFromDeclaration(_) => "ExportFromDeclaration",
Self::ExportDefaultDeclaration(_) => "ExportDefaultDeclaration",
Self::ExportAllDeclaration(_) => "ExportAllDeclaration",
Self::ExportSpecifier(_) => "ExportSpecifier",
@@ -5509,6 +5517,14 @@ impl<'a> AstNode<'a, ModuleDeclaration<'a>> {
following_span_start: self.following_span_start,
}))
}
ModuleDeclaration::ExportDeclaration(s) => {
AstNodes::ExportDeclaration(self.allocator.alloc(AstNode {
inner: s.as_ref(),
parent,
allocator: self.allocator,
following_span_start: self.following_span_start,
}))
}
ModuleDeclaration::ExportNamedDeclaration(s) => {
AstNodes::ExportNamedDeclaration(self.allocator.alloc(AstNode {
inner: s.as_ref(),
@@ -5517,6 +5533,14 @@ impl<'a> AstNode<'a, ModuleDeclaration<'a>> {
following_span_start: self.following_span_start,
}))
}
ModuleDeclaration::ExportFromDeclaration(s) => {
AstNodes::ExportFromDeclaration(self.allocator.alloc(AstNode {
inner: s.as_ref(),
parent,
allocator: self.allocator,
following_span_start: self.following_span_start,
}))
}
ModuleDeclaration::TSExportAssignment(s) => {
AstNodes::TSExportAssignment(self.allocator.alloc(AstNode {
inner: s.as_ref(),
@@ -5986,41 +6010,42 @@ impl<'a> AstNode<'a, ImportAttributeKey<'a>> {
}
}
impl<'a> AstNode<'a, ExportDeclaration<'a>> {
#[inline]
pub fn node_id(&self) -> NodeId {
self.inner.node_id()
}
#[inline]
pub fn declaration(&self) -> &AstNode<'a, Declaration<'a>> {
let following_span_start = 0;
self.allocator.alloc(AstNode {
inner: &self.inner.declaration,
allocator: self.allocator,
parent: AstNodes::ExportDeclaration(transmute_self(self)),
following_span_start,
})
}
pub fn format_leading_comments(&self, f: &mut JsFormatter<'_, 'a>) {
format_leading_comments(self.span()).fmt(f);
}
pub fn format_trailing_comments(&self, f: &mut JsFormatter<'_, 'a>) {
format_trailing_comments(self.parent.span(), self.inner.span(), self.following_span_start)
.fmt(f);
}
}
impl<'a> AstNode<'a, ExportNamedDeclaration<'a>> {
#[inline]
pub fn node_id(&self) -> NodeId {
self.inner.node_id()
}
#[inline]
pub fn declaration(&self) -> Option<&AstNode<'a, Declaration<'a>>> {
let following_span_start = self
.inner
.specifiers
.first()
.map(|n| n.span().start)
.or_else(|| self.inner.source.as_ref().map(|n| n.span().start))
.or_else(|| self.inner.with_clause.as_deref().map(|n| n.span().start))
.unwrap_or(0);
self.allocator
.alloc(self.inner.declaration.as_ref().map(|inner| AstNode {
inner,
allocator: self.allocator,
parent: AstNodes::ExportNamedDeclaration(transmute_self(self)),
following_span_start,
}))
.as_ref()
}
#[inline]
pub fn specifiers(&self) -> &AstNode<'a, ArenaVec<'a, ExportSpecifier<'a>>> {
let following_span_start = self
.inner
.source
.as_ref()
.map(|n| n.span().start)
.or_else(|| self.inner.with_clause.as_deref().map(|n| n.span().start))
.unwrap_or(0);
let following_span_start = 0;
self.allocator.alloc(AstNode {
inner: &self.inner.specifiers,
allocator: self.allocator,
@@ -6030,16 +6055,46 @@ impl<'a> AstNode<'a, ExportNamedDeclaration<'a>> {
}
#[inline]
pub fn source(&self) -> Option<&AstNode<'a, StringLiteral<'a>>> {
pub fn export_kind(&self) -> ImportOrExportKind {
self.inner.export_kind
}
pub fn format_leading_comments(&self, f: &mut JsFormatter<'_, 'a>) {
format_leading_comments(self.span()).fmt(f);
}
pub fn format_trailing_comments(&self, f: &mut JsFormatter<'_, 'a>) {
format_trailing_comments(self.parent.span(), self.inner.span(), self.following_span_start)
.fmt(f);
}
}
impl<'a> AstNode<'a, ExportFromDeclaration<'a>> {
#[inline]
pub fn node_id(&self) -> NodeId {
self.inner.node_id()
}
#[inline]
pub fn specifiers(&self) -> &AstNode<'a, ArenaVec<'a, ExportSpecifier<'a>>> {
let following_span_start = self.inner.source.span().start;
self.allocator.alloc(AstNode {
inner: &self.inner.specifiers,
allocator: self.allocator,
parent: AstNodes::ExportFromDeclaration(transmute_self(self)),
following_span_start,
})
}
#[inline]
pub fn source(&self) -> &AstNode<'a, StringLiteral<'a>> {
let following_span_start = self.inner.with_clause.as_deref().map_or(0, |n| n.span().start);
self.allocator
.alloc(self.inner.source.as_ref().map(|inner| AstNode {
inner,
allocator: self.allocator,
parent: AstNodes::ExportNamedDeclaration(transmute_self(self)),
following_span_start,
}))
.as_ref()
self.allocator.alloc(AstNode {
inner: &self.inner.source,
allocator: self.allocator,
parent: AstNodes::ExportFromDeclaration(transmute_self(self)),
following_span_start,
})
}
#[inline]
@@ -6054,7 +6109,7 @@ impl<'a> AstNode<'a, ExportNamedDeclaration<'a>> {
.alloc(self.inner.with_clause.as_ref().map(|inner| AstNode {
inner: inner.as_ref(),
allocator: self.allocator,
parent: AstNodes::ExportNamedDeclaration(transmute_self(self)),
parent: AstNodes::ExportFromDeclaration(transmute_self(self)),
following_span_start,
}))
.as_ref()
@@ -2750,6 +2750,16 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ModuleDeclaration<'a>>
})
.fmt(f);
}
ModuleDeclaration::ExportDeclaration(inner) => {
allocator
.alloc(AstNode::<ExportDeclaration> {
inner,
parent,
allocator,
following_span_start: self.following_span_start,
})
.fmt(f);
}
ModuleDeclaration::ExportNamedDeclaration(inner) => {
allocator
.alloc(AstNode::<ExportNamedDeclaration> {
@@ -2760,6 +2770,16 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ModuleDeclaration<'a>>
})
.fmt(f);
}
ModuleDeclaration::ExportFromDeclaration(inner) => {
allocator
.alloc(AstNode::<ExportFromDeclaration> {
inner,
parent,
allocator,
following_span_start: self.following_span_start,
})
.fmt(f);
}
ModuleDeclaration::TSExportAssignment(inner) => {
allocator
.alloc(AstNode::<TSExportAssignment> {
@@ -2965,6 +2985,19 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ImportAttributeKey<'a>>
}
}
impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ExportDeclaration<'a>> {
fn fmt(&self, f: &mut JsFormatter<'_, 'a>) {
let is_suppressed = f.comments().is_suppressed(self.span().start);
if is_suppressed {
self.format_leading_comments(f);
FormatSuppressedNode(self.span()).fmt(f);
self.format_trailing_comments(f);
} else {
self.write(f);
}
}
}
impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ExportNamedDeclaration<'a>> {
fn fmt(&self, f: &mut JsFormatter<'_, 'a>) {
let is_suppressed = f.comments().is_suppressed(self.span().start);
@@ -2978,6 +3011,19 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ExportNamedDeclaration<
}
}
impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ExportFromDeclaration<'a>> {
fn fmt(&self, f: &mut JsFormatter<'_, 'a>) {
let is_suppressed = f.comments().is_suppressed(self.span().start);
if is_suppressed {
self.format_leading_comments(f);
FormatSuppressedNode(self.span()).fmt(f);
self.format_trailing_comments(f);
} else {
self.write(f);
}
}
}
impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ExportDefaultDeclaration<'a>> {
fn fmt(&self, f: &mut JsFormatter<'_, 'a>) {
let is_suppressed = f.comments().is_suppressed(self.span().start);
@@ -51,8 +51,8 @@ fn get_statement_span(stmt: &Statement<'_>) -> u32 {
export.span.start
}
}
Statement::ExportNamedDeclaration(export) => {
if let Some(Declaration::ClassDeclaration(class)) = &export.declaration
Statement::ExportDeclaration(export) => {
if let Declaration::ClassDeclaration(class) = &export.declaration
&& let Some(decorator) = class.decorators.first()
{
min(decorator.span.start, export.span.start)
+1 -1
View File
@@ -290,7 +290,7 @@ impl<'a> Format<'a, JsFormatContext<'a>> for FormatClass<'a, '_> {
if self.is_expression()
|| !matches!(
self.parent(),
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_)
AstNodes::ExportDeclaration(_) | AstNodes::ExportDefaultDeclaration(_)
)
{
write!(f, decorators);
+1 -1
View File
@@ -38,7 +38,7 @@ impl<'a> Format<'a, JsFormatContext<'a>> for AstNode<'a, ArenaVec<'a, Decorator<
AstNodes::FormalParameter(_) => {
write!(f, should_expand_decorators(self, f).then_some(expand_parent()));
}
AstNodes::ExportNamedDeclaration(_) | AstNodes::ExportDefaultDeclaration(_) => {
AstNodes::ExportDeclaration(_) | AstNodes::ExportDefaultDeclaration(_) => {
write!(f, [hard_line_break()]);
}
_ => {
@@ -5,6 +5,7 @@ use oxc_span::GetSpan;
use crate::{
FormatTrailingCommas,
ast_nodes::{AstNode, AstNodes},
format_args,
formatter::{
JsFormatter,
prelude::*,
@@ -12,9 +13,7 @@ use crate::{
trivia::{FormatLeadingComments, FormatTrailingComments},
},
print::{
import_declaration::{
format_import_and_export_source_with_clause, import_and_export_source_with_clause_end,
},
import_declaration::format_source_with_clause_and_semicolon,
semicolon::{FormatContentWithSemicolon, OptionalSemicolon},
},
write,
@@ -65,16 +64,65 @@ fn format_export_keyword_with_class_decorators<'a>(
}
}
/// Formats the `kind { specifiers }` part of
/// - `export { ... }`
/// - and `export { ... } from "..."`
///
/// including the comments around the braces.
fn format_export_specifiers_block<'a>(
span: Span,
export_kind: ImportOrExportKind,
specifiers: &AstNode<'a, ArenaVec<'a, ExportSpecifier<'a>>>,
f: &mut JsFormatter<'_, 'a>,
) {
let needs_space = f.options().bracket_spacing.value();
if specifiers.is_empty() {
let comments = f.context().comments().comments_before_character(span.start, b'{');
let has_line_comment = comments.iter().any(|c| c.is_line());
// Block comment example:
// Input: `export /* comment */ {}`
// Output: `export /* comment */ {}`
//
// Line comment example:
// Input: `export // comment
// {}`
// Output: `export // comment
// {}`
if !comments.is_empty() {
write!(
f,
[
FormatTrailingComments::Comments(comments),
has_line_comment.then_some(soft_line_break()),
" "
]
);
}
write!(f, [export_kind, "{", format_dangling_comments(span).with_block_indent()]);
} else if specifiers.len() == 1
&& f.comments().comments_before_character(span.start, b'}').is_empty()
{
let space = maybe_space(needs_space).memoized();
write!(f, [export_kind, "{", space, specifiers.first(), space]);
} else {
write!(
f,
[export_kind, "{", group(&soft_block_indent_with_maybe_space(specifiers, needs_space))]
);
}
write!(f, "}");
}
impl<'a> FormatWrite<'a> for AstNode<'a, ExportDefaultDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
let declaration = self.declaration();
format_export_keyword_with_class_decorators(
self.span,
"export default",
self.declaration().as_ast_nodes(),
declaration.as_ast_nodes(),
f,
);
let declaration = self.declaration();
if declaration.is_expression() {
write!(
f,
@@ -90,100 +138,62 @@ impl<'a> FormatWrite<'a> for AstNode<'a, ExportDefaultDeclaration<'a>> {
impl<'a> FormatWrite<'a> for AstNode<'a, ExportAllDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
let content = format_with(|f| {
let prefix = format_with(|f| {
write!(f, ["export", space(), self.export_kind(), "*", space()]);
if let Some(name) = &self.exported() {
write!(f, ["as", space(), name, space()]);
}
write!(f, ["from", space()]);
format_import_and_export_source_with_clause(self.source(), self.with_clause(), f);
});
let content_end =
import_and_export_source_with_clause_end(self.source(), self.with_clause());
write!(f, FormatContentWithSemicolon::new(&content, content_end, self.span.end));
format_source_with_clause_and_semicolon(
&prefix,
self.source(),
self.with_clause(),
self.span.end,
f,
);
}
}
impl<'a> FormatWrite<'a> for AstNode<'a, ExportDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
let declaration = self.declaration();
format_export_keyword_with_class_decorators(
self.span,
"export",
declaration.as_ast_nodes(),
f,
);
write!(f, declaration);
// No semicolon here: the declaration prints its own,
// together with its trailing comments
self.format_trailing_comments(f);
}
}
impl<'a> FormatWrite<'a> for AstNode<'a, ExportNamedDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
let declaration = self.declaration();
let export_kind = self.export_kind();
let specifiers = self.specifiers();
let source = self.source();
self.format_leading_comments(f);
write!(f, ["export", space()]);
format_export_specifiers_block(self.span, self.export_kind(), self.specifiers(), f);
write!(f, OptionalSemicolon);
self.format_trailing_comments(f);
}
}
if let Some(decl) = declaration {
format_export_keyword_with_class_decorators(
self.span,
"export",
decl.as_ast_nodes(),
f,
);
write!(f, decl);
} else {
self.format_leading_comments(f);
write!(f, ["export", space()]);
let needs_space = f.options().bracket_spacing.value();
if specifiers.is_empty() {
let comments =
f.context().comments().comments_before_character(self.span.start, b'{');
let has_line_comment = comments.iter().any(|c| c.is_line());
// Block comment example:
// Input: `export /* comment */ {}`
// Output: `export /* comment */ {}`
//
// Line comment example:
// Input: `export // comment
// {}`
// Output: `export // comment
// {}`
if !comments.is_empty() {
write!(
f,
[
FormatTrailingComments::Comments(comments),
has_line_comment.then_some(soft_line_break()),
" "
]
);
}
write!(
f,
[export_kind, "{", format_dangling_comments(self.span).with_block_indent()]
);
} else if specifiers.len() == 1
&& f.comments().comments_before_character(self.span.start, b'}').is_empty()
{
let space = maybe_space(needs_space).memoized();
write!(f, [export_kind, "{", space, specifiers.first(), space]);
} else {
write!(
f,
[
export_kind,
"{",
group(&soft_block_indent_with_maybe_space(specifiers, needs_space))
]
);
}
write!(f, "}");
let with_clause = self.with_clause();
if let Some(source) = source {
let content = format_with(|f| {
write!(f, [space(), "from", space()]);
format_import_and_export_source_with_clause(source, with_clause, f);
});
let content_end = import_and_export_source_with_clause_end(source, with_clause);
write!(f, FormatContentWithSemicolon::new(&content, content_end, self.span.end));
} else {
write!(f, OptionalSemicolon);
}
}
// No semicolon when there is a declaration:
// an exported variable declaration prints it itself, together with its trailing comments
impl<'a> FormatWrite<'a> for AstNode<'a, ExportFromDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
self.format_leading_comments(f);
write!(f, ["export", space()]);
format_export_specifiers_block(self.span, self.export_kind(), self.specifiers(), f);
format_source_with_clause_and_semicolon(
&format_args!(space(), "from", space()),
self.source(),
self.with_clause(),
self.span.end,
f,
);
self.format_trailing_comments(f);
}
}
@@ -33,34 +33,34 @@ impl<'a> Format<'a, JsFormatContext<'a>> for ImportPhase {
}
}
/// End position of the source + optional with-clause pair formatted by
/// [`format_import_and_export_source_with_clause`].
pub fn import_and_export_source_with_clause_end(
source: &AstNode<'_, StringLiteral>,
with_clause: Option<&AstNode<'_, WithClause>>,
) -> u32 {
with_clause.map_or(source.span.end, |with| with.span.end)
}
pub fn format_import_and_export_source_with_clause<'a>(
/// Formats `prefix` followed by the module source and its optional with-clause,
/// then the semicolon, moving a same-line trailing comment behind it.
pub fn format_source_with_clause_and_semicolon<'a>(
prefix: &impl Format<'a, JsFormatContext<'a>>,
source: &AstNode<'a, StringLiteral>,
with_clause: Option<&AstNode<'a, WithClause>>,
span_end: u32,
f: &mut JsFormatter<'_, 'a>,
) {
source.fmt(f);
let content = format_with(|f| {
prefix.fmt(f);
source.fmt(f);
if let Some(with_clause) = with_clause {
if f.comments().has_comment_before(with_clause.span.start) {
write!(f, [space()]);
if let Some(with_clause) = with_clause {
if f.comments().has_comment_before(with_clause.span.start) {
write!(f, [space()]);
}
write!(f, [with_clause]);
}
write!(f, [with_clause]);
}
});
let content_end = with_clause.map_or(source.span.end, |with| with.span.end);
write!(f, FormatContentWithSemicolon::new(&content, content_end, span_end));
}
impl<'a> FormatWrite<'a> for AstNode<'a, ImportDeclaration<'a>> {
fn write(&self, f: &mut JsFormatter<'_, 'a>) {
let content = format_with(|f| {
let prefix = format_with(|f| {
write!(f, ["import", space()]);
if let Some(phase) = self.phase() {
write!(f, phase);
@@ -71,12 +71,16 @@ impl<'a> FormatWrite<'a> for AstNode<'a, ImportDeclaration<'a>> {
if let Some(specifiers) = self.specifiers() {
write!(f, [specifiers, space(), "from", space()]);
}
format_import_and_export_source_with_clause(self.source(), self.with_clause(), f);
});
let content_end =
import_and_export_source_with_clause_end(self.source(), self.with_clause());
let decl = FormatContentWithSemicolon::new(&content, content_end, self.span.end);
let decl = format_with(|f| {
format_source_with_clause_and_semicolon(
&prefix,
self.source(),
self.with_clause(),
self.span.end,
f,
);
});
if f.options().sort_imports.is_some() {
write!(f, [labelled(LabelId::of(JsLabels::ImportDeclaration), &decl)]);
+2 -2
View File
@@ -81,8 +81,8 @@ impl<'a> Format<'a, JsFormatContext<'a>> for FormatStatementsWithImports<'a, '_>
let span = match stmt.as_ref() {
// `@decorator export class A {}`
// Get the span of the decorator.
Statement::ExportNamedDeclaration(export) => {
if let Some(Declaration::ClassDeclaration(decl)) = &export.declaration
Statement::ExportDeclaration(export) => {
if let Declaration::ClassDeclaration(decl) = &export.declaration
&& let Some(decorator) = decl.decorators.first()
&& decorator.span().start < export.span.start
{
@@ -24,7 +24,7 @@ impl<'a> FormatWrite<'a> for AstNode<'a, VariableDeclaration<'a>> {
AstNodes::ForInStatement(stmt) => stmt.left().span() != self.span(),
AstNodes::ForOfStatement(stmt) => stmt.left().span() != self.span(),
// Everywhere else the declaration terminates itself, including `export const ...`,
// whose `ExportNamedDeclaration` prints no semicolon of its own (see its `FormatWrite` implementation).
// whose `ExportDeclaration` prints no semicolon of its own (see its `FormatWrite` implementation).
_ => true,
};
+30 -27
View File
@@ -294,20 +294,31 @@ impl<'a> IsolatedDeclarations<'a> {
need_empty_export_marker = false;
}
ModuleDeclaration::ExportNamedDeclaration(decl) => {
if decl.declaration.is_none() {
need_empty_export_marker = false;
}
if let Some(new_decl) = self.transform_export_named_declaration(decl) {
self.scope.visit_export_named_declaration(&new_decl);
ModuleDeclaration::ExportDeclaration(decl) => {
if let Some(new_decl) = self.transform_export_declaration(decl) {
self.scope.visit_export_declaration(&new_decl);
transformed_stmts[idx] =
Some(Statement::ExportNamedDeclaration(new_decl));
Some(Statement::ExportDeclaration(new_decl));
} else {
// Declaration couldn't be transformed; preserve as-is
transformed_stmts[idx] = Some(stmt.clone_in(self.allocator()));
}
transformed_count += 1;
}
ModuleDeclaration::ExportNamedDeclaration(decl) => {
need_empty_export_marker = false;
self.scope.visit_export_named_declaration(decl);
transformed_stmts[idx] = Some(stmt.clone_in(self.allocator()));
transformed_count += 1;
}
ModuleDeclaration::ExportFromDeclaration(decl) => {
let new_decl = self.transform_export_from_declaration(decl);
need_empty_export_marker = false;
self.scope.visit_export_from_declaration(&new_decl);
transformed_stmts[idx] =
Some(Statement::ExportFromDeclaration(new_decl));
transformed_count += 1;
}
ModuleDeclaration::ImportDeclaration(_) => {
// We must transform this in the end, because we need to know all references
}
@@ -434,15 +445,7 @@ impl<'a> IsolatedDeclarations<'a> {
if need_empty_export_marker {
let kind = ImportOrExportKind::Value;
new_stmts.push(Statement::new_export_named_declaration(
SPAN,
None,
[],
None,
kind,
None,
self,
));
new_stmts.push(Statement::new_export_named_declaration(SPAN, [], kind, self));
} else if self.scope.is_ts_module_block() {
// If we are in a module block and we don't need to add `export {}`, in that case we need to remove `export` keyword from all ExportNamedDeclaration
// <https://github.com/microsoft/TypeScript/blob/a709f9899c2a544b6de65a0f2623ecbbe1394eab/src/compiler/transformers/declarations.ts#L1556-L1563>
@@ -478,8 +481,8 @@ impl<'a> IsolatedDeclarations<'a> {
}
true
}
Statement::ExportNamedDeclaration(decl) => {
if let Some(Declaration::FunctionDeclaration(func)) = &decl.declaration {
Statement::ExportDeclaration(decl) => {
if let Declaration::FunctionDeclaration(func) = &decl.declaration {
let name: Str<'a> = func
.id
.as_ref()
@@ -530,9 +533,9 @@ impl<'a> IsolatedDeclarations<'a> {
let TSModuleDeclarationName::Identifier(ident) = &decl.id else { return };
let Some(TSModuleDeclarationBody::TSModuleBlock(block)) = &decl.body else { return };
for stmt in &block.body {
let Statement::ExportNamedDeclaration(decl) = stmt else { continue };
let Statement::ExportDeclaration(decl) = stmt else { continue };
match &decl.declaration {
Some(Declaration::VariableDeclaration(var)) => {
Declaration::VariableDeclaration(var) => {
for declarator in &var.declarations {
if let Some(name) = declarator.id.get_identifier_name() {
assignable_properties
@@ -542,7 +545,7 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
}
Some(Declaration::FunctionDeclaration(func)) => {
Declaration::FunctionDeclaration(func) => {
if let Some(name) = func.name() {
assignable_properties
.entry(ident.name.as_str())
@@ -550,7 +553,7 @@ impl<'a> IsolatedDeclarations<'a> {
.insert(name.into());
}
}
Some(Declaration::ClassDeclaration(cls)) => {
Declaration::ClassDeclaration(cls) => {
if let Some(id) = cls.id.as_ref() {
assignable_properties
.entry(ident.name.as_str())
@@ -558,7 +561,7 @@ impl<'a> IsolatedDeclarations<'a> {
.insert(id.name.into());
}
}
Some(Declaration::TSEnumDeclaration(decl)) => {
Declaration::TSEnumDeclaration(decl) => {
assignable_properties
.entry(ident.name.as_str())
.or_default()
@@ -574,15 +577,15 @@ impl<'a> IsolatedDeclarations<'a> {
let mut can_expando_function_names = IdentHashSet::default();
for stmt in stmts {
match stmt {
Statement::ExportNamedDeclaration(decl) => match decl.declaration.as_ref() {
Some(Declaration::FunctionDeclaration(func)) => {
Statement::ExportDeclaration(decl) => match &decl.declaration {
Declaration::FunctionDeclaration(func) => {
if func.body.is_some()
&& let Some(id) = func.id.as_ref()
{
can_expando_function_names.insert(id.name);
}
}
Some(Declaration::VariableDeclaration(decl)) => {
Declaration::VariableDeclaration(decl) => {
for declarator in &decl.declarations {
if declarator.type_annotation.is_none()
&& declarator.init.as_ref().is_some_and(Expression::is_function)
@@ -592,7 +595,7 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
}
Some(Declaration::TSModuleDeclaration(decl)) => {
Declaration::TSModuleDeclaration(decl) => {
Self::collect_namespace_properties(
decl,
&mut assignable_properties_for_namespace,
+20 -20
View File
@@ -13,31 +13,33 @@ impl<'a> IsolatedDeclarations<'a> {
ExportAllDeclaration::boxed(
prev_decl.span,
prev_decl.exported.clone_in(self.allocator()),
prev_decl.source.clone(),
prev_decl.source.clone_in(self.allocator()),
None,
prev_decl.export_kind,
self,
)
}
pub(crate) fn transform_export_named_declaration(
&mut self,
prev_decl: &ExportNamedDeclaration<'a>,
) -> Option<ArenaBox<'a, ExportNamedDeclaration<'a>>> {
let declaration = match &prev_decl.declaration {
Some(decl) => Some(self.transform_declaration(decl, false)?),
None => None,
};
Some(ExportNamedDeclaration::boxed(
pub(crate) fn transform_export_from_declaration(
&self,
prev_decl: &ExportFromDeclaration<'a>,
) -> ArenaBox<'a, ExportFromDeclaration<'a>> {
ExportFromDeclaration::boxed(
prev_decl.span,
declaration,
prev_decl.specifiers.clone_in(self.allocator()),
prev_decl.source.clone(),
prev_decl.source.clone_in(self.allocator()),
prev_decl.export_kind,
None,
self,
))
)
}
pub(crate) fn transform_export_declaration(
&mut self,
prev_decl: &ExportDeclaration<'a>,
) -> Option<ArenaBox<'a, ExportDeclaration<'a>>> {
let decl = self.transform_declaration(&prev_decl.declaration, false)?;
Some(ExportDeclaration::boxed(prev_decl.span, decl, self))
}
pub(crate) fn create_unique_name(&self, name: &str) -> Str<'a> {
@@ -186,7 +188,7 @@ impl<'a> IsolatedDeclarations<'a> {
}
}
/// Strip export keyword from ExportNamedDeclaration
/// Strip export keyword from ExportDeclaration
///
/// ```ts
/// export const a = 1;
@@ -199,12 +201,10 @@ impl<'a> IsolatedDeclarations<'a> {
/// ```
pub(crate) fn strip_export_keyword(stmts: &mut ArenaVec<'a, Statement<'a>>) {
stmts.iter_mut().for_each(|stmt| {
if let Statement::ExportNamedDeclaration(decl) = stmt
&& decl.declaration.is_some()
{
if let Statement::ExportDeclaration(_) = stmt {
stmt.replace_with(|stmt| {
let Statement::ExportNamedDeclaration(decl) = stmt else { unreachable!() };
Statement::from(decl.unbox().declaration.unwrap())
let Statement::ExportDeclaration(decl) = stmt else { unreachable!() };
Statement::from(decl.unbox().declaration)
});
}
});
@@ -152,19 +152,20 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
}
}
fn visit_export_declaration(&mut self, decl: &ExportDeclaration<'a>) {
walk_declaration(self, &decl.declaration);
}
fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
if let Some(declaration) = &decl.declaration {
walk_declaration(self, declaration);
} else if decl.source.is_none() {
// export { ... }
for specifier in &decl.specifiers {
if let Some(name) = specifier.local.identifier_name() {
self.add_reference(name.into(), KindFlags::All);
}
for specifier in &decl.specifiers {
if let Some(name) = specifier.local.identifier_name() {
self.add_reference(name.into(), KindFlags::All);
}
}
}
fn visit_export_from_declaration(&mut self, _decl: &ExportFromDeclaration<'a>) {}
fn visit_export_default_declaration(&mut self, decl: &ExportDefaultDeclaration<'a>) {
if let ExportDefaultDeclarationKind::Identifier(ident) = &decl.declaration {
self.add_reference(ident.name.into(), KindFlags::All);
+2
View File
@@ -194,8 +194,10 @@ fn should_attach_jsdoc(kind: &AstKind) -> bool {
| AstKind::Decorator(_)
| AstKind::ExportAllDeclaration(_)
| AstKind::ExportDeclaration(_)
| AstKind::ExportDefaultDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportFromDeclaration(_)
| AstKind::ImportDeclaration(_)
// Maybe JSX, TS related kinds should be added?
+17 -7
View File
@@ -128,6 +128,7 @@ impl RuleRunner for crate::rules::import::no_empty_named_blocks::NoEmptyNamedBlo
impl RuleRunner for crate::rules::import::no_mutable_exports::NoMutableExports {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportDeclaration,
AstType::ExportDefaultDeclaration,
AstType::ExportNamedDeclaration,
]));
@@ -152,6 +153,8 @@ impl RuleRunner for crate::rules::import::no_named_default::NoNamedDefault {
impl RuleRunner for crate::rules::import::no_named_export::NoNamedExport {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportAllDeclaration,
AstType::ExportDeclaration,
AstType::ExportFromDeclaration,
AstType::ExportNamedDeclaration,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
@@ -166,7 +169,7 @@ impl RuleRunner for crate::rules::import::no_nodejs_modules::NoNodejsModules {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::ExportAllDeclaration,
AstType::ExportNamedDeclaration,
AstType::ExportFromDeclaration,
AstType::ImportDeclaration,
AstType::ImportExpression,
AstType::TSImportEqualsDeclaration,
@@ -178,7 +181,7 @@ impl RuleRunner for crate::rules::import::no_relative_parent_imports::NoRelative
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::ExportAllDeclaration,
AstType::ExportNamedDeclaration,
AstType::ExportFromDeclaration,
AstType::ImportDeclaration,
AstType::ImportExpression,
]));
@@ -977,7 +980,9 @@ impl RuleRunner for crate::rules::eslint::no_regex_spaces::NoRegexSpaces {
impl RuleRunner for crate::rules::eslint::no_restricted_exports::NoRestrictedExports {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportAllDeclaration,
AstType::ExportDeclaration,
AstType::ExportDefaultDeclaration,
AstType::ExportFromDeclaration,
AstType::ExportNamedDeclaration,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
@@ -1264,6 +1269,7 @@ impl RuleRunner for crate::rules::eslint::no_useless_escape::NoUselessEscape {
impl RuleRunner for crate::rules::eslint::no_useless_rename::NoUselessRename {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportFromDeclaration,
AstType::ExportNamedDeclaration,
AstType::ImportSpecifier,
AstType::ObjectAssignmentTarget,
@@ -1627,6 +1633,7 @@ impl RuleRunner
for crate::rules::typescript::explicit_module_boundary_types::ExplicitModuleBoundaryTypes
{
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportDeclaration,
AstType::ExportDefaultDeclaration,
AstType::ExportNamedDeclaration,
AstType::TSExportAssignment,
@@ -3065,7 +3072,7 @@ impl RuleRunner for crate::rules::unicorn::filename_case::FilenameCase {
impl RuleRunner for crate::rules::unicorn::import_style::ImportStyle {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportAllDeclaration,
AstType::ExportNamedDeclaration,
AstType::ExportFromDeclaration,
AstType::ExpressionStatement,
AstType::ImportDeclaration,
AstType::ImportExpression,
@@ -3318,6 +3325,8 @@ impl RuleRunner for crate::rules::unicorn::no_thenable::NoThenable {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::AssignmentExpression,
AstType::CallExpression,
AstType::ExportDeclaration,
AstType::ExportFromDeclaration,
AstType::ExportNamedDeclaration,
AstType::MethodDefinition,
AstType::ObjectExpression,
@@ -3689,7 +3698,7 @@ impl RuleRunner for crate::rules::unicorn::prefer_negative_index::PreferNegative
impl RuleRunner for crate::rules::unicorn::prefer_node_protocol::PreferNodeProtocol {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::CallExpression,
AstType::ExportNamedDeclaration,
AstType::ExportFromDeclaration,
AstType::ImportDeclaration,
AstType::ImportExpression,
AstType::TSImportEqualsDeclaration,
@@ -3852,7 +3861,7 @@ impl RuleRunner for crate::rules::unicorn::require_array_join_separator::Require
impl RuleRunner for crate::rules::unicorn::require_module_attributes::RequireModuleAttributes {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportAllDeclaration,
AstType::ExportNamedDeclaration,
AstType::ExportFromDeclaration,
AstType::ImportDeclaration,
AstType::ImportExpression,
]));
@@ -3861,6 +3870,7 @@ impl RuleRunner for crate::rules::unicorn::require_module_attributes::RequireMod
impl RuleRunner for crate::rules::unicorn::require_module_specifiers::RequireModuleSpecifiers {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportFromDeclaration,
AstType::ExportNamedDeclaration,
AstType::ImportDeclaration,
]));
@@ -4273,8 +4283,8 @@ impl RuleRunner for crate::rules::oxc::no_rest_spread_properties::NoRestSpreadPr
impl RuleRunner for crate::rules::oxc::no_this_in_exported_function::NoThisInExportedFunction {
const NODE_TYPES: Option<&AstTypesBitset> = Some(&AstTypesBitset::from_types(&[
AstType::ExportDeclaration,
AstType::ExportDefaultDeclaration,
AstType::ExportNamedDeclaration,
AstType::ExportSpecifier,
]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
@@ -4412,7 +4422,7 @@ impl RuleRunner for crate::rules::nextjs::no_title_in_document_head::NoTitleInDo
impl RuleRunner for crate::rules::nextjs::no_typos::NoTypos {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::ExportNamedDeclaration]));
Some(&AstTypesBitset::from_types(&[AstType::ExportDeclaration]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
@@ -209,7 +209,7 @@ declare_oxc_lint!(
fn is_ancestor_export_name_decl<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>) -> bool {
if let Some(export_decl_ancestor) = nth_outermost_paren_parent(node, ctx, 2)
&& let AstKind::ExportNamedDeclaration(_) = export_decl_ancestor.kind()
&& let AstKind::ExportDeclaration(_) = export_decl_ancestor.kind()
{
return true;
}
@@ -268,7 +268,7 @@ impl FuncStyle {
if *style != Style::Declaration {
let should_diagnostic = match parent.kind() {
AstKind::ExportDefaultDeclaration(_) => false,
AstKind::ExportNamedDeclaration(_) => config.named_exports().is_none(),
AstKind::ExportDeclaration(_) => config.named_exports().is_none(),
_ => true,
};
if should_diagnostic {
@@ -277,7 +277,7 @@ impl FuncStyle {
}
if config.named_exports() == Some(&NamedExports::Expression)
&& matches!(parent.kind(), AstKind::ExportNamedDeclaration(_))
&& matches!(parent.kind(), AstKind::ExportDeclaration(_))
{
ctx.diagnostic(func_style_diagnostic(func.span, "expression"));
}
@@ -294,8 +294,8 @@ fn export_specifier_identifier_should_skip(
matches!(
ctx.nodes().parent_kind(specifier_node.id()),
AstKind::ExportNamedDeclaration(declaration)
if declaration.source.is_some() && specifier.local.span() == current_node.span()
AstKind::ExportFromDeclaration(_)
if specifier.local.span() == current_node.span()
)
}
@@ -176,7 +176,7 @@ fn check_rule<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>, allow_namespaces: b
// A declaration may be wrapped in `export`; look through it to find the real enclosing scope.
let enclosing = if matches!(
parent_kind,
AstKind::ExportNamedDeclaration(_) | AstKind::ExportDefaultDeclaration(_)
AstKind::ExportDeclaration(_) | AstKind::ExportDefaultDeclaration(_)
) {
ctx.nodes().parent_node(parent_node.id()).kind()
} else {
@@ -194,7 +194,7 @@ fn check_rule<'a>(node: &AstNode<'a>, ctx: &LintContext<'a>, allow_namespaces: b
AstKind::Program(_)
| AstKind::FunctionBody(_)
| AstKind::StaticBlock(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportDeclaration(_)
| AstKind::ExportDefaultDeclaration(_)
) {
return;
@@ -7,7 +7,10 @@ use serde::Deserialize;
use oxc_ast::{
AstKind,
ast::{Declaration, ExportAllDeclaration, ExportDefaultDeclaration, ExportNamedDeclaration},
ast::{
Declaration, ExportAllDeclaration, ExportDeclaration, ExportDefaultDeclaration,
ExportFromDeclaration, ExportNamedDeclaration, ExportSpecifier,
},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
@@ -210,7 +213,9 @@ impl Rule for NoRestrictedExports {
match node.kind() {
AstKind::ExportAllDeclaration(export) => self.check_export_all(export, ctx),
AstKind::ExportDefaultDeclaration(export) => self.check_export_default(export, ctx),
AstKind::ExportDeclaration(export) => self.check_export_declaration(export, ctx),
AstKind::ExportNamedDeclaration(export) => self.check_export_named(export, ctx),
AstKind::ExportFromDeclaration(export) => self.check_export_from(export, ctx),
_ => {}
}
}
@@ -243,7 +248,21 @@ impl NoRestrictedExports {
}
fn check_export_named(&self, export: &ExportNamedDeclaration, ctx: &LintContext) {
let (named_exports, has_default_exports, local_specifiers) = export.specifiers.iter().fold(
self.check_export_specifiers(export.span, &export.specifiers, false, ctx);
}
fn check_export_from(&self, export: &ExportFromDeclaration, ctx: &LintContext) {
self.check_export_specifiers(export.span, &export.specifiers, true, ctx);
}
fn check_export_specifiers(
&self,
span: Span,
specifiers: &[ExportSpecifier<'_>],
has_source: bool,
ctx: &LintContext,
) {
let (named_exports, has_default_exports, local_specifiers) = specifiers.iter().fold(
(Vec::new(), false, Vec::new()),
|(mut names, mut has_default, mut specifiers), spec| {
names.push(spec.exported.name().into_string());
@@ -261,41 +280,34 @@ impl NoRestrictedExports {
},
);
self.check_no_restricted_named_exports(ctx, export.span, named_exports);
self.check_no_restricted_named_exports(ctx, span, named_exports);
if has_default_exports {
self.check_no_restricted_named_default_exports(
ctx,
export.span,
export.source.is_some(),
local_specifiers,
);
self.check_no_restricted_named_default_exports(ctx, span, has_source, local_specifiers);
}
}
if let Some(declaration) = export.declaration.as_ref() {
match declaration {
Declaration::FunctionDeclaration(_) | Declaration::ClassDeclaration(_) => {
if let Some(id) = declaration.id() {
self.check_no_restricted_named_exports(
ctx,
export.span,
std::iter::once(id.name.into_string()),
);
}
}
Declaration::VariableDeclaration(variable) => {
fn check_export_declaration(&self, export: &ExportDeclaration, ctx: &LintContext) {
match &export.declaration {
Declaration::FunctionDeclaration(_) | Declaration::ClassDeclaration(_) => {
if let Some(id) = export.declaration.id() {
self.check_no_restricted_named_exports(
ctx,
export.span,
variable.declarations.iter().flat_map(|d| {
d.id.get_binding_identifiers()
.into_iter()
.map(|id| id.name.into_string())
}),
std::iter::once(id.name.into_string()),
);
}
_ => {}
}
Declaration::VariableDeclaration(variable) => {
self.check_no_restricted_named_exports(
ctx,
export.span,
variable.declarations.iter().flat_map(|d| {
d.id.get_binding_identifiers().into_iter().map(|id| id.name.into_string())
}),
);
}
_ => {}
}
}
@@ -749,7 +749,7 @@ fn is_initializer_sentinel(kind: AstKind) -> bool {
| AstKind::ArrowFunctionExpression(_)
| AstKind::CatchClause(_)
| AstKind::ImportDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportDeclaration(_)
)
}
@@ -101,7 +101,9 @@ fn is_ambient_namespace_without_explicit_exports(namespace: &TSModuleDeclaration
stmt,
Statement::ExportAllDeclaration(_)
| Statement::ExportDefaultDeclaration(_)
| Statement::ExportDeclaration(_)
| Statement::ExportNamedDeclaration(_)
| Statement::ExportFromDeclaration(_)
| Statement::TSExportAssignment(_)
)
});
@@ -188,7 +188,7 @@ impl Symbol<'_, '_> {
fn in_export_node(&self) -> bool {
for parent in self.nodes().ancestors(self.declaration_id()) {
match parent.kind() {
AstKind::ExportNamedDeclaration(_) | AstKind::ExportDefaultDeclaration(_) => {
AstKind::ExportDeclaration(_) | AstKind::ExportDefaultDeclaration(_) => {
return true;
}
AstKind::VariableDeclaration(_)
@@ -318,7 +318,9 @@ impl<'a> Symbol<'_, 'a> {
| AstKind::TSGlobalDeclaration(_)
| AstKind::VariableDeclaration(_)
| AstKind::VariableDeclarator(_)
| AstKind::ExportDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportFromDeclaration(_)
| AstKind::ExportDefaultDeclaration(_)
| AstKind::ExportAllDeclaration(_)
| AstKind::Program(_)
@@ -439,7 +439,9 @@ where
| AstKind::ArrowFunctionExpression(_)
| AstKind::CatchClause(_)
| AstKind::ImportDeclaration(_)
| AstKind::ExportNamedDeclaration(_) => break,
| AstKind::ExportDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportFromDeclaration(_) => break,
_ => {}
}
}
@@ -189,6 +189,28 @@ impl Rule for NoUselessRename {
}
}
}
AstKind::ExportFromDeclaration(export_from_decl) => {
if self.ignore_export {
return;
}
for specifier in &export_from_decl.specifiers {
if specifier.local.span() != specifier.exported.span()
&& specifier.local.name() == specifier.exported.name()
{
ctx.diagnostic_with_fix(
no_useless_rename_diagnostic(specifier.local.span()),
|fixer| {
let local_text = specifier
.local
.span()
.source_text(ctx.source_text())
.to_string();
fixer.replace(specifier.span, local_text)
},
);
}
}
}
_ => {}
}
}
@@ -110,7 +110,7 @@ impl Rule for VarsOnTop {
let parent = ctx.nodes().parent_node(node.id());
match parent.kind() {
AstKind::ExportNamedDeclaration(_) => {
AstKind::ExportDeclaration(_) => {
let grand_parent = ctx.nodes().parent_node(parent.id());
if let AstKind::Program(grand_parent) = grand_parent.kind() {
global_var_check(parent, grand_parent, ctx);
@@ -143,8 +143,8 @@ fn is_variable_declaration(node: &Statement) -> bool {
return true;
}
if let Statement::ExportNamedDeclaration(export) = node {
return matches!(export.declaration, Some(Declaration::VariableDeclaration(_)));
if let Statement::ExportDeclaration(export) = node {
return matches!(export.declaration, Declaration::VariableDeclaration(_));
}
false
@@ -74,8 +74,10 @@ fn is_exports_declaration(statement: &Statement) -> bool {
matches!(
declaration,
ModuleDeclaration::ExportAllDeclaration(_)
| ModuleDeclaration::ExportDeclaration(_)
| ModuleDeclaration::ExportDefaultDeclaration(_)
| ModuleDeclaration::ExportNamedDeclaration(_)
| ModuleDeclaration::ExportFromDeclaration(_)
)
})
}
@@ -75,28 +75,28 @@ impl Rule for GroupExports {
for node in semantic.nodes() {
match node.kind() {
AstKind::ExportNamedDeclaration(export_decl) => match export_decl.export_kind {
AstKind::ExportFromDeclaration(export_decl) => match export_decl.export_kind {
ImportOrExportKind::Value => {
if let Some(source) = &export_decl.source {
modules_source_record
.entry(source.value.to_string())
.or_default()
.push(export_decl.span);
} else {
modules_nodes.push(export_decl.span);
}
modules_source_record
.entry(export_decl.source.value.to_string())
.or_default()
.push(export_decl.span);
}
ImportOrExportKind::Type => {
if let Some(source) = &export_decl.source {
type_source_record
.entry(source.value.to_string())
.or_default()
.push(export_decl.span);
} else {
type_nodes.push(export_decl.span);
}
type_source_record
.entry(export_decl.source.value.to_string())
.or_default()
.push(export_decl.span);
}
},
AstKind::ExportNamedDeclaration(export_decl) => match export_decl.export_kind {
ImportOrExportKind::Value => modules_nodes.push(export_decl.span),
ImportOrExportKind::Type => type_nodes.push(export_decl.span),
},
AstKind::ExportDeclaration(export_decl) => match export_decl.export_kind() {
ImportOrExportKind::Value => modules_nodes.push(export_decl.span),
ImportOrExportKind::Type => type_nodes.push(export_decl.span),
},
AstKind::AssignmentExpression(assignment_expr) => {
let Some(member_expr) = assignment_expr.left.as_member_expression() else {
continue;
@@ -485,14 +485,12 @@ fn first_decorator_start(stmt: &Statement<'_>) -> Option<u32> {
}
_ => None,
},
Statement::ExportNamedDeclaration(export_named) => {
match export_named.declaration.as_ref() {
Some(Declaration::ClassDeclaration(class)) => {
class.decorators.first().map(|decorator| decorator.span.start)
}
_ => None,
Statement::ExportDeclaration(export_decl) => match &export_decl.declaration {
Declaration::ClassDeclaration(class) => {
class.decorators.first().map(|decorator| decorator.span.start)
}
}
_ => None,
},
_ => None,
}
}
@@ -62,32 +62,29 @@ declare_oxc_lint!(
impl Rule for NoMutableExports {
fn run<'a>(&self, node: &oxc_semantic::AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::ExportNamedDeclaration(export_name_decl) => {
AstKind::ExportDeclaration(export_decl) => {
// e.g. "export let a = 4;"
if let Some(declaration) = &export_name_decl.declaration {
let Declaration::VariableDeclaration(decl) = declaration else {
return;
};
if matches!(
decl.kind,
VariableDeclarationKind::Var | VariableDeclarationKind::Let
) {
ctx.diagnostic(no_mutable_exports_diagnostic(decl.span, decl.kind));
}
} else if export_name_decl.source.is_none() {
// e.g. "let a = 3; export { a }"
for specifier in &export_name_decl.specifiers {
if let ModuleExportName::IdentifierReference(ident) = &specifier.local {
let Some(declaration) =
get_reference_declaration(ident.reference_id(), ctx)
else {
continue;
};
ctx.diagnostic(no_mutable_exports_diagnostic(
declaration.span,
declaration.kind,
));
}
let Declaration::VariableDeclaration(decl) = &export_decl.declaration else {
return;
};
if matches!(decl.kind, VariableDeclarationKind::Var | VariableDeclarationKind::Let)
{
ctx.diagnostic(no_mutable_exports_diagnostic(decl.span, decl.kind));
}
}
AstKind::ExportNamedDeclaration(export_name_decl) => {
// e.g. "let a = 3; export { a }"
for specifier in &export_name_decl.specifiers {
if let ModuleExportName::IdentifierReference(ident) = &specifier.local {
let Some(declaration) =
get_reference_declaration(ident.reference_id(), ctx)
else {
continue;
};
ctx.diagnostic(no_mutable_exports_diagnostic(
declaration.span,
declaration.kind,
));
}
}
}
@@ -55,6 +55,9 @@ impl Rule for NoNamedExport {
AstKind::ExportAllDeclaration(all_decl) => {
ctx.diagnostic(no_named_export_diagnostic(all_decl.span));
}
AstKind::ExportDeclaration(export_decl) => {
ctx.diagnostic(no_named_export_diagnostic(export_decl.span));
}
AstKind::ExportNamedDeclaration(named_decl) => {
let specifiers = &named_decl.specifiers;
if specifiers.is_empty() {
@@ -64,6 +67,15 @@ impl Rule for NoNamedExport {
ctx.diagnostic(no_named_export_diagnostic(named_decl.span));
}
}
AstKind::ExportFromDeclaration(from_decl)
if from_decl.specifiers.is_empty()
|| from_decl
.specifiers
.iter()
.any(|specifier| specifier.exported.name() != "default") =>
{
ctx.diagnostic(no_named_export_diagnostic(from_decl.span));
}
_ => {}
}
}
@@ -107,9 +107,7 @@ impl Rule for NoNodejsModules {
call.common_js_require().map(|s| s.value)
}
AstKind::ImportDeclaration(import) => Some(import.source.value),
AstKind::ExportNamedDeclaration(export) => {
export.source.as_ref().map(|item| item.value)
}
AstKind::ExportFromDeclaration(export) => Some(export.source.value),
AstKind::ExportAllDeclaration(export_all) => Some(export_all.source.value),
_ => return,
};
@@ -61,11 +61,9 @@ impl Rule for NoRelativeParentImports {
ctx.diagnostic(no_relative_parent_imports_diagnostic(import_decl.source.span));
}
// ESM export { } from '...'
AstKind::ExportNamedDeclaration(export_decl) => {
if let Some(source) = &export_decl.source
&& is_parent_import(source.value.as_str())
{
ctx.diagnostic(no_relative_parent_imports_diagnostic(source.span));
AstKind::ExportFromDeclaration(export_decl) => {
if is_parent_import(export_decl.source.value.as_str()) {
ctx.diagnostic(no_relative_parent_imports_diagnostic(export_decl.source.span));
}
}
// ESM export * from '...'
@@ -77,10 +77,8 @@ impl Rule for NoTypos {
}
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::ExportNamedDeclaration(en_decl) = node.kind()
&& let Some(decl) = &en_decl.declaration
{
match decl {
if let AstKind::ExportDeclaration(en_decl) = node.kind() {
match &en_decl.declaration {
Declaration::VariableDeclaration(decl) => {
for decl in &decl.declarations {
if let BindingPattern::BindingIdentifier(id) = &decl.id {
@@ -68,8 +68,8 @@ declare_oxc_lint!(
impl Rule for NoThisInExportedFunction {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::ExportNamedDeclaration(export_decl) => {
if let Some(Declaration::FunctionDeclaration(func)) = &export_decl.declaration {
AstKind::ExportDeclaration(export_decl) => {
if let Declaration::FunctionDeclaration(func) = &export_decl.declaration {
check_function_for_this(func, ctx);
}
}
@@ -255,7 +255,10 @@ impl OnlyExportComponents {
.any(|id| {
matches!(
nodes.get_node(id).kind(),
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_)
AstKind::ExportDefaultDeclaration(_)
| AstKind::ExportDeclaration(_)
| AstKind::ExportFromDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
)
})
}
@@ -285,10 +288,20 @@ impl OnlyExportComponents {
}
analysis.merge(result);
}
AstKind::ExportDeclaration(export_decl) => {
let result = self.analyze_export_declaration(ctx, export_decl);
analysis.merge(result);
}
AstKind::ExportNamedDeclaration(export_named)
if export_named.export_kind.is_value() =>
{
let result = self.analyze_export_named(ctx, export_named);
let result = self.analyze_export_specifiers(&export_named.specifiers);
analysis.merge(result);
}
AstKind::ExportFromDeclaration(export_from)
if export_from.export_kind.is_value() =>
{
let result = self.analyze_export_specifiers(&export_from.specifiers);
analysis.merge(result);
}
_ => {}
@@ -436,82 +449,77 @@ impl OnlyExportComponents {
analysis
}
fn analyze_export_named(
fn analyze_export_declaration(
&self,
ctx: &LintContext,
export_named: &ExportNamedDeclaration,
export_decl: &ExportDeclaration,
) -> ExportAnalysis {
let mut analysis = ExportAnalysis::default();
if let Some(declaration) = &export_named.declaration {
let exports = match declaration {
Declaration::VariableDeclaration(var_decl) => var_decl
.declarations
.iter()
.map(|declarator| match &declarator.id {
BindingPattern::BindingIdentifier(binding_id) => {
let is_func =
self.can_be_react_function_component(declarator.init.as_ref());
self.classify_export(
binding_id.name.as_str(),
binding_id.span,
is_func,
declarator.init.as_ref(),
)
}
_ => ExportType::NonComponent(declarator.id.span()),
})
.collect::<Vec<_>>(),
Declaration::FunctionDeclaration(func) => func.id.as_ref().map_or_else(
|| {
ctx.diagnostic(anonymous_components_diagnostic(func.span));
vec![]
},
|id| vec![self.classify_export(id.name.as_str(), id.span, true, None)],
),
Declaration::ClassDeclaration(class) => class.id.as_ref().map_or(vec![], |id| {
vec![if is_react_component_name(&id.name)
&& Self::extends_react_component(class)
{
ExportType::ReactComponent
} else {
ExportType::NonComponent(id.span)
}]
}),
Declaration::TSEnumDeclaration(ts_enum) => {
vec![ExportType::NonComponent(ts_enum.id.span)]
}
_ => vec![],
};
for export in exports {
analysis.add_export(export);
let exports = match &export_decl.declaration {
Declaration::VariableDeclaration(var_decl) => var_decl
.declarations
.iter()
.map(|declarator| match &declarator.id {
BindingPattern::BindingIdentifier(binding_id) => {
let is_func =
self.can_be_react_function_component(declarator.init.as_ref());
self.classify_export(
binding_id.name.as_str(),
binding_id.span,
is_func,
declarator.init.as_ref(),
)
}
_ => ExportType::NonComponent(declarator.id.span()),
})
.collect::<Vec<_>>(),
Declaration::FunctionDeclaration(func) => func.id.as_ref().map_or_else(
|| {
ctx.diagnostic(anonymous_components_diagnostic(func.span));
vec![]
},
|id| vec![self.classify_export(id.name.as_str(), id.span, true, None)],
),
Declaration::ClassDeclaration(class) => class.id.as_ref().map_or(vec![], |id| {
vec![if is_react_component_name(&id.name) && Self::extends_react_component(class) {
ExportType::ReactComponent
} else {
ExportType::NonComponent(id.span)
}]
}),
Declaration::TSEnumDeclaration(ts_enum) => {
vec![ExportType::NonComponent(ts_enum.id.span)]
}
_ => vec![],
};
for export in exports {
analysis.add_export(export);
}
let specifier_exports: Vec<ExportType> = export_named
.specifiers
.iter()
.map(|export_spec| {
let exported_name = match &export_spec.exported {
ModuleExportName::IdentifierName(name) => Some(name.name.as_str()),
ModuleExportName::IdentifierReference(ident) => Some(ident.name.as_str()),
ModuleExportName::StringLiteral(_) => None,
};
analysis
}
let local_name = export_spec.local.name();
let span = export_spec.local.span();
fn analyze_export_specifiers(&self, specifiers: &[ExportSpecifier]) -> ExportAnalysis {
let mut analysis = ExportAnalysis::default();
if exported_name == Some("default") {
self.classify_export(local_name.as_str(), span, false, None)
} else if let Some(name) = exported_name {
self.classify_export(name, span, false, None)
} else {
ExportType::NonComponent(span)
}
})
.collect();
for export_spec in specifiers {
let exported_name = match &export_spec.exported {
ModuleExportName::IdentifierName(name) => Some(name.name.as_str()),
ModuleExportName::IdentifierReference(ident) => Some(ident.name.as_str()),
ModuleExportName::StringLiteral(_) => None,
};
for export in specifier_exports {
let local_name = export_spec.local.name();
let span = export_spec.local.span();
let export = if exported_name == Some("default") {
self.classify_export(local_name.as_str(), span, false, None)
} else if let Some(name) = exported_name {
self.classify_export(name, span, false, None)
} else {
ExportType::NonComponent(span)
};
analysis.add_export(export);
}
@@ -786,6 +794,8 @@ fn test() {
("function Foo() {}; export default React.memo(Foo);", None),
("function Foo() {}; export default React.memo(Foo) as typeof Foo;", None),
("export type * from './module';", None),
("export { Foo } from './mod';", None),
("export type { Foo, helper } from './mod';", None),
("type foo = string; export const Foo = () => null; export type { foo };", None),
("export type foo = string; export const Foo = () => null;", None),
(
@@ -901,6 +911,7 @@ export function Button(props: PropsWithChildren): ReactNode {
("export const foo = 4; export const Bar = () => {};", None),
("export function Component() {}; export const Aa = 'a'", None),
("const foo = 4; const Bar = () => {}; export { foo, Bar };", None),
("export { Foo, helper } from './mod';", None),
("export * from './foo';", None),
("export default () => {};", None),
("export default memo(() => {});", None),
@@ -206,8 +206,8 @@ impl GetMethod for ModuleDeclaration<'_> {
_ => None,
}
}
ModuleDeclaration::ExportNamedDeclaration(named_decl) => {
if let Some(Declaration::FunctionDeclaration(func_decl)) = &named_decl.declaration {
ModuleDeclaration::ExportDeclaration(export_decl) => {
if let Declaration::FunctionDeclaration(func_decl) = &export_decl.declaration {
return func_decl.id.as_ref().map(|id| Method {
name: id.name.to_compact_str(),
r#static: false,
@@ -181,20 +181,15 @@ impl Rule for ExplicitModuleBoundaryTypes {
match node.kind() {
// look for `export function foo() { ... }`, `export const foo = () => { ... }`,
// etc.
AstKind::ExportDeclaration(export) => {
let mut checker = ExplicitTypesChecker::new(self, ctx);
walk_js::walk_declaration(&mut checker, &export.declaration);
}
AstKind::ExportNamedDeclaration(export) => {
// export { foo } from 'bar';
if export.source.is_some() {
return;
}
if let Some(decl) = &export.declaration {
let mut checker = ExplicitTypesChecker::new(self, ctx);
walk_js::walk_declaration(&mut checker, decl);
} else {
let mut checker = ExplicitTypesChecker::new(self, ctx);
for specifier in &export.specifiers {
if let ModuleExportName::IdentifierReference(id) = &specifier.local {
Self::run_on_identifier_reference(ctx, id, &mut checker);
}
let mut checker = ExplicitTypesChecker::new(self, ctx);
for specifier in &export.specifiers {
if let ModuleExportName::IdentifierReference(id) = &specifier.local {
Self::run_on_identifier_reference(ctx, id, &mut checker);
}
}
}
@@ -147,7 +147,7 @@ impl Rule for NoExtraneousClass {
if has_decorators {
return fixer.noop();
}
if let AstKind::ExportNamedDeclaration(decl) =
if let AstKind::ExportDeclaration(decl) =
ctx.nodes().parent_kind(node.id())
{
fixer.delete(decl)
@@ -408,7 +408,7 @@ fn has_function_overload_signatures(
ctx: &LintContext<'_>,
) -> bool {
let wrapper = match ctx.nodes().parent_kind(function_node.id()) {
AstKind::ExportNamedDeclaration(_) => FunctionStatementWrapper::ExportNamed,
AstKind::ExportDeclaration(_) => FunctionStatementWrapper::ExportNamed,
AstKind::ExportDefaultDeclaration(_) => FunctionStatementWrapper::ExportDefault,
_ => FunctionStatementWrapper::Plain,
};
@@ -474,8 +474,8 @@ fn statement_function_candidate<'a>(
if let Some(module_decl) = statement.as_module_declaration() {
match module_decl {
ModuleDeclaration::ExportNamedDeclaration(named_decl) => {
if let Some(Declaration::FunctionDeclaration(function)) = &named_decl.declaration {
ModuleDeclaration::ExportDeclaration(export_decl) => {
if let Declaration::FunctionDeclaration(function) = &export_decl.declaration {
return Some((function, FunctionStatementWrapper::ExportNamed));
}
}
@@ -60,7 +60,7 @@ declare_oxc_lint!(
impl Rule for NoUselessEmptyExport {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
let AstKind::ExportNamedDeclaration(decl) = node.kind() else { return };
if decl.declaration.is_some() || !decl.specifiers.is_empty() {
if !decl.specifiers.is_empty() {
return;
}
let module_record = ctx.module_record();
@@ -151,7 +151,7 @@ fn check_member(member: &TSSignature, node: &AstNode<'_>, ctx: &LintContext<'_>)
let mut is_parent_exported = false;
let mut node_start = interface_decl.span.start;
let mut node_end = interface_decl.span.end;
if let AstKind::ExportNamedDeclaration(export_name_decl) =
if let AstKind::ExportDeclaration(export_name_decl) =
ctx.nodes().parent_kind(node.id())
{
is_parent_exported = true;
@@ -364,8 +364,8 @@ fn get_statement_overload<'a>(
let module_declaration = statement.as_module_declaration()?;
match module_declaration {
oxc_ast::ast::ModuleDeclaration::ExportNamedDeclaration(export_named) => {
let Some(Declaration::FunctionDeclaration(function)) = &export_named.declaration else {
oxc_ast::ast::ModuleDeclaration::ExportDeclaration(export_decl) => {
let Declaration::FunctionDeclaration(function) = &export_decl.declaration else {
return None;
};
if function.r#type != FunctionType::TSDeclareFunction {
@@ -377,7 +377,7 @@ fn get_statement_overload<'a>(
key,
OverloadCandidate {
signature: SignatureDefinition::Function(function),
comment_target_start: export_named.span.start,
comment_target_start: export_decl.span.start,
},
))
}
@@ -12,7 +12,7 @@ use oxc_ast::{
AstKind,
ast::{
BinaryOperator, BindingPattern, CallExpression, ExportAllDeclaration,
ExportNamedDeclaration, Expression, ImportDeclaration, ImportDeclarationSpecifier,
ExportFromDeclaration, Expression, ImportDeclaration, ImportDeclarationSpecifier,
ModuleExportName, VariableDeclarator,
},
};
@@ -325,7 +325,7 @@ impl Rule for ImportStyle {
AstKind::ExportAllDeclaration(export_decl) if self.check_export_from => {
self.check_export_all_declaration(export_decl, ctx);
}
AstKind::ExportNamedDeclaration(export_decl) if self.check_export_from => {
AstKind::ExportFromDeclaration(export_decl) if self.check_export_from => {
self.check_export_named_declaration(export_decl, ctx);
}
AstKind::ExpressionStatement(statement) if self.check_require => {
@@ -375,14 +375,13 @@ impl ImportStyle {
fn check_export_named_declaration(
&self,
export_decl: &ExportNamedDeclaration<'_>,
export_decl: &ExportFromDeclaration<'_>,
ctx: &LintContext<'_>,
) {
let Some(source) = &export_decl.source else { return };
let actual_styles = get_actual_export_declaration_styles(export_decl);
self.report_if_needed(
export_decl.span,
source.value.as_str(),
export_decl.source.value.as_str(),
actual_styles,
SourceKind::ModuleSyntax,
ctx,
@@ -494,7 +493,7 @@ fn get_actual_import_declaration_styles(import_decl: &ImportDeclaration<'_>) ->
styles
}
fn get_actual_export_declaration_styles(export_decl: &ExportNamedDeclaration<'_>) -> StyleSet {
fn get_actual_export_declaration_styles(export_decl: &ExportFromDeclaration<'_>) -> StyleSet {
if export_decl.specifiers.is_empty() {
return StyleSet::unassigned();
}
@@ -100,33 +100,41 @@ impl Rule for NoThenable {
ctx.diagnostic(class(span));
}
}
AstKind::ExportNamedDeclaration(decl) => {
AstKind::ExportDeclaration(decl) => {
// check declaration
if let Some(decl) = &decl.declaration {
match decl {
Declaration::VariableDeclaration(decl) => {
for decl in &decl.declarations {
check_binding_pattern(&decl.id, ctx);
}
let decl = &decl.declaration;
match decl {
Declaration::VariableDeclaration(decl) => {
for decl in &decl.declarations {
check_binding_pattern(&decl.id, ctx);
}
Declaration::FunctionDeclaration(decl) => {
if let Some(bind) = decl.id.as_ref()
&& bind.name == "then"
{
ctx.diagnostic(export(bind.span));
}
}
Declaration::FunctionDeclaration(decl) => {
if let Some(bind) = decl.id.as_ref()
&& bind.name == "then"
{
ctx.diagnostic(export(bind.span));
}
Declaration::ClassDeclaration(decl) => {
if let Some(bind) = decl.id.as_ref()
&& bind.name == "then"
{
ctx.diagnostic(export(bind.span));
}
}
Declaration::ClassDeclaration(decl) => {
if let Some(bind) = decl.id.as_ref()
&& bind.name == "then"
{
ctx.diagnostic(export(bind.span));
}
_ => {}
}
_ => {}
}
}
AstKind::ExportNamedDeclaration(decl) => {
// check specifier
for spec in &decl.specifiers {
if spec.exported.name() == "then" {
ctx.diagnostic(export(spec.exported.span()));
}
}
// check specifier
}
AstKind::ExportFromDeclaration(decl) => {
for spec in &decl.specifiers {
if spec.exported.name() == "then" {
ctx.diagnostic(export(spec.exported.span()));
@@ -151,10 +151,7 @@ impl Rule for PreferArrayFind {
&& is_filter_call(call_expr)
&& !matches!(
ctx.nodes().ancestor_kinds(node.id()).nth(1),
Some(
AstKind::ExportDefaultDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
)
Some(AstKind::ExportDefaultDeclaration(_) | AstKind::ExportDeclaration(_))
)
&& let Some(ident) = var_decl.id.get_binding_identifier()
{
@@ -7,7 +7,7 @@ use serde::Deserialize;
use oxc_ast::{
AstKind,
ast::{
BindingPattern, ExportNamedDeclaration, ExportSpecifier, ImportAttributeKey,
BindingPattern, ExportFromDeclaration, ExportSpecifier, ImportAttributeKey,
ImportDeclaration, ImportDeclarationSpecifier, ImportOrExportKind, ModuleExportName,
Statement, VariableDeclarationKind, VariableDeclarator, WithClause, WithClauseKeyword,
},
@@ -104,7 +104,7 @@ impl Rule for PreferExportFrom {
return;
}
let corresponding_export: Option<&ExportNamedDeclaration> =
let corresponding_export: Option<&ExportFromDeclaration> =
find_corresponding_export(ctx, import_decl);
let symbol_to_specifier_specs = Self::get_symbol_to_specifier(import_decl);
@@ -144,7 +144,7 @@ impl PreferExportFrom {
ctx: &LintContext<'a>,
symbol_to_specifier: &FxIndexMap<SymbolId, SpecifierSpec<'a>>,
import_decl: &'a ImportDeclaration<'a>,
re_export_decl: Option<&'a ExportNamedDeclaration<'a>>,
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
) {
let (locally_used_specifiers, violations) =
self.analyze_import_usage(ctx, symbol_to_specifier, import_decl);
@@ -317,7 +317,7 @@ impl PreferExportFrom {
if variable_declaration.kind == VariableDeclarationKind::Const
&& matches!(
ctx.nodes().parent_node(declaration_node.id()).kind(),
AstKind::ExportNamedDeclaration(_)
AstKind::ExportDeclaration(_)
)
)
}
@@ -430,9 +430,8 @@ impl PreferExportFrom {
false
};
let needs_source = !ts_kind
&& matches!(export_decl.export_kind, ImportOrExportKind::Type)
&& export_decl.source.is_none();
let needs_source =
!ts_kind && matches!(export_decl.export_kind, ImportOrExportKind::Type);
let violation = Violation {
export_name,
@@ -462,7 +461,7 @@ impl PreferExportFrom {
if let AstKind::VariableDeclaration(var_declaration) = next_parent_node.kind()
&& var_declaration.kind == VariableDeclarationKind::Const
&& let AstKind::ExportNamedDeclaration(export_named_decl) =
&& let AstKind::ExportDeclaration(export_named_decl) =
ctx.nodes().parent_node(next_parent_node.id()).kind()
{
if Self::is_variable_used_elsewhere(ctx, var_decl) {
@@ -667,7 +666,7 @@ impl PreferExportFrom {
locally_used_specifiers: &FxHashSet<SymbolId>,
symbol_to_specifier: &FxIndexMap<SymbolId, SpecifierSpec<'a>>,
import_decl: &'a ImportDeclaration<'a>,
re_export_decl: Option<&'a ExportNamedDeclaration<'a>>,
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
source: &str,
with_clause: Option<&str>,
replace_span: Span,
@@ -817,7 +816,7 @@ impl PreferExportFrom {
locally_used_specifiers: &FxHashSet<SymbolId>,
symbol_to_specifier: &FxIndexMap<SymbolId, SpecifierSpec<'a>>,
import_decl: &'a ImportDeclaration<'a>,
re_export_decl: Option<&'a ExportNamedDeclaration<'a>>,
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
re_export_source_text: &str,
replace_span: Span,
replace_export_spans: &[Span],
@@ -871,7 +870,7 @@ impl PreferExportFrom {
fixer: RuleFixer<'_, '_>,
rule_fixes: &mut RuleFix,
import_decl: &'a ImportDeclaration<'a>,
re_export_decl: Option<&'a ExportNamedDeclaration<'a>>,
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
re_export_source_text: &str,
replace_span: Span,
replace_export_spans: &[Span],
@@ -902,7 +901,7 @@ impl PreferExportFrom {
fn handle_reexport_case<'a>(
fixer: RuleFixer<'_, '_>,
rule_fixes: &mut RuleFix,
re_export: &'a ExportNamedDeclaration<'a>,
re_export: &'a ExportFromDeclaration<'a>,
re_export_source_text: &str,
import_decl: &'a ImportDeclaration<'a>,
replace_span: Span,
@@ -916,7 +915,7 @@ impl PreferExportFrom {
let processed_exports_str = Self::get_processed_exports_str(exports_str, re_export);
if is_namespace {
let source = re_export.source.as_ref().unwrap().raw.unwrap();
let source = re_export.source.raw.unwrap();
let final_replacement = format!("export {processed_exports_str} from {source}");
rule_fixes.push(fixer.replace(import_decl.span(), final_replacement));
} else {
@@ -938,7 +937,7 @@ impl PreferExportFrom {
fn get_last_export_span(
last_specifier: Option<&ExportSpecifier>,
re_export_source_text: &str,
re_export: &ExportNamedDeclaration,
re_export: &ExportFromDeclaration,
) -> Span {
if let Some(specifier) = last_specifier {
specifier.span()
@@ -957,7 +956,7 @@ impl PreferExportFrom {
retained_specifiers: &[(&SymbolId, &SpecifierSpec<'a>)],
import_decl: &'a ImportDeclaration<'a>,
replace_span: Span,
re_export_decl: Option<&'a ExportNamedDeclaration<'a>>,
re_export_decl: Option<&'a ExportFromDeclaration<'a>>,
delete_span: Span,
exports_str: &str,
replacement_str: &str,
@@ -1038,7 +1037,7 @@ impl PreferExportFrom {
}
}
fn get_processed_exports_str(exports_str: &str, re_export: &ExportNamedDeclaration) -> String {
fn get_processed_exports_str(exports_str: &str, re_export: &ExportFromDeclaration) -> String {
if matches!(re_export.export_kind, ImportOrExportKind::Type) {
exports_str.cow_replace("type ", "").to_string()
} else {
@@ -1049,7 +1048,7 @@ impl PreferExportFrom {
fn get_insertion_text_for_regular_export(
last_specifier: Option<&ExportSpecifier>,
processed_exports_str: &str,
re_export: &ExportNamedDeclaration,
re_export: &ExportFromDeclaration,
re_export_source_text: &str,
) -> String {
match last_specifier {
@@ -1146,7 +1145,7 @@ fn has_matching_type_alias<'a>(
fn find_corresponding_export<'a>(
ctx: &LintContext<'a>,
import_decl: &'a ImportDeclaration<'a>,
) -> Option<&'a ExportNamedDeclaration<'a>> {
) -> Option<&'a ExportFromDeclaration<'a>> {
let source = import_decl.source.value.as_str();
for requested_module in ctx.module_record().requested_modules.get(source)? {
@@ -1177,9 +1176,9 @@ fn find_corresponding_export<'a>(
fn find_export_named_declaration_by_span<'a>(
ctx: &LintContext<'a>,
span: Span,
) -> Option<&'a ExportNamedDeclaration<'a>> {
) -> Option<&'a ExportFromDeclaration<'a>> {
ctx.nodes().iter().find_map(|node| {
if let AstKind::ExportNamedDeclaration(export_decl) = node.kind()
if let AstKind::ExportFromDeclaration(export_decl) = node.kind()
&& export_decl.span() == span
{
Some(export_decl)
@@ -1191,7 +1190,7 @@ fn find_export_named_declaration_by_span<'a>(
fn is_matching_export_kind(
import_decl: &ImportDeclaration<'_>,
export_decl: &ExportNamedDeclaration<'_>,
export_decl: &ExportFromDeclaration<'_>,
) -> bool {
if import_decl.import_kind == export_decl.export_kind {
return true;
@@ -65,8 +65,8 @@ impl Rule for PreferNodeProtocol {
call.common_js_require().map(|s| (s.value, s.span))
}
AstKind::ImportDeclaration(import) => Some((import.source.value, import.source.span)),
AstKind::ExportNamedDeclaration(export) => {
export.source.as_ref().map(|item| (item.value, item.span))
AstKind::ExportFromDeclaration(export) => {
Some((export.source.value, export.source.span))
}
_ => return,
};
@@ -88,10 +88,8 @@ impl Rule for PreferStringRaw {
AstKind::ImportDeclaration(decl) if string_literal.span == decl.source.span => {
return;
}
AstKind::ExportNamedDeclaration(decl) => {
if let Some(source) = &decl.source
&& string_literal.span == source.span
{
AstKind::ExportFromDeclaration(decl) => {
if string_literal.span == decl.source.span {
return;
}
}
@@ -135,15 +135,13 @@ impl Rule for RequireModuleAttributes {
"import statement",
);
}
AstKind::ExportNamedDeclaration(decl) => {
if let Some(source) = &decl.source {
check_with_clause(
ctx,
decl.with_clause.as_deref(),
source.span,
"export statement",
);
}
AstKind::ExportFromDeclaration(decl) => {
check_with_clause(
ctx,
decl.with_clause.as_deref(),
decl.source.span,
"export statement",
);
}
AstKind::ExportAllDeclaration(decl) => {
check_with_clause(
@@ -67,9 +67,7 @@ impl Rule for RequireModuleSpecifiers {
|fixer| fix_import(fixer, import_decl),
);
}
AstKind::ExportNamedDeclaration(export_decl)
if export_decl.declaration.is_none() && export_decl.specifiers.is_empty() =>
{
AstKind::ExportNamedDeclaration(export_decl) if export_decl.specifiers.is_empty() => {
let span =
find_empty_braces_in_export(ctx, export_decl).unwrap_or(export_decl.span);
ctx.diagnostic_with_fix(
@@ -77,6 +75,12 @@ impl Rule for RequireModuleSpecifiers {
|fixer| fix_export(fixer, export_decl),
);
}
AstKind::ExportFromDeclaration(export_decl) if export_decl.specifiers.is_empty() => {
let span =
find_empty_braces_in_text(ctx.source_range(export_decl.span), export_decl.span)
.unwrap_or(export_decl.span);
ctx.diagnostic(require_module_specifiers_diagnostic(span, "export"));
}
_ => {}
}
}
@@ -144,10 +148,6 @@ fn fix_import<'a>(fixer: RuleFixer<'_, 'a>, import_decl: &ImportDeclaration<'a>)
}
fn fix_export<'a>(fixer: RuleFixer<'_, 'a>, export_decl: &ExportNamedDeclaration<'a>) -> RuleFix {
if export_decl.source.is_some() {
return fixer.noop();
}
// Remove the entire `export {}` statement
fixer.delete(&export_decl.span)
}
@@ -184,7 +184,7 @@ fn has_vue_component_annotation(node: &AstNode, ctx: &LintContext) -> bool {
if matches!(
ancestor.kind(),
AstKind::ExportDefaultDeclaration(_)
| AstKind::ExportNamedDeclaration(_)
| AstKind::ExportDeclaration(_)
| AstKind::ExpressionStatement(_)
| AstKind::VariableDeclaration(_)
) {
@@ -38,6 +38,12 @@ source: crates/oxc_linter/src/tester.rs
· ───
╰────
⚠ react(only-export-components): Fast refresh only works when a file only exports components. Use a new file to share constants or functions between components.
╭─[only_export_components.tsx:1:15]
1 │ export { Foo, helper } from './mod';
· ──────
╰────
⚠ react(only-export-components): This rule can't verify that `export *` only exports components.
╭─[only_export_components.tsx:1:1]
1 │ export * from './foo';
+1 -1
View File
@@ -104,7 +104,7 @@ pub fn get_function_nearest_jsdoc_node<'a, 'b>(
// export const foo = () => {}
let parent_node = semantic.nodes().parent_node(current_node.id());
match parent_node.kind() {
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportNamedDeclaration(_) => return Some(parent_node),
AstKind::ExportDefaultDeclaration(_) | AstKind::ExportDeclaration(_) => return Some(parent_node),
_ => return None
}
},
+2 -2
View File
@@ -875,8 +875,8 @@ fn collect_exported_symbols<'a>(
let mut exported_symbols = BitSet::new_in(symbols_len, allocator);
let mut exported_names = ArenaHashSet::new_in(allocator);
for statement in &program.body {
let Statement::ExportNamedDeclaration(v) = statement else { continue };
let Some(decl) = &v.declaration else { continue };
let Statement::ExportDeclaration(v) = statement else { continue };
let decl = &v.declaration;
if let Declaration::VariableDeclaration(decl) = decl {
// Use `bound_names` rather than `get_binding_identifier`: a destructuring
// pattern (`export const { find } = x`) exports every bound name, and
+278 -279
View File
@@ -181,146 +181,147 @@ pub(crate) enum AncestorType {
WithClauseWithEntries = 157,
ImportAttributeKey = 158,
ImportAttributeValue = 159,
ExportNamedDeclarationDeclaration = 160,
ExportDeclarationDeclaration = 160,
ExportNamedDeclarationSpecifiers = 161,
ExportNamedDeclarationSource = 162,
ExportNamedDeclarationWithClause = 163,
ExportDefaultDeclarationDeclaration = 164,
ExportAllDeclarationExported = 165,
ExportAllDeclarationSource = 166,
ExportAllDeclarationWithClause = 167,
ExportSpecifierLocal = 168,
ExportSpecifierExported = 169,
V8IntrinsicExpressionName = 170,
V8IntrinsicExpressionArguments = 171,
JSXElementOpeningElement = 172,
JSXElementChildren = 173,
JSXElementClosingElement = 174,
JSXOpeningElementName = 175,
JSXOpeningElementTypeArguments = 176,
JSXOpeningElementAttributes = 177,
JSXClosingElementName = 178,
JSXFragmentOpeningFragment = 179,
JSXFragmentChildren = 180,
JSXFragmentClosingFragment = 181,
JSXNamespacedNameNamespace = 182,
JSXNamespacedNameName = 183,
JSXMemberExpressionObject = 184,
JSXMemberExpressionProperty = 185,
JSXExpressionContainerExpression = 186,
JSXAttributeName = 187,
JSXAttributeValue = 188,
JSXSpreadAttributeArgument = 189,
JSXSpreadChildExpression = 190,
TSThisParameterTypeAnnotation = 191,
TSEnumDeclarationId = 192,
TSEnumDeclarationBody = 193,
TSEnumBodyMembers = 194,
TSEnumMemberId = 195,
TSEnumMemberInitializer = 196,
TSTypeAnnotationTypeAnnotation = 197,
TSLiteralTypeLiteral = 198,
TSConditionalTypeCheckType = 199,
TSConditionalTypeExtendsType = 200,
TSConditionalTypeTrueType = 201,
TSConditionalTypeFalseType = 202,
TSUnionTypeTypes = 203,
TSIntersectionTypeTypes = 204,
TSParenthesizedTypeTypeAnnotation = 205,
TSTypeOperatorTypeAnnotation = 206,
TSArrayTypeElementType = 207,
TSIndexedAccessTypeObjectType = 208,
TSIndexedAccessTypeIndexType = 209,
TSTupleTypeElementTypes = 210,
TSNamedTupleMemberLabel = 211,
TSNamedTupleMemberElementType = 212,
TSOptionalTypeTypeAnnotation = 213,
TSRestTypeTypeAnnotation = 214,
TSTypeReferenceTypeName = 215,
TSTypeReferenceTypeArguments = 216,
TSQualifiedNameLeft = 217,
TSQualifiedNameRight = 218,
TSTypeParameterInstantiationParams = 219,
TSTypeParameterName = 220,
TSTypeParameterConstraint = 221,
TSTypeParameterDefault = 222,
TSTypeParameterDeclarationParams = 223,
TSTypeAliasDeclarationId = 224,
TSTypeAliasDeclarationTypeParameters = 225,
TSTypeAliasDeclarationTypeAnnotation = 226,
TSClassImplementsExpression = 227,
TSClassImplementsTypeArguments = 228,
TSInterfaceDeclarationId = 229,
TSInterfaceDeclarationTypeParameters = 230,
TSInterfaceDeclarationExtends = 231,
TSInterfaceDeclarationBody = 232,
TSInterfaceBodyBody = 233,
TSPropertySignatureKey = 234,
TSPropertySignatureTypeAnnotation = 235,
TSIndexSignatureParameters = 236,
TSIndexSignatureTypeAnnotation = 237,
TSCallSignatureDeclarationTypeParameters = 238,
TSCallSignatureDeclarationThisParam = 239,
TSCallSignatureDeclarationParams = 240,
TSCallSignatureDeclarationReturnType = 241,
TSMethodSignatureKey = 242,
TSMethodSignatureTypeParameters = 243,
TSMethodSignatureThisParam = 244,
TSMethodSignatureParams = 245,
TSMethodSignatureReturnType = 246,
TSConstructSignatureDeclarationTypeParameters = 247,
TSConstructSignatureDeclarationParams = 248,
TSConstructSignatureDeclarationReturnType = 249,
TSIndexSignatureNameTypeAnnotation = 250,
TSInterfaceHeritageExpression = 251,
TSInterfaceHeritageTypeArguments = 252,
TSTypePredicateParameterName = 253,
TSTypePredicateTypeAnnotation = 254,
TSModuleDeclarationId = 255,
TSModuleDeclarationBody = 256,
TSGlobalDeclarationBody = 257,
TSModuleBlockDirectives = 258,
TSModuleBlockBody = 259,
TSTypeLiteralMembers = 260,
TSInferTypeTypeParameter = 261,
TSTypeQueryExprName = 262,
TSTypeQueryTypeArguments = 263,
TSImportTypeSource = 264,
TSImportTypeOptions = 265,
TSImportTypeQualifier = 266,
TSImportTypeTypeArguments = 267,
TSImportTypeQualifiedNameLeft = 268,
TSImportTypeQualifiedNameRight = 269,
TSFunctionTypeTypeParameters = 270,
TSFunctionTypeThisParam = 271,
TSFunctionTypeParams = 272,
TSFunctionTypeReturnType = 273,
TSConstructorTypeTypeParameters = 274,
TSConstructorTypeParams = 275,
TSConstructorTypeReturnType = 276,
TSMappedTypeKey = 277,
TSMappedTypeConstraint = 278,
TSMappedTypeNameType = 279,
TSMappedTypeTypeAnnotation = 280,
TSTemplateLiteralTypeQuasis = 281,
TSTemplateLiteralTypeTypes = 282,
TSAsExpressionExpression = 283,
TSAsExpressionTypeAnnotation = 284,
TSSatisfiesExpressionExpression = 285,
TSSatisfiesExpressionTypeAnnotation = 286,
TSTypeAssertionTypeAnnotation = 287,
TSTypeAssertionExpression = 288,
TSImportEqualsDeclarationId = 289,
TSImportEqualsDeclarationModuleReference = 290,
TSExternalModuleReferenceExpression = 291,
TSNonNullExpressionExpression = 292,
DecoratorExpression = 293,
TSExportAssignmentExpression = 294,
TSNamespaceExportDeclarationId = 295,
TSInstantiationExpressionExpression = 296,
TSInstantiationExpressionTypeArguments = 297,
JSDocNullableTypeTypeAnnotation = 298,
JSDocNonNullableTypeTypeAnnotation = 299,
ExportFromDeclarationSpecifiers = 162,
ExportFromDeclarationSource = 163,
ExportFromDeclarationWithClause = 164,
ExportDefaultDeclarationDeclaration = 165,
ExportAllDeclarationExported = 166,
ExportAllDeclarationSource = 167,
ExportAllDeclarationWithClause = 168,
ExportSpecifierLocal = 169,
ExportSpecifierExported = 170,
V8IntrinsicExpressionName = 171,
V8IntrinsicExpressionArguments = 172,
JSXElementOpeningElement = 173,
JSXElementChildren = 174,
JSXElementClosingElement = 175,
JSXOpeningElementName = 176,
JSXOpeningElementTypeArguments = 177,
JSXOpeningElementAttributes = 178,
JSXClosingElementName = 179,
JSXFragmentOpeningFragment = 180,
JSXFragmentChildren = 181,
JSXFragmentClosingFragment = 182,
JSXNamespacedNameNamespace = 183,
JSXNamespacedNameName = 184,
JSXMemberExpressionObject = 185,
JSXMemberExpressionProperty = 186,
JSXExpressionContainerExpression = 187,
JSXAttributeName = 188,
JSXAttributeValue = 189,
JSXSpreadAttributeArgument = 190,
JSXSpreadChildExpression = 191,
TSThisParameterTypeAnnotation = 192,
TSEnumDeclarationId = 193,
TSEnumDeclarationBody = 194,
TSEnumBodyMembers = 195,
TSEnumMemberId = 196,
TSEnumMemberInitializer = 197,
TSTypeAnnotationTypeAnnotation = 198,
TSLiteralTypeLiteral = 199,
TSConditionalTypeCheckType = 200,
TSConditionalTypeExtendsType = 201,
TSConditionalTypeTrueType = 202,
TSConditionalTypeFalseType = 203,
TSUnionTypeTypes = 204,
TSIntersectionTypeTypes = 205,
TSParenthesizedTypeTypeAnnotation = 206,
TSTypeOperatorTypeAnnotation = 207,
TSArrayTypeElementType = 208,
TSIndexedAccessTypeObjectType = 209,
TSIndexedAccessTypeIndexType = 210,
TSTupleTypeElementTypes = 211,
TSNamedTupleMemberLabel = 212,
TSNamedTupleMemberElementType = 213,
TSOptionalTypeTypeAnnotation = 214,
TSRestTypeTypeAnnotation = 215,
TSTypeReferenceTypeName = 216,
TSTypeReferenceTypeArguments = 217,
TSQualifiedNameLeft = 218,
TSQualifiedNameRight = 219,
TSTypeParameterInstantiationParams = 220,
TSTypeParameterName = 221,
TSTypeParameterConstraint = 222,
TSTypeParameterDefault = 223,
TSTypeParameterDeclarationParams = 224,
TSTypeAliasDeclarationId = 225,
TSTypeAliasDeclarationTypeParameters = 226,
TSTypeAliasDeclarationTypeAnnotation = 227,
TSClassImplementsExpression = 228,
TSClassImplementsTypeArguments = 229,
TSInterfaceDeclarationId = 230,
TSInterfaceDeclarationTypeParameters = 231,
TSInterfaceDeclarationExtends = 232,
TSInterfaceDeclarationBody = 233,
TSInterfaceBodyBody = 234,
TSPropertySignatureKey = 235,
TSPropertySignatureTypeAnnotation = 236,
TSIndexSignatureParameters = 237,
TSIndexSignatureTypeAnnotation = 238,
TSCallSignatureDeclarationTypeParameters = 239,
TSCallSignatureDeclarationThisParam = 240,
TSCallSignatureDeclarationParams = 241,
TSCallSignatureDeclarationReturnType = 242,
TSMethodSignatureKey = 243,
TSMethodSignatureTypeParameters = 244,
TSMethodSignatureThisParam = 245,
TSMethodSignatureParams = 246,
TSMethodSignatureReturnType = 247,
TSConstructSignatureDeclarationTypeParameters = 248,
TSConstructSignatureDeclarationParams = 249,
TSConstructSignatureDeclarationReturnType = 250,
TSIndexSignatureNameTypeAnnotation = 251,
TSInterfaceHeritageExpression = 252,
TSInterfaceHeritageTypeArguments = 253,
TSTypePredicateParameterName = 254,
TSTypePredicateTypeAnnotation = 255,
TSModuleDeclarationId = 256,
TSModuleDeclarationBody = 257,
TSGlobalDeclarationBody = 258,
TSModuleBlockDirectives = 259,
TSModuleBlockBody = 260,
TSTypeLiteralMembers = 261,
TSInferTypeTypeParameter = 262,
TSTypeQueryExprName = 263,
TSTypeQueryTypeArguments = 264,
TSImportTypeSource = 265,
TSImportTypeOptions = 266,
TSImportTypeQualifier = 267,
TSImportTypeTypeArguments = 268,
TSImportTypeQualifiedNameLeft = 269,
TSImportTypeQualifiedNameRight = 270,
TSFunctionTypeTypeParameters = 271,
TSFunctionTypeThisParam = 272,
TSFunctionTypeParams = 273,
TSFunctionTypeReturnType = 274,
TSConstructorTypeTypeParameters = 275,
TSConstructorTypeParams = 276,
TSConstructorTypeReturnType = 277,
TSMappedTypeKey = 278,
TSMappedTypeConstraint = 279,
TSMappedTypeNameType = 280,
TSMappedTypeTypeAnnotation = 281,
TSTemplateLiteralTypeQuasis = 282,
TSTemplateLiteralTypeTypes = 283,
TSAsExpressionExpression = 284,
TSAsExpressionTypeAnnotation = 285,
TSSatisfiesExpressionExpression = 286,
TSSatisfiesExpressionTypeAnnotation = 287,
TSTypeAssertionTypeAnnotation = 288,
TSTypeAssertionExpression = 289,
TSImportEqualsDeclarationId = 290,
TSImportEqualsDeclarationModuleReference = 291,
TSExternalModuleReferenceExpression = 292,
TSNonNullExpressionExpression = 293,
DecoratorExpression = 294,
TSExportAssignmentExpression = 295,
TSNamespaceExportDeclarationId = 296,
TSInstantiationExpressionExpression = 297,
TSInstantiationExpressionTypeArguments = 298,
JSDocNullableTypeTypeAnnotation = 299,
JSDocNonNullableTypeTypeAnnotation = 300,
}
/// Ancestor type used in AST traversal.
@@ -627,14 +628,16 @@ pub enum Ancestor<'a, 't> {
ImportAttributeKey(ImportAttributeWithoutKey<'a, 't>) = AncestorType::ImportAttributeKey as u16,
ImportAttributeValue(ImportAttributeWithoutValue<'a, 't>) =
AncestorType::ImportAttributeValue as u16,
ExportNamedDeclarationDeclaration(ExportNamedDeclarationWithoutDeclaration<'a, 't>) =
AncestorType::ExportNamedDeclarationDeclaration as u16,
ExportDeclarationDeclaration(ExportDeclarationWithoutDeclaration<'a, 't>) =
AncestorType::ExportDeclarationDeclaration as u16,
ExportNamedDeclarationSpecifiers(ExportNamedDeclarationWithoutSpecifiers<'a, 't>) =
AncestorType::ExportNamedDeclarationSpecifiers as u16,
ExportNamedDeclarationSource(ExportNamedDeclarationWithoutSource<'a, 't>) =
AncestorType::ExportNamedDeclarationSource as u16,
ExportNamedDeclarationWithClause(ExportNamedDeclarationWithoutWithClause<'a, 't>) =
AncestorType::ExportNamedDeclarationWithClause as u16,
ExportFromDeclarationSpecifiers(ExportFromDeclarationWithoutSpecifiers<'a, 't>) =
AncestorType::ExportFromDeclarationSpecifiers as u16,
ExportFromDeclarationSource(ExportFromDeclarationWithoutSource<'a, 't>) =
AncestorType::ExportFromDeclarationSource as u16,
ExportFromDeclarationWithClause(ExportFromDeclarationWithoutWithClause<'a, 't>) =
AncestorType::ExportFromDeclarationWithClause as u16,
ExportDefaultDeclarationDeclaration(ExportDefaultDeclarationWithoutDeclaration<'a, 't>) =
AncestorType::ExportDefaultDeclarationDeclaration as u16,
ExportAllDeclarationExported(ExportAllDeclarationWithoutExported<'a, 't>) =
@@ -1412,14 +1415,23 @@ impl<'a, 't> Ancestor<'a, 't> {
matches!(self, Self::ImportAttributeKey(_) | Self::ImportAttributeValue(_))
}
#[inline]
pub fn is_export_declaration(self) -> bool {
matches!(self, Self::ExportDeclarationDeclaration(_))
}
#[inline]
pub fn is_export_named_declaration(self) -> bool {
matches!(self, Self::ExportNamedDeclarationSpecifiers(_))
}
#[inline]
pub fn is_export_from_declaration(self) -> bool {
matches!(
self,
Self::ExportNamedDeclarationDeclaration(_)
| Self::ExportNamedDeclarationSpecifiers(_)
| Self::ExportNamedDeclarationSource(_)
| Self::ExportNamedDeclarationWithClause(_)
Self::ExportFromDeclarationSpecifiers(_)
| Self::ExportFromDeclarationSource(_)
| Self::ExportFromDeclarationWithClause(_)
)
}
@@ -2108,7 +2120,7 @@ impl<'a, 't> Ancestor<'a, 't> {
#[inline]
pub fn is_parent_of_declaration(self) -> bool {
matches!(self, Self::ExportNamedDeclarationDeclaration(_))
matches!(self, Self::ExportDeclarationDeclaration(_))
}
#[inline]
@@ -2412,10 +2424,11 @@ impl<'a, 't> GetAddress for Ancestor<'a, 't> {
Self::WithClauseWithEntries(a) => a.address(),
Self::ImportAttributeKey(a) => a.address(),
Self::ImportAttributeValue(a) => a.address(),
Self::ExportNamedDeclarationDeclaration(a) => a.address(),
Self::ExportDeclarationDeclaration(a) => a.address(),
Self::ExportNamedDeclarationSpecifiers(a) => a.address(),
Self::ExportNamedDeclarationSource(a) => a.address(),
Self::ExportNamedDeclarationWithClause(a) => a.address(),
Self::ExportFromDeclarationSpecifiers(a) => a.address(),
Self::ExportFromDeclarationSource(a) => a.address(),
Self::ExportFromDeclarationWithClause(a) => a.address(),
Self::ExportDefaultDeclarationDeclaration(a) => a.address(),
Self::ExportAllDeclarationExported(a) => a.address(),
Self::ExportAllDeclarationSource(a) => a.address(),
@@ -11432,84 +11445,48 @@ impl<'a, 't> GetAddress for ImportAttributeWithoutValue<'a, 't> {
}
}
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_NODE_ID: usize =
offset_of!(ExportNamedDeclaration, node_id);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_SPAN: usize =
offset_of!(ExportNamedDeclaration, span);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_DECLARATION: usize =
offset_of!(ExportNamedDeclaration, declaration);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS: usize =
offset_of!(ExportNamedDeclaration, specifiers);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_SOURCE: usize =
offset_of!(ExportNamedDeclaration, source);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_EXPORT_KIND: usize =
offset_of!(ExportNamedDeclaration, export_kind);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_WITH_CLAUSE: usize =
offset_of!(ExportNamedDeclaration, with_clause);
pub(crate) const OFFSET_EXPORT_DECLARATION_NODE_ID: usize = offset_of!(ExportDeclaration, node_id);
pub(crate) const OFFSET_EXPORT_DECLARATION_SPAN: usize = offset_of!(ExportDeclaration, span);
pub(crate) const OFFSET_EXPORT_DECLARATION_DECLARATION: usize =
offset_of!(ExportDeclaration, declaration);
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct ExportNamedDeclarationWithoutDeclaration<'a, 't>(
pub(crate) *const ExportNamedDeclaration<'a>,
pub struct ExportDeclarationWithoutDeclaration<'a, 't>(
pub(crate) *const ExportDeclaration<'a>,
pub(crate) PhantomData<&'t ()>,
);
impl<'a, 't> ExportNamedDeclarationWithoutDeclaration<'a, 't> {
impl<'a, 't> ExportDeclarationWithoutDeclaration<'a, 't> {
#[inline]
pub fn node_id(self) -> &'t Cell<NodeId> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_NODE_ID)
as *const Cell<NodeId>)
&*((self.0 as *const u8).add(OFFSET_EXPORT_DECLARATION_NODE_ID) as *const Cell<NodeId>)
}
}
#[inline]
pub fn span(self) -> &'t Span {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPAN) as *const Span)
}
}
#[inline]
pub fn specifiers(self) -> &'t ArenaVec<'a, ExportSpecifier<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS)
as *const ArenaVec<'a, ExportSpecifier<'a>>)
}
}
#[inline]
pub fn source(self) -> &'t Option<StringLiteral<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SOURCE)
as *const Option<StringLiteral<'a>>)
}
}
#[inline]
pub fn export_kind(self) -> &'t ImportOrExportKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_EXPORT_KIND)
as *const ImportOrExportKind)
}
}
#[inline]
pub fn with_clause(self) -> &'t Option<ArenaBox<'a, WithClause<'a>>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_WITH_CLAUSE)
as *const Option<ArenaBox<'a, WithClause<'a>>>)
}
unsafe { &*((self.0 as *const u8).add(OFFSET_EXPORT_DECLARATION_SPAN) as *const Span) }
}
}
impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutDeclaration<'a, 't> {
impl<'a, 't> GetAddress for ExportDeclarationWithoutDeclaration<'a, 't> {
#[inline]
fn address(&self) -> Address {
unsafe { Address::from_ptr(self.0) }
}
}
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_NODE_ID: usize =
offset_of!(ExportNamedDeclaration, node_id);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_SPAN: usize =
offset_of!(ExportNamedDeclaration, span);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS: usize =
offset_of!(ExportNamedDeclaration, specifiers);
pub(crate) const OFFSET_EXPORT_NAMED_DECLARATION_EXPORT_KIND: usize =
offset_of!(ExportNamedDeclaration, export_kind);
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct ExportNamedDeclarationWithoutSpecifiers<'a, 't>(
@@ -11533,22 +11510,6 @@ impl<'a, 't> ExportNamedDeclarationWithoutSpecifiers<'a, 't> {
}
}
#[inline]
pub fn declaration(self) -> &'t Option<Declaration<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_DECLARATION)
as *const Option<Declaration<'a>>)
}
}
#[inline]
pub fn source(self) -> &'t Option<StringLiteral<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SOURCE)
as *const Option<StringLiteral<'a>>)
}
}
#[inline]
pub fn export_kind(self) -> &'t ImportOrExportKind {
unsafe {
@@ -11556,14 +11517,6 @@ impl<'a, 't> ExportNamedDeclarationWithoutSpecifiers<'a, 't> {
as *const ImportOrExportKind)
}
}
#[inline]
pub fn with_clause(self) -> &'t Option<ArenaBox<'a, WithClause<'a>>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_WITH_CLAUSE)
as *const Option<ArenaBox<'a, WithClause<'a>>>)
}
}
}
impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutSpecifiers<'a, 't> {
@@ -11573,49 +11526,52 @@ impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutSpecifiers<'a, 't> {
}
}
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_NODE_ID: usize =
offset_of!(ExportFromDeclaration, node_id);
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_SPAN: usize =
offset_of!(ExportFromDeclaration, span);
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_SPECIFIERS: usize =
offset_of!(ExportFromDeclaration, specifiers);
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_SOURCE: usize =
offset_of!(ExportFromDeclaration, source);
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_EXPORT_KIND: usize =
offset_of!(ExportFromDeclaration, export_kind);
pub(crate) const OFFSET_EXPORT_FROM_DECLARATION_WITH_CLAUSE: usize =
offset_of!(ExportFromDeclaration, with_clause);
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct ExportNamedDeclarationWithoutSource<'a, 't>(
pub(crate) *const ExportNamedDeclaration<'a>,
pub struct ExportFromDeclarationWithoutSpecifiers<'a, 't>(
pub(crate) *const ExportFromDeclaration<'a>,
pub(crate) PhantomData<&'t ()>,
);
impl<'a, 't> ExportNamedDeclarationWithoutSource<'a, 't> {
impl<'a, 't> ExportFromDeclarationWithoutSpecifiers<'a, 't> {
#[inline]
pub fn node_id(self) -> &'t Cell<NodeId> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_NODE_ID)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_NODE_ID)
as *const Cell<NodeId>)
}
}
#[inline]
pub fn span(self) -> &'t Span {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPAN) as *const Span)
}
unsafe { &*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SPAN) as *const Span) }
}
#[inline]
pub fn declaration(self) -> &'t Option<Declaration<'a>> {
pub fn source(self) -> &'t StringLiteral<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_DECLARATION)
as *const Option<Declaration<'a>>)
}
}
#[inline]
pub fn specifiers(self) -> &'t ArenaVec<'a, ExportSpecifier<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS)
as *const ArenaVec<'a, ExportSpecifier<'a>>)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SOURCE)
as *const StringLiteral<'a>)
}
}
#[inline]
pub fn export_kind(self) -> &'t ImportOrExportKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_EXPORT_KIND)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_EXPORT_KIND)
as *const ImportOrExportKind)
}
}
@@ -11623,13 +11579,13 @@ impl<'a, 't> ExportNamedDeclarationWithoutSource<'a, 't> {
#[inline]
pub fn with_clause(self) -> &'t Option<ArenaBox<'a, WithClause<'a>>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_WITH_CLAUSE)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_WITH_CLAUSE)
as *const Option<ArenaBox<'a, WithClause<'a>>>)
}
}
}
impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutSource<'a, 't> {
impl<'a, 't> GetAddress for ExportFromDeclarationWithoutSpecifiers<'a, 't> {
#[inline]
fn address(&self) -> Address {
unsafe { Address::from_ptr(self.0) }
@@ -11638,61 +11594,104 @@ impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutSource<'a, 't> {
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct ExportNamedDeclarationWithoutWithClause<'a, 't>(
pub(crate) *const ExportNamedDeclaration<'a>,
pub struct ExportFromDeclarationWithoutSource<'a, 't>(
pub(crate) *const ExportFromDeclaration<'a>,
pub(crate) PhantomData<&'t ()>,
);
impl<'a, 't> ExportNamedDeclarationWithoutWithClause<'a, 't> {
impl<'a, 't> ExportFromDeclarationWithoutSource<'a, 't> {
#[inline]
pub fn node_id(self) -> &'t Cell<NodeId> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_NODE_ID)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_NODE_ID)
as *const Cell<NodeId>)
}
}
#[inline]
pub fn span(self) -> &'t Span {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPAN) as *const Span)
}
}
#[inline]
pub fn declaration(self) -> &'t Option<Declaration<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_DECLARATION)
as *const Option<Declaration<'a>>)
}
unsafe { &*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SPAN) as *const Span) }
}
#[inline]
pub fn specifiers(self) -> &'t ArenaVec<'a, ExportSpecifier<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SPECIFIERS)
as *const ArenaVec<'a, ExportSpecifier<'a>>)
}
}
#[inline]
pub fn source(self) -> &'t Option<StringLiteral<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_SOURCE)
as *const Option<StringLiteral<'a>>)
}
}
#[inline]
pub fn export_kind(self) -> &'t ImportOrExportKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_NAMED_DECLARATION_EXPORT_KIND)
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_EXPORT_KIND)
as *const ImportOrExportKind)
}
}
#[inline]
pub fn with_clause(self) -> &'t Option<ArenaBox<'a, WithClause<'a>>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_WITH_CLAUSE)
as *const Option<ArenaBox<'a, WithClause<'a>>>)
}
}
}
impl<'a, 't> GetAddress for ExportFromDeclarationWithoutSource<'a, 't> {
#[inline]
fn address(&self) -> Address {
unsafe { Address::from_ptr(self.0) }
}
}
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
pub struct ExportFromDeclarationWithoutWithClause<'a, 't>(
pub(crate) *const ExportFromDeclaration<'a>,
pub(crate) PhantomData<&'t ()>,
);
impl<'a, 't> ExportFromDeclarationWithoutWithClause<'a, 't> {
#[inline]
pub fn node_id(self) -> &'t Cell<NodeId> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_NODE_ID)
as *const Cell<NodeId>)
}
}
#[inline]
pub fn span(self) -> &'t Span {
unsafe { &*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SPAN) as *const Span) }
}
#[inline]
pub fn specifiers(self) -> &'t ArenaVec<'a, ExportSpecifier<'a>> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SPECIFIERS)
as *const ArenaVec<'a, ExportSpecifier<'a>>)
}
}
#[inline]
pub fn source(self) -> &'t StringLiteral<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_SOURCE)
as *const StringLiteral<'a>)
}
}
#[inline]
pub fn export_kind(self) -> &'t ImportOrExportKind {
unsafe {
&*((self.0 as *const u8).add(OFFSET_EXPORT_FROM_DECLARATION_EXPORT_KIND)
as *const ImportOrExportKind)
}
}
}
impl<'a, 't> GetAddress for ExportNamedDeclarationWithoutWithClause<'a, 't> {
impl<'a, 't> GetAddress for ExportFromDeclarationWithoutWithClause<'a, 't> {
#[inline]
fn address(&self) -> Address {
unsafe { Address::from_ptr(self.0) }
@@ -1200,6 +1200,21 @@ pub trait Traverse<'a> {
) {
}
#[inline]
fn enter_export_declaration(
&mut self,
node: &mut ExportDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn exit_export_declaration(
&mut self,
node: &mut ExportDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn enter_export_named_declaration(
&mut self,
@@ -1215,6 +1230,21 @@ pub trait Traverse<'a> {
) {
}
#[inline]
fn enter_export_from_declaration(
&mut self,
node: &mut ExportFromDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn exit_export_from_declaration(
&mut self,
node: &mut ExportFromDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn enter_export_default_declaration(
&mut self,
+54 -17
View File
@@ -1382,7 +1382,9 @@ unsafe fn walk_statement<'a, Tr: Traverse<'a>>(
Statement::ImportDeclaration(_)
| Statement::ExportAllDeclaration(_)
| Statement::ExportDefaultDeclaration(_)
| Statement::ExportDeclaration(_)
| Statement::ExportNamedDeclaration(_)
| Statement::ExportFromDeclaration(_)
| Statement::TSExportAssignment(_)
| Statement::TSNamespaceExportDeclaration(_) => {
walk_module_declaration(traverser, node as *mut _, ctx)
@@ -2796,9 +2798,15 @@ unsafe fn walk_module_declaration<'a, Tr: Traverse<'a>>(
ModuleDeclaration::ExportDefaultDeclaration(node) => {
walk_export_default_declaration(traverser, (&mut **node) as *mut _, ctx)
}
ModuleDeclaration::ExportDeclaration(node) => {
walk_export_declaration(traverser, (&mut **node) as *mut _, ctx)
}
ModuleDeclaration::ExportNamedDeclaration(node) => {
walk_export_named_declaration(traverser, (&mut **node) as *mut _, ctx)
}
ModuleDeclaration::ExportFromDeclaration(node) => {
walk_export_from_declaration(traverser, (&mut **node) as *mut _, ctx)
}
ModuleDeclaration::TSExportAssignment(node) => {
walk_ts_export_assignment(traverser, (&mut **node) as *mut _, ctx)
}
@@ -3045,43 +3053,72 @@ unsafe fn walk_import_attribute_key<'a, Tr: Traverse<'a>>(
traverser.exit_import_attribute_key(&mut *node, ctx);
}
unsafe fn walk_export_declaration<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut ExportDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
traverser.enter_export_declaration(&mut *node, ctx);
let pop_token = ctx.push_stack(Ancestor::ExportDeclarationDeclaration(
ancestor::ExportDeclarationWithoutDeclaration(node, PhantomData),
));
walk_declaration(
traverser,
(node as *mut u8).add(ancestor::OFFSET_EXPORT_DECLARATION_DECLARATION) as *mut Declaration,
ctx,
);
ctx.pop_stack(pop_token);
traverser.exit_export_declaration(&mut *node, ctx);
}
unsafe fn walk_export_named_declaration<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut ExportNamedDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
traverser.enter_export_named_declaration(&mut *node, ctx);
let pop_token = ctx.push_stack(Ancestor::ExportNamedDeclarationDeclaration(
ancestor::ExportNamedDeclarationWithoutDeclaration(node, PhantomData),
let pop_token = ctx.push_stack(Ancestor::ExportNamedDeclarationSpecifiers(
ancestor::ExportNamedDeclarationWithoutSpecifiers(node, PhantomData),
));
if let Some(field) = &mut *((node as *mut u8)
.add(ancestor::OFFSET_EXPORT_NAMED_DECLARATION_DECLARATION)
as *mut Option<Declaration>)
{
walk_declaration(traverser, field as *mut _, ctx);
}
ctx.retag_stack(AncestorType::ExportNamedDeclarationSpecifiers);
for item in &mut *((node as *mut u8).add(ancestor::OFFSET_EXPORT_NAMED_DECLARATION_SPECIFIERS)
as *mut ArenaVec<ExportSpecifier>)
{
walk_export_specifier(traverser, item as *mut _, ctx);
}
if let Some(field) = &mut *((node as *mut u8)
.add(ancestor::OFFSET_EXPORT_NAMED_DECLARATION_SOURCE)
as *mut Option<StringLiteral>)
ctx.pop_stack(pop_token);
traverser.exit_export_named_declaration(&mut *node, ctx);
}
unsafe fn walk_export_from_declaration<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut ExportFromDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
traverser.enter_export_from_declaration(&mut *node, ctx);
let pop_token = ctx.push_stack(Ancestor::ExportFromDeclarationSpecifiers(
ancestor::ExportFromDeclarationWithoutSpecifiers(node, PhantomData),
));
for item in &mut *((node as *mut u8).add(ancestor::OFFSET_EXPORT_FROM_DECLARATION_SPECIFIERS)
as *mut ArenaVec<ExportSpecifier>)
{
ctx.retag_stack(AncestorType::ExportNamedDeclarationSource);
walk_string_literal(traverser, field as *mut _, ctx);
walk_export_specifier(traverser, item as *mut _, ctx);
}
ctx.retag_stack(AncestorType::ExportFromDeclarationSource);
walk_string_literal(
traverser,
(node as *mut u8).add(ancestor::OFFSET_EXPORT_FROM_DECLARATION_SOURCE)
as *mut StringLiteral,
ctx,
);
if let Some(field) = &mut *((node as *mut u8)
.add(ancestor::OFFSET_EXPORT_NAMED_DECLARATION_WITH_CLAUSE)
.add(ancestor::OFFSET_EXPORT_FROM_DECLARATION_WITH_CLAUSE)
as *mut Option<ArenaBox<WithClause>>)
{
ctx.retag_stack(AncestorType::ExportNamedDeclarationWithClause);
ctx.retag_stack(AncestorType::ExportFromDeclarationWithClause);
walk_with_clause(traverser, (&mut **field) as *mut _, ctx);
}
ctx.pop_stack(pop_token);
traverser.exit_export_named_declaration(&mut *node, ctx);
traverser.exit_export_from_declaration(&mut *node, ctx);
}
unsafe fn walk_export_default_declaration<'a, Tr: Traverse<'a>>(
+1 -1
View File
@@ -72,7 +72,7 @@ impl<'a> PeepholeOptimizations {
for ancestor in ctx.ancestors() {
match ancestor {
Ancestor::VariableDeclarationDeclarations(_)
| Ancestor::ExportNamedDeclarationDeclaration(_) => {}
| Ancestor::ExportDeclarationDeclaration(_) => {}
Ancestor::ProgramBody(_) | Ancestor::FunctionBodyStatements(_) => return true,
_ => return false,
}
+4 -4
View File
@@ -69,14 +69,14 @@ impl<'a> PeepholeOptimizations {
match stmt {
Statement::EmptyStatement(_)
| Statement::ImportDeclaration(_)
| Statement::ExportAllDeclaration(_) => true,
| Statement::ExportAllDeclaration(_)
| Statement::ExportNamedDeclaration(_)
| Statement::ExportFromDeclaration(_) => true,
// `export { foo }`, `export { foo } from './x'`, `export type T = …` —
// no executable code at the statement itself. The cyclic-eval hazard
// from a `from` source is gated separately at program scope (see
// `enter_program`).
Statement::ExportNamedDeclaration(e) => {
e.declaration.as_ref().is_none_or(Self::is_declarative_declaration)
}
Statement::ExportDeclaration(e) => Self::is_declarative_declaration(&e.declaration),
// `export default function() {}` is hoisted; `export default <expr>`
// or `export default class C extends … {}` runs user code.
Statement::ExportDefaultDeclaration(e) => {
@@ -82,6 +82,14 @@ impl<'a> Traverse<'a> for Normalize {
symbol_liveness::register_named_export(node, ctx);
}
fn enter_export_declaration(
&mut self,
node: &mut ExportDeclaration<'a>,
ctx: &mut TraverseCtx<'a>,
) {
symbol_liveness::register_export_declaration(node, ctx);
}
fn enter_export_default_declaration(
&mut self,
node: &mut ExportDefaultDeclaration<'a>,
+11 -9
View File
@@ -490,21 +490,23 @@ pub fn register_using_declaration(
liveness.mark_bound_names(declaration);
}
/// Normalize hook: record runtime bindings exposed by a named export.
pub fn register_named_export(declaration: &ExportNamedDeclaration<'_>, ctx: &mut TraverseCtx<'_>) {
let TraverseCtx { state, scoping, .. } = ctx;
/// Normalize hook: record runtime bindings exposed by an exported declaration.
pub fn register_export_declaration(declaration: &ExportDeclaration<'_>, ctx: &mut TraverseCtx<'_>) {
let TraverseCtx { state, .. } = ctx;
let Some(liveness) = state.symbols.liveness_mut() else { return };
if !declaration.export_kind.is_type()
&& let Some(inner) = &declaration.declaration
{
liveness.mark_bound_names(inner);
if !declaration.export_kind().is_type() {
liveness.mark_bound_names(&declaration.declaration);
}
}
if declaration.source.is_some() || declaration.export_kind.is_type() {
/// Normalize hook: record runtime bindings exposed by a local named export.
pub fn register_named_export(declaration: &ExportNamedDeclaration<'_>, ctx: &mut TraverseCtx<'_>) {
if declaration.export_kind.is_type() {
return;
}
let TraverseCtx { state, scoping, .. } = ctx;
let Some(liveness) = state.symbols.liveness_mut() else { return };
for specifier in &declaration.specifiers {
if specifier.export_kind.is_type() {
continue;
@@ -626,7 +626,7 @@ impl<'a> Visit<'a> for ChildScopeCollector {
Statement::TSModuleDeclaration(it) => self.visit_ts_module_declaration(it),
Statement::TSGlobalDeclaration(it) => self.visit_ts_global_declaration(it),
Statement::ExportDefaultDeclaration(it) => self.visit_export_default_declaration(it),
Statement::ExportNamedDeclaration(it) => self.visit_export_named_declaration(it),
Statement::ExportDeclaration(it) => self.visit_export_declaration(it),
Statement::TSExportAssignment(it) => self.visit_ts_export_assignment(it),
_ => {
// Remaining variants do not contain scopes:
@@ -637,6 +637,8 @@ impl<'a> Visit<'a> for ChildScopeCollector {
// `TSImportEqualsDeclaration`
// `ImportDeclaration`
// `ExportAllDeclaration`
// `ExportNamedDeclaration`
// `ExportFromDeclaration`
// `TSNamespaceExportDeclaration`
}
}
@@ -1125,14 +1127,14 @@ impl<'a> Visit<'a> for ChildScopeCollector {
ModuleDeclaration::ExportDefaultDeclaration(it) => {
self.visit_export_default_declaration(it)
}
ModuleDeclaration::ExportNamedDeclaration(it) => {
self.visit_export_named_declaration(it)
}
ModuleDeclaration::ExportDeclaration(it) => self.visit_export_declaration(it),
ModuleDeclaration::TSExportAssignment(it) => self.visit_ts_export_assignment(it),
_ => {
// Remaining variants do not contain scopes:
// `ImportDeclaration`
// `ExportAllDeclaration`
// `ExportNamedDeclaration`
// `ExportFromDeclaration`
// `TSNamespaceExportDeclaration`
}
}
@@ -1199,10 +1201,18 @@ impl<'a> Visit<'a> for ChildScopeCollector {
}
#[inline]
fn visit_export_declaration(&mut self, it: &ExportDeclaration<'a>) {
self.visit_declaration(&it.declaration);
}
#[inline(always)]
fn visit_export_named_declaration(&mut self, it: &ExportNamedDeclaration<'a>) {
if let Some(declaration) = &it.declaration {
self.visit_declaration(declaration);
}
// Struct does not contain a scope. Halt traversal.
}
#[inline(always)]
fn visit_export_from_declaration(&mut self, it: &ExportFromDeclaration<'a>) {
// Struct does not contain a scope. Halt traversal.
}
#[inline]
+39 -64
View File
@@ -460,20 +460,15 @@ impl<'a, C: Config> ParserImpl<'a, C> {
// being created. It's an export not an import.
let stmt = self.parse_import_declaration(import_span, false);
if stmt.is_declaration() {
let export_named_decl = ExportNamedDeclaration::boxed(
let export_decl = ExportDeclaration::boxed(
self.end_span(span),
Some(stmt.into_declaration()),
[],
None,
ImportOrExportKind::Value,
None,
stmt.into_declaration(),
self,
);
if self.ctx.has_top_level() {
self.module_record_builder
.visit_export_named_declaration(&export_named_decl);
self.module_record_builder.visit_export_declaration(&export_decl);
}
ModuleDeclaration::ExportNamedDeclaration(export_named_decl)
ModuleDeclaration::ExportDeclaration(export_decl)
} else {
return self.fatal_error(diagnostics::unexpected_export(stmt.span()));
}
@@ -490,19 +485,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
let modifiers = self.parse_modifiers(false, false);
let class_decl = self.parse_class_declaration(class_span, &modifiers, decorators);
let decl = Declaration::ClassDeclaration(class_decl);
let export_named_decl = ExportNamedDeclaration::boxed(
self.end_span(span),
Some(decl),
[],
None,
ImportOrExportKind::Value,
None,
self,
);
let export_decl = ExportDeclaration::boxed(self.end_span(span), decl, self);
if self.ctx.has_top_level() {
self.module_record_builder.visit_export_named_declaration(&export_named_decl);
self.module_record_builder.visit_export_declaration(&export_decl);
}
ModuleDeclaration::ExportNamedDeclaration(export_named_decl)
ModuleDeclaration::ExportDeclaration(export_decl)
}
Kind::Eq if self.is_ts => ModuleDeclaration::TSExportAssignment(
self.parse_ts_export_assignment_declaration(span),
@@ -519,23 +506,19 @@ impl<'a, C: Config> ParserImpl<'a, C> {
Kind::Star => {
ModuleDeclaration::ExportAllDeclaration(self.parse_export_all_declaration(span))
}
Kind::LCurly => {
ModuleDeclaration::ExportNamedDeclaration(self.parse_export_named_specifiers(span))
}
Kind::LCurly => self.parse_export_named_specifiers(span),
Kind::Type if self.is_ts => {
let next_kind = self.lexer.peek_token().kind();
match next_kind {
// `export type { ...`
Kind::LCurly => ModuleDeclaration::ExportNamedDeclaration(
self.parse_export_named_specifiers(span),
),
Kind::LCurly => self.parse_export_named_specifiers(span),
// `export type * as ...`
Kind::Star => ModuleDeclaration::ExportAllDeclaration(
self.parse_export_all_declaration(span),
),
_ => ModuleDeclaration::ExportNamedDeclaration(
self.parse_export_named_declaration(span, decorators),
_ => ModuleDeclaration::ExportDeclaration(
self.parse_exported_declaration(span, decorators),
),
}
}
@@ -547,8 +530,8 @@ impl<'a, C: Config> ParserImpl<'a, C> {
)));
self.bump_any();
}
ModuleDeclaration::ExportNamedDeclaration(
self.parse_export_named_declaration(span, decorators),
ModuleDeclaration::ExportDeclaration(
self.parse_exported_declaration(span, decorators),
)
}
};
@@ -566,10 +549,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
// ExportSpecifier :
// ModuleExportName
// ModuleExportName as ModuleExportName
fn parse_export_named_specifiers(
&mut self,
span: u32,
) -> ArenaBox<'a, ExportNamedDeclaration<'a>> {
fn parse_export_named_specifiers(&mut self, span: u32) -> ModuleDeclaration<'a> {
let export_kind = self.parse_import_or_export_kind();
let opening_span = self.cur_token().span();
self.expect(Kind::LCurly);
@@ -625,27 +605,35 @@ impl<'a, C: Config> ParserImpl<'a, C> {
self.asi();
let span = self.end_span(span);
let export_named_decl = ExportNamedDeclaration::boxed(
span,
None,
specifiers,
source,
export_kind,
with_clause,
self,
);
if self.ctx.has_top_level() {
self.module_record_builder.visit_export_named_declaration(&export_named_decl);
if let Some(source) = source {
let export_from_decl = ExportFromDeclaration::boxed(
span,
specifiers,
source,
export_kind,
with_clause,
self,
);
if self.ctx.has_top_level() {
self.module_record_builder.visit_export_from_declaration(&export_from_decl);
}
ModuleDeclaration::ExportFromDeclaration(export_from_decl)
} else {
let export_named_decl =
ExportNamedDeclaration::boxed(span, specifiers, export_kind, self);
if self.ctx.has_top_level() {
self.module_record_builder.visit_export_named_declaration(&export_named_decl);
}
ModuleDeclaration::ExportNamedDeclaration(export_named_decl)
}
export_named_decl
}
// export Declaration
fn parse_export_named_declaration(
fn parse_exported_declaration(
&mut self,
span: u32,
decorators: ArenaVec<'a, Decorator<'a>>,
) -> ArenaBox<'a, ExportNamedDeclaration<'a>> {
) -> ArenaBox<'a, ExportDeclaration<'a>> {
let decl_span = self.start_span();
let reserved_ctx = self.ctx;
let modifiers =
@@ -653,25 +641,12 @@ impl<'a, C: Config> ParserImpl<'a, C> {
self.ctx = self.ctx.union_ambient_if(modifiers.contains_declare());
let declaration = self.parse_declaration(decl_span, &modifiers, decorators);
let export_kind = if declaration.declare() || declaration.is_type() {
ImportOrExportKind::Type
} else {
ImportOrExportKind::Value
};
self.ctx = reserved_ctx;
let export_named_decl = ExportNamedDeclaration::boxed(
self.end_span(span),
Some(declaration),
[],
None,
export_kind,
None,
self,
);
let export_decl = ExportDeclaration::boxed(self.end_span(span), declaration, self);
if self.ctx.has_top_level() {
self.module_record_builder.visit_export_named_declaration(&export_named_decl);
self.module_record_builder.visit_export_declaration(&export_decl);
}
export_named_decl
export_decl
}
// export default HoistableDeclaration[~Yield, +Await, +Default]
+3 -3
View File
@@ -228,11 +228,11 @@ impl<'a, C: Config> ParserImpl<'a, C> {
}
_ => {}
},
Statement::ExportNamedDeclaration(decl) => match &mut decl.declaration {
Some(Declaration::FunctionDeclaration(func)) => {
Statement::ExportDeclaration(decl) => match &mut decl.declaration {
Declaration::FunctionDeclaration(func) => {
func.pure = true;
}
Some(Declaration::VariableDeclaration(var_decl)) if var_decl.kind.is_const() => {
Declaration::VariableDeclaration(var_decl) if var_decl.kind.is_const() => {
if let Some(Some(expr)) = var_decl.declarations.first_mut().map(|d| &mut d.init)
{
Self::set_pure_on_function_expr(expr);
+59 -47
View File
@@ -314,67 +314,79 @@ impl<'a> ModuleRecordBuilder<'a> {
self.module_record.has_module_syntax = true;
}
pub fn visit_export_declaration(&mut self, decl: &ExportDeclaration<'a>) {
let export_kind = decl.export_kind();
let declaration = &decl.declaration;
iter_binding_identifiers_of_declaration(declaration, &mut |ident| {
let export_name = ExportExportName::Name(NameSpan::new(ident.name.into(), ident.span));
let local_name = ExportLocalName::Name(NameSpan::new(ident.name.into(), ident.span));
let export_entry = ExportEntry {
statement_span: decl.span,
span: declaration.span(),
module_request: None,
import_name: ExportImportName::Null,
export_name,
local_name,
is_type: export_kind.is_type(),
};
self.add_export_entry(export_entry);
self.add_export_binding(ident.name.into(), ident.span);
});
self.module_record.has_module_syntax = true;
}
pub fn visit_export_named_declaration(&mut self, decl: &ExportNamedDeclaration<'a>) {
let module_request =
decl.source.as_ref().map(|source| NameSpan::new(source.value, source.span));
if let Some(module_request) = &module_request {
self.add_module_request(
module_request.name,
RequestedModule {
statement_span: decl.span,
span: module_request.span,
is_type: decl.export_kind.is_type(),
is_import: false,
},
);
for specifier in &decl.specifiers {
let export_name = ExportExportName::Name(NameSpan::new(
specifier.exported.name(),
specifier.exported.span(),
));
let export_entry = ExportEntry {
statement_span: decl.span,
span: specifier.span,
module_request: None,
import_name: ExportImportName::Null,
export_name,
local_name: ExportLocalName::Name(NameSpan::new(
specifier.local.name(),
specifier.local.span(),
)),
is_type: specifier.export_kind.is_type() || decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
self.add_export_binding(specifier.exported.name(), specifier.exported.span());
}
self.module_record.has_module_syntax = true;
}
if let Some(d) = &decl.declaration {
iter_binding_identifiers_of_declaration(d, &mut |ident| {
let export_name =
ExportExportName::Name(NameSpan::new(ident.name.into(), ident.span));
let local_name =
ExportLocalName::Name(NameSpan::new(ident.name.into(), ident.span));
let export_entry = ExportEntry {
statement_span: decl.span,
span: d.span(),
module_request: module_request.clone(),
import_name: ExportImportName::Null,
export_name,
local_name,
is_type: decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
self.add_export_binding(ident.name.into(), ident.span);
});
}
pub fn visit_export_from_declaration(&mut self, decl: &ExportFromDeclaration<'a>) {
let module_request = NameSpan::new(decl.source.value, decl.source.span);
self.add_module_request(
module_request.name,
RequestedModule {
statement_span: decl.span,
span: module_request.span,
is_type: decl.export_kind.is_type(),
is_import: false,
},
);
for specifier in &decl.specifiers {
let export_name = ExportExportName::Name(NameSpan::new(
specifier.exported.name(),
specifier.exported.span(),
));
let import_name = if module_request.is_some() {
ExportImportName::Name(NameSpan::new(
specifier.local.name(),
specifier.local.span(),
))
} else {
ExportImportName::Null
};
let local_name = if module_request.is_some() {
ExportLocalName::Null
} else {
ExportLocalName::Name(NameSpan::new(specifier.local.name(), specifier.local.span()))
};
let import_name = ExportImportName::Name(NameSpan::new(
specifier.local.name(),
specifier.local.span(),
));
let export_entry = ExportEntry {
statement_span: decl.span,
span: specifier.span,
module_request: module_request.clone(),
module_request: Some(module_request.clone()),
import_name,
export_name,
local_name,
local_name: ExportLocalName::Null,
is_type: specifier.export_kind.is_type() || decl.export_kind.is_type(),
};
self.add_export_entry(export_entry);
+3 -3
View File
@@ -448,14 +448,14 @@ impl<'a, C: Config> ParserImpl<'a, C> {
}
// `export { ... } from "..."` (re-export from a module). A bare `export { ... }`
// with no module source re-exports locals and is allowed in a namespace.
Statement::ExportNamedDeclaration(decl) if decl.source.is_some() => {
Statement::ExportFromDeclaration(decl) => {
self.error(diagnostics::export_in_namespace(decl.span));
}
// `export import x = require("...")` is wrapped in an export declaration.
Statement::ExportNamedDeclaration(decl)
Statement::ExportDeclaration(decl)
if matches!(
&decl.declaration,
Some(Declaration::TSImportEqualsDeclaration(import_decl))
Declaration::TSImportEqualsDeclaration(import_decl)
if import_decl.module_reference.is_external()
) =>
{
@@ -1459,10 +1459,8 @@ impl<'a, 'b, 'ast> DiscoveryWalker<'a, 'b, 'ast> {
self.walk_expression(&node.object);
self.walk_statement(&node.body);
}
Statement::ExportNamedDeclaration(node) => {
if let Some(decl) = &node.declaration {
self.walk_declaration(decl);
}
Statement::ExportDeclaration(node) => {
self.walk_declaration(&node.declaration);
}
Statement::ExportDefaultDeclaration(node) => {
self.walk_export_default(&node.declaration);
@@ -2289,8 +2287,8 @@ impl<'a> OxcVisitor<'a, '_> {
Statement::FunctionDeclaration(f) if f.scope_id.get() == Some(scope_id) => {
Some(f.id.as_ref().map(|id| id.name))
}
Statement::ExportNamedDeclaration(e) => match &e.declaration {
Some(Declaration::FunctionDeclaration(f)) if f.scope_id.get() == Some(scope_id) => {
Statement::ExportDeclaration(e) => match &e.declaration {
Declaration::FunctionDeclaration(f) if f.scope_id.get() == Some(scope_id) => {
Some(f.id.as_ref().map(|id| id.name))
}
_ => None,
@@ -2299,22 +2297,14 @@ impl<'a> OxcVisitor<'a, '_> {
};
if let Some(name) = replace_name {
let name = name.as_deref().unwrap_or("anonymous");
let is_export = matches!(stmt, Statement::ExportNamedDeclaration(_));
let is_export = matches!(stmt, Statement::ExportDeclaration(_));
let const_decl = ox_build_gated_const_decl(ast, gating_expression, name);
if is_export {
let decl = match const_decl {
Statement::VariableDeclaration(d) => Declaration::VariableDeclaration(d),
_ => unreachable!(),
};
*stmt = Statement::new_export_named_declaration(
SPAN,
Some(decl),
[],
None,
ImportOrExportKind::Value,
None,
ast,
);
*stmt = Statement::new_export_declaration(SPAN, decl, ast);
} else {
*stmt = const_decl;
}
@@ -2655,8 +2645,8 @@ fn ox_insert_outlined_after<'a>(
let is_target = |f: &Function<'a>| -> bool { f.scope_id.get() == Some(scope_id) };
match stmt {
Statement::FunctionDeclaration(f) => is_target(f),
Statement::ExportNamedDeclaration(e) => {
matches!(&e.declaration, Some(Declaration::FunctionDeclaration(f)) if is_target(f))
Statement::ExportDeclaration(e) => {
matches!(&e.declaration, Declaration::FunctionDeclaration(f) if is_target(f))
}
Statement::ExportDefaultDeclaration(e) => {
matches!(&e.declaration, ExportDefaultDeclarationKind::FunctionDeclaration(f) if is_target(f))
@@ -6298,7 +6298,9 @@ fn lower_statement<'a>(
)?;
}
oxc::Statement::ImportDeclaration(_)
| oxc::Statement::ExportDeclaration(_)
| oxc::Statement::ExportNamedDeclaration(_)
| oxc::Statement::ExportFromDeclaration(_)
| oxc::Statement::ExportDefaultDeclaration(_)
| oxc::Statement::ExportAllDeclaration(_) => {
builder.record_error(
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff. Show more