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.
This commit is contained in:
Nathan Shively-Sanders
2018-11-02 09:08:04 -07:00
committed by GitHub
parent 8056e2b12f
commit a682a525b8
3 changed files with 24 additions and 2 deletions
+1 -1
View File
@@ -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) {
+2 -1
View File
@@ -2490,6 +2490,7 @@ namespace ts {
// export { x as <symbol> } from ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
// module.exports = <EntityNameExpression>
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(<ExportAssignment>node) ||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports;
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node);
}
export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean {
@@ -0,0 +1,21 @@
/// <reference path="fourslash.ts" />
// @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`]);