use super::CheckerContext;
use tsz_parser::parser::NodeIndex;
use tsz_parser::parser::syntax_kind_ext;
use tsz_scanner::SyntaxKind;
impl CheckerContext<'_> {
pub fn is_strict_mode_for_node(&self, idx: NodeIndex) -> bool {
if self.compiler_options.always_strict {
return true;
}
if self.is_external_module() {
return true;
}
let mut current = idx;
loop {
let Some(node) = self.arena.get(current) else {
return false;
};
if node.kind == syntax_kind_ext::CLASS_DECLARATION
|| node.kind == syntax_kind_ext::CLASS_EXPRESSION
{
return true;
}
let Some(ext) = self.arena.get_extended(current) else {
return false;
};
let parent = ext.parent;
if parent.is_none() {
return false;
}
let Some(parent_node) = self.arena.get(parent) else {
return false;
};
match parent_node.kind {
k if k == syntax_kind_ext::SOURCE_FILE => {
if let Some(sf) = self.arena.get_source_file(parent_node)
&& sf
.statements
.nodes
.iter()
.any(|&stmt_idx| statement_is_use_strict(self, stmt_idx))
{
return true;
}
return false;
}
k if k == syntax_kind_ext::FUNCTION_DECLARATION
|| k == syntax_kind_ext::FUNCTION_EXPRESSION
|| k == syntax_kind_ext::ARROW_FUNCTION =>
{
if let Some(func) = self.arena.get_function(parent_node)
&& func.body.is_some()
&& block_has_use_strict(self, func.body)
{
return true;
}
}
_ => {}
}
current = parent;
}
}
fn is_external_module(&self) -> bool {
if let Some(ref map) = self.is_external_module_by_file
&& let Some(&is_ext) = map.get(&self.file_name)
{
return is_ext;
}
self.binder.is_external_module()
}
}
fn statement_is_use_strict(ctx: &CheckerContext<'_>, stmt_idx: NodeIndex) -> bool {
ctx.arena
.get(stmt_idx)
.filter(|stmt| stmt.kind == syntax_kind_ext::EXPRESSION_STATEMENT)
.and_then(|stmt| ctx.arena.get_expression_statement(stmt))
.and_then(|expr_stmt| ctx.arena.get(expr_stmt.expression))
.filter(|expr_node| expr_node.kind == SyntaxKind::StringLiteral as u16)
.and_then(|expr_node| ctx.arena.get_literal(expr_node))
.is_some_and(|lit| lit.text == "use strict")
}
fn block_has_use_strict(ctx: &CheckerContext<'_>, block_idx: NodeIndex) -> bool {
let Some(block_node) = ctx.arena.get(block_idx) else {
return false;
};
let Some(block) = ctx.arena.get_block(block_node) else {
return false;
};
for &stmt_idx in &block.statements.nodes {
if statement_is_use_strict(ctx, stmt_idx) {
return true;
}
let Some(stmt_node) = ctx.arena.get(stmt_idx) else {
return false;
};
if stmt_node.kind != syntax_kind_ext::EXPRESSION_STATEMENT {
break;
}
}
false
}