mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(playground): visualize scope (#1882)
Partial support https://github.com/oxc-project/oxc/issues/1048
This commit is contained in:
parent
dae5f628b0
commit
45a7985524
5 changed files with 81 additions and 3 deletions
|
|
@ -67,6 +67,10 @@ impl ScopeTree {
|
|||
list.into_iter()
|
||||
}
|
||||
|
||||
pub fn get_child_ids(&self, scope_id: ScopeId) -> Option<&Vec<ScopeId>> {
|
||||
self.child_ids.get(&scope_id)
|
||||
}
|
||||
|
||||
pub fn descendants_from_root(&self) -> impl Iterator<Item = ScopeId> + '_ {
|
||||
self.parent_ids.iter_enumerated().map(|(scope_id, _)| scope_id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use oxc::{
|
|||
formatter::{Formatter, FormatterOptions},
|
||||
minifier::{CompressOptions, Minifier, MinifierOptions},
|
||||
parser::{Parser, ParserReturn},
|
||||
semantic::{SemanticBuilder, SemanticBuilderReturn},
|
||||
semantic::{ScopeId, Semantic, SemanticBuilder, SemanticBuilderReturn},
|
||||
span::SourceType,
|
||||
transformer::{TransformOptions, TransformTarget, Transformer},
|
||||
};
|
||||
|
|
@ -45,6 +45,7 @@ pub struct Oxc {
|
|||
ast: JsValue,
|
||||
ir: JsValue,
|
||||
|
||||
scope_text: String,
|
||||
codegen_text: String,
|
||||
formatted_text: String,
|
||||
prettier_formatted_text: String,
|
||||
|
|
@ -114,6 +115,11 @@ impl Oxc {
|
|||
self.codegen_text.clone()
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter = scopeText)]
|
||||
pub fn scope_text(&self) -> String {
|
||||
self.scope_text.clone()
|
||||
}
|
||||
|
||||
/// Returns Array of String
|
||||
/// # Errors
|
||||
/// # Panics
|
||||
|
|
@ -191,14 +197,16 @@ impl Oxc {
|
|||
|
||||
let program = allocator.alloc(ret.program);
|
||||
|
||||
let semantic_builder = SemanticBuilder::new(source_text, source_type);
|
||||
|
||||
if run_options.syntax() && !run_options.lint() {
|
||||
let semantic_ret = SemanticBuilder::new(source_text, source_type)
|
||||
let semantic_ret = semantic_builder
|
||||
.with_trivias(ret.trivias)
|
||||
.with_check_syntax_error(true)
|
||||
.build(program);
|
||||
self.save_diagnostics(semantic_ret.errors);
|
||||
} else if run_options.lint() {
|
||||
let semantic_ret = SemanticBuilder::new(source_text, source_type)
|
||||
let semantic_ret = semantic_builder
|
||||
.with_trivias(ret.trivias)
|
||||
.with_check_syntax_error(true)
|
||||
.build(program);
|
||||
|
|
@ -266,6 +274,11 @@ impl Oxc {
|
|||
}
|
||||
}
|
||||
|
||||
if run_options.scope() {
|
||||
let semantic = SemanticBuilder::new(source_text, source_type).build(program).semantic;
|
||||
self.scope_text = Self::get_scope_text(&semantic);
|
||||
}
|
||||
|
||||
let program = allocator.alloc(program);
|
||||
|
||||
if minifier_options.compress() || minifier_options.mangle() {
|
||||
|
|
@ -289,6 +302,45 @@ impl Oxc {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_scope_text(semantic: &Semantic) -> String {
|
||||
fn write_scope_text(
|
||||
semantic: &Semantic,
|
||||
scope_text: &mut String,
|
||||
depth: usize,
|
||||
scope_ids: &Vec<ScopeId>,
|
||||
) {
|
||||
let space = " ".repeat(depth * 2);
|
||||
|
||||
for scope_id in scope_ids {
|
||||
let flag = semantic.scopes().get_flags(*scope_id);
|
||||
let next_scope_ids = semantic.scopes().get_child_ids(*scope_id);
|
||||
|
||||
scope_text.push_str(&format!("{space}Scope{:?} ({flag:?}) {{\n", *scope_id + 1));
|
||||
let bindings = semantic.scopes().get_bindings(*scope_id);
|
||||
let binding_space = " ".repeat((depth + 1) * 2);
|
||||
if !bindings.is_empty() {
|
||||
scope_text.push_str(&format!("{binding_space}Bindings: {{"));
|
||||
}
|
||||
bindings.iter().for_each(|(name, symbol_id)| {
|
||||
let symbol_flag = semantic.symbols().get_flag(*symbol_id);
|
||||
scope_text.push_str(&format!("\n{binding_space} {name} ({symbol_flag:?})",));
|
||||
});
|
||||
if !bindings.is_empty() {
|
||||
scope_text.push_str(&format!("\n{binding_space}}}\n"));
|
||||
}
|
||||
|
||||
if let Some(next_scope_ids) = next_scope_ids {
|
||||
write_scope_text(semantic, scope_text, depth + 1, next_scope_ids);
|
||||
}
|
||||
scope_text.push_str(&format!("{space}}}\n"));
|
||||
}
|
||||
}
|
||||
|
||||
let mut scope_text = String::default();
|
||||
write_scope_text(semantic, &mut scope_text, 0, &vec![semantic.scopes().root_scope_id()]);
|
||||
scope_text
|
||||
}
|
||||
|
||||
fn save_diagnostics(&self, diagnostics: Vec<Error>) {
|
||||
self.diagnostics.borrow_mut().extend(diagnostics);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pub struct OxcRunOptions {
|
|||
prettier_ir: bool,
|
||||
transform: bool,
|
||||
type_check: bool,
|
||||
scope: bool,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
|
@ -88,6 +89,16 @@ impl OxcRunOptions {
|
|||
pub fn set_type_check(&mut self, yes: bool) {
|
||||
self.type_check = yes;
|
||||
}
|
||||
|
||||
#[wasm_bindgen(getter)]
|
||||
pub fn scope(self) -> bool {
|
||||
self.scope
|
||||
}
|
||||
|
||||
#[wasm_bindgen(setter)]
|
||||
pub fn set_scope(&mut self, yes: bool) {
|
||||
self.scope = yes;
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
<button type="button" id="prettier-ir">Prettier IR</button>
|
||||
<button type="button" id="prettier">Format (Prettier)</button>
|
||||
<button type="button" id="query">Query Playground</button>
|
||||
<button type="button" id="scope">Scope</button>
|
||||
<button type="button" id="query-args-or-outputs" class="query-button-red">Show Query Arguments</button>
|
||||
<button type="button" id="ir-copy">Copy IR to clipboard</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -519,6 +519,12 @@ class Playground {
|
|||
this.run();
|
||||
text = JSON.stringify(this.oxc.ast, null, 2);
|
||||
break;
|
||||
case "scope":
|
||||
this.runOptions.scope = true;
|
||||
this.run();
|
||||
this.runOptions.scope = false
|
||||
text = this.oxc.scopeText;
|
||||
break;
|
||||
case "codegen":
|
||||
this.run();
|
||||
text = this.oxc.codegenText;
|
||||
|
|
@ -793,6 +799,10 @@ async function main() {
|
|||
playground.updateView("ast");
|
||||
};
|
||||
|
||||
document.getElementById("scope").onclick = () => {
|
||||
playground.updateView("scope");
|
||||
};
|
||||
|
||||
document.getElementById("codegen").onclick = () => {
|
||||
playground.updateView("codegen");
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue