Merge pull request #8739 from evansb/fix-8738

Fix #8738: Handles Re-assignment of Exported Clause Member
This commit is contained in:
Vladimir Matveev 2016-06-07 16:23:02 -07:00
commit 8b7fb8e7e8
5 changed files with 212 additions and 10 deletions

View File

@ -2613,11 +2613,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return isSourceFileLevelDeclarationInSystemJsModule(targetDeclaration, /*isExported*/ true);
}
function isNameOfExportedDeclarationInNonES6Module(node: Node): boolean {
if (modulekind === ModuleKind.System || node.kind !== SyntaxKind.Identifier || nodeIsSynthesized(node)) {
return false;
}
return !exportEquals && exportSpecifiers && hasProperty(exportSpecifiers, (<Identifier>node).text);
}
function emitPrefixUnaryExpression(node: PrefixUnaryExpression) {
const exportChanged = (node.operator === SyntaxKind.PlusPlusToken || node.operator === SyntaxKind.MinusMinusToken) &&
const isPlusPlusOrMinusMinus = (node.operator === SyntaxKind.PlusPlusToken
|| node.operator === SyntaxKind.MinusMinusToken);
const externalExportChanged = isPlusPlusOrMinusMinus &&
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
if (exportChanged) {
if (externalExportChanged) {
// emit
// ++x
// as
@ -2626,6 +2636,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
emitNodeWithoutSourceMap(node.operand);
write(`", `);
}
const internalExportChanged = isPlusPlusOrMinusMinus &&
isNameOfExportedDeclarationInNonES6Module(node.operand);
if (internalExportChanged) {
emitAliasEqual(<Identifier> node.operand);
}
write(tokenToString(node.operator));
// 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
}
emit(node.operand);
if (exportChanged) {
if (externalExportChanged) {
write(")");
}
}
function emitPostfixUnaryExpression(node: PostfixUnaryExpression) {
const exportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
if (exportChanged) {
const externalExportChanged = isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.operand);
const internalExportChanged = isNameOfExportedDeclarationInNonES6Module(node.operand);
if (externalExportChanged) {
// export function returns the value that was passes as the second argument
// however for postfix unary expressions result value should be the value before modification.
// 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
write(") + 1)");
}
}
else if (internalExportChanged) {
emitAliasEqual(<Identifier> node.operand);
emit(node.operand);
if (node.operator === SyntaxKind.PlusPlusToken) {
write(" += 1");
}
else {
write(" -= 1");
}
}
else {
emit(node.operand);
write(tokenToString(node.operator));
@ -2777,24 +2805,50 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
}
function emitAliasEqual(name: Identifier): boolean {
for (const specifier of exportSpecifiers[name.text]) {
emitStart(specifier.name);
emitContainingModuleName(specifier);
if (languageVersion === ScriptTarget.ES3 && name.text === "default") {
write('["default"]');
}
else {
write(".");
emitNodeWithCommentsAndWithoutSourcemap(specifier.name);
}
emitEnd(specifier.name);
write(" = ");
}
return true;
}
function emitBinaryExpression(node: BinaryExpression) {
if (languageVersion < ScriptTarget.ES6 && node.operatorToken.kind === SyntaxKind.EqualsToken &&
(node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) {
emitDestructuring(node, node.parent.kind === SyntaxKind.ExpressionStatement);
}
else {
const exportChanged =
node.operatorToken.kind >= SyntaxKind.FirstAssignment &&
node.operatorToken.kind <= SyntaxKind.LastAssignment &&
const isAssignment = isAssignmentOperator(node.operatorToken.kind);
const externalExportChanged = isAssignment &&
isNameOfExportedSourceLevelDeclarationInSystemExternalModule(node.left);
if (exportChanged) {
if (externalExportChanged) {
// emit assignment 'x <op> y' as 'exports("x", x <op> y)'
write(`${exportFunctionForFile}("`);
emitNodeWithoutSourceMap(node.left);
write(`", `);
}
const internalExportChanged = isAssignment &&
isNameOfExportedDeclarationInNonES6Module(node.left);
if (internalExportChanged) {
// export { foo }
// emit foo = 2 as exports.foo = foo = 2
emitAliasEqual(<Identifier>node.left);
}
if (node.operatorToken.kind === SyntaxKind.AsteriskAsteriskToken || node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
// Downleveled emit exponentiation operator using Math.pow
emitExponentiationOperator(node);
@ -2815,7 +2869,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
decreaseIndentIf(indentedBeforeOperator, indentedAfterOperator);
}
if (exportChanged) {
if (externalExportChanged) {
write(")");
}
}

View File

@ -0,0 +1,36 @@
//// [server.ts]
var foo = 2;
foo = 3;
var baz = 3;
baz = 4;
var buzz = 10;
buzz += 3;
var bizz = 8;
bizz++; // compiles to exports.bizz = bizz += 1
bizz--; // similarly
++bizz; // compiles to exports.bizz = ++bizz
export { foo, baz, baz as quux, buzz, bizz };
//// [server.js]
"use strict";
var foo = 2;
exports.foo = foo;
exports.foo = foo = 3;
var baz = 3;
exports.baz = baz;
exports.quux = baz;
exports.baz = exports.quux = baz = 4;
var buzz = 10;
exports.buzz = buzz;
exports.buzz = buzz += 3;
var bizz = 8;
exports.bizz = bizz;
exports.bizz = bizz += 1; // compiles to exports.bizz = bizz += 1
exports.bizz = bizz -= 1; // similarly
exports.bizz = ++bizz; // compiles to exports.bizz = ++bizz

View File

@ -0,0 +1,40 @@
=== tests/cases/compiler/server.ts ===
var foo = 2;
>foo : Symbol(foo, Decl(server.ts, 1, 3))
foo = 3;
>foo : Symbol(foo, Decl(server.ts, 1, 3))
var baz = 3;
>baz : Symbol(baz, Decl(server.ts, 4, 3))
baz = 4;
>baz : Symbol(baz, Decl(server.ts, 4, 3))
var buzz = 10;
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
buzz += 3;
>buzz : Symbol(buzz, Decl(server.ts, 7, 3))
var bizz = 8;
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
bizz++; // compiles to exports.bizz = bizz += 1
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
bizz--; // similarly
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
++bizz; // compiles to exports.bizz = ++bizz
>bizz : Symbol(bizz, Decl(server.ts, 10, 3))
export { foo, baz, baz as quux, buzz, bizz };
>foo : Symbol(foo, Decl(server.ts, 15, 8))
>baz : Symbol(baz, Decl(server.ts, 15, 13))
>baz : Symbol(quux, Decl(server.ts, 15, 18))
>quux : Symbol(quux, Decl(server.ts, 15, 18))
>buzz : Symbol(buzz, Decl(server.ts, 15, 31))
>bizz : Symbol(bizz, Decl(server.ts, 15, 37))

View File

@ -0,0 +1,53 @@
=== tests/cases/compiler/server.ts ===
var foo = 2;
>foo : number
>2 : number
foo = 3;
>foo = 3 : number
>foo : number
>3 : number
var baz = 3;
>baz : number
>3 : number
baz = 4;
>baz = 4 : number
>baz : number
>4 : number
var buzz = 10;
>buzz : number
>10 : number
buzz += 3;
>buzz += 3 : number
>buzz : number
>3 : number
var bizz = 8;
>bizz : number
>8 : number
bizz++; // compiles to exports.bizz = bizz += 1
>bizz++ : number
>bizz : number
bizz--; // similarly
>bizz-- : number
>bizz : number
++bizz; // compiles to exports.bizz = ++bizz
>++bizz : number
>bizz : number
export { foo, baz, baz as quux, buzz, bizz };
>foo : number
>baz : number
>baz : number
>quux : number
>buzz : number
>bizz : number

View File

@ -0,0 +1,19 @@
// @target: es5
// @module: commonjs
// @filename: server.ts
var foo = 2;
foo = 3;
var baz = 3;
baz = 4;
var buzz = 10;
buzz += 3;
var bizz = 8;
bizz++; // compiles to exports.bizz = bizz += 1
bizz--; // similarly
++bizz; // compiles to exports.bizz = ++bizz
export { foo, baz, baz as quux, buzz, bizz };