Allow export = and export default to alias any EntityNameExpression, not just identifiers.

This commit is contained in:
Andy Hanson
2016-07-29 08:12:00 -07:00
parent 97bbbd729e
commit f9fd4967af
12 changed files with 613 additions and 26 deletions
+6 -7
View File
@@ -1887,18 +1887,17 @@ namespace ts {
}
function bindExportAssignment(node: ExportAssignment | BinaryExpression) {
const boundExpression = node.kind === SyntaxKind.ExportAssignment ? (<ExportAssignment>node).expression : (<BinaryExpression>node).right;
if (!container.symbol || !container.symbol.exports) {
// Export assignment in some sort of block construct
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else if (boundExpression.kind === SyntaxKind.Identifier && node.kind === SyntaxKind.ExportAssignment) {
// An export default clause with an identifier exports all meanings of that identifier
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Alias, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
else {
// An export default clause with an expression exports a value
declareSymbol(container.symbol.exports, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node)
// An export default clause with an EntityNameExpression exports all meanings of that identifier
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.PropertyExcludes | SymbolFlags.AliasExcludes);
}
}
+2 -2
View File
@@ -1044,7 +1044,7 @@ namespace ts {
}
function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration {
return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
return find(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
}
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
@@ -1175,7 +1175,7 @@ namespace ts {
}
function getTargetOfExportAssignment(node: ExportAssignment): Symbol {
return resolveEntityName(<Identifier>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
return resolveEntityName(<EntityNameExpression>node.expression, SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace);
}
function getTargetOfAliasDeclaration(node: Declaration): Symbol {
+13 -2
View File
@@ -81,7 +81,7 @@ namespace ts {
* returns a truthy value, then returns that value.
* If no such value is found, the callback is applied to each element of array and undefined is returned.
*/
export function forEach<T, U>(array: T[], callback: (element: T, index: number) => U): U {
export function forEach<T, U>(array: T[] | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array) {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
@@ -93,6 +93,17 @@ namespace ts {
return undefined;
}
/** Like `forEach`, but assumes existence of array and fails if no truthy value is found. */
export function find<T, U>(array: T[], callback: (element: T, index: number) => U | undefined): U {
for (let i = 0, len = array.length; i < len; i++) {
const result = callback(array[i], i);
if (result) {
return result;
}
}
Debug.fail();
}
export function contains<T>(array: T[], value: T): boolean {
if (array) {
for (const v of array) {
@@ -941,7 +952,7 @@ namespace ts {
* [^./] # matches everything up to the first . character (excluding directory seperators)
* (\\.(?!min\\.js$))? # matches . characters but not if they are part of the .min.js file extension
*/
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentFiles = "([^./]|(\\.(?!min\\.js$))?)*";
const singleAsteriskRegexFragmentOther = "[^/]*";
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
+7 -3
View File
@@ -1693,8 +1693,8 @@ namespace ts {
// import * as <symbol> from ...
// import { x as <symbol> } from ...
// export { x as <symbol> } from ...
// export = ...
// export default ...
// export = <EntityNameExpression>
// export default <EntityNameExpression>
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
@@ -1702,7 +1702,11 @@ namespace ts {
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node);
}
export function exportAssignmentIsAlias(node: ExportAssignment): boolean {
return isEntityNameExpression(node.expression);
}
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) {
@@ -1,8 +1,76 @@
//// [exportDefaultProperty.ts]
export default "".length
//// [tests/cases/compiler/exportDefaultProperty.ts] ////
//// [declarations.d.ts]
// This test is just like exportEqualsProperty, but with `export default`.
declare namespace foo.bar {
export type X = number;
export const X: number;
}
declare module "foobar" {
export default foo.bar;
}
declare module "foobarx" {
export default foo.bar.X;
}
//// [a.ts]
namespace A {
export class B { constructor(b: number) {} }
export namespace B { export const b: number = 0; }
}
export default A.B;
//// [b.ts]
export default "foo".length;
//// [index.ts]
/// <reference path="declarations.d.ts" />
import fooBar from "foobar";
import X = fooBar.X;
import X2 from "foobarx";
const x: X = X;
const x2: X2 = X2;
import B from "./a";
const b: B = new B(B.b);
import fooLength from "./b";
fooLength + 1;
//// [exportDefaultProperty.js]
//// [a.js]
"use strict";
var A;
(function (A) {
var B = (function () {
function B(b) {
}
return B;
}());
A.B = B;
var B;
(function (B) {
B.b = 0;
})(B = A.B || (A.B = {}));
})(A || (A = {}));
exports.__esModule = true;
exports["default"] = A.B;
//// [b.js]
"use strict";
exports.__esModule = true;
exports["default"] = "".length;
exports["default"] = "foo".length;
//// [index.js]
"use strict";
/// <reference path="declarations.d.ts" />
var foobar_1 = require("foobar");
var X = foobar_1["default"].X;
var foobarx_1 = require("foobarx");
var x = X;
var x2 = foobarx_1["default"];
var a_1 = require("./a");
var b = new a_1["default"](a_1["default"].b);
var b_1 = require("./b");
b_1["default"] + 1;
@@ -1,5 +1,92 @@
=== tests/cases/compiler/exportDefaultProperty.ts ===
export default "".length
>"".length : Symbol(String.length, Decl(lib.d.ts, --, --))
=== tests/cases/compiler/index.ts ===
/// <reference path="declarations.d.ts" />
import fooBar from "foobar";
>fooBar : Symbol(fooBar, Decl(index.ts, 1, 6))
import X = fooBar.X;
>X : Symbol(X, Decl(index.ts, 1, 28))
>fooBar : Symbol(fooBar, Decl(index.ts, 1, 6))
>X : Symbol(fooBar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
import X2 from "foobarx";
>X2 : Symbol(X2, Decl(index.ts, 3, 6))
const x: X = X;
>x : Symbol(x, Decl(index.ts, 4, 5))
>X : Symbol(X, Decl(index.ts, 1, 28))
>X : Symbol(X, Decl(index.ts, 1, 28))
const x2: X2 = X2;
>x2 : Symbol(x2, Decl(index.ts, 5, 5))
>X2 : Symbol(X2, Decl(index.ts, 3, 6))
>X2 : Symbol(X2, Decl(index.ts, 3, 6))
import B from "./a";
>B : Symbol(B, Decl(index.ts, 7, 6))
const b: B = new B(B.b);
>b : Symbol(b, Decl(index.ts, 8, 5))
>B : Symbol(B, Decl(index.ts, 7, 6))
>B : Symbol(B, Decl(index.ts, 7, 6))
>B.b : Symbol(B.b, Decl(a.ts, 2, 37))
>B : Symbol(B, Decl(index.ts, 7, 6))
>b : Symbol(B.b, Decl(a.ts, 2, 37))
import fooLength from "./b";
>fooLength : Symbol(fooLength, Decl(index.ts, 10, 6))
fooLength + 1;
>fooLength : Symbol(fooLength, Decl(index.ts, 10, 6))
=== tests/cases/compiler/declarations.d.ts ===
// This test is just like exportEqualsProperty, but with `export default`.
declare namespace foo.bar {
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(bar, Decl(declarations.d.ts, 2, 22))
export type X = number;
>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
export const X: number;
>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
}
declare module "foobar" {
export default foo.bar;
>foo.bar : Symbol(default, Decl(declarations.d.ts, 2, 22))
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(default, Decl(declarations.d.ts, 2, 22))
}
declare module "foobarx" {
export default foo.bar.X;
>foo.bar.X : Symbol(default, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
>X : Symbol(default, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
}
=== tests/cases/compiler/a.ts ===
namespace A {
>A : Symbol(A, Decl(a.ts, 0, 0))
export class B { constructor(b: number) {} }
>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>b : Symbol(b, Decl(a.ts, 1, 33))
export namespace B { export const b: number = 0; }
>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>b : Symbol(b, Decl(a.ts, 2, 37))
}
export default A.B;
>A.B : Symbol(default, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>A : Symbol(A, Decl(a.ts, 0, 0))
>B : Symbol(default, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
=== tests/cases/compiler/b.ts ===
export default "foo".length;
>"foo".length : Symbol(String.length, Decl(lib.d.ts, --, --))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
@@ -1,6 +1,97 @@
=== tests/cases/compiler/exportDefaultProperty.ts ===
export default "".length
>"".length : number
>"" : string
=== tests/cases/compiler/index.ts ===
/// <reference path="declarations.d.ts" />
import fooBar from "foobar";
>fooBar : typeof fooBar
import X = fooBar.X;
>X : number
>fooBar : typeof fooBar
>X : number
import X2 from "foobarx";
>X2 : number
const x: X = X;
>x : number
>X : number
>X : number
const x2: X2 = X2;
>x2 : number
>X2 : number
>X2 : number
import B from "./a";
>B : typeof B
const b: B = new B(B.b);
>b : B
>B : B
>new B(B.b) : B
>B : typeof B
>B.b : number
>B : typeof B
>b : number
import fooLength from "./b";
>fooLength : number
fooLength + 1;
>fooLength + 1 : number
>fooLength : number
>1 : number
=== tests/cases/compiler/declarations.d.ts ===
// This test is just like exportEqualsProperty, but with `export default`.
declare namespace foo.bar {
>foo : typeof foo
>bar : typeof bar
export type X = number;
>X : number
export const X: number;
>X : number
}
declare module "foobar" {
export default foo.bar;
>foo.bar : typeof default
>foo : typeof foo
>bar : typeof default
}
declare module "foobarx" {
export default foo.bar.X;
>foo.bar.X : number
>foo.bar : typeof foo.bar
>foo : typeof foo
>bar : typeof foo.bar
>X : number
}
=== tests/cases/compiler/a.ts ===
namespace A {
>A : typeof A
export class B { constructor(b: number) {} }
>B : B
>b : number
export namespace B { export const b: number = 0; }
>B : typeof B
>b : number
>0 : number
}
export default A.B;
>A.B : typeof default
>A : typeof A
>B : typeof default
=== tests/cases/compiler/b.ts ===
export default "foo".length;
>"foo".length : number
>"foo" : string
>length : number
@@ -0,0 +1,72 @@
//// [tests/cases/compiler/exportEqualsProperty.ts] ////
//// [declarations.d.ts]
// This test is just like exportDefaultProperty, but with `export =`.
declare namespace foo.bar {
export type X = number;
export const X: number;
}
declare module "foobar" {
export = foo.bar;
}
declare module "foobarx" {
export = foo.bar.X;
}
//// [a.ts]
namespace A {
export class B { constructor(b: number) {} }
export namespace B { export const b: number = 0; }
}
export = A.B;
//// [b.ts]
export = "foo".length;
//// [index.ts]
/// <reference path="declarations.d.ts" />
import { X } from "foobar";
import X2 = require("foobarx");
const x: X = X;
const x2: X2 = X2;
import B = require("./a");
const b: B = new B(B.b);
import fooLength = require("./b");
fooLength + 1;
//// [a.js]
"use strict";
var A;
(function (A) {
var B = (function () {
function B(b) {
}
return B;
}());
A.B = B;
var B;
(function (B) {
B.b = 0;
})(B = A.B || (A.B = {}));
})(A || (A = {}));
module.exports = A.B;
//// [b.js]
"use strict";
module.exports = "foo".length;
//// [index.js]
"use strict";
/// <reference path="declarations.d.ts" />
var foobar_1 = require("foobar");
var X2 = require("foobarx");
var x = foobar_1.X;
var x2 = X2;
var B = require("./a");
var b = new B(B.b);
var fooLength = require("./b");
fooLength + 1;
@@ -0,0 +1,87 @@
=== tests/cases/compiler/index.ts ===
/// <reference path="declarations.d.ts" />
import { X } from "foobar";
>X : Symbol(X, Decl(index.ts, 1, 8))
import X2 = require("foobarx");
>X2 : Symbol(X2, Decl(index.ts, 1, 27))
const x: X = X;
>x : Symbol(x, Decl(index.ts, 3, 5))
>X : Symbol(X, Decl(index.ts, 1, 8))
>X : Symbol(X, Decl(index.ts, 1, 8))
const x2: X2 = X2;
>x2 : Symbol(x2, Decl(index.ts, 4, 5))
>X2 : Symbol(X2, Decl(index.ts, 1, 27))
>X2 : Symbol(X2, Decl(index.ts, 1, 27))
import B = require("./a");
>B : Symbol(B, Decl(index.ts, 4, 18))
const b: B = new B(B.b);
>b : Symbol(b, Decl(index.ts, 7, 5))
>B : Symbol(B, Decl(index.ts, 4, 18))
>B : Symbol(B, Decl(index.ts, 4, 18))
>B.b : Symbol(B.b, Decl(a.ts, 2, 37))
>B : Symbol(B, Decl(index.ts, 4, 18))
>b : Symbol(B.b, Decl(a.ts, 2, 37))
import fooLength = require("./b");
>fooLength : Symbol(fooLength, Decl(index.ts, 7, 24))
fooLength + 1;
>fooLength : Symbol(fooLength, Decl(index.ts, 7, 24))
=== tests/cases/compiler/declarations.d.ts ===
// This test is just like exportDefaultProperty, but with `export =`.
declare namespace foo.bar {
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(bar, Decl(declarations.d.ts, 2, 22))
export type X = number;
>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
export const X: number;
>X : Symbol(X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
}
declare module "foobar" {
export = foo.bar;
>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
}
declare module "foobarx" {
export = foo.bar.X;
>foo.bar.X : Symbol(foo.bar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
>foo.bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
>foo : Symbol(foo, Decl(declarations.d.ts, 0, 0))
>bar : Symbol(foo.bar, Decl(declarations.d.ts, 2, 22))
>X : Symbol(foo.bar.X, Decl(declarations.d.ts, 2, 27), Decl(declarations.d.ts, 4, 16))
}
=== tests/cases/compiler/a.ts ===
namespace A {
>A : Symbol(A, Decl(a.ts, 0, 0))
export class B { constructor(b: number) {} }
>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>b : Symbol(b, Decl(a.ts, 1, 33))
export namespace B { export const b: number = 0; }
>B : Symbol(B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>b : Symbol(b, Decl(a.ts, 2, 37))
}
export = A.B;
>A.B : Symbol(A.B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
>A : Symbol(A, Decl(a.ts, 0, 0))
>B : Symbol(A.B, Decl(a.ts, 0, 13), Decl(a.ts, 1, 48))
=== tests/cases/compiler/b.ts ===
export = "foo".length;
>"foo".length : Symbol(String.length, Decl(lib.d.ts, --, --))
>length : Symbol(String.length, Decl(lib.d.ts, --, --))
@@ -0,0 +1,92 @@
=== tests/cases/compiler/index.ts ===
/// <reference path="declarations.d.ts" />
import { X } from "foobar";
>X : number
import X2 = require("foobarx");
>X2 : number
const x: X = X;
>x : number
>X : number
>X : number
const x2: X2 = X2;
>x2 : number
>X2 : number
>X2 : number
import B = require("./a");
>B : typeof B
const b: B = new B(B.b);
>b : B
>B : B
>new B(B.b) : B
>B : typeof B
>B.b : number
>B : typeof B
>b : number
import fooLength = require("./b");
>fooLength : number
fooLength + 1;
>fooLength + 1 : number
>fooLength : number
>1 : number
=== tests/cases/compiler/declarations.d.ts ===
// This test is just like exportDefaultProperty, but with `export =`.
declare namespace foo.bar {
>foo : typeof foo
>bar : typeof bar
export type X = number;
>X : number
export const X: number;
>X : number
}
declare module "foobar" {
export = foo.bar;
>foo.bar : typeof foo.bar
>foo : typeof foo
>bar : typeof foo.bar
}
declare module "foobarx" {
export = foo.bar.X;
>foo.bar.X : number
>foo.bar : typeof foo.bar
>foo : typeof foo
>bar : typeof foo.bar
>X : number
}
=== tests/cases/compiler/a.ts ===
namespace A {
>A : typeof A
export class B { constructor(b: number) {} }
>B : B
>b : number
export namespace B { export const b: number = 0; }
>B : typeof B
>b : number
>0 : number
}
export = A.B;
>A.B : typeof A.B
>A : typeof A
>B : typeof A.B
=== tests/cases/compiler/b.ts ===
export = "foo".length;
>"foo".length : number
>"foo" : string
>length : number
+39 -1
View File
@@ -1 +1,39 @@
export default "".length
// This test is just like exportEqualsProperty, but with `export default`.
// @Filename: declarations.d.ts
declare namespace foo.bar {
export type X = number;
export const X: number;
}
declare module "foobar" {
export default foo.bar;
}
declare module "foobarx" {
export default foo.bar.X;
}
// @Filename: a.ts
namespace A {
export class B { constructor(b: number) {} }
export namespace B { export const b: number = 0; }
}
export default A.B;
// @Filename: b.ts
export default "foo".length;
// @Filename: index.ts
/// <reference path="declarations.d.ts" />
import fooBar from "foobar";
import X = fooBar.X;
import X2 from "foobarx";
const x: X = X;
const x2: X2 = X2;
import B from "./a";
const b: B = new B(B.b);
import fooLength from "./b";
fooLength + 1;
@@ -0,0 +1,38 @@
// This test is just like exportDefaultProperty, but with `export =`.
// @Filename: declarations.d.ts
declare namespace foo.bar {
export type X = number;
export const X: number;
}
declare module "foobar" {
export = foo.bar;
}
declare module "foobarx" {
export = foo.bar.X;
}
// @Filename: a.ts
namespace A {
export class B { constructor(b: number) {} }
export namespace B { export const b: number = 0; }
}
export = A.B;
// @Filename: b.ts
export = "foo".length;
// @Filename: index.ts
/// <reference path="declarations.d.ts" />
import { X } from "foobar";
import X2 = require("foobarx");
const x: X = X;
const x2: X2 = X2;
import B = require("./a");
const b: B = new B(B.b);
import fooLength = require("./b");
fooLength + 1;