From 2e01a45b2b23f62addc9db3f8fc052a81cbbf67d Mon Sep 17 00:00:00 2001 From: Don Isaac Date: Fri, 26 Jul 2024 20:46:21 -0400 Subject: [PATCH] fix(semantic): non-exported namespace member symbols flagged as exported (#4493) > Part of #4445 Fixes a bug where non-exported functions and variables inside of exported TS namespaces were being flagged with `SymbolFlags::Export` ```ts export namespace Foo { // incorrectly flagged as exported function foo() { } } ``` --- crates/oxc_semantic/src/builder.rs | 1 + .../oxc_semantic/tests/integration/modules.rs | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/crates/oxc_semantic/src/builder.rs b/crates/oxc_semantic/src/builder.rs index 80c742c1eb901..35ece85937de3 100644 --- a/crates/oxc_semantic/src/builder.rs +++ b/crates/oxc_semantic/src/builder.rs @@ -1759,6 +1759,7 @@ impl<'a> SemanticBuilder<'a> { .get_bindings(self.current_scope_id) .get(module_declaration.id.name().as_str()); self.namespace_stack.push(*symbol_id.unwrap()); + self.current_symbol_flags -= SymbolFlags::Export; } AstKind::TSTypeAliasDeclaration(type_alias_declaration) => { type_alias_declaration.bind(self); diff --git a/crates/oxc_semantic/tests/integration/modules.rs b/crates/oxc_semantic/tests/integration/modules.rs index f221e94bdbbf6..86d0e7f45181d 100644 --- a/crates/oxc_semantic/tests/integration/modules.rs +++ b/crates/oxc_semantic/tests/integration/modules.rs @@ -186,6 +186,38 @@ fn test_exports_in_namespace() { test.has_some_symbol("bar").is_exported().test(); let semantic = test.build(); assert!(!semantic.module_record().exported_bindings.contains_key("bar")); + + // namespace exported, member is not + let sources = + ["export namespace N { function foo() {} } ", "export namespace N { const foo = 1 } "]; + for src in sources { + let test = SemanticTester::ts(src); + test.has_some_symbol("N").contains_flags(SymbolFlags::NameSpaceModule).is_exported().test(); + test.has_some_symbol("foo").is_not_exported().test(); + } + + // namespace and member are both exported + let sources = [ + "export namespace N { export function foo() {} } ", + "export namespace N { export const foo = 1 } ", + ]; + for src in sources { + let test = SemanticTester::ts(src); + test.has_some_symbol("N").contains_flags(SymbolFlags::NameSpaceModule).is_exported().test(); + test.has_some_symbol("foo").is_exported().test(); + } + + // namespace is not exported, but member is + let sources = + ["namespace N { export function foo() {} } ", "namespace N { export const foo = 1 } "]; + for src in sources { + let test = SemanticTester::ts(src); + test.has_some_symbol("N") + .contains_flags(SymbolFlags::NameSpaceModule) + .is_not_exported() + .test(); + test.has_some_symbol("foo").is_exported().test(); + } } #[test]