Merge 5effa67638
into 4d4ff9f1d6
This commit is contained in:
commit
9ae1b138a3
|
@ -6,6 +6,9 @@
|
|||
these types virtually unusable in practice.
|
||||
[#8449](https://github.com/pulumi/pulumi/pull/8449)
|
||||
|
||||
- [sdk/nodejs] Support using native ES modules as Pulumi scripts
|
||||
[#7764](https://github.com/pulumi/pulumi/pull/7764)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- [codegen/go] - Respect default values in Pulumi object types.
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// limitations under the License.
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as url from "url";
|
||||
import * as minimist from "minimist";
|
||||
import * as path from "path";
|
||||
import * as tsnode from "ts-node";
|
||||
|
@ -38,6 +39,25 @@ function reportModuleLoadFailure(program: string, error: Error): never {
|
|||
return process.exit(mod.nodeJSProcessExitedAfterLoggingUserActionableMessage);
|
||||
}
|
||||
|
||||
function projectRootFromProgramPath(program: string): string {
|
||||
const stat = fs.lstatSync(program);
|
||||
if (stat.isDirectory()) {
|
||||
return program;
|
||||
} else {
|
||||
return path.dirname(program);
|
||||
}
|
||||
}
|
||||
|
||||
function packageObjectFromProjectRoot(projectRoot: string): Record<string, any> {
|
||||
try {
|
||||
const packageJson = path.join(projectRoot, "package.json");
|
||||
return require(packageJson);
|
||||
} catch {
|
||||
// This is all best-effort so if we can't load the package.json file, that's
|
||||
// fine.
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function throwOrPrintModuleLoadError(program: string, error: Error): void {
|
||||
// error is guaranteed to be a Node module load error. Node emits a very
|
||||
|
@ -72,23 +92,8 @@ function throwOrPrintModuleLoadError(program: string, error: Error): void {
|
|||
//
|
||||
// The first step of this is trying to slurp up a package.json for this program, if
|
||||
// one exists.
|
||||
const stat = fs.lstatSync(program);
|
||||
let projectRoot: string;
|
||||
if (stat.isDirectory()) {
|
||||
projectRoot = program;
|
||||
} else {
|
||||
projectRoot = path.dirname(program);
|
||||
}
|
||||
|
||||
let packageObject: Record<string, any>;
|
||||
try {
|
||||
const packageJson = path.join(projectRoot, "package.json");
|
||||
packageObject = require(packageJson);
|
||||
} catch {
|
||||
// This is all best-effort so if we can't load the package.json file, that's
|
||||
// fine.
|
||||
return;
|
||||
}
|
||||
const projectRoot = projectRootFromProgramPath(program);
|
||||
const packageObject = packageObjectFromProjectRoot(projectRoot);
|
||||
|
||||
console.error("Here's what we think went wrong:");
|
||||
|
||||
|
@ -251,6 +256,24 @@ ${defaultMessage}`);
|
|||
// Now go ahead and execute the code. The process will remain alive until the message loop empties.
|
||||
log.debug(`Running program '${program}' in pwd '${process.cwd()}' w/ args: ${programArgs}`);
|
||||
try {
|
||||
const packageObject = packageObjectFromProjectRoot(projectRootFromProgramPath(program));
|
||||
|
||||
// We use dynamic import instead of require for projects using native ES modules instead of commonjs
|
||||
if (packageObject["type"] === "module") {
|
||||
// Workaround for typescript transpiling dynamic import into `Promise.resolve().then(() => require`
|
||||
// Follow this issue for progress on when we can remove this:
|
||||
// https://github.com/microsoft/TypeScript/issues/43329
|
||||
//
|
||||
// Workaround inspired by es-module-shims:
|
||||
// https://github.com/guybedford/es-module-shims/blob/main/src/common.js#L21
|
||||
// eslint-disable-next-line no-eval
|
||||
const dynamicImport = (0, eval)("u=>import(u)");
|
||||
// Import the module and capture any module outputs it exported. Finally, await the value we get
|
||||
// back. That way, if it is async and throws an exception, we properly capture it here
|
||||
// and handle it.
|
||||
return await dynamicImport(url.pathToFileURL(program).toString());
|
||||
}
|
||||
|
||||
// Execute the module and capture any module outputs it exported. If the exported value
|
||||
// was itself a Function, then just execute it. This allows for exported top level
|
||||
// async functions that pulumi programs can live in. Finally, await the value we get
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// This tests the basic creation of a single propertyless resource using a native ES module
|
||||
|
||||
import pulumi from "../../../../../index.js";
|
||||
|
||||
class MyResource extends pulumi.CustomResource {
|
||||
constructor(name) {
|
||||
super("test:index:MyResource", name);
|
||||
}
|
||||
}
|
||||
|
||||
new MyResource("testResource1");
|
||||
|
|
@ -0,0 +1 @@
|
|||
{ "type": "module" }
|
|
@ -1181,6 +1181,17 @@ describe("rpc", () => {
|
|||
};
|
||||
},
|
||||
},
|
||||
// A program that allocates a single resource using a native ES module
|
||||
"native_es_module": {
|
||||
// Dynamic import won't automatically resolve to /index.js on a directory, specifying explicitly
|
||||
program: path.join(base, "067.native_es_module/index.js"),
|
||||
expectResourceCount: 1,
|
||||
registerResource: (ctx: any, dryrun: boolean, t: string, name: string, res: any) => {
|
||||
assert.strictEqual(t, "test:index:MyResource");
|
||||
assert.strictEqual(name, "testResource1");
|
||||
return { urn: makeUrn(t, name), id: undefined, props: undefined };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
for (const casename of Object.keys(cases)) {
|
||||
|
|
Loading…
Reference in a new issue