diff --git a/crates/oxc_ast/src/ast/ts.rs b/crates/oxc_ast/src/ast/ts.rs index 8a12cbb11ec72..d5e922c307c07 100644 --- a/crates/oxc_ast/src/ast/ts.rs +++ b/crates/oxc_ast/src/ast/ts.rs @@ -782,7 +782,11 @@ pub enum TSTypePredicateName<'a> { This(TSThisType), } -#[visited_node(scope(ScopeFlags::TsModuleBlock), enter_scope_before(body))] +#[visited_node( + scope(ScopeFlags::TsModuleBlock), + enter_scope_before(body), + strict_if(self.body.as_ref().is_some_and(|body| body.is_strict())) +)] #[derive(Debug)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] diff --git a/crates/oxc_ast/src/ast_impl/ts.rs b/crates/oxc_ast/src/ast_impl/ts.rs index f28bf1750a7e6..749ab3325d654 100644 --- a/crates/oxc_ast/src/ast_impl/ts.rs +++ b/crates/oxc_ast/src/ast_impl/ts.rs @@ -153,6 +153,10 @@ impl<'a> TSModuleDeclaration<'a> { ) -> Self { Self { span, id, body, kind, declare, scope_id: Cell::default() } } + + pub fn is_strict(&self) -> bool { + self.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) + } } impl<'a> Hash for TSModuleDeclaration<'a> { @@ -177,6 +181,18 @@ impl<'a> TSModuleDeclarationName<'a> { } } +impl<'a> TSModuleDeclarationBody<'a> { + pub fn is_strict(&self) -> bool { + matches!(self, Self::TSModuleBlock(block) if block.is_strict()) + } +} + +impl<'a> TSModuleBlock<'a> { + pub fn is_strict(&self) -> bool { + self.directives.iter().any(Directive::is_use_strict) + } +} + impl<'a> Decorator<'a> { /// Get the name of the decorator /// ```ts diff --git a/crates/oxc_ast/src/visit/visit.rs b/crates/oxc_ast/src/visit/visit.rs index 72d9741957a34..022a7a887000e 100644 --- a/crates/oxc_ast/src/visit/visit.rs +++ b/crates/oxc_ast/src/visit/visit.rs @@ -2647,7 +2647,13 @@ pub mod walk { TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), } - visitor.enter_scope(ScopeFlags::TsModuleBlock); + visitor.enter_scope({ + let mut flags = ScopeFlags::TsModuleBlock; + if decl.is_strict() { + flags |= ScopeFlags::StrictMode; + } + flags + }); match &decl.body { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { visitor.visit_ts_module_declaration(decl); diff --git a/crates/oxc_ast/src/visit/visit_mut.rs b/crates/oxc_ast/src/visit/visit_mut.rs index 20df92f975ee7..e39c0aa5e6b3c 100644 --- a/crates/oxc_ast/src/visit/visit_mut.rs +++ b/crates/oxc_ast/src/visit/visit_mut.rs @@ -2727,7 +2727,13 @@ pub mod walk_mut { TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), } - visitor.enter_scope(ScopeFlags::TsModuleBlock); + visitor.enter_scope({ + let mut flags = ScopeFlags::TsModuleBlock; + if decl.is_strict() { + flags |= ScopeFlags::StrictMode; + } + flags + }); match &mut decl.body { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { visitor.visit_ts_module_declaration(decl); diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 9aa732819b867..267274d14a713 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -424,7 +424,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> { let parent_scope_flags = self.scope.get_flags(parent_scope_id); if !strict_mode - && parent_scope_flags.is_function() + && (parent_scope_flags.is_function() || parent_scope_flags.is_ts_module_block()) && parent_scope_flags.is_strict_mode() { strict_mode = true;