Support async function serialization. (#1311)
This commit is contained in:
parent
cc8b87ce3d
commit
5387e78cfa
|
@ -27,6 +27,7 @@ lint::
|
|||
build::
|
||||
go install -ldflags "-X github.com/pulumi/pulumi/pkg/version.Version=${VERSION}" ${LANGUAGE_HOST}
|
||||
tsc
|
||||
cp tests/runtime/jsClosureCases.js bin/tests/runtime
|
||||
cp README.md ../../LICENSE package.json ./dist/* bin/
|
||||
node ../../scripts/reversion.js bin/package.json ${VERSION}
|
||||
node ../../scripts/reversion.js bin/version.js ${VERSION}
|
||||
|
|
|
@ -369,11 +369,19 @@ function createFunctionInfo(
|
|||
func.toString().startsWith("class ") &&
|
||||
proto !== Function.prototype(func);
|
||||
|
||||
// Note, i can't think of a better way to determine this. This is particularly hard because
|
||||
// we can't even necessary refer to async function objects here as this code is rewritten by
|
||||
// TS, converting all async functions to non async functions.
|
||||
const isAsyncFunction = func.constructor && func.constructor.name === "AsyncFunction";
|
||||
|
||||
// Ensure that the prototype of this function is properly serialized as well. We only need to do
|
||||
// this for functions with a custom prototype (like a derived class constructor, or a functoin
|
||||
// this for functions with a custom prototype (like a derived class constructor, or a function
|
||||
// that a user has explicit set the prototype for). Normal functions will pick up
|
||||
// Function.prototype by default, so we don't need to do anything for them.
|
||||
if (proto !== Function.prototype && !isDerivedNoCaptureConstructor(func)) {
|
||||
if (proto !== Function.prototype &&
|
||||
!isAsyncFunction &&
|
||||
!isDerivedNoCaptureConstructor(func)) {
|
||||
|
||||
const protoEntry = getOrCreateEntry(proto, undefined, context, serialize);
|
||||
functionInfo.proto = protoEntry;
|
||||
|
||||
|
|
|
@ -140,6 +140,12 @@ function parseFunctionCode(funcString: string): [string, ParsedFunctionCode] {
|
|||
return ["", { funcExprWithoutName: funcString, isArrowFunction: true }];
|
||||
}
|
||||
|
||||
let isAsync = false;
|
||||
if (funcString.startsWith("async ")) {
|
||||
isAsync = true;
|
||||
funcString = funcString.substr("async".length).trimLeft();
|
||||
}
|
||||
|
||||
if (funcString.startsWith("function get ") || funcString.startsWith("function set ")) {
|
||||
const trimmed = funcString.substr("function get".length);
|
||||
return makeFunctionDeclaration(trimmed, /*isFunctionDeclaration: */ false);
|
||||
|
@ -171,8 +177,8 @@ function parseFunctionCode(funcString: string): [string, ParsedFunctionCode] {
|
|||
const isSubClass = classDecl.heritageClauses && classDecl.heritageClauses.some(
|
||||
c => c.token === ts.SyntaxKind.ExtendsKeyword);
|
||||
return isSubClass
|
||||
? makeFunctionDeclaration("constructor() { super(); }", /*isFunctionDeclaration: */ false)
|
||||
: makeFunctionDeclaration("constructor() { }", /*isFunctionDeclaration: */ false);
|
||||
? makeFunctionDeclaration("constructor() { super(); }", /*isFunctionDeclaration:*/ false)
|
||||
: makeFunctionDeclaration("constructor() { }", /*isFunctionDeclaration:*/ false);
|
||||
}
|
||||
|
||||
const constructorCode = funcString.substring(constructor.pos, constructor.end).trim();
|
||||
|
@ -185,7 +191,9 @@ function parseFunctionCode(funcString: string): [string, ParsedFunctionCode] {
|
|||
return makeFunctionDeclaration(funcString, /*isFunctionDeclaration: */ false);
|
||||
|
||||
function makeFunctionDeclaration(v: string, isFunctionDeclaration: boolean): [string, ParsedFunctionCode] {
|
||||
let prefix = "function ";
|
||||
let prefix = isAsync ? "async " : "";
|
||||
prefix += "function ";
|
||||
|
||||
v = v.trimLeft();
|
||||
|
||||
if (v.startsWith("*")) {
|
||||
|
|
|
@ -3780,6 +3780,16 @@ return function /*f3*/() {
|
|||
});
|
||||
}
|
||||
|
||||
// Run a bunch of direct checks on async js functions if we're in node 8 or above.
|
||||
// We can't do this inline as node6 doesn't understand 'async functions'. And we
|
||||
// can't do this in TS as TS will convert the async-function to be a normal non-async
|
||||
// function.
|
||||
const version = Number(process.version.match(/^v(\d+)\.\d+/)![1]);
|
||||
if (version >= 8) {
|
||||
const jsCases = require("./jsClosureCases");
|
||||
cases.push(...jsCases.cases);
|
||||
}
|
||||
|
||||
// Make a callback to keep running tests.
|
||||
let remaining = cases;
|
||||
while (true) {
|
||||
|
|
79
sdk/nodejs/tests/runtime/jsClosureCases.js
Normal file
79
sdk/nodejs/tests/runtime/jsClosureCases.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
"use strict";
|
||||
// Copyright 2016-2018, Pulumi Corporation. All rights reserved.
|
||||
|
||||
const cases = [];
|
||||
cases.push({
|
||||
title: "Async anonymous function closure (js)",
|
||||
// tslint:disable-next-line
|
||||
func: async function (a) { await a; },
|
||||
expectText: `exports.handler = __f0;
|
||||
|
||||
function __f0() {
|
||||
return (function() {
|
||||
with({ }) {
|
||||
|
||||
return async function (a) { await a; };
|
||||
|
||||
}
|
||||
}).apply(undefined, undefined).apply(this, arguments);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
cases.push({
|
||||
title: "Async anonymous function closure - extra space (js)",
|
||||
// tslint:disable-next-line
|
||||
func: async function (a) { await a; },
|
||||
expectText: `exports.handler = __f0;
|
||||
|
||||
function __f0() {
|
||||
return (function() {
|
||||
with({ }) {
|
||||
|
||||
return async function (a) { await a; };
|
||||
|
||||
}
|
||||
}).apply(undefined, undefined).apply(this, arguments);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
cases.push({
|
||||
title: "Async named function closure (js)",
|
||||
// tslint:disable-next-line
|
||||
func: async function foo(a) { await a; },
|
||||
expectText: `exports.handler = __foo;
|
||||
|
||||
function __foo() {
|
||||
return (function() {
|
||||
with({ foo: __foo }) {
|
||||
|
||||
return async function /*foo*/(a) { await a; };
|
||||
|
||||
}
|
||||
}).apply(undefined, undefined).apply(this, arguments);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
cases.push({
|
||||
title: "Async arrow function closure (js)",
|
||||
// tslint:disable-next-line
|
||||
func: async (a) => { await a; },
|
||||
expectText: `exports.handler = __f0;
|
||||
|
||||
function __f0() {
|
||||
return (function() {
|
||||
with({ }) {
|
||||
|
||||
return async (a) => { await a; };
|
||||
|
||||
}
|
||||
}).apply(undefined, undefined).apply(this, arguments);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
|
||||
module.exports.cases = cases;
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strictNullChecks": true
|
||||
"strictNullChecks": true,
|
||||
},
|
||||
"files": [
|
||||
"index.ts",
|
||||
|
|
Loading…
Reference in a new issue