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()
|
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> + '_ {
|
pub fn descendants_from_root(&self) -> impl Iterator<Item = ScopeId> + '_ {
|
||||||
self.parent_ids.iter_enumerated().map(|(scope_id, _)| scope_id)
|
self.parent_ids.iter_enumerated().map(|(scope_id, _)| scope_id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use oxc::{
|
||||||
formatter::{Formatter, FormatterOptions},
|
formatter::{Formatter, FormatterOptions},
|
||||||
minifier::{CompressOptions, Minifier, MinifierOptions},
|
minifier::{CompressOptions, Minifier, MinifierOptions},
|
||||||
parser::{Parser, ParserReturn},
|
parser::{Parser, ParserReturn},
|
||||||
semantic::{SemanticBuilder, SemanticBuilderReturn},
|
semantic::{ScopeId, Semantic, SemanticBuilder, SemanticBuilderReturn},
|
||||||
span::SourceType,
|
span::SourceType,
|
||||||
transformer::{TransformOptions, TransformTarget, Transformer},
|
transformer::{TransformOptions, TransformTarget, Transformer},
|
||||||
};
|
};
|
||||||
|
|
@ -45,6 +45,7 @@ pub struct Oxc {
|
||||||
ast: JsValue,
|
ast: JsValue,
|
||||||
ir: JsValue,
|
ir: JsValue,
|
||||||
|
|
||||||
|
scope_text: String,
|
||||||
codegen_text: String,
|
codegen_text: String,
|
||||||
formatted_text: String,
|
formatted_text: String,
|
||||||
prettier_formatted_text: String,
|
prettier_formatted_text: String,
|
||||||
|
|
@ -114,6 +115,11 @@ impl Oxc {
|
||||||
self.codegen_text.clone()
|
self.codegen_text.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(getter = scopeText)]
|
||||||
|
pub fn scope_text(&self) -> String {
|
||||||
|
self.scope_text.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns Array of String
|
/// Returns Array of String
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
|
@ -191,14 +197,16 @@ impl Oxc {
|
||||||
|
|
||||||
let program = allocator.alloc(ret.program);
|
let program = allocator.alloc(ret.program);
|
||||||
|
|
||||||
|
let semantic_builder = SemanticBuilder::new(source_text, source_type);
|
||||||
|
|
||||||
if run_options.syntax() && !run_options.lint() {
|
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_trivias(ret.trivias)
|
||||||
.with_check_syntax_error(true)
|
.with_check_syntax_error(true)
|
||||||
.build(program);
|
.build(program);
|
||||||
self.save_diagnostics(semantic_ret.errors);
|
self.save_diagnostics(semantic_ret.errors);
|
||||||
} else if run_options.lint() {
|
} else if run_options.lint() {
|
||||||
let semantic_ret = SemanticBuilder::new(source_text, source_type)
|
let semantic_ret = semantic_builder
|
||||||
.with_trivias(ret.trivias)
|
.with_trivias(ret.trivias)
|
||||||
.with_check_syntax_error(true)
|
.with_check_syntax_error(true)
|
||||||
.build(program);
|
.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);
|
let program = allocator.alloc(program);
|
||||||
|
|
||||||
if minifier_options.compress() || minifier_options.mangle() {
|
if minifier_options.compress() || minifier_options.mangle() {
|
||||||
|
|
@ -289,6 +302,45 @@ impl Oxc {
|
||||||
Ok(())
|
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>) {
|
fn save_diagnostics(&self, diagnostics: Vec<Error>) {
|
||||||
self.diagnostics.borrow_mut().extend(diagnostics);
|
self.diagnostics.borrow_mut().extend(diagnostics);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ pub struct OxcRunOptions {
|
||||||
prettier_ir: bool,
|
prettier_ir: bool,
|
||||||
transform: bool,
|
transform: bool,
|
||||||
type_check: bool,
|
type_check: bool,
|
||||||
|
scope: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
|
@ -88,6 +89,16 @@ impl OxcRunOptions {
|
||||||
pub fn set_type_check(&mut self, yes: bool) {
|
pub fn set_type_check(&mut self, yes: bool) {
|
||||||
self.type_check = yes;
|
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]
|
#[wasm_bindgen]
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
<button type="button" id="prettier-ir">Prettier IR</button>
|
<button type="button" id="prettier-ir">Prettier IR</button>
|
||||||
<button type="button" id="prettier">Format (Prettier)</button>
|
<button type="button" id="prettier">Format (Prettier)</button>
|
||||||
<button type="button" id="query">Query Playground</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="query-args-or-outputs" class="query-button-red">Show Query Arguments</button>
|
||||||
<button type="button" id="ir-copy">Copy IR to clipboard</button>
|
<button type="button" id="ir-copy">Copy IR to clipboard</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -519,6 +519,12 @@ class Playground {
|
||||||
this.run();
|
this.run();
|
||||||
text = JSON.stringify(this.oxc.ast, null, 2);
|
text = JSON.stringify(this.oxc.ast, null, 2);
|
||||||
break;
|
break;
|
||||||
|
case "scope":
|
||||||
|
this.runOptions.scope = true;
|
||||||
|
this.run();
|
||||||
|
this.runOptions.scope = false
|
||||||
|
text = this.oxc.scopeText;
|
||||||
|
break;
|
||||||
case "codegen":
|
case "codegen":
|
||||||
this.run();
|
this.run();
|
||||||
text = this.oxc.codegenText;
|
text = this.oxc.codegenText;
|
||||||
|
|
@ -793,6 +799,10 @@ async function main() {
|
||||||
playground.updateView("ast");
|
playground.updateView("ast");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
document.getElementById("scope").onclick = () => {
|
||||||
|
playground.updateView("scope");
|
||||||
|
};
|
||||||
|
|
||||||
document.getElementById("codegen").onclick = () => {
|
document.getElementById("codegen").onclick = () => {
|
||||||
playground.updateView("codegen");
|
playground.updateView("codegen");
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue