Fix 'this' capturing for dynamic import

This commit is contained in:
Ron Buckton
2017-10-09 17:15:13 -07:00
parent 1db762356e
commit dc607c29b4
10 changed files with 292 additions and 23 deletions

View File

@@ -2699,6 +2699,12 @@ namespace ts {
if (expression.kind === SyntaxKind.ImportKeyword) {
transformFlags |= TransformFlags.ContainsDynamicImport;
// A dynamic 'import()' call that contains a lexical 'this' will
// require a captured 'this' when emitting down-level.
if (subtreeFlags & TransformFlags.ContainsLexicalThis) {
transformFlags |= TransformFlags.ContainsCapturedLexicalThis;
}
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;

View File

@@ -561,46 +561,89 @@ namespace ts {
// });
const resolve = createUniqueName("resolve");
const reject = createUniqueName("reject");
return createNew(
createIdentifier("Promise"),
/*typeArguments*/ undefined,
[createFunctionExpression(
const parameters = [
createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve),
createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject)
];
const body = createBlock([
createStatement(
createCall(
createIdentifier("require"),
/*typeArguments*/ undefined,
[createArrayLiteral([firstOrUndefined(node.arguments) || createOmittedExpression()]), resolve, reject]
)
)
]);
let func: FunctionExpression | ArrowFunction;
if (languageVersion >= ScriptTarget.ES2015) {
func = createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
parameters,
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
body);
}
else {
func = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
[createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ resolve),
createParameter(/*decorator*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, /*name*/ reject)],
parameters,
/*type*/ undefined,
createBlock([createStatement(
createCall(
createIdentifier("require"),
/*typeArguments*/ undefined,
[createArrayLiteral([firstOrUndefined(node.arguments) || createOmittedExpression()]), resolve, reject]
))])
)]);
body);
// if there is a lexical 'this' in the import call arguments, ensure we indicate
// that this new function expression indicates it captures 'this' so that the
// es2015 transformer will properly substitute 'this' with '_this'.
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
setEmitFlags(func, EmitFlags.CapturesThis);
}
}
return createNew(createIdentifier("Promise"), /*typeArguments*/ undefined, [func]);
}
function transformImportCallExpressionCommonJS(node: ImportCall): Expression {
function transformImportCallExpressionCommonJS(node: ImportCall): Expression {
// import("./blah")
// emit as
// Promise.resolve().then(function () { return require(x); }) /*CommonJs Require*/
// We have to wrap require in then callback so that require is done in asynchronously
// if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately
return createCall(
createPropertyAccess(
createCall(createPropertyAccess(createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []),
"then"),
/*typeArguments*/ undefined,
[createFunctionExpression(
const promiseResolveCall = createCall(createPropertyAccess(createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []);
const requireCall = createCall(createIdentifier("require"), /*typeArguments*/ undefined, node.arguments);
let func: FunctionExpression | ArrowFunction;
if (languageVersion >= ScriptTarget.ES2015) {
func = createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
requireCall);
}
else {
func = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
createBlock([createReturn(createCall(createIdentifier("require"), /*typeArguments*/ undefined, node.arguments))])
)]);
createBlock([createReturn(requireCall)]));
// if there is a lexical 'this' in the import call arguments, ensure we indicate
// that this new function expression indicates it captures 'this' so that the
// es2015 transformer will properly substitute 'this' with '_this'.
if (node.transformFlags & TransformFlags.ContainsLexicalThis) {
setEmitFlags(func, EmitFlags.CapturesThis);
}
}
return createCall(createPropertyAccess(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);
}
/**