Skip to content

Commit 5475f3a

Browse files
authored
Merge pull request #11609 from Microsoft/consolidateImportElision
Consolidate Import/Export Elision
2 parents b5d1e4c + 994dae7 commit 5475f3a

19 files changed

+251
-187
lines changed

src/compiler/core.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,17 @@ namespace ts {
422422
return result;
423423
}
424424

425+
export function some<T>(array: T[], predicate?: (value: T) => boolean): boolean {
426+
if (array) {
427+
for (const v of array) {
428+
if (!predicate || predicate(v)) {
429+
return true;
430+
}
431+
}
432+
}
433+
return false;
434+
}
435+
425436
export function concatenate<T>(array1: T[], array2: T[]): T[] {
426437
if (!array2 || !array2.length) return array1;
427438
if (!array1 || !array1.length) return array2;
@@ -1201,7 +1212,7 @@ namespace ts {
12011212

12021213
/**
12031214
* Returns the path except for its basename. Eg:
1204-
*
1215+
*
12051216
* /path/to/file.ext -> /path/to
12061217
*/
12071218
export function getDirectoryPath(path: Path): Path;

src/compiler/factory.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ namespace ts {
22062206
* @param visitor: Optional callback used to visit any custom prologue directives.
22072207
*/
22082208
export function addPrologueDirectives(target: Statement[], source: Statement[], ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult<Node>): number {
2209-
Debug.assert(target.length === 0, "PrologueDirectives should be at the first statement in the target statements array");
2209+
Debug.assert(target.length === 0, "Prologue directives should be at the first statement in the target statements array");
22102210
let foundUseStrict = false;
22112211
let statementOffset = 0;
22122212
const numStatements = source.length;
@@ -2219,16 +2219,20 @@ namespace ts {
22192219
target.push(statement);
22202220
}
22212221
else {
2222-
if (ensureUseStrict && !foundUseStrict) {
2223-
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
2224-
foundUseStrict = true;
2225-
}
2226-
if (getEmitFlags(statement) & EmitFlags.CustomPrologue) {
2227-
target.push(visitor ? visitNode(statement, visitor, isStatement) : statement);
2228-
}
2229-
else {
2230-
break;
2231-
}
2222+
break;
2223+
}
2224+
statementOffset++;
2225+
}
2226+
if (ensureUseStrict && !foundUseStrict) {
2227+
target.push(startOnNewLine(createStatement(createLiteral("use strict"))));
2228+
}
2229+
while (statementOffset < numStatements) {
2230+
const statement = source[statementOffset];
2231+
if (getEmitFlags(statement) & EmitFlags.CustomPrologue) {
2232+
target.push(visitor ? visitNode(statement, visitor, isStatement) : statement);
2233+
}
2234+
else {
2235+
break;
22322236
}
22332237
statementOffset++;
22342238
}

src/compiler/transformers/module/es6.ts

Lines changed: 7 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55
namespace ts {
66
export function transformES6Module(context: TransformationContext) {
77
const compilerOptions = context.getCompilerOptions();
8-
const resolver = context.getEmitResolver();
9-
10-
let currentSourceFile: SourceFile;
11-
128
return transformSourceFile;
139

1410
function transformSourceFile(node: SourceFile) {
@@ -17,128 +13,31 @@ namespace ts {
1713
}
1814

1915
if (isExternalModule(node) || compilerOptions.isolatedModules) {
20-
currentSourceFile = node;
2116
return visitEachChild(node, visitor, context);
2217
}
18+
2319
return node;
2420
}
2521

2622
function visitor(node: Node): VisitResult<Node> {
2723
switch (node.kind) {
28-
case SyntaxKind.ImportDeclaration:
29-
return visitImportDeclaration(<ImportDeclaration>node);
3024
case SyntaxKind.ImportEqualsDeclaration:
3125
return visitImportEqualsDeclaration(<ImportEqualsDeclaration>node);
32-
case SyntaxKind.ImportClause:
33-
return visitImportClause(<ImportClause>node);
34-
case SyntaxKind.NamedImports:
35-
case SyntaxKind.NamespaceImport:
36-
return visitNamedBindings(<NamedImportBindings>node);
37-
case SyntaxKind.ImportSpecifier:
38-
return visitImportSpecifier(<ImportSpecifier>node);
3926
case SyntaxKind.ExportAssignment:
4027
return visitExportAssignment(<ExportAssignment>node);
41-
case SyntaxKind.ExportDeclaration:
42-
return visitExportDeclaration(<ExportDeclaration>node);
43-
case SyntaxKind.NamedExports:
44-
return visitNamedExports(<NamedExports>node);
45-
case SyntaxKind.ExportSpecifier:
46-
return visitExportSpecifier(<ExportSpecifier>node);
4728
}
4829

4930
return node;
5031
}
5132

52-
function visitExportAssignment(node: ExportAssignment): ExportAssignment {
53-
if (node.isExportEquals) {
54-
return undefined; // do not emit export equals for ES6
55-
}
56-
const original = getOriginalNode(node);
57-
return nodeIsSynthesized(original) || resolver.isValueAliasDeclaration(original) ? node : undefined;
58-
}
59-
60-
function visitExportDeclaration(node: ExportDeclaration): ExportDeclaration {
61-
if (!node.exportClause) {
62-
return resolver.moduleExportsSomeValue(node.moduleSpecifier) ? node : undefined;
63-
}
64-
if (!resolver.isValueAliasDeclaration(node)) {
65-
return undefined;
66-
}
67-
const newExportClause = visitNode(node.exportClause, visitor, isNamedExports, /*optional*/ true);
68-
if (node.exportClause === newExportClause) {
69-
return node;
70-
}
71-
return newExportClause
72-
? createExportDeclaration(
73-
/*decorators*/ undefined,
74-
/*modifiers*/ undefined,
75-
newExportClause,
76-
node.moduleSpecifier)
77-
: undefined;
78-
}
79-
80-
function visitNamedExports(node: NamedExports): NamedExports {
81-
const newExports = visitNodes(node.elements, visitor, isExportSpecifier);
82-
if (node.elements === newExports) {
83-
return node;
84-
}
85-
return newExports.length ? createNamedExports(newExports) : undefined;
86-
}
87-
88-
function visitExportSpecifier(node: ExportSpecifier): ExportSpecifier {
89-
return resolver.isValueAliasDeclaration(node) ? node : undefined;
90-
}
91-
92-
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): ImportEqualsDeclaration {
93-
return !isExternalModuleImportEqualsDeclaration(node) || resolver.isReferencedAliasDeclaration(node) ? node : undefined;
94-
}
95-
96-
function visitImportDeclaration(node: ImportDeclaration) {
97-
if (node.importClause) {
98-
const newImportClause = visitNode(node.importClause, visitor, isImportClause);
99-
if (!newImportClause.name && !newImportClause.namedBindings) {
100-
return undefined;
101-
}
102-
else if (newImportClause !== node.importClause) {
103-
return createImportDeclaration(
104-
/*decorators*/ undefined,
105-
/*modifiers*/ undefined,
106-
newImportClause,
107-
node.moduleSpecifier);
108-
}
109-
}
110-
return node;
111-
}
112-
113-
function visitImportClause(node: ImportClause): ImportClause {
114-
let newDefaultImport = node.name;
115-
if (!resolver.isReferencedAliasDeclaration(node)) {
116-
newDefaultImport = undefined;
117-
}
118-
const newNamedBindings = visitNode(node.namedBindings, visitor, isNamedImportBindings, /*optional*/ true);
119-
return newDefaultImport !== node.name || newNamedBindings !== node.namedBindings
120-
? createImportClause(newDefaultImport, newNamedBindings)
121-
: node;
122-
}
123-
124-
function visitNamedBindings(node: NamedImportBindings): VisitResult<NamedImportBindings> {
125-
if (node.kind === SyntaxKind.NamespaceImport) {
126-
return resolver.isReferencedAliasDeclaration(node) ? node : undefined;
127-
}
128-
else {
129-
const newNamedImportElements = visitNodes((<NamedImports>node).elements, visitor, isImportSpecifier);
130-
if (!newNamedImportElements || newNamedImportElements.length == 0) {
131-
return undefined;
132-
}
133-
if (newNamedImportElements === (<NamedImports>node).elements) {
134-
return node;
135-
}
136-
return createNamedImports(newNamedImportElements);
137-
}
33+
function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult<ImportEqualsDeclaration> {
34+
// Elide `import=` as it is not legal with --module ES6
35+
return undefined;
13836
}
13937

140-
function visitImportSpecifier(node: ImportSpecifier) {
141-
return resolver.isReferencedAliasDeclaration(node) ? node : undefined;
38+
function visitExportAssignment(node: ExportAssignment): VisitResult<ExportAssignment> {
39+
// Elide `export=` as it is not legal with --module ES6
40+
return node.isExportEquals ? undefined : node;
14241
}
14342
}
14443
}

src/compiler/transformers/module/module.ts

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ namespace ts {
5959
currentSourceFile = node;
6060

6161
// Collect information about the external module.
62-
({ externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues } = collectExternalModuleInfo(node, resolver));
62+
({ externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues } = collectExternalModuleInfo(node));
6363

6464
// Perform the transformation.
6565
const transformModule = transformModuleDelegates[moduleKind] || transformModuleDelegates[ModuleKind.None];
@@ -228,7 +228,7 @@ namespace ts {
228228
}
229229

230230
function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) {
231-
if (exportEquals && resolver.isValueAliasDeclaration(exportEquals)) {
231+
if (exportEquals) {
232232
if (emitAsReturn) {
233233
const statement = createReturn(
234234
exportEquals.expression,
@@ -461,23 +461,21 @@ namespace ts {
461461
);
462462
}
463463
for (const specifier of node.exportClause.elements) {
464-
if (resolver.isValueAliasDeclaration(specifier)) {
465-
const exportedValue = createPropertyAccess(
466-
generatedName,
467-
specifier.propertyName || specifier.name
468-
);
469-
statements.push(
470-
createStatement(
471-
createExportAssignment(specifier.name, exportedValue),
472-
/*location*/ specifier
473-
)
474-
);
475-
}
464+
const exportedValue = createPropertyAccess(
465+
generatedName,
466+
specifier.propertyName || specifier.name
467+
);
468+
statements.push(
469+
createStatement(
470+
createExportAssignment(specifier.name, exportedValue),
471+
/*location*/ specifier
472+
)
473+
);
476474
}
477475

478476
return singleOrMany(statements);
479477
}
480-
else if (resolver.moduleExportsSomeValue(node.moduleSpecifier)) {
478+
else {
481479
// export * from "mod";
482480
return createStatement(
483481
createCall(
@@ -495,15 +493,14 @@ namespace ts {
495493
}
496494

497495
function visitExportAssignment(node: ExportAssignment): VisitResult<Statement> {
498-
if (!node.isExportEquals) {
499-
if (nodeIsSynthesized(node) || resolver.isValueAliasDeclaration(node)) {
500-
const statements: Statement[] = [];
501-
addExportDefault(statements, node.expression, /*location*/ node);
502-
return statements;
503-
}
496+
if (node.isExportEquals) {
497+
// Elide as `export=` is handled in addExportEqualsIfNeeded
498+
return undefined;
504499
}
505500

506-
return undefined;
501+
const statements: Statement[] = [];
502+
addExportDefault(statements, node.expression, /*location*/ node);
503+
return statements;
507504
}
508505

509506
function addExportDefault(statements: Statement[], expression: Expression, location: TextRange): void {
@@ -568,7 +565,7 @@ namespace ts {
568565
}
569566

570567
function collectExportMembers(names: Identifier[], node: Node): Identifier[] {
571-
if (isAliasSymbolDeclaration(node) && resolver.isValueAliasDeclaration(node) && isDeclaration(node)) {
568+
if (isAliasSymbolDeclaration(node) && isDeclaration(node)) {
572569
const name = node.name;
573570
if (isIdentifier(name)) {
574571
names.push(name);

src/compiler/transformers/module/system.ts

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ namespace ts {
9191
Debug.assert(!exportFunctionForFile);
9292

9393
// Collect information about the external module and dependency groups.
94-
({ externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues } = collectExternalModuleInfo(node, resolver));
94+
({ externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues } = collectExternalModuleInfo(node));
9595

9696
// Make sure that the name of the 'exports' function does not conflict with
9797
// existing identifiers.
@@ -573,28 +573,23 @@ namespace ts {
573573
}
574574

575575
function visitExportSpecifier(specifier: ExportSpecifier): Statement {
576-
if (resolver.getReferencedValueDeclaration(specifier.propertyName || specifier.name)
577-
|| resolver.isValueAliasDeclaration(specifier)) {
578-
recordExportName(specifier.name);
579-
return createExportStatement(
580-
specifier.name,
581-
specifier.propertyName || specifier.name
582-
);
583-
}
584-
return undefined;
576+
recordExportName(specifier.name);
577+
return createExportStatement(
578+
specifier.name,
579+
specifier.propertyName || specifier.name
580+
);
585581
}
586582

587583
function visitExportAssignment(node: ExportAssignment): Statement {
588-
if (!node.isExportEquals) {
589-
if (nodeIsSynthesized(node) || resolver.isValueAliasDeclaration(node)) {
590-
return createExportStatement(
591-
createLiteral("default"),
592-
node.expression
593-
);
594-
}
584+
if (node.isExportEquals) {
585+
// Elide `export=` as it is illegal in a SystemJS module.
586+
return undefined;
595587
}
596588

597-
return undefined;
589+
return createExportStatement(
590+
createLiteral("default"),
591+
node.expression
592+
);
598593
}
599594

600595
/**

0 commit comments

Comments
 (0)