Skip to content

Commit bf030a2

Browse files
committed
Changed module.exports = to export an alias
1 parent e2df645 commit bf030a2

6 files changed

Lines changed: 59 additions & 9 deletions

File tree

src/compiler/binder.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1389,8 +1389,13 @@ namespace ts {
13891389
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
13901390
}
13911391
else {
1392+
if (getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports) {
1393+
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
1394+
}
1395+
else {
13921396
// An export default clause with an expression exports a value
1393-
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
1397+
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
1398+
}
13941399
}
13951400
}
13961401

src/compiler/checker.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,13 @@ namespace ts {
10051005
return getTargetOfExportSpecifier(<ExportSpecifier>node);
10061006
case SyntaxKind.ExportAssignment:
10071007
return getTargetOfExportAssignment(<ExportAssignment>node);
1008+
case SyntaxKind.BinaryExpression:
1009+
// module.exports = ...
1010+
const targetExpr = (node as BinaryExpression).right;
1011+
if (targetExpr.kind === SyntaxKind.Identifier) {
1012+
return resolveName(node, (targetExpr as Identifier).text, SymbolFlags.Value, Diagnostics.Cannot_find_name_0, (targetExpr as Identifier));
1013+
}
1014+
return getSymbolOfNode((node as BinaryExpression).right);
10081015
}
10091016
}
10101017

@@ -1197,6 +1204,12 @@ namespace ts {
11971204
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
11981205
function resolveESModuleSymbol(moduleSymbol: Symbol, moduleReferenceExpression: Expression): Symbol {
11991206
let symbol = resolveExternalModuleSymbol(moduleSymbol);
1207+
1208+
if (moduleSymbol && moduleSymbol.valueDeclaration && (<SourceFile>moduleSymbol.valueDeclaration).commonJsModuleIndicator) {
1209+
// CommonJS module could module.export nearly any value. TODO(billti): Should check for some valid value?
1210+
return symbol;
1211+
}
1212+
12001213
if (symbol && !(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable))) {
12011214
error(moduleReferenceExpression, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol));
12021215
symbol = undefined;
@@ -2973,6 +2986,14 @@ namespace ts {
29732986
return links.type;
29742987
}
29752988

2989+
function getTypeOfObjectLiteralSymbol(symbol: Symbol): Type {
2990+
const links = getSymbolLinks(symbol);
2991+
if (!links.type) {
2992+
links.type = checkObjectLiteral(symbol.declarations[0] as ObjectLiteralExpression);
2993+
}
2994+
return links.type;
2995+
}
2996+
29762997
function getTypeOfSymbol(symbol: Symbol): Type {
29772998
if (symbol.flags & SymbolFlags.Instantiated) {
29782999
return getTypeOfInstantiatedSymbol(symbol);
@@ -2992,6 +3013,9 @@ namespace ts {
29923013
if (symbol.flags & SymbolFlags.Alias) {
29933014
return getTypeOfAlias(symbol);
29943015
}
3016+
if (symbol.flags & SymbolFlags.ObjectLiteral) {
3017+
return getTypeOfObjectLiteralSymbol(symbol);
3018+
}
29953019
return unknownType;
29963020
}
29973021

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1934,7 +1934,7 @@ namespace ts {
19341934

19351935
Enum = RegularEnum | ConstEnum,
19361936
Variable = FunctionScopedVariable | BlockScopedVariable,
1937-
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
1937+
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | ObjectLiteral,
19381938
Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias,
19391939
Namespace = ValueModule | NamespaceModule,
19401940
Module = ValueModule | NamespaceModule,

src/compiler/utilities.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,13 +1469,15 @@ namespace ts {
14691469
// export { x as <symbol> } from ...
14701470
// export = ...
14711471
// export default ...
1472+
// module.exports =
14721473
export function isAliasSymbolDeclaration(node: Node): boolean {
14731474
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
14741475
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
14751476
node.kind === SyntaxKind.NamespaceImport ||
14761477
node.kind === SyntaxKind.ImportSpecifier ||
14771478
node.kind === SyntaxKind.ExportSpecifier ||
1478-
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
1479+
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier ||
1480+
node.kind === SyntaxKind.BinaryExpression && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports;
14791481
}
14801482

14811483
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) {

tests/cases/fourslash/importJsNodeModule4.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
goTo.file('consumer.js');
1313
goTo.marker();
1414
edit.insert('.');
15-
// TODO: Bug: Fix ES6 import of assignments to module.exports
16-
// verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
17-
// verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
18-
// verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
19-
// edit.insert('n.');
20-
// verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method");
15+
verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
16+
verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
17+
verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
18+
edit.insert('n.');
19+
verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method");
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
///<reference path="fourslash.ts" />
2+
3+
// @allowJs: true
4+
5+
// @Filename: node_modules/myMod/index.ts
6+
//// var exp = { n: 3, s: 'foo', b: true };
7+
//// export = exp;
8+
9+
// @Filename: consumer.js
10+
//// import * as x from 'myMod';
11+
//// x/**/;
12+
13+
goTo.file('consumer.js');
14+
goTo.marker();
15+
edit.insert('.');
16+
verify.completionListContains("n", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
17+
verify.completionListContains("s", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
18+
verify.completionListContains("b", /*displayText:*/ undefined, /*documentation*/ undefined, "property");
19+
edit.insert('n.');
20+
verify.completionListContains("toFixed", /*displayText:*/ undefined, /*documentation*/ undefined, "method");

0 commit comments

Comments
 (0)