Skip to content

Commit 903951e

Browse files
committed
feat: Add SemanticIdsRunner for symbol/reference ID validation
1 parent 182f9c2 commit 903951e

File tree

3 files changed

+102
-1
lines changed

3 files changed

+102
-1
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ pub mod isolated_declarations;
77
pub mod mangler;
88
pub mod minifier;
99
pub mod remove_whitespace;
10+
pub mod semantic_ids;
1011
pub mod transformer;
1112

1213
mod case;

src/main.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use monitor_oxc::{
77
compressor::CompressorRunner, dce::DceRunner, formatter::FormatterRunner,
88
formatter_dcr::FormatterDCRRunner, isolated_declarations, mangler::ManglerRunner,
99
minifier::MinifierRunner, remove_whitespace::RemoveWhitespaceRunner,
10-
transformer::TransformerRunner,
10+
semantic_ids::SemanticSymbolIdsRunner, transformer::TransformerRunner,
1111
};
1212

1313
fn main() -> ExitCode {
@@ -67,6 +67,10 @@ fn main() -> ExitCode {
6767
node_modules_runner.add_case(Box::new(FormatterDCRRunner));
6868
}
6969

70+
if matches!(task, "semantic_symbol_ids") {
71+
node_modules_runner.add_case(Box::new(SemanticSymbolIdsRunner));
72+
}
73+
7074
let result = node_modules_runner.run_all();
7175

7276
if let Err(diagnostics) = result {

src/semantic_ids.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use std::ops::ControlFlow;
2+
3+
use oxc::{
4+
CompilerInterface,
5+
ast::ast::BindingIdentifier,
6+
ast_visit::{Visit, walk},
7+
diagnostics::OxcDiagnostic,
8+
semantic::SemanticBuilderReturn,
9+
};
10+
11+
use crate::{Case, Diagnostic, Driver, Source};
12+
13+
pub struct SemanticSymbolIdsRunner;
14+
15+
impl Case for SemanticSymbolIdsRunner {
16+
fn name(&self) -> &'static str {
17+
"SemanticSymbolIds"
18+
}
19+
20+
fn enable_runtime_test(&self) -> bool {
21+
false
22+
}
23+
24+
fn test(&self, source: &Source) -> Result<(), Vec<Diagnostic>> {
25+
if !self.run_test(source) {
26+
return Ok(());
27+
}
28+
29+
let mut driver = SemanticIdsCheckDriver::new(source);
30+
driver.compile(&source.source_text, source.source_type, &source.path);
31+
32+
if driver.checker.errors.is_empty() { Ok(()) } else { Err(driver.checker.errors) }
33+
}
34+
35+
fn driver(&self) -> Driver {
36+
Driver::default()
37+
}
38+
}
39+
40+
struct SemanticIdsCheckDriver<'a> {
41+
checker: SemanticIdsChecker<'a>,
42+
}
43+
44+
impl<'s> SemanticIdsCheckDriver<'s> {
45+
fn new(source: &'s Source) -> Self {
46+
Self { checker: SemanticIdsChecker { source, errors: vec![] } }
47+
}
48+
}
49+
50+
impl CompilerInterface for SemanticIdsCheckDriver<'_> {
51+
fn handle_errors(&mut self, errors: Vec<OxcDiagnostic>) {
52+
// Ignore parse/semantic errors - we only care about missing symbol IDs
53+
// and reference IDs on successfully parsed identifiers
54+
let _ = errors;
55+
}
56+
57+
fn after_semantic(&mut self, semantic_return: &mut SemanticBuilderReturn) -> ControlFlow<()> {
58+
self.checker.visit_program(semantic_return.semantic.nodes().program());
59+
ControlFlow::Continue(())
60+
}
61+
}
62+
63+
struct SemanticIdsChecker<'a> {
64+
source: &'a Source,
65+
errors: Vec<Diagnostic>,
66+
}
67+
68+
impl<'a> Visit<'a> for SemanticIdsChecker<'_> {
69+
fn visit_binding_identifier(&mut self, it: &BindingIdentifier<'a>) {
70+
if it.symbol_id.get().is_none() {
71+
self.errors.push(Diagnostic {
72+
case: "SemanticSymbolIds",
73+
path: self.source.path.clone(),
74+
message: format!(
75+
"BindingIdentifier '{}' at {:?} has no symbol_id",
76+
it.name, it.span
77+
),
78+
});
79+
}
80+
walk::walk_binding_identifier(self, it);
81+
}
82+
83+
fn visit_identifier_reference(&mut self, it: &oxc::ast::ast::IdentifierReference<'a>) {
84+
if it.reference_id.get().is_none() {
85+
self.errors.push(Diagnostic {
86+
case: "SemanticSymbolIds",
87+
path: self.source.path.clone(),
88+
message: format!(
89+
"IdentifierReference '{}' at {:?} has no reference_id",
90+
it.name, it.span
91+
),
92+
});
93+
}
94+
walk::walk_identifier_reference(self, it);
95+
}
96+
}

0 commit comments

Comments
 (0)