refactor(ast)!: replace Modifiers with declare on VariableDeclaration (#3839)

part of #2958
This commit is contained in:
Boshen 2024-06-23 10:34:52 +00:00
parent f029273b04
commit 9b38119ec9
25 changed files with 224 additions and 200 deletions

View file

@ -1,7 +1,6 @@
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]` // Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::ast::*;
use std::cell::Cell; use std::cell::Cell;
use oxc_allocator::{Box, Vec}; use oxc_allocator::{Box, Vec};
@ -17,6 +16,7 @@ use oxc_syntax::{
}; };
use super::macros::inherit_variants; use super::macros::inherit_variants;
use super::*;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use serde::Serialize; use serde::Serialize;
@ -1000,8 +1000,7 @@ pub struct VariableDeclaration<'a> {
pub span: Span, pub span: Span,
pub kind: VariableDeclarationKind, pub kind: VariableDeclarationKind,
pub declarations: Vec<'a, VariableDeclarator<'a>>, pub declarations: Vec<'a, VariableDeclarator<'a>>,
/// Valid Modifiers: `export`, `declare` pub declare: bool,
pub modifiers: Modifiers<'a>,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -1,3 +1,5 @@
// Silence erroneous warnings from Rust Analyser for `#[derive(Tsify)]`
#![allow(non_snake_case)]
//! AST Definitions //! AST Definitions
//! //!
//! # Enum inheritance //! # Enum inheritance
@ -181,3 +183,128 @@ mod ts;
use macros::inherit_variants; use macros::inherit_variants;
pub use self::{js::*, jsx::*, literal::*, ts::*}; 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<Vec<'a, Modifier>>);
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<Item = &Modifier> + '_ {
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<F>(&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",
}
}
}

View file

@ -20,7 +20,7 @@ use serde::Serialize;
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
use tsify::Tsify; use tsify::Tsify;
use super::{inherit_variants, js::*, jsx::*, literal::*}; use super::{inherit_variants, js::*, jsx::*, literal::*, Modifiers};
#[cfg(feature = "serialize")] #[cfg(feature = "serialize")]
#[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)] #[wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section)]
@ -1094,41 +1094,6 @@ pub struct Decorator<'a> {
pub expression: Expression<'a>, pub expression: Expression<'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,
}
#[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>(pub(crate) Option<Vec<'a, Modifier>>);
/// Export Assignment in non-module files /// Export Assignment in non-module files
/// ///
/// `export = foo` /// `export = foo`

View file

@ -111,7 +111,7 @@ impl<'a> AstBuilder<'a> {
Span::default(), Span::default(),
VariableDeclarationKind::Var, VariableDeclarationKind::Var,
self.new_vec(), self.new_vec(),
Modifiers::empty(), false,
); );
let empty_decl = Declaration::VariableDeclaration(empty_decl); let empty_decl = Declaration::VariableDeclaration(empty_decl);
mem::replace(decl, empty_decl) mem::replace(decl, empty_decl)
@ -1167,9 +1167,9 @@ impl<'a> AstBuilder<'a> {
span: Span, span: Span,
kind: VariableDeclarationKind, kind: VariableDeclarationKind,
declarations: Vec<'a, VariableDeclarator<'a>>, declarations: Vec<'a, VariableDeclarator<'a>>,
modifiers: Modifiers<'a>, declare: bool,
) -> Box<'a, VariableDeclaration<'a>> { ) -> Box<'a, VariableDeclaration<'a>> {
self.alloc(VariableDeclaration { span, kind, declarations, modifiers }) self.alloc(VariableDeclaration { span, kind, declarations, declare })
} }
#[inline] #[inline]

View file

@ -705,23 +705,23 @@ impl<'a> Declaration<'a> {
} }
} }
pub fn modifiers(&self) -> Option<&Modifiers<'a>> { pub fn declare(&self) -> bool {
match self { match self {
Declaration::VariableDeclaration(decl) => Some(&decl.modifiers), Declaration::VariableDeclaration(decl) => decl.declare,
Declaration::FunctionDeclaration(decl) => Some(&decl.modifiers), Declaration::FunctionDeclaration(decl) => decl.modifiers.is_contains_declare(),
Declaration::ClassDeclaration(decl) => Some(&decl.modifiers), Declaration::ClassDeclaration(decl) => decl.modifiers.is_contains_declare(),
Declaration::TSEnumDeclaration(decl) => Some(&decl.modifiers), Declaration::TSEnumDeclaration(decl) => decl.modifiers.is_contains_declare(),
Declaration::TSTypeAliasDeclaration(decl) => Some(&decl.modifiers), Declaration::TSTypeAliasDeclaration(decl) => decl.modifiers.is_contains_declare(),
Declaration::TSModuleDeclaration(decl) => Some(&decl.modifiers), Declaration::TSModuleDeclaration(decl) => decl.modifiers.is_contains_declare(),
Declaration::TSInterfaceDeclaration(decl) => Some(&decl.modifiers), Declaration::TSInterfaceDeclaration(decl) => decl.modifiers.is_contains_declare(),
_ => None, _ => false,
} }
} }
} }
impl<'a> VariableDeclaration<'a> { impl<'a> VariableDeclaration<'a> {
pub fn is_typescript_syntax(&self) -> bool { pub fn is_typescript_syntax(&self) -> bool {
self.modifiers.contains(ModifierKind::Declare) self.declare
} }
pub fn has_init(&self) -> bool { pub fn has_init(&self) -> bool {

View file

@ -6,13 +6,14 @@
// NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file. // NB: `#[visited_node]` attribute on AST nodes does not do anything to the code in this file.
// It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate. // It is purely a marker for codegen used in `oxc_traverse`. See docs in that crate.
use crate::ast::*;
use std::{cell::Cell, hash::Hash}; use std::{cell::Cell, hash::Hash};
use oxc_allocator::Vec; use oxc_allocator::Vec;
use oxc_span::{Atom, GetSpan, Span}; use oxc_span::{Atom, GetSpan, Span};
use crate::ast::Modifiers;
use crate::ast::*;
impl<'a> TSEnumDeclaration<'a> { impl<'a> TSEnumDeclaration<'a> {
pub fn new( pub fn new(
span: Span, span: Span,
@ -198,68 +199,6 @@ impl<'a> Decorator<'a> {
} }
} }
impl ModifierKind {
pub fn is_typescript_syntax(&self) -> bool {
!matches!(self, Self::Async | Self::Default | Self::Export | Self::Static)
}
}
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<Item = &Modifier> + '_ {
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<F>(&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);
}
}
}
impl ImportOrExportKind { impl ImportOrExportKind {
pub fn is_value(&self) -> bool { pub fn is_value(&self) -> bool {
matches!(self, Self::Value) matches!(self, Self::Value)

View file

@ -580,7 +580,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for UsingDeclaration<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for VariableDeclaration<'a> { impl<'a, const MINIFY: bool> Gen<MINIFY> for VariableDeclaration<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) { fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
p.add_source_mapping(self.span.start); p.add_source_mapping(self.span.start);
if self.modifiers.is_contains_declare() { if self.declare {
p.print_str(b"declare "); p.print_str(b"declare ");
} }

View file

@ -19,7 +19,7 @@ impl<'a> IsolatedDeclarations<'a> {
decl: &VariableDeclaration<'a>, decl: &VariableDeclaration<'a>,
check_binding: bool, check_binding: bool,
) -> Option<Box<'a, VariableDeclaration<'a>>> { ) -> Option<Box<'a, VariableDeclaration<'a>>> {
if decl.modifiers.is_contains_declare() { if decl.declare {
None None
} else { } else {
let declarations = let declarations =
@ -39,7 +39,7 @@ impl<'a> IsolatedDeclarations<'a> {
decl.span, decl.span,
decl.kind, decl.kind,
self.ast.new_vec_from_iter(declarations), 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, decl.span,
VariableDeclarationKind::Const, VariableDeclarationKind::Const,
declarations, declarations,
self.modifiers_declare(), self.modifiers_declare().is_contains_declare(),
) )
} }

View file

@ -75,7 +75,7 @@ impl<'a> IsolatedDeclarations<'a> {
span: SPAN, span: SPAN,
kind, kind,
declarations, declarations,
modifiers: self.modifiers_declare(), declare: self.modifiers_declare().is_contains_declare(),
}), }),
ExportDefaultDeclarationKind::from( ExportDefaultDeclarationKind::from(
self.ast.identifier_reference_expression( self.ast.identifier_reference_expression(

View file

@ -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}'.")) OxcDiagnostic::error(format!("Expected corresponding JSX closing tag for '{name}'."))
.with_labels([span0.into(), span1.into()]) .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)
}

View file

@ -41,7 +41,7 @@ impl<'a> ParserImpl<'a> {
&mut self, &mut self,
start_span: Span, start_span: Span,
decl_ctx: VariableDeclarationContext, decl_ctx: VariableDeclarationContext,
modifiers: Modifiers<'a>, modifiers: &Modifiers<'a>,
) -> Result<Box<'a, VariableDeclaration<'a>>> { ) -> Result<Box<'a, VariableDeclaration<'a>>> {
let kind = match self.cur_kind() { let kind = match self.cur_kind() {
Kind::Var => VariableDeclarationKind::Var, Kind::Var => VariableDeclarationKind::Var,
@ -67,7 +67,21 @@ impl<'a> ParserImpl<'a> {
self.asi()?; 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( fn parse_variable_declarator(

View file

@ -160,7 +160,7 @@ impl<'a> ParserImpl<'a> {
let decl = self.parse_variable_declaration( let decl = self.parse_variable_declaration(
start_span, start_span,
VariableDeclarationContext::new(VariableDeclarationParent::Statement), VariableDeclarationContext::new(VariableDeclarationParent::Statement),
Modifiers::empty(), &Modifiers::empty(),
)?; )?;
if stmt_ctx.is_single_statement() && decl.kind.is_lexical() { 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 start_span = self.start_span();
let init_declaration = self.context(Context::empty(), Context::In, |p| { let init_declaration = self.context(Context::empty(), Context::In, |p| {
let decl_ctx = VariableDeclarationContext::new(VariableDeclarationParent::For); 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) // for (.. a in) for (.. a of)

View file

@ -304,7 +304,7 @@ impl<'a> ParserImpl<'a> {
.parse_variable_declaration( .parse_variable_declaration(
start_span, start_span,
VariableDeclarationContext::new(VariableDeclarationParent::Clause), VariableDeclarationContext::new(VariableDeclarationParent::Clause),
modifiers, &modifiers,
) )
.map(Declaration::VariableDeclaration), .map(Declaration::VariableDeclaration),
_ if self.at_function_with_async() => { _ if self.at_function_with_async() => {

View file

@ -94,7 +94,6 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
AstKind::ObjectExpression(expr) => js::check_object_expression(expr, ctx), AstKind::ObjectExpression(expr) => js::check_object_expression(expr, ctx),
AstKind::UnaryExpression(expr) => js::check_unary_expression(expr, node, ctx), AstKind::UnaryExpression(expr) => js::check_unary_expression(expr, node, ctx),
AstKind::YieldExpression(expr) => js::check_yield_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::VariableDeclarator(decl) => ts::check_variable_declarator(decl, ctx),
AstKind::SimpleAssignmentTarget(target) => ts::check_simple_assignment_target(target, ctx), AstKind::SimpleAssignmentTarget(target) => ts::check_simple_assignment_target(target, ctx),
AstKind::TSTypeParameterDeclaration(declaration) => { AstKind::TSTypeParameterDeclaration(declaration) => {

View file

@ -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>) { pub fn check_function<'a>(function: &Function<'a>, node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) {
check_declaration_modifiers(&function.modifiers, node, ctx); check_declaration_modifiers(&function.modifiers, node, ctx);

View file

@ -114,20 +114,3 @@ fn test_export_flag() {
tester.has_root_symbol("b").contains_flags(SymbolFlags::Export).test(); tester.has_root_symbol("b").contains_flags(SymbolFlags::Export).test();
tester.has_root_symbol("c").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);
}

View file

@ -131,7 +131,7 @@ impl<'a> ArrowFunctions<'a> {
SPAN, SPAN,
VariableDeclarationKind::Var, VariableDeclarationKind::Var,
self.ctx.ast.new_vec_single(variable_declarator), self.ctx.ast.new_vec_single(variable_declarator),
Modifiers::empty(), false,
); );
let stmt = Statement::VariableDeclaration(stmt); let stmt = Statement::VariableDeclaration(stmt);

View file

@ -141,7 +141,7 @@ impl<'a> ModuleImports<'a> {
let decl = self.ast.variable_declarator(SPAN, var_kind, id, Some(init), false); let decl = self.ast.variable_declarator(SPAN, var_kind, id, Some(init), false);
self.ast.new_vec_single(decl) 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) Statement::VariableDeclaration(var_decl)
} }
} }

View file

@ -160,7 +160,7 @@ impl<'a> ReactJsxSource<'a> {
let decl = self.ctx.ast.variable_declarator(SPAN, var_kind, id, Some(init), false); let decl = self.ctx.ast.variable_declarator(SPAN, var_kind, id, Some(init), false);
self.ctx.ast.new_vec_single(decl) 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)) Some(Statement::VariableDeclaration(var_decl))
} }

View file

@ -311,13 +311,15 @@ impl<'a> TypeScriptAnnotations<'a> {
pub fn transform_statements(&mut self, stmts: &mut ArenaVec<'a, Statement<'a>>) { pub fn transform_statements(&mut self, stmts: &mut ArenaVec<'a, Statement<'a>>) {
// Remove declare declaration // Remove declare declaration
stmts.retain(|stmt| { stmts.retain(
|stmt| {
if let Some(decl) = stmt.as_declaration() { if let Some(decl) = stmt.as_declaration() {
decl.modifiers().map_or(true, |m| !m.is_contains_declare()) !decl.declare()
} else { } else {
true true
} }
}); },
);
} }
pub fn transform_statements_on_exit( pub fn transform_statements_on_exit(

View file

@ -134,8 +134,7 @@ impl<'a> TypeScriptEnum<'a> {
decls.push(decl); decls.push(decl);
decls decls
}; };
let variable_declaration = let variable_declaration = self.ctx.ast.variable_declaration(span, kind, decls, false);
self.ctx.ast.variable_declaration(span, kind, decls, Modifiers::empty());
let variable_declaration = Declaration::VariableDeclaration(variable_declaration); let variable_declaration = Declaration::VariableDeclaration(variable_declaration);
let stmt = if is_export { let stmt = if is_export {

View file

@ -66,8 +66,7 @@ impl<'a> TypeScript<'a> {
false, false,
)) ))
}; };
let variable_declaration = let variable_declaration = self.ctx.ast.variable_declaration(SPAN, kind, decls, false);
self.ctx.ast.variable_declaration(SPAN, kind, decls, Modifiers::empty());
Declaration::VariableDeclaration(variable_declaration) Declaration::VariableDeclaration(variable_declaration)
} }

View file

@ -190,7 +190,7 @@ impl<'a> TypeScript<'a> {
// legal syntax in TS namespaces // legal syntax in TS namespaces
let export_decl = export_decl.unbox(); let export_decl = export_decl.unbox();
if let Some(decl) = export_decl.declaration { if let Some(decl) = export_decl.declaration {
if decl.modifiers().is_some_and(Modifiers::is_contains_declare) { if decl.declare() {
continue; continue;
} }
match decl { match decl {
@ -290,7 +290,7 @@ impl<'a> TypeScript<'a> {
SPAN, SPAN,
kind, kind,
declarations, declarations,
Modifiers::empty(), false,
)) ))
} }

View file

@ -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_KIND: usize = offset_of!(VariableDeclaration, kind);
pub(crate) const OFFSET_VARIABLE_DECLARATION_DECLARATIONS: usize = pub(crate) const OFFSET_VARIABLE_DECLARATION_DECLARATIONS: usize =
offset_of!(VariableDeclaration, declarations); offset_of!(VariableDeclaration, declarations);
pub(crate) const OFFSET_VARIABLE_DECLARATION_MODIFIERS: usize = pub(crate) const OFFSET_VARIABLE_DECLARATION_DECLARE: usize =
offset_of!(VariableDeclaration, modifiers); offset_of!(VariableDeclaration, declare);
#[repr(transparent)] #[repr(transparent)]
#[derive(Debug)] #[derive(Debug)]
@ -3857,11 +3857,8 @@ impl<'a> VariableDeclarationWithoutDeclarations<'a> {
} }
#[inline] #[inline]
pub fn modifiers(&self) -> &Modifiers<'a> { pub fn declare(&self) -> &bool {
unsafe { unsafe { &*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATION_DECLARE) as *const bool) }
&*((self.0 as *const u8).add(OFFSET_VARIABLE_DECLARATION_MODIFIERS)
as *const Modifiers<'a>)
}
} }
} }

View file

@ -6414,7 +6414,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
· ╰── `from` expected · ╰── `from` expected
╰──── ╰────
× Modifiers cannot be used here. × TS1044: 'export' modifier cannot appear on a module or namespace element.
╭─[compiler/exportAlreadySeen.ts:2:12] ╭─[compiler/exportAlreadySeen.ts:2:12]
1 │ module M { 1 │ module M {
2 │ export export var x = 1; 2 │ export export var x = 1;
@ -6422,6 +6422,14 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
3 │ export export function f() { } 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. × Modifiers cannot be used here.
╭─[compiler/exportAlreadySeen.ts:3:12] ╭─[compiler/exportAlreadySeen.ts:3:12]
2 │ export export var x = 1; 2 │ export export var x = 1;
@ -6454,14 +6462,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
6 │ export export class C { } 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. × Modifiers cannot be used here.
╭─[compiler/exportAlreadySeen.ts:13:12] ╭─[compiler/exportAlreadySeen.ts:13:12]
12 │ export export var x; 12 │ export export var x;
@ -16373,7 +16373,7 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
77 │ } 77 │ }
╰──── ╰────
× Modifiers cannot be used here. × TS1044: 'public' modifier cannot appear on a module or namespace element.
╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:4:5] ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:4:5]
3 │ module Y { 3 │ module Y {
4 │ public var x: number = 0; 4 │ public var x: number = 0;
@ -16381,6 +16381,22 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
5 │ } 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. × Modifiers cannot be used here.
╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:8:5] ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:8:5]
7 │ module Y2 { 7 │ module Y2 {
@ -16389,14 +16405,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
9 │ } 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. × Modifiers cannot be used here.
╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:16:5] ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:16:5]
15 │ module YY { 15 │ module YY {
@ -16405,14 +16413,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
17 │ } 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. × Modifiers cannot be used here.
╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:25:5] ╭─[conformance/internalModules/moduleBody/invalidModuleWithVarStatements.ts:25:5]
24 │ module YY3 { 24 │ module YY3 {