Skip to content
Open
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
22 changes: 22 additions & 0 deletions src/ast/ast_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,26 @@ pub struct Ast<'a> {
pub has_commonjs_export_names: bool,
pub has_import_meta: bool,
pub import_meta_ref: Ref,

/// First non-ambient TypeScript construct with runtime semantics (not
/// erasable by type stripping). `node:module`'s `stripTypeScriptTypes`
/// rejects these in `'strip'` mode, matching Node's amaro/swc strip-only
/// behavior. `declare` contexts never set this.
pub ts_runtime_syntax: Option<TsRuntimeSyntax>,
/// An identifier-named `module Foo {}` declaration was parsed. Node's
/// `stripTypeScriptTypes` rejects the `module` keyword in both modes
/// (string-named `declare module "foo"` is ambient and allowed).
pub uses_ts_module_keyword: bool,
}

/// TypeScript syntax with runtime semantics; see `Ast::ts_runtime_syntax`.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum TsRuntimeSyntax {
Enum,
Namespace,
ParameterProperty,
ImportEquals,
ExportAssignment,
}

// `parts`/`symbols`/`import_records` are now `ArenaVec`s and need an allocator,
Expand Down Expand Up @@ -137,6 +157,8 @@ impl<'a> Ast<'a> {
has_commonjs_export_names: false,
has_import_meta: false,
import_meta_ref: Ref::NONE,
ts_runtime_syntax: None,
uses_ts_module_keyword: false,
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/ast/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3193,7 +3193,7 @@ pub mod target;

pub use ast_result::{
Ast, CommonJSNamedExport, CommonJSNamedExports, ConstValuesMap, NamedExports, NamedImports,
TopLevelSymbolToParts, TsEnumsMap,
TopLevelSymbolToParts, TsEnumsMap, TsRuntimeSyntax,
};
pub use import_record::{
Flags as ImportRecordFlags, ImportRecord, PrintMode as ImportRecordPrintMode,
Expand Down
17 changes: 17 additions & 0 deletions src/js_parser/p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,10 @@ pub struct P<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> {
pub latest_return_had_semicolon: bool,
pub has_import_meta: bool,
pub has_es_module_syntax: bool,
/// See `Ast::ts_runtime_syntax`; records the first occurrence.
pub ts_runtime_syntax: Option<bun_ast::TsRuntimeSyntax>,
/// See `Ast::uses_ts_module_keyword`.
pub uses_ts_module_keyword: bool,
pub top_level_await_keyword: bun_ast::Range,
pub fn_or_arrow_data_parse: FnOrArrowDataParse,
pub fn_or_arrow_data_visit: FnOrArrowDataVisit,
Expand Down Expand Up @@ -8283,6 +8287,15 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
// independently. `compute_character_frequency` is fully un-gated
// (lexer.all_comments + CharFreq.scan live).
impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_ONLY> {
/// Record the first non-ambient TS runtime-syntax construct in the file;
/// see `Ast::ts_runtime_syntax`.
#[inline]
pub fn record_ts_runtime_syntax(&mut self, kind: bun_ast::TsRuntimeSyntax) {
if self.ts_runtime_syntax.is_none() {
self.ts_runtime_syntax = Some(kind);
}
}

pub fn to_ast(
&mut self,
parts: &mut ListManaged<'a, js_ast::Part>,
Expand Down Expand Up @@ -8862,6 +8875,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
has_top_level_return: false,
redirect_import_record_index: None,
target: js_ast::Target::Browser,
ts_runtime_syntax: self.ts_runtime_syntax,
uses_ts_module_keyword: self.uses_ts_module_keyword,
}))
}

Expand Down Expand Up @@ -9148,6 +9163,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
latest_return_had_semicolon: false,
has_import_meta: false,
has_es_module_syntax: false,
ts_runtime_syntax: None,
uses_ts_module_keyword: false,
top_level_await_keyword: bun_ast::Range::NONE,
fn_or_arrow_data_parse,
fn_or_arrow_data_visit: FnOrArrowDataVisit::default(),
Expand Down
8 changes: 8 additions & 0 deletions src/js_parser/parse/parse_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1342,6 +1342,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
p.lexer.next()?;
let value = p.parse_expr(Level::Lowest)?;
p.lexer.expect_or_insert_semicolon()?;
if !opts.is_typescript_declare {
p.record_ts_runtime_syntax(js_ast::TsRuntimeSyntax::ExportAssignment);
}
return Ok(p.s(S::ExportEquals { value }, loc));
}
p.lexer.unexpected()?;
Expand Down Expand Up @@ -1760,6 +1763,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
&& (p.lexer.token == T::TIdentifier
|| (p.lexer.token == T::TStringLiteral && opts.is_typescript_declare))
{
if matches!(ts_stmt, js_lexer::TypescriptStmtKeyword::TsStmtModule)
&& p.lexer.token == T::TIdentifier
{
p.uses_ts_module_keyword = true;
}
return Ok(Some(p.parse_type_script_namespace_stmt(loc, opts)?));
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/js_parser/parse/parse_typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
.insert(name.ref_.expect("infallible: ref bound"), ns_member_data);
}

p.record_ts_runtime_syntax(bun_ast::TsRuntimeSyntax::Namespace);

// S::Namespace.stmts is `StoreSlice<Stmt>` (arena slice). BumpVec → bump slice.
let stmts_slice: &'a mut [Stmt] = stmts.into_bump_slice_mut();
Ok(p.s(
Expand Down Expand Up @@ -509,6 +511,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
return Ok(p.s(S::TypeScript {}, loc));
}

p.record_ts_runtime_syntax(bun_ast::TsRuntimeSyntax::ImportEquals);

let ref_ = p
.declare_symbol(SymbolKind::Constant, default_name_loc, default_name)
.expect("unreachable");
Expand Down Expand Up @@ -717,6 +721,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
let prev = p.scopes_in_order_for_enum.insert(loc, scope_order_clone);
debug_assert!(prev.is_none());

p.record_ts_runtime_syntax(bun_ast::TsRuntimeSyntax::Enum);

Ok(p.s(
S::Enum {
name,
Expand Down
6 changes: 6 additions & 0 deletions src/js_parser/visit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,12 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
to_add += 1;
}
}
if to_add > 0 {
// `declare class` statements never reach the visit
// pass, so this only fires for real (runtime)
// parameter properties.
self.record_ts_runtime_syntax(bun_ast::TsRuntimeSyntax::ParameterProperty);
}

// if this is an expression, we can move statements after super() because there will be 0 decorators
let mut super_index: Option<usize> = None;
Expand Down
11 changes: 10 additions & 1 deletion src/jsc/ErrorCode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,9 +709,13 @@ impl ErrorCode {
pub const FS_CP_SYMLINK_TO_SUBDIRECTORY: ErrorCode = ErrorCode(325);
/// `ERR_DIR_CONCURRENT_OPERATION` (instanceof Error)
pub const DIR_CONCURRENT_OPERATION: ErrorCode = ErrorCode(326);
/// `ERR_INVALID_TYPESCRIPT_SYNTAX` (instanceof SyntaxError)
pub const INVALID_TYPESCRIPT_SYNTAX: ErrorCode = ErrorCode(327);
/// `ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX` (instanceof SyntaxError)
pub const UNSUPPORTED_TYPESCRIPT_SYNTAX: ErrorCode = ErrorCode(328);

/// == C++ `NODE_ERROR_COUNT`.
pub const COUNT: u16 = 327;
pub const COUNT: u16 = 329;
}

// ──────────────────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -961,6 +965,9 @@ impl ErrorCode {
pub const ERR_MYSQL_CONNECTION_CLOSED: ErrorCode = ErrorCode::MYSQL_CONNECTION_CLOSED;
pub const ERR_MYSQL_CONNECTION_FAILED: ErrorCode = ErrorCode::MYSQL_CONNECTION_FAILED;
pub const ERR_MYSQL_CONNECTION_REFUSED: ErrorCode = ErrorCode::MYSQL_CONNECTION_REFUSED;
pub const ERR_INVALID_TYPESCRIPT_SYNTAX: ErrorCode = ErrorCode::INVALID_TYPESCRIPT_SYNTAX;
pub const ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX: ErrorCode =
ErrorCode::UNSUPPORTED_TYPESCRIPT_SYNTAX;
pub const ERR_MYSQL_CONNECTION_TIMEOUT: ErrorCode = ErrorCode::MYSQL_CONNECTION_TIMEOUT;
pub const ERR_MYSQL_IDLE_TIMEOUT: ErrorCode = ErrorCode::MYSQL_IDLE_TIMEOUT;
pub const ERR_MYSQL_LIFETIME_TIMEOUT: ErrorCode = ErrorCode::MYSQL_LIFETIME_TIMEOUT;
Expand Down Expand Up @@ -1425,6 +1432,8 @@ static CODE_STR: [&str; ErrorCode::COUNT as usize] = [
"ERR_FS_CP_EEXIST",
"ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY",
"ERR_DIR_CONCURRENT_OPERATION",
"ERR_INVALID_TYPESCRIPT_SYNTAX",
"ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX",
];

// ──────────────────────────────────────────────────────────────────────────
Expand Down
Loading
Loading