From a682a525b803f99e39b3be5c6b1557746599e80b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 2 Nov 2018 09:08:04 -0700 Subject: [PATCH] module.exports aliases have correct flags (#28303) * module.exports aliases have correct flags They are marked both as (1) alias and (2) assignment declaration. This fixes alias resolution in cases where multiple module.exports assignments exist, but differ in whether they are aliases or not: ```js function f() { } module.exports = f module.exports = 23 ``` Previously, this construct would fail to resolve the alias `f` because the `export=` symbol would be marked as Alias | Value but not Assignment. This change just adds Assignment so that the assignment declaration alias-following rules apply: you should always follow the alias, regardless of other flags. Also, isAliasSymbolDeclaration needed to be tightened up. Previously, I missed the condition that `module.exports =` aliases required an EntityNameDeclaration on right-hand-side, just like `export default` and `export =` aliases. * Address PR comments 1. Rename test to be more accurate. 2. Always mark module.exports assignments with SymbolFlags.Assignment. --- src/compiler/binder.ts | 2 +- src/compiler/utilities.ts | 3 ++- ...rtFixWithMultipleModuleExportAssignment.ts | 21 +++++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/importFixWithMultipleModuleExportAssignment.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c35a62b8448..6881dc60e98 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2418,7 +2418,7 @@ namespace ts { const flags = exportAssignmentIsAlias(node) ? SymbolFlags.Alias // An export= with an EntityNameExpression or a ClassExpression exports all meanings of that identifier or class : SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.ValueModule; - declareSymbol(file.symbol.exports!, file.symbol, node, flags, SymbolFlags.None); + declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None); } function bindThisPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 991e403f52e..d0564f7ef01 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2490,6 +2490,7 @@ namespace ts { // export { x as } from ... // export = // export default + // module.exports = export function isAliasSymbolDeclaration(node: Node): boolean { return node.kind === SyntaxKind.ImportEqualsDeclaration || node.kind === SyntaxKind.NamespaceExportDeclaration || @@ -2498,7 +2499,7 @@ namespace ts { node.kind === SyntaxKind.ImportSpecifier || node.kind === SyntaxKind.ExportSpecifier || node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node) || - isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports; + isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node); } export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean { diff --git a/tests/cases/fourslash/importFixWithMultipleModuleExportAssignment.ts b/tests/cases/fourslash/importFixWithMultipleModuleExportAssignment.ts new file mode 100644 index 00000000000..546a613947f --- /dev/null +++ b/tests/cases/fourslash/importFixWithMultipleModuleExportAssignment.ts @@ -0,0 +1,21 @@ +/// + +// @allowJs: true +// @checkJs: true + +// @Filename: /a.js +////function f() {} +////module.exports = f; +////module.exports = 42; + +// @Filename: /b.js +////export const foo = 0; + +// @Filename: /c.js +////foo + +goTo.file("/c.js"); +verify.importFixAtPosition([ +`import { foo } from "./b"; + +foo`]);