feat(playground): visualize scope (#1882)

Partial support https://github.com/oxc-project/oxc/issues/1048
This commit is contained in:
Dunqing 2024-01-03 16:10:42 +08:00 committed by GitHub
parent dae5f628b0
commit 45a7985524
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 3 deletions

View file

@ -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)
}

View file

@ -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);
}

View file

@ -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]

View file

@ -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>

View file

@ -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");
};