diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js b/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js index d7927f94667..3464e556137 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js +++ b/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js @@ -67,3 +67,5 @@ const a = { a; +export const { A } = z; +export const [ B ] = z; \ No newline at end of file diff --git a/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js.snap b/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js.snap index d70fd9f11cc..4117b1040ac 100644 --- a/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js.snap +++ b/crates/rome_js_analyze/tests/specs/correctness/noUnusedVariables/noUnusedVariables.js.snap @@ -73,7 +73,8 @@ const a = { a; - +export const { A } = z; +export const [ B ] = z; ``` # Diagnostics diff --git a/crates/rome_js_semantic/src/events.rs b/crates/rome_js_semantic/src/events.rs index 0eb5f725a8d..eeba4f29cb1 100644 --- a/crates/rome_js_semantic/src/events.rs +++ b/crates/rome_js_semantic/src/events.rs @@ -371,6 +371,27 @@ impl SemanticEventExtractor { self.push_binding_into_scope(hoisted_scope_id, &name_token); self.export_class_expression(node, &parent); } + JS_OBJECT_BINDING_PATTERN_SHORTHAND_PROPERTY + | JS_OBJECT_BINDING_PATTERN_PROPERTY + | JS_ARRAY_BINDING_PATTERN_ELEMENT_LIST => { + self.push_binding_into_scope(None, &name_token); + + let possible_declarator = parent.ancestors().find(|x| { + !matches!( + x.kind(), + JS_OBJECT_BINDING_PATTERN_SHORTHAND_PROPERTY + | JS_OBJECT_BINDING_PATTERN_PROPERTY_LIST + | JS_OBJECT_BINDING_PATTERN_PROPERTY + | JS_OBJECT_BINDING_PATTERN + | JS_ARRAY_BINDING_PATTERN_ELEMENT_LIST + | JS_ARRAY_BINDING_PATTERN + ) + })?; + + if let JS_VARIABLE_DECLARATOR = possible_declarator.kind() { + self.export_variable_declarator(node, &possible_declarator); + } + } TS_TYPE_ALIAS_DECLARATION => { let hoisted_scope_id = self.scope_index_to_hoist_declarations(1); self.push_binding_into_scope(hoisted_scope_id, &name_token); @@ -542,7 +563,7 @@ impl SemanticEventExtractor { /// 1 - Match all references and declarations; /// 2 - Unmatched references are promoted to its parent scope or become [UnresolvedReference] events; /// 3 - All declarations of this scope are removed; - /// 4 - All shawed declarations are restored. + /// 4 - All shadowed declarations are restored. fn pop_scope(&mut self, range: TextRange) { debug_assert!(!self.scopes.is_empty()); @@ -820,7 +841,7 @@ impl SemanticEventExtractor { } } - // Check if a function is exported and raise the [Exported] event. + // Check if a variable is exported and raise the [Exported] event. fn export_variable_declarator( &mut self, binding: &JsSyntaxNode, diff --git a/crates/rome_js_semantic/src/semantic_model.rs b/crates/rome_js_semantic/src/semantic_model.rs index 935c5e28e2d..5e4242c4d88 100644 --- a/crates/rome_js_semantic/src/semantic_model.rs +++ b/crates/rome_js_semantic/src/semantic_model.rs @@ -1428,6 +1428,14 @@ mod test { assert_is_exported(true, "A", "enum A {}; module.exports = A"); assert_is_exported(true, "A", "enum A {}; exports = A"); assert_is_exported(true, "A", "enum A {}; exports.A = A"); + + // Object and Array bindings + assert_is_exported(true, "A", "export const { A } = a;"); + assert_is_exported(true, "b", "export const { A: b } = a;"); + assert_is_exported(true, "A", "export const [ A ] = a;"); + assert_is_exported(true, "A", "export const [{ A }] = a;"); + assert_is_exported(true, "D", "export const [{ C: [ D ] }] = a;"); + assert_is_exported(true, "E", "export const [{ C: [{ E }] }] = a;"); } #[test]