From 3ebf0fc383554ddc84dba8f85fb3fd56d68144fe Mon Sep 17 00:00:00 2001 From: Bill Ticehurst Date: Sun, 28 Feb 2016 18:25:04 -0800 Subject: [PATCH] Fixed default import from export equals (cherry picked from commit c4a10cfcdd51f831c3039e305c1c465a85c93b0b) --- src/compiler/binder.ts | 2 +- src/compiler/checker.ts | 9 ++++-- src/compiler/utilities.ts | 3 ++ .../reference/exportEqualsDefaultProperty.js | 27 ++++++++++++++++++ .../exportEqualsDefaultProperty.symbols | 21 ++++++++++++++ .../exportEqualsDefaultProperty.types | 28 +++++++++++++++++++ .../compiler/exportEqualsDefaultProperty.ts | 12 ++++++++ tests/cases/fourslash/javascriptModules22.ts | 19 +++++++++++++ 8 files changed, 117 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/exportEqualsDefaultProperty.js create mode 100644 tests/baselines/reference/exportEqualsDefaultProperty.symbols create mode 100644 tests/baselines/reference/exportEqualsDefaultProperty.types create mode 100644 tests/cases/compiler/exportEqualsDefaultProperty.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index b44ca51a33e..5f5d7c46b04 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -278,7 +278,7 @@ namespace ts { function declareSymbol(symbolTable: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol { Debug.assert(!hasDynamicName(node)); - const isJsModuleExport = node.kind === SyntaxKind.BinaryExpression ? getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports : false; + const isJsModuleExport = getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports; const isDefaultExport = node.flags & NodeFlags.Default; // The exported symbol for an export default function/class node is always named "default" diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7ef8578d959..c046780f07d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -892,8 +892,12 @@ namespace ts { function getTargetOfImportClause(node: ImportClause): Symbol { const moduleSymbol = resolveExternalModuleName(node, (node.parent).moduleSpecifier); + if (moduleSymbol) { - const exportDefaultSymbol = resolveSymbol(moduleSymbol.exports["default"]); + const exportDefaultSymbol = moduleSymbol.exports["export="] ? + getPropertyOfType(getTypeOfSymbol(moduleSymbol.exports["export="]), "default") : + resolveSymbol(moduleSymbol.exports["default"]); + if (!exportDefaultSymbol && !allowSyntheticDefaultImports) { error(node.name, Diagnostics.Module_0_has_no_default_export, symbolToString(moduleSymbol)); } @@ -967,8 +971,7 @@ namespace ts { let symbolFromVariable: Symbol; // First check if module was specified with "export=". If so, get the member from the resolved type if (moduleSymbol && moduleSymbol.exports && moduleSymbol.exports["export="]) { - const members = (getTypeOfSymbol(targetSymbol) as ResolvedType).members; - symbolFromVariable = members && members[name.text]; + symbolFromVariable = getPropertyOfType(getTypeOfSymbol(targetSymbol), name.text); } else { symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 3916d0022c8..5d18009ee83 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1105,6 +1105,9 @@ namespace ts { /// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property /// assignments we treat as special in the binder export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind { + if (!isInJavaScriptFile(expression)) { + return SpecialPropertyAssignmentKind.None; + } if (expression.kind !== SyntaxKind.BinaryExpression) { return SpecialPropertyAssignmentKind.None; } diff --git a/tests/baselines/reference/exportEqualsDefaultProperty.js b/tests/baselines/reference/exportEqualsDefaultProperty.js new file mode 100644 index 00000000000..6d75ef5d95d --- /dev/null +++ b/tests/baselines/reference/exportEqualsDefaultProperty.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/exportEqualsDefaultProperty.ts] //// + +//// [exp.ts] + +var x = { + "greeting": "hello, world", + "default": 42 +}; + +export = x + +//// [imp.ts] +import foo from "./exp"; +foo.toExponential(2); + + +//// [exp.js] +"use strict"; +var x = { + "greeting": "hello, world", + "default": 42 +}; +module.exports = x; +//// [imp.js] +"use strict"; +var exp_1 = require("./exp"); +exp_1["default"].toExponential(2); diff --git a/tests/baselines/reference/exportEqualsDefaultProperty.symbols b/tests/baselines/reference/exportEqualsDefaultProperty.symbols new file mode 100644 index 00000000000..54bbbde6956 --- /dev/null +++ b/tests/baselines/reference/exportEqualsDefaultProperty.symbols @@ -0,0 +1,21 @@ +=== tests/cases/compiler/exp.ts === + +var x = { +>x : Symbol(x, Decl(exp.ts, 1, 3)) + + "greeting": "hello, world", + "default": 42 +}; + +export = x +>x : Symbol(x, Decl(exp.ts, 1, 3)) + +=== tests/cases/compiler/imp.ts === +import foo from "./exp"; +>foo : Symbol(foo, Decl(imp.ts, 0, 6)) + +foo.toExponential(2); +>foo.toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) +>foo : Symbol(foo, Decl(imp.ts, 0, 6)) +>toExponential : Symbol(Number.toExponential, Decl(lib.d.ts, --, --)) + diff --git a/tests/baselines/reference/exportEqualsDefaultProperty.types b/tests/baselines/reference/exportEqualsDefaultProperty.types new file mode 100644 index 00000000000..31a6c8052f9 --- /dev/null +++ b/tests/baselines/reference/exportEqualsDefaultProperty.types @@ -0,0 +1,28 @@ +=== tests/cases/compiler/exp.ts === + +var x = { +>x : { "greeting": string; "default": number; } +>{ "greeting": "hello, world", "default": 42} : { "greeting": string; "default": number; } + + "greeting": "hello, world", +>"hello, world" : string + + "default": 42 +>42 : number + +}; + +export = x +>x : { "greeting": string; "default": number; } + +=== tests/cases/compiler/imp.ts === +import foo from "./exp"; +>foo : number + +foo.toExponential(2); +>foo.toExponential(2) : string +>foo.toExponential : (fractionDigits?: number) => string +>foo : number +>toExponential : (fractionDigits?: number) => string +>2 : number + diff --git a/tests/cases/compiler/exportEqualsDefaultProperty.ts b/tests/cases/compiler/exportEqualsDefaultProperty.ts new file mode 100644 index 00000000000..1adce3cabe1 --- /dev/null +++ b/tests/cases/compiler/exportEqualsDefaultProperty.ts @@ -0,0 +1,12 @@ + +// @Filename: exp.ts +var x = { + "greeting": "hello, world", + "default": 42 +}; + +export = x + +// @Filename: imp.ts +import foo from "./exp"; +foo.toExponential(2); diff --git a/tests/cases/fourslash/javascriptModules22.ts b/tests/cases/fourslash/javascriptModules22.ts index 67e3423ec40..89fa99b5ea2 100644 --- a/tests/cases/fourslash/javascriptModules22.ts +++ b/tests/cases/fourslash/javascriptModules22.ts @@ -5,9 +5,28 @@ //// function foo() { return {a: "hello, world"}; } //// module.exports = foo(); +// @Filename: mod2.js +//// var x = {name: 'test'}; +//// (function createExport(obj){ +//// module.exports = { +//// "default": x, +//// "sausages": {eggs: 2} +//// }; +//// })(); + // @Filename: app.js //// import {a} from "./mod" +//// import def, {sausages} from "./mod2" //// a./**/ goTo.marker(); verify.completionListContains('toString'); + +edit.backspace(2); +edit.insert("def."); +verify.completionListContains("name"); + +edit.insert("name;\nsausages."); +verify.completionListContains("eggs"); +edit.insert("eggs;"); +verify.numberOfErrorsInCurrentFile(0);