mirror of
https://github.com/nodejs/node.git
synced 2025-05-02 03:31:35 +00:00

Handle situations in which the main `Promise` from a TLA module is not fulfilled better: - When not resolving the `Promise` at all, set a non-zero exit code (unless another one has been requested explicitly) to distinguish the result from a successful completion. - When rejecting the `Promise`, always treat it like an uncaught exception. In particular, this also ensures a non-zero exit code. Refs: https://github.com/nodejs/node/pull/34558 PR-URL: https://github.com/nodejs/node/pull/34640 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
80 lines
2.5 KiB
JavaScript
80 lines
2.5 KiB
JavaScript
'use strict';
|
|
|
|
const CJSLoader = require('internal/modules/cjs/loader');
|
|
const { Module, toRealPath, readPackageScope } = CJSLoader;
|
|
const { getOptionValue } = require('internal/options');
|
|
const path = require('path');
|
|
|
|
function resolveMainPath(main) {
|
|
// Note extension resolution for the main entry point can be deprecated in a
|
|
// future major.
|
|
// Module._findPath is monkey-patchable here.
|
|
let mainPath = Module._findPath(path.resolve(main), null, true);
|
|
if (!mainPath)
|
|
return;
|
|
|
|
const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
|
|
if (!preserveSymlinksMain)
|
|
mainPath = toRealPath(mainPath);
|
|
|
|
return mainPath;
|
|
}
|
|
|
|
function shouldUseESMLoader(mainPath) {
|
|
const userLoader = getOptionValue('--experimental-loader');
|
|
if (userLoader)
|
|
return true;
|
|
const esModuleSpecifierResolution =
|
|
getOptionValue('--es-module-specifier-resolution');
|
|
if (esModuleSpecifierResolution === 'node')
|
|
return true;
|
|
// Determine the module format of the main
|
|
if (mainPath && mainPath.endsWith('.mjs'))
|
|
return true;
|
|
if (!mainPath || mainPath.endsWith('.cjs'))
|
|
return false;
|
|
const pkg = readPackageScope(mainPath);
|
|
return pkg && pkg.data.type === 'module';
|
|
}
|
|
|
|
function runMainESM(mainPath) {
|
|
const esmLoader = require('internal/process/esm_loader');
|
|
const { pathToFileURL } = require('internal/url');
|
|
handleMainPromise(esmLoader.loadESM((ESMLoader) => {
|
|
const main = path.isAbsolute(mainPath) ?
|
|
pathToFileURL(mainPath).href : mainPath;
|
|
return ESMLoader.import(main);
|
|
}));
|
|
}
|
|
|
|
function handleMainPromise(promise) {
|
|
// Handle a Promise from running code that potentially does Top-Level Await.
|
|
// In that case, it makes sense to set the exit code to a specific non-zero
|
|
// value if the main code never finishes running.
|
|
function handler() {
|
|
if (process.exitCode === undefined)
|
|
process.exitCode = 13;
|
|
}
|
|
process.on('exit', handler);
|
|
return promise.finally(() => process.off('exit', handler));
|
|
}
|
|
|
|
// For backwards compatibility, we have to run a bunch of
|
|
// monkey-patchable code that belongs to the CJS loader (exposed by
|
|
// `require('module')`) even when the entry point is ESM.
|
|
function executeUserEntryPoint(main = process.argv[1]) {
|
|
const resolvedMain = resolveMainPath(main);
|
|
const useESMLoader = shouldUseESMLoader(resolvedMain);
|
|
if (useESMLoader) {
|
|
runMainESM(resolvedMain || main);
|
|
} else {
|
|
// Module._load is the monkey-patchable CJS module loader.
|
|
Module._load(main, null, true);
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
executeUserEntryPoint,
|
|
handleMainPromise,
|
|
};
|