fix(semantic): apply strict mode scope flag for strict mode TS Modules (#3861)

#3830 added a `directives` field to `TSModuleBlock`. Make semantic apply strict mode scope flag if directives include `'use strict'`.
This commit is contained in:
overlookmotel 2024-06-24 02:38:59 +00:00
parent acf69fa1b6
commit 8c9fc6347d
5 changed files with 36 additions and 4 deletions

View file

@ -782,7 +782,11 @@ pub enum TSTypePredicateName<'a> {
This(TSThisType), 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)] #[derive(Debug)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))] #[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]

View file

@ -153,6 +153,10 @@ impl<'a> TSModuleDeclaration<'a> {
) -> Self { ) -> Self {
Self { span, id, body, kind, declare, scope_id: Cell::default() } 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> { 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> { impl<'a> Decorator<'a> {
/// Get the name of the decorator /// Get the name of the decorator
/// ```ts /// ```ts

View file

@ -2647,7 +2647,13 @@ pub mod walk {
TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident),
TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), 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 { match &decl.body {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
visitor.visit_ts_module_declaration(decl); visitor.visit_ts_module_declaration(decl);

View file

@ -2727,7 +2727,13 @@ pub mod walk_mut {
TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident), TSModuleDeclarationName::Identifier(ident) => visitor.visit_identifier_name(ident),
TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit), 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 { match &mut decl.body {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => { Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
visitor.visit_ts_module_declaration(decl); visitor.visit_ts_module_declaration(decl);

View file

@ -424,7 +424,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
let parent_scope_flags = self.scope.get_flags(parent_scope_id); let parent_scope_flags = self.scope.get_flags(parent_scope_id);
if !strict_mode 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() && parent_scope_flags.is_strict_mode()
{ {
strict_mode = true; strict_mode = true;