diff --git a/crates/oxc_ast/src/ast/js.rs b/crates/oxc_ast/src/ast/js.rs index 4e1b4c6facdb7f..03fe485245e8c1 100644 --- a/crates/oxc_ast/src/ast/js.rs +++ b/crates/oxc_ast/src/ast/js.rs @@ -1,7 +1,6 @@ // Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]` #![allow(non_snake_case)] -use crate::ast::*; use std::cell::Cell; use oxc_allocator::{Box, Vec}; @@ -17,6 +16,7 @@ use oxc_syntax::{ }; use super::macros::inherit_variants; +use super::*; #[cfg(feature = "serialize")] use serde::Serialize; @@ -1000,8 +1000,7 @@ pub struct VariableDeclaration<'a> { pub span: Span, pub kind: VariableDeclarationKind, pub declarations: Vec<'a, VariableDeclarator<'a>>, - /// Valid Modifiers: `export`, `declare` - pub modifiers: Modifiers<'a>, + pub declare: bool, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/oxc_ast/src/ast/mod.rs b/crates/oxc_ast/src/ast/mod.rs index add319c965b3e5..51441ef82bb8d3 100644 --- a/crates/oxc_ast/src/ast/mod.rs +++ b/crates/oxc_ast/src/ast/mod.rs @@ -1,3 +1,5 @@ +// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]` +#![allow(non_snake_case)] //! AST Definitions //! //! # Enum inheritance @@ -181,3 +183,128 @@ mod ts; use macros::inherit_variants; pub use self::{js::*, jsx::*, literal::*, ts::*}; + +#[cfg(feature = "serialize")] +use serde::Serialize; +#[cfg(feature = "serialize")] +use tsify::Tsify; + +use oxc_allocator::Vec; +use oxc_span::Span; + +#[derive(Debug, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] +#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] +pub struct Modifier { + #[cfg_attr(feature = "serialize", serde(flatten))] + pub span: Span, + pub kind: ModifierKind, +} + +#[derive(Debug, Default, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] +#[cfg_attr(feature = "serialize", serde(transparent))] +pub struct Modifiers<'a>(Option>); + +impl<'a> Modifiers<'a> { + pub fn new(modifiers: Vec<'a, Modifier>) -> Self { + Self(Some(modifiers)) + } + + pub fn empty() -> Self { + Self(None) + } + + pub fn is_none(&self) -> bool { + self.0.is_none() + } + + pub fn contains(&self, target: ModifierKind) -> bool { + self.0 + .as_ref() + .map_or(false, |modifiers| modifiers.iter().any(|modifier| modifier.kind == target)) + } + + pub fn iter(&self) -> impl Iterator + '_ { + self.0.as_ref().into_iter().flat_map(|modifiers| modifiers.iter()) + } + + /// Find a modifier by kind + pub fn find(&self, kind: ModifierKind) -> Option<&Modifier> { + self.find_where(|modifier| modifier.kind == kind) + } + + pub fn find_where(&self, f: F) -> Option<&Modifier> + where + F: Fn(&Modifier) -> bool, + { + self.0.as_ref().and_then(|modifiers| modifiers.iter().find(|modifier| f(modifier))) + } + + pub fn is_contains_declare(&self) -> bool { + self.contains(ModifierKind::Declare) + } + + pub fn is_contains_abstract(&self) -> bool { + self.contains(ModifierKind::Abstract) + } + + pub fn remove_type_modifiers(&mut self) { + if let Some(list) = &mut self.0 { + list.retain(|m| !m.kind.is_typescript_syntax()); + } + } + + pub fn add_modifier(&mut self, modifier: Modifier) { + if let Some(list) = self.0.as_mut() { + list.push(modifier); + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] +#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] +pub enum ModifierKind { + Abstract, + Accessor, + Async, + Const, + Declare, + Default, + Export, + In, + Public, + Private, + Protected, + Readonly, + Static, + Out, + Override, +} + +impl ModifierKind { + pub fn is_typescript_syntax(&self) -> bool { + !matches!(self, Self::Async | Self::Default | Self::Export | Self::Static) + } + + pub fn as_str(self) -> &'static str { + match self { + Self::Abstract => "abstract", + Self::Accessor => "accessor", + Self::Async => "async", + Self::Const => "const", + Self::Declare => "declare", + Self::Default => "default", + Self::Export => "export", + Self::In => "in", + Self::Public => "public", + Self::Private => "private", + Self::Protected => "protected", + Self::Readonly => "readonly", + Self::Static => "static", + Self::Out => "out", + Self::Override => "override", + } + } +} diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index 2c02efb7578a23..b18727dffb9eb5 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -20,7 +20,7 @@ use serde::Serialize; #[cfg(feature = "serialize")] use tsify::Tsify; -use super::{inherit_variants, js::*, jsx::*, literal::*}; +use super::{inherit_variants, js::*, jsx::*, literal::*, Modifiers}; #[cfg(feature = "serialize")] #[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)] @@ -1279,103 +1279,6 @@ impl<'a> Decorator<'a> { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] -#[cfg_attr(feature = "serialize", serde(rename_all = "camelCase"))] -pub enum ModifierKind { - Abstract, - Accessor, - Async, - Const, - Declare, - Default, - Export, - In, - Public, - Private, - Protected, - Readonly, - Static, - Out, - Override, -} - -impl ModifierKind { - pub fn is_typescript_syntax(&self) -> bool { - !matches!(self, Self::Async | Self::Default | Self::Export | Self::Static) - } -} - -#[derive(Debug, Hash)] -#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] -#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] -pub struct Modifier { - #[cfg_attr(feature = "serialize", serde(flatten))] - pub span: Span, - pub kind: ModifierKind, -} - -#[derive(Debug, Default, Hash)] -#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] -#[cfg_attr(feature = "serialize", serde(transparent))] -pub struct Modifiers<'a>(Option>); - -impl<'a> Modifiers<'a> { - pub fn new(modifiers: Vec<'a, Modifier>) -> Self { - Self(Some(modifiers)) - } - - pub fn empty() -> Self { - Self(None) - } - - pub fn is_none(&self) -> bool { - self.0.is_none() - } - - pub fn contains(&self, target: ModifierKind) -> bool { - self.0 - .as_ref() - .map_or(false, |modifiers| modifiers.iter().any(|modifier| modifier.kind == target)) - } - - pub fn iter(&self) -> impl Iterator + '_ { - self.0.as_ref().into_iter().flat_map(|modifiers| modifiers.iter()) - } - - /// Find a modifier by kind - pub fn find(&self, kind: ModifierKind) -> Option<&Modifier> { - self.find_where(|modifier| modifier.kind == kind) - } - - pub fn find_where(&self, f: F) -> Option<&Modifier> - where - F: Fn(&Modifier) -> bool, - { - self.0.as_ref().and_then(|modifiers| modifiers.iter().find(|modifier| f(modifier))) - } - - pub fn is_contains_declare(&self) -> bool { - self.contains(ModifierKind::Declare) - } - - pub fn is_contains_abstract(&self) -> bool { - self.contains(ModifierKind::Abstract) - } - - pub fn remove_type_modifiers(&mut self) { - if let Some(list) = &mut self.0 { - list.retain(|m| !m.kind.is_typescript_syntax()); - } - } - - pub fn add_modifier(&mut self, modifier: Modifier) { - if let Some(list) = self.0.as_mut() { - list.push(modifier); - } - } -} - /// Export Assignment in non-module files /// /// `export = foo` diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index 16339bb7ee232a..33751363b5fbf2 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -111,7 +111,7 @@ impl<'a> AstBuilder<'a> { Span::default(), VariableDeclarationKind::Var, self.new_vec(), - Modifiers::empty(), + false, ); let empty_decl = Declaration::VariableDeclaration(empty_decl); mem::replace(decl, empty_decl) @@ -1167,9 +1167,9 @@ impl<'a> AstBuilder<'a> { span: Span, kind: VariableDeclarationKind, declarations: Vec<'a, VariableDeclarator<'a>>, - modifiers: Modifiers<'a>, + declare: bool, ) -> Box<'a, VariableDeclaration<'a>> { - self.alloc(VariableDeclaration { span, kind, declarations, modifiers }) + self.alloc(VariableDeclaration { span, kind, declarations, declare }) } #[inline] diff --git a/crates/oxc_ast/src/ast_impl/js.rs b/crates/oxc_ast/src/ast_impl/js.rs index 000e6ebb7897d6..d08d47e9962d46 100644 --- a/crates/oxc_ast/src/ast_impl/js.rs +++ b/crates/oxc_ast/src/ast_impl/js.rs @@ -705,23 +705,23 @@ impl<'a> Declaration<'a> { } } - pub fn modifiers(&self) -> Option<&Modifiers<'a>> { + pub fn declare(&self) -> bool { match self { - Declaration::VariableDeclaration(decl) => Some(&decl.modifiers), - Declaration::FunctionDeclaration(decl) => Some(&decl.modifiers), - Declaration::ClassDeclaration(decl) => Some(&decl.modifiers), - Declaration::TSEnumDeclaration(decl) => Some(&decl.modifiers), - Declaration::TSTypeAliasDeclaration(decl) => Some(&decl.modifiers), - Declaration::TSModuleDeclaration(decl) => Some(&decl.modifiers), - Declaration::TSInterfaceDeclaration(decl) => Some(&decl.modifiers), - _ => None, + Declaration::VariableDeclaration(decl) => decl.declare, + Declaration::FunctionDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::ClassDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::TSEnumDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::TSTypeAliasDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::TSModuleDeclaration(decl) => decl.modifiers.is_contains_declare(), + Declaration::TSInterfaceDeclaration(decl) => decl.modifiers.is_contains_declare(), + _ => false, } } } impl<'a> VariableDeclaration<'a> { pub fn is_typescript_syntax(&self) -> bool { - self.modifiers.contains(ModifierKind::Declare) + self.declare } pub fn has_init(&self) -> bool { diff --git a/crates/oxc_codegen/src/gen.rs b/crates/oxc_codegen/src/gen.rs index ebc4cbf04ae359..992e4f29fb527f 100644 --- a/crates/oxc_codegen/src/gen.rs +++ b/crates/oxc_codegen/src/gen.rs @@ -580,7 +580,7 @@ impl<'a, const MINIFY: bool> Gen for UsingDeclaration<'a> { impl<'a, const MINIFY: bool> Gen for VariableDeclaration<'a> { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { p.add_source_mapping(self.span.start); - if self.modifiers.is_contains_declare() { + if self.declare { p.print_str(b"declare "); } diff --git a/crates/oxc_isolated_declarations/src/declaration.rs b/crates/oxc_isolated_declarations/src/declaration.rs index 2dfb2f54967bcc..2b233ba536253e 100644 --- a/crates/oxc_isolated_declarations/src/declaration.rs +++ b/crates/oxc_isolated_declarations/src/declaration.rs @@ -19,7 +19,7 @@ impl<'a> IsolatedDeclarations<'a> { decl: &VariableDeclaration<'a>, check_binding: bool, ) -> Option>> { - if decl.modifiers.is_contains_declare() { + if decl.declare { None } else { let declarations = @@ -39,7 +39,7 @@ impl<'a> IsolatedDeclarations<'a> { decl.span, decl.kind, self.ast.new_vec_from_iter(declarations), - self.modifiers_declare(), + self.modifiers_declare().is_contains_declare(), ) } @@ -126,7 +126,7 @@ impl<'a> IsolatedDeclarations<'a> { decl.span, VariableDeclarationKind::Const, declarations, - self.modifiers_declare(), + self.modifiers_declare().is_contains_declare(), ) } diff --git a/crates/oxc_isolated_declarations/src/module.rs b/crates/oxc_isolated_declarations/src/module.rs index b09bc1a218245b..32e773a5cd902d 100644 --- a/crates/oxc_isolated_declarations/src/module.rs +++ b/crates/oxc_isolated_declarations/src/module.rs @@ -75,7 +75,7 @@ impl<'a> IsolatedDeclarations<'a> { span: SPAN, kind, declarations, - modifiers: self.modifiers_declare(), + declare: self.modifiers_declare().is_contains_declare(), }), ExportDefaultDeclarationKind::from( self.ast.identifier_reference_expression( diff --git a/crates/oxc_parser/src/diagnostics.rs b/crates/oxc_parser/src/diagnostics.rs index 48260e5fe49929..ee09d7fb7b51e1 100644 --- a/crates/oxc_parser/src/diagnostics.rs +++ b/crates/oxc_parser/src/diagnostics.rs @@ -408,3 +408,11 @@ pub fn jsx_element_no_match(span0: Span, span1: Span, name: &str) -> OxcDiagnost OxcDiagnostic::error(format!("Expected corresponding JSX closing tag for '{name}'.")) .with_labels([span0.into(), span1.into()]) } + +#[cold] +pub fn modifiers_cannot_appear(span: Span, name: &str) -> OxcDiagnostic { + OxcDiagnostic::error(format!( + "TS1044: '{name}' modifier cannot appear on a module or namespace element." + )) + .with_label(span) +} diff --git a/crates/oxc_parser/src/js/declaration.rs b/crates/oxc_parser/src/js/declaration.rs index d2f0d259c8d95f..24cb1035d1a89f 100644 --- a/crates/oxc_parser/src/js/declaration.rs +++ b/crates/oxc_parser/src/js/declaration.rs @@ -41,7 +41,7 @@ impl<'a> ParserImpl<'a> { &mut self, start_span: Span, decl_ctx: VariableDeclarationContext, - modifiers: Modifiers<'a>, + modifiers: &Modifiers<'a>, ) -> Result>> { let kind = match self.cur_kind() { Kind::Var => VariableDeclarationKind::Var, @@ -67,7 +67,21 @@ impl<'a> ParserImpl<'a> { self.asi()?; } - Ok(self.ast.variable_declaration(self.end_span(start_span), kind, declarations, modifiers)) + for modifier in modifiers.iter() { + if modifier.kind != ModifierKind::Declare { + self.error(diagnostics::modifiers_cannot_appear( + modifier.span, + modifier.kind.as_str(), + )) + } + } + + Ok(self.ast.variable_declaration( + self.end_span(start_span), + kind, + declarations, + modifiers.is_contains_declare(), + )) } fn parse_variable_declarator( diff --git a/crates/oxc_parser/src/js/statement.rs b/crates/oxc_parser/src/js/statement.rs index a592e062f8e1af..109b1d118d5155 100644 --- a/crates/oxc_parser/src/js/statement.rs +++ b/crates/oxc_parser/src/js/statement.rs @@ -160,7 +160,7 @@ impl<'a> ParserImpl<'a> { let decl = self.parse_variable_declaration( start_span, VariableDeclarationContext::new(VariableDeclarationParent::Statement), - Modifiers::empty(), + &Modifiers::empty(), )?; if stmt_ctx.is_single_statement() && decl.kind.is_lexical() { @@ -287,7 +287,7 @@ impl<'a> ParserImpl<'a> { let start_span = self.start_span(); let init_declaration = self.context(Context::empty(), Context::In, |p| { let decl_ctx = VariableDeclarationContext::new(VariableDeclarationParent::For); - p.parse_variable_declaration(start_span, decl_ctx, Modifiers::empty()) + p.parse_variable_declaration(start_span, decl_ctx, &Modifiers::empty()) })?; // for (.. a in) for (.. a of) diff --git a/crates/oxc_parser/src/ts/statement.rs b/crates/oxc_parser/src/ts/statement.rs index 263de11cf74e0e..6aaffd660ca1d0 100644 --- a/crates/oxc_parser/src/ts/statement.rs +++ b/crates/oxc_parser/src/ts/statement.rs @@ -304,7 +304,7 @@ impl<'a> ParserImpl<'a> { .parse_variable_declaration( start_span, VariableDeclarationContext::new(VariableDeclarationParent::Clause), - modifiers, + &modifiers, ) .map(Declaration::VariableDeclaration), _ if self.at_function_with_async() => { diff --git a/crates/oxc_semantic/src/checker/mod.rs b/crates/oxc_semantic/src/checker/mod.rs index 6a726abf5ab00e..3e6e4e3dda356d 100644 --- a/crates/oxc_semantic/src/checker/mod.rs +++ b/crates/oxc_semantic/src/checker/mod.rs @@ -94,7 +94,6 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { AstKind::ObjectExpression(expr) => js::check_object_expression(expr, ctx), AstKind::UnaryExpression(expr) => js::check_unary_expression(expr, node, ctx), AstKind::YieldExpression(expr) => js::check_yield_expression(expr, node, ctx), - AstKind::VariableDeclaration(decl) => ts::check_variable_declaration(decl, node, ctx), AstKind::VariableDeclarator(decl) => ts::check_variable_declarator(decl, ctx), AstKind::SimpleAssignmentTarget(target) => ts::check_simple_assignment_target(target, ctx), AstKind::TSTypeParameterDeclaration(declaration) => { diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index d4143190a5d945..d4b6c938742abd 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -172,13 +172,6 @@ fn check_declaration_modifiers<'a>( } } } -pub fn check_variable_declaration<'a>( - decl: &VariableDeclaration<'a>, - node: &AstNode<'a>, - ctx: &SemanticBuilder<'a>, -) { - check_declaration_modifiers(&decl.modifiers, node, ctx); -} pub fn check_function<'a>(function: &Function<'a>, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { check_declaration_modifiers(&function.modifiers, node, ctx); diff --git a/crates/oxc_semantic/tests/integration/symbols.rs b/crates/oxc_semantic/tests/integration/symbols.rs index 9bc67699cfce23..8b43297749a19c 100644 --- a/crates/oxc_semantic/tests/integration/symbols.rs +++ b/crates/oxc_semantic/tests/integration/symbols.rs @@ -114,20 +114,3 @@ fn test_export_flag() { tester.has_root_symbol("b").contains_flags(SymbolFlags::Export).test(); tester.has_root_symbol("c").contains_flags(SymbolFlags::Export).test(); } - -#[test] -fn test_invalid_modifiers() { - const PARAM_PROPERTY: &str = - "A parameter property is only allowed in a constructor implementation."; - const ILLEGAL_MODIFIER: &str = "Modifiers cannot be used here."; - const READONLY: &str = - "'readonly' modifier can only appear on a property declaration or index signature."; - - SemanticTester::ts("function foo(public x: number) { }").has_error(PARAM_PROPERTY); - // SemanticTester::ts("function foo() { export const x = 1; }").has_error(illegal_modifier); - SemanticTester::ts("function foo() { public const x = 1; }").has_error(ILLEGAL_MODIFIER); - SemanticTester::ts("function foo() { private const x = 1; }").has_error(ILLEGAL_MODIFIER); - SemanticTester::ts("function foo() { protected const x = 1; }").has_error(ILLEGAL_MODIFIER); - SemanticTester::ts("function foo() { abstract const x = 1; }").has_error(ILLEGAL_MODIFIER); - SemanticTester::ts("function foo() { readonly const x = 1; }").has_error(READONLY); -} diff --git a/crates/oxc_transformer/src/es2015/arrow_functions.rs b/crates/oxc_transformer/src/es2015/arrow_functions.rs index 86b7b9d046f260..86ffad21c090e3 100644 --- a/crates/oxc_transformer/src/es2015/arrow_functions.rs +++ b/crates/oxc_transformer/src/es2015/arrow_functions.rs @@ -131,7 +131,7 @@ impl<'a> ArrowFunctions<'a> { SPAN, VariableDeclarationKind::Var, self.ctx.ast.new_vec_single(variable_declarator), - Modifiers::empty(), + false, ); let stmt = Statement::VariableDeclaration(stmt); diff --git a/crates/oxc_transformer/src/helpers/module_imports.rs b/crates/oxc_transformer/src/helpers/module_imports.rs index a312ebfb31760d..dad026b8e529e2 100644 --- a/crates/oxc_transformer/src/helpers/module_imports.rs +++ b/crates/oxc_transformer/src/helpers/module_imports.rs @@ -141,7 +141,7 @@ impl<'a> ModuleImports<'a> { let decl = self.ast.variable_declarator(SPAN, var_kind, id, Some(init), false); self.ast.new_vec_single(decl) }; - let var_decl = self.ast.variable_declaration(SPAN, var_kind, decl, Modifiers::empty()); + let var_decl = self.ast.variable_declaration(SPAN, var_kind, decl, false); Statement::VariableDeclaration(var_decl) } } diff --git a/crates/oxc_transformer/src/react/jsx_source.rs b/crates/oxc_transformer/src/react/jsx_source.rs index 3d78ab95a43f37..185bf81d7a9b67 100644 --- a/crates/oxc_transformer/src/react/jsx_source.rs +++ b/crates/oxc_transformer/src/react/jsx_source.rs @@ -160,7 +160,7 @@ impl<'a> ReactJsxSource<'a> { let decl = self.ctx.ast.variable_declarator(SPAN, var_kind, id, Some(init), false); self.ctx.ast.new_vec_single(decl) }; - let var_decl = self.ctx.ast.variable_declaration(SPAN, var_kind, decl, Modifiers::empty()); + let var_decl = self.ctx.ast.variable_declaration(SPAN, var_kind, decl, false); Some(Statement::VariableDeclaration(var_decl)) } diff --git a/crates/oxc_transformer/src/typescript/annotations.rs b/crates/oxc_transformer/src/typescript/annotations.rs index 5bd33549d78980..74f634ec87ab7b 100644 --- a/crates/oxc_transformer/src/typescript/annotations.rs +++ b/crates/oxc_transformer/src/typescript/annotations.rs @@ -382,9 +382,7 @@ impl<'a> TypeScriptAnnotations<'a> { pub fn transform_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) { // Remove declare declaration stmts.retain(|stmt| match stmt { - match_declaration!(Statement) => { - stmt.to_declaration().modifiers().map_or(true, |m| !m.is_contains_declare()) - } + match_declaration!(Statement) => !stmt.to_declaration().declare(), _ => true, }); } diff --git a/crates/oxc_transformer/src/typescript/enum.rs b/crates/oxc_transformer/src/typescript/enum.rs index ab3a09147bb554..b4648db4566b49 100644 --- a/crates/oxc_transformer/src/typescript/enum.rs +++ b/crates/oxc_transformer/src/typescript/enum.rs @@ -134,8 +134,7 @@ impl<'a> TypeScriptEnum<'a> { decls.push(decl); decls }; - let variable_declaration = - self.ctx.ast.variable_declaration(span, kind, decls, Modifiers::empty()); + let variable_declaration = self.ctx.ast.variable_declaration(span, kind, decls, false); let variable_declaration = Declaration::VariableDeclaration(variable_declaration); let stmt = if is_export { diff --git a/crates/oxc_transformer/src/typescript/module.rs b/crates/oxc_transformer/src/typescript/module.rs index 8df76486d95e0e..ce55b4b9f991c6 100644 --- a/crates/oxc_transformer/src/typescript/module.rs +++ b/crates/oxc_transformer/src/typescript/module.rs @@ -66,8 +66,7 @@ impl<'a> TypeScript<'a> { false, )) }; - let variable_declaration = - self.ctx.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty()); + let variable_declaration = self.ctx.ast.variable_declaration(SPAN, kind, decls, false); Declaration::VariableDeclaration(variable_declaration) } diff --git a/crates/oxc_transformer/src/typescript/namespace.rs b/crates/oxc_transformer/src/typescript/namespace.rs index 7e81b4efdb314d..e2a26fbb1d4d69 100644 --- a/crates/oxc_transformer/src/typescript/namespace.rs +++ b/crates/oxc_transformer/src/typescript/namespace.rs @@ -190,7 +190,7 @@ impl<'a> TypeScript<'a> { // legal syntax in TS namespaces let export_decl = export_decl.unbox(); if let Some(decl) = export_decl.declaration { - if decl.modifiers().is_some_and(Modifiers::is_contains_declare) { + if decl.declare() { continue; } match decl { @@ -290,7 +290,7 @@ impl<'a> TypeScript<'a> { SPAN, kind, declarations, - Modifiers::empty(), + false, )) } diff --git a/crates/oxc_traverse/src/ancestor.rs b/crates/oxc_traverse/src/ancestor.rs index 55b7dfa1984ca3..6b1677ce8e8200 100644 --- a/crates/oxc_traverse/src/ancestor.rs +++ b/crates/oxc_traverse/src/ancestor.rs @@ -3835,8 +3835,8 @@ pub(crate) const OFFSET_VARIABLE_DECLARATION_SPAN: usize = offset_of!(VariableDe pub(crate) const OFFSET_VARIABLE_DECLARATION_KIND: usize = offset_of!(VariableDeclaration, kind); pub(crate) const OFFSET_VARIABLE_DECLARATION_DECLARATIONS: usize = offset_of!(VariableDeclaration, declarations); -pub(crate) const OFFSET_VARIABLE_DECLARATION_MODIFIERS: usize = - offset_of!(VariableDeclaration, modifiers); +pub(crate) const OFFSET_VARIABLE_DECLARATION_DECLARE: usize = + offset_of!(VariableDeclaration, declare); #[repr(transparent)] #[derive(Debug)] @@ -3857,11 +3857,8 @@ impl<'a> VariableDeclarationWithoutDeclarations<'a> { } #[inline] - pub fn modifiers(&self) -> &Modifiers<'a> { - unsafe { - &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATION_MODIFIERS) - as *const Modifiers<'a>) - } + pub fn declare(&self) -> &bool { + unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATION_DECLARE) as *const bool) } } } diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index b1384bc7b6711d..c8355a4eaf5d9d 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -6414,7 +6414,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" · ╰── `from` expected ╰──── - × Modifiers cannot be used here. + × TS1044: 'export' modifier cannot appear on a module or namespace element. ╭─[compiler/exportAlreadySeen.ts:2:12] 1 │ module M { 2 │ export export var x = 1; @@ -6422,6 +6422,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 3 │ export export function f() { } ╰──── + × TS1044: 'export' modifier cannot appear on a module or namespace element. + ╭─[compiler/exportAlreadySeen.ts:12:12] + 11 │ declare module A { + 12 │ export export var x; + · ────── + 13 │ export export function f() + ╰──── + × Modifiers cannot be used here. ╭─[compiler/exportAlreadySeen.ts:3:12] 2 │ export export var x = 1; @@ -6454,14 +6462,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 6 │ export export class C { } ╰──── - × Modifiers cannot be used here. - ╭─[compiler/exportAlreadySeen.ts:12:12] - 11 │ declare module A { - 12 │ export export var x; - · ────── - 13 │ export export function f() - ╰──── - × Modifiers cannot be used here. ╭─[compiler/exportAlreadySeen.ts:13:12] 12 │ export export var x; @@ -16373,7 +16373,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 77 │ } ╰──── - × Modifiers cannot be used here. + × TS1044: 'public' modifier cannot appear on a module or namespace element. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:4:5] 3 │ module Y { 4 │ public var x: number = 0; @@ -16381,6 +16381,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 5 │ } ╰──── + × TS1044: 'static' modifier cannot appear on a module or namespace element. + ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:12:5] + 11 │ module Y4 { + 12 │ static var x: number = 0; + · ────── + 13 │ } + ╰──── + + × TS1044: 'private' modifier cannot appear on a module or namespace element. + ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:20:5] + 19 │ module YY2 { + 20 │ private var x: number = 0; + · ─────── + 21 │ } + ╰──── + × Modifiers cannot be used here. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:8:5] 7 │ module Y2 { @@ -16389,14 +16405,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 9 │ } ╰──── - × Modifiers cannot be used here. - ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:12:5] - 11 │ module Y4 { - 12 │ static var x: number = 0; - · ────── - 13 │ } - ╰──── - × Modifiers cannot be used here. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:16:5] 15 │ module YY { @@ -16405,14 +16413,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts" 17 │ } ╰──── - × Modifiers cannot be used here. - ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:20:5] - 19 │ module YY2 { - 20 │ private var x: number = 0; - · ─────── - 21 │ } - ╰──── - × Modifiers cannot be used here. ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:25:5] 24 │ module YY3 {