Skip to content

Commit 8cec6a5

Browse files
authored
fix: Correctly handle computed object assignments (#18)
1 parent 9f2e0b1 commit 8cec6a5

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

src/swc.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ fn prefix_getters_setters(kind: ast::MethodKind, scope_name: &mut ScopeName) {
340340
/// This is only possible if the expression is an identifier or a member expression.
341341
fn infer_name_from_expr(mut expr: &ast::Expr) -> Option<ScopeName> {
342342
let mut scope_name = ScopeName::new();
343+
343344
loop {
344345
match expr {
345346
ast::Expr::Ident(ident) => {
@@ -356,6 +357,11 @@ fn infer_name_from_expr(mut expr: &ast::Expr) -> Option<ScopeName> {
356357
.push_front(NameComponent::ident(ident.clone()));
357358
scope_name.components.push_front(NameComponent::interp("."));
358359
}
360+
361+
if let Some(computed_prop) = member.prop.as_computed() {
362+
push_computed_prop_name(computed_prop, &mut scope_name)
363+
}
364+
359365
expr = &member.obj;
360366
}
361367

@@ -371,6 +377,35 @@ fn infer_name_from_expr(mut expr: &ast::Expr) -> Option<ScopeName> {
371377
}
372378
}
373379

380+
fn push_computed_prop_name(prop_name: &ast::ComputedPropName, scope_name: &mut ScopeName) {
381+
if let Some(literal) = prop_name.expr.as_lit() {
382+
let component = NameComponent::interp(format!("[{}]", lit_as_string(literal)));
383+
scope_name.components.push_front(component);
384+
} else if let Some(ident) = prop_name.expr.as_ident() {
385+
scope_name.components.push_front(NameComponent::interp("]"));
386+
scope_name
387+
.components
388+
.push_front(NameComponent::ident(ident.clone()));
389+
scope_name.components.push_front(NameComponent::interp("["));
390+
} else {
391+
scope_name
392+
.components
393+
.push_front(NameComponent::interp("[<computed>]"));
394+
}
395+
}
396+
397+
fn lit_as_string(lit: &ast::Lit) -> String {
398+
match lit {
399+
ast::Lit::Str(v) => format!("\"{}\"", v.value),
400+
ast::Lit::Num(v) => v.value.to_string(),
401+
ast::Lit::BigInt(v) => format!("{}n", v.value),
402+
ast::Lit::Bool(v) => v.value.to_string(),
403+
ast::Lit::Regex(v) => format!("/{}/{}", v.exp, v.flags),
404+
ast::Lit::Null(_) => String::from("null"),
405+
ast::Lit::JSXText(v) => v.value.to_string(),
406+
}
407+
}
408+
374409
fn prop_name_to_component(prop: &ast::PropName) -> NameComponent {
375410
match prop {
376411
ast::PropName::Ident(ref i) => NameComponent::ident(i.clone()),

tests/extract.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ fn extract_anon_obj_literal() {
218218
#[test]
219219
fn extract_empty_function() {
220220
let src = r#"
221-
(function () {
221+
(function () {
222222
return () => {};
223223
})()
224224
"#;
@@ -254,3 +254,23 @@ fn extract_nested_iife_objects() {
254254
];
255255
assert_eq!(scopes, expected);
256256
}
257+
258+
#[test]
259+
fn extract_computed_properties() {
260+
let src = r#"
261+
Klass.prototype[42] = () => {}
262+
Klass.prototype["method"] = () => {}
263+
Klass.prototype[method] = () => {}
264+
Klass.prototype[1 + 1] = () => {};
265+
"#;
266+
let scopes = extract_scope_names(src).unwrap();
267+
let scopes = scope_strs(scopes);
268+
269+
let expected = [
270+
Some("Klass.prototype[42]".into()),
271+
Some("Klass.prototype[\"method\"]".into()),
272+
Some("Klass.prototype[method]".into()),
273+
Some("Klass.prototype[<computed>]".into()),
274+
];
275+
assert_eq!(scopes, expected);
276+
}

0 commit comments

Comments
 (0)