Skip to content

Commit 8b7fb8e

Browse files
committed
Merge pull request microsoft#8739 from evansb/fix-8738
Fix microsoft#8738: Handles Re-assignment of Exported Clause Member
2 parents 6913c32 + 47eac4f commit 8b7fb8e

5 files changed

Lines changed: 212 additions & 10 deletions

File tree

src/compiler/emitter.ts

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2613,11 +2613,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
26132613
return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
26142614
}
26152615

2616+
function isNameOfExportedDeclarationInNonES6Module(node: Node): boolean {
2617+
if (modulekind === ModuleKind.System || node.kind !== SyntaxKind.Identifier || nodeIsSynthesized(node)) {
2618+
return false;
2619+
}
2620+
2621+
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
2622+
}
2623+
26162624
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
2617-
const exportChanged = (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) &&
2625+
const isPlusPlusOrMinusMinus = (node.operator === SyntaxKind.PlusPlusToken
2626+
|| node.operator === SyntaxKind.MinusMinusToken);
2627+
const externalExportChanged = isPlusPlusOrMinusMinus &&
26182628
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
26192629

2620-
if (exportChanged) {
2630+
if (externalExportChanged) {
26212631
// emit
26222632
// ++x
26232633
// as
@@ -2626,6 +2636,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
26262636
emitNodeWithoutSourceMap(node.operand);
26272637
write(`", `);
26282638
}
2639+
const internalExportChanged = isPlusPlusOrMinusMinus &&
2640+
isNameOfExportedDeclarationInNonES6Module(node.operand);
2641+
2642+
if (internalExportChanged) {
2643+
emitAliasEqual(<Identifier> node.operand);
2644+
}
26292645

26302646
write(tokenToString(node.operator));
26312647
// In some cases, we need to emit a space between the operator and the operand. One obvious case
@@ -2651,14 +2667,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
26512667
}
26522668
emit(node.operand);
26532669

2654-
if (exportChanged) {
2670+
if (externalExportChanged) {
26552671
write(")");
26562672
}
26572673
}
26582674

26592675
function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
2660-
const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
2661-
if (exportChanged) {
2676+
const externalExportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
2677+
const internalExportChanged = isNameOfExportedDeclarationInNonES6Module(node.operand);
2678+
2679+
if (externalExportChanged) {
26622680
// export function returns the value that was passes as the second argument
26632681
// however for postfix unary expressions result value should be the value before modification.
26642682
// emit 'x++' as '(export('x', ++x) - 1)' and 'x--' as '(export('x', --x) + 1)'
@@ -2676,6 +2694,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
26762694
write(") + 1)");
26772695
}
26782696
}
2697+
else if (internalExportChanged) {
2698+
emitAliasEqual(<Identifier> node.operand);
2699+
emit(node.operand);
2700+
if (node.operator === SyntaxKind.PlusPlusToken) {
2701+
write(" += 1");
2702+
}
2703+
else {
2704+
write(" -= 1");
2705+
}
2706+
}
26792707
else {
26802708
emit(node.operand);
26812709
write(tokenToString(node.operator));
@@ -2777,24 +2805,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
27772805
}
27782806
}
27792807

2808+
function emitAliasEqual(name: Identifier): boolean {
2809+
for (const specifier of exportSpecifiers[name.text]) {
2810+
emitStart(specifier.name);
2811+
emitContainingModuleName(specifier);
2812+
if (languageVersion === ScriptTarget.ES3 && name.text === "default") {
2813+
write('["default"]');
2814+
}
2815+
else {
2816+
write(".");
2817+
emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
2818+
}
2819+
emitEnd(specifier.name);
2820+
write(" = ");
2821+
}
2822+
return true;
2823+
}
2824+
27802825
function emitBinaryExpression(node: BinaryExpression) {
27812826
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken &&
27822827
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
27832828
emitDestructuring(node, node.parent.kind === SyntaxKind.ExpressionStatement);
27842829
}
27852830
else {
2786-
const exportChanged =
2787-
node.operatorToken.kind >= SyntaxKind.FirstAssignment &&
2788-
node.operatorToken.kind <= SyntaxKind.LastAssignment &&
2831+
const isAssignment = isAssignmentOperator(node.operatorToken.kind);
2832+
2833+
const externalExportChanged = isAssignment &&
27892834
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
27902835

2791-
if (exportChanged) {
2836+
if (externalExportChanged) {
27922837
// emit assignment 'x <op> y' as 'exports("x", x <op> y)'
27932838
write(`${exportFunctionForFile}("`);
27942839
emitNodeWithoutSourceMap(node.left);
27952840
write(`", `);
27962841
}
27972842

2843+
const internalExportChanged = isAssignment &&
2844+
isNameOfExportedDeclarationInNonES6Module(node.left);
2845+
2846+
if (internalExportChanged) {
2847+
// export { foo }
2848+
// emit foo = 2 as exports.foo = foo = 2
2849+
emitAliasEqual(<Identifier>node.left);
2850+
}
2851+
27982852
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
27992853
// Downleveled emit exponentiation operator using Math.pow
28002854
emitExponentiationOperator(node);
@@ -2815,7 +2869,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
28152869
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
28162870
}
28172871

2818-
if (exportChanged) {
2872+
if (externalExportChanged) {
28192873
write(")");
28202874
}
28212875
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [server.ts]
2+
3+
var foo = 2;
4+
foo = 3;
5+
6+
var baz = 3;
7+
baz = 4;
8+
9+
var buzz = 10;
10+
buzz += 3;
11+
12+
var bizz = 8;
13+
bizz++; // compiles to exports.bizz = bizz += 1
14+
bizz--; // similarly
15+
++bizz; // compiles to exports.bizz = ++bizz
16+
17+
export { foo, baz, baz as quux, buzz, bizz };
18+
19+
20+
//// [server.js]
21+
"use strict";
22+
var foo = 2;
23+
exports.foo = foo;
24+
exports.foo = foo = 3;
25+
var baz = 3;
26+
exports.baz = baz;
27+
exports.quux = baz;
28+
exports.baz = exports.quux = baz = 4;
29+
var buzz = 10;
30+
exports.buzz = buzz;
31+
exports.buzz = buzz += 3;
32+
var bizz = 8;
33+
exports.bizz = bizz;
34+
exports.bizz = bizz += 1; // compiles to exports.bizz = bizz += 1
35+
exports.bizz = bizz -= 1; // similarly
36+
exports.bizz = ++bizz; // compiles to exports.bizz = ++bizz
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
=== tests/cases/compiler/server.ts ===
2+
3+
var foo = 2;
4+
>foo : Symbol(foo, Decl(server.ts, 1, 3))
5+
6+
foo = 3;
7+
>foo : Symbol(foo, Decl(server.ts, 1, 3))
8+
9+
var baz = 3;
10+
>baz : Symbol(baz, Decl(server.ts, 4, 3))
11+
12+
baz = 4;
13+
>baz : Symbol(baz, Decl(server.ts, 4, 3))
14+
15+
var buzz = 10;
16+
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
17+
18+
buzz += 3;
19+
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
20+
21+
var bizz = 8;
22+
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
23+
24+
bizz++; // compiles to exports.bizz = bizz += 1
25+
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
26+
27+
bizz--; // similarly
28+
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
29+
30+
++bizz; // compiles to exports.bizz = ++bizz
31+
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
32+
33+
export { foo, baz, baz as quux, buzz, bizz };
34+
>foo : Symbol(foo, Decl(server.ts, 15, 8))
35+
>baz : Symbol(baz, Decl(server.ts, 15, 13))
36+
>baz : Symbol(quux, Decl(server.ts, 15, 18))
37+
>quux : Symbol(quux, Decl(server.ts, 15, 18))
38+
>buzz : Symbol(buzz, Decl(server.ts, 15, 31))
39+
>bizz : Symbol(bizz, Decl(server.ts, 15, 37))
40+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
=== tests/cases/compiler/server.ts ===
2+
3+
var foo = 2;
4+
>foo : number
5+
>2 : number
6+
7+
foo = 3;
8+
>foo = 3 : number
9+
>foo : number
10+
>3 : number
11+
12+
var baz = 3;
13+
>baz : number
14+
>3 : number
15+
16+
baz = 4;
17+
>baz = 4 : number
18+
>baz : number
19+
>4 : number
20+
21+
var buzz = 10;
22+
>buzz : number
23+
>10 : number
24+
25+
buzz += 3;
26+
>buzz += 3 : number
27+
>buzz : number
28+
>3 : number
29+
30+
var bizz = 8;
31+
>bizz : number
32+
>8 : number
33+
34+
bizz++; // compiles to exports.bizz = bizz += 1
35+
>bizz++ : number
36+
>bizz : number
37+
38+
bizz--; // similarly
39+
>bizz-- : number
40+
>bizz : number
41+
42+
++bizz; // compiles to exports.bizz = ++bizz
43+
>++bizz : number
44+
>bizz : number
45+
46+
export { foo, baz, baz as quux, buzz, bizz };
47+
>foo : number
48+
>baz : number
49+
>baz : number
50+
>quux : number
51+
>buzz : number
52+
>bizz : number
53+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @target: es5
2+
// @module: commonjs
3+
4+
// @filename: server.ts
5+
var foo = 2;
6+
foo = 3;
7+
8+
var baz = 3;
9+
baz = 4;
10+
11+
var buzz = 10;
12+
buzz += 3;
13+
14+
var bizz = 8;
15+
bizz++; // compiles to exports.bizz = bizz += 1
16+
bizz--; // similarly
17+
++bizz; // compiles to exports.bizz = ++bizz
18+
19+
export { foo, baz, baz as quux, buzz, bizz };

0 commit comments

Comments
 (0)