Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion crates/oxc_ast/src/ast/ts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1073,13 +1073,22 @@ pub enum TSModuleDeclarationBody<'a> {
TSModuleBlock(Box<'a, TSModuleBlock<'a>>) = 1,
}

impl TSModuleDeclarationBody<'_> {
impl<'a> TSModuleDeclarationBody<'a> {
pub fn is_empty(&self) -> bool {
match self {
TSModuleDeclarationBody::TSModuleDeclaration(declaration) => declaration.body.is_none(),
TSModuleDeclarationBody::TSModuleBlock(block) => block.body.len() == 0,
}
}

pub fn as_module_block_mut(&mut self) -> Option<&mut TSModuleBlock<'a>> {
match self {
TSModuleDeclarationBody::TSModuleBlock(block) => Some(block.as_mut()),
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
decl.body.as_mut().and_then(|body| body.as_module_block_mut())
}
}
}
}

// See serializer in serialize.rs
Expand Down
25 changes: 20 additions & 5 deletions crates/oxc_isolated_declarations/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,16 +204,27 @@ impl<'a> IsolatedDeclarations<'a> {
for mut stmt in filtered_stmts {
match stmt {
match_declaration!(Statement) => {
if let Declaration::TSModuleDeclaration(decl) = stmt.to_declaration() {
if let Statement::TSModuleDeclaration(ref mut decl) = stmt {
if self.has_internal_annotation(decl.span) {
continue;
}
// declare global { ... } or declare module "foo" { ... }
// `declare global { ... }` or `declare module "foo" { ... }`
// We need to emit it anyway
if decl.kind.is_global() || decl.id.is_string_literal() {
let is_global = decl.kind.is_global();
if is_global || decl.id.is_string_literal() {
transformed_spans.insert(decl.span);

// Remove export keyword from all statements in `declare module "xxx" { ... }`
if !is_global {
if let Some(body) =
decl.body.as_mut().and_then(|body| body.as_module_block_mut())
{
self.strip_export_keyword(&mut body.body);
}
}

// We need to visit the module declaration to collect all references
self.scope.visit_ts_module_declaration(decl);
transformed_spans.insert(decl.span);
}
}
if !self.has_internal_annotation(stmt.span()) {
Expand Down Expand Up @@ -367,6 +378,10 @@ impl<'a> IsolatedDeclarations<'a> {
self.ast.alloc_export_named_declaration(SPAN, None, specifiers, None, kind, NONE);
new_stmts
.push(Statement::from(ModuleDeclaration::ExportNamedDeclaration(empty_export)));
} 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>
self.strip_export_keyword(&mut new_stmts);
}

new_stmts
Expand Down Expand Up @@ -600,6 +615,6 @@ impl<'a> IsolatedDeclarations<'a> {

pub fn is_declare(&self) -> bool {
// If we are in a module block, we don't need to add declare
!self.scope.is_ts_module_block_flag()
!self.scope.is_ts_module_block()
}
}
22 changes: 22 additions & 0 deletions crates/oxc_isolated_declarations/src/module.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use oxc_allocator::Box;
use oxc_allocator::Vec;
#[allow(clippy::wildcard_imports)]
use oxc_ast::ast::*;
use oxc_span::{Atom, GetSpan, SPAN};
Expand Down Expand Up @@ -124,4 +125,25 @@ impl<'a> IsolatedDeclarations<'a> {
))
}
}

/// Strip export keyword from ExportNamedDeclaration
///
/// ```ts
/// export const a = 1;
/// export function b() {}
/// ```
/// to
/// ```ts
/// const a = 1;
/// function b() {}
/// ```
pub fn strip_export_keyword(&self, stmts: &mut Vec<'a, Statement<'a>>) {
stmts.iter_mut().for_each(|stmt| {
if let Statement::ExportNamedDeclaration(decl) = stmt {
if let Some(declaration) = &mut decl.declaration {
*stmt = Statement::from(self.ast.move_declaration(declaration));
}
}
});
}
}
2 changes: 1 addition & 1 deletion crates/oxc_isolated_declarations/src/scope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl<'a> ScopeTree<'a> {
Self { levels }
}

pub fn is_ts_module_block_flag(&self) -> bool {
pub fn is_ts_module_block(&self) -> bool {
let scope = self.levels.last().unwrap();
scope.flags.contains(ScopeFlags::TsModuleBlock)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export namespace OnlyOneExport {
export const a = 0;
}


export namespace TwoExports {
export const c = 0;
export const a: typeof c = 0;
}


export namespace OneExportReferencedANonExported {
const c = 0;
export const a: typeof c = c;
}

declare module "OnlyOneExport" {
export const a = 0;
}


declare module "TwoExports" {
export const c = 0;
export const a: typeof c;
}


declare module "OneExportReferencedANonExported" {
const c = 0;
export const a: typeof c;
}

declare global {
const c = 0;
export const a: typeof c;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/expando-function.ts
export declare function foo(): void;
export declare const bar: () => void;
export declare namespace NS {
export const goo: () => void;
const goo: () => void;
}
export declare namespace foo {
export let baz: number;
let baz: number;
}
declare function qux(): void;
declare namespace qux {
export let woo: number;
let woo: number;
}
export default qux;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
source: crates/oxc_isolated_declarations/tests/mod.rs
input_file: crates/oxc_isolated_declarations/tests/fixtures/module-declaration-with-export.ts
---
```
==================== .D.TS ====================

export declare namespace OnlyOneExport {
const a = 0;
}
export declare namespace TwoExports {
const c = 0;
const a: typeof c;
}
export declare namespace OneExportReferencedANonExported {
const c = 0;
export const a: typeof c;
export {};
}
declare module "OnlyOneExport" {
const a = 0;
}
declare module "TwoExports" {
const c = 0;
const a: typeof c;
}
declare module "OneExportReferencedANonExported" {
const c = 0;
const a: typeof c;
}
declare global {
const c = 0;
export const a: typeof c;
}
5 changes: 2 additions & 3 deletions tasks/coverage/snapshots/transpile.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ commit: a709f989

transpile Summary:
AST Parsed : 20/20 (100.00%)
Positive Passed: 17/20 (85.00%)
Positive Passed: 18/20 (90.00%)
Mismatch: tasks/coverage/typescript/tests/cases/transpile/declarationBasicSyntax.ts
Mismatch: tasks/coverage/typescript/tests/cases/transpile/declarationEmitPartialNodeReuse.ts
Mismatch: tasks/coverage/typescript/tests/cases/transpile/declarationRestParameters.ts

#### "typescript/tests/cases/transpile/declarationComputedPropertyNames.ts" ####
Expand Down Expand Up @@ -68,7 +67,7 @@ export const D = {

//// [declarationComputedPropertyNames.d.ts] ////
export declare namespace presentNs {
export const a: unknown;
const a: unknown;
}
declare const aliasing: unknown;
export type A = {
Expand Down