Initial
This commit is contained in:
304
resources/app/node_modules/@peggyjs/from-mem/index.js
generated
vendored
Normal file
304
resources/app/node_modules/@peggyjs/from-mem/index.js
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
"use strict";
|
||||
|
||||
// Import or require module text from memory, rather than disk. Runs
|
||||
// in a node vm, very similar to how node loads modules.
|
||||
//
|
||||
// Ideas taken from the "module-from-string" and "eval" modules, neither of
|
||||
// which were situated correctly to be used as-is.
|
||||
|
||||
const { Module } = require("node:module");
|
||||
const fs = require("node:fs/promises");
|
||||
const path = require("node:path");
|
||||
const semver = require("semver");
|
||||
const url = require("node:url");
|
||||
const vm = require("node:vm");
|
||||
|
||||
// These already exist in a new, blank VM. Date, JSON, NaN, etc.
|
||||
// Things from the core language.
|
||||
const vmGlobals = new vm
|
||||
.Script("Object.getOwnPropertyNames(globalThis)")
|
||||
.runInNewContext()
|
||||
.sort();
|
||||
vmGlobals.push("global", "globalThis", "sys");
|
||||
|
||||
// These are the things that are normally in the environment, that vm doesn't
|
||||
// make available. This that you expect to be available in a node environment
|
||||
// that aren't in the laguage itself.
|
||||
const neededKeys = Object
|
||||
.getOwnPropertyNames(global)
|
||||
.filter(k => !vmGlobals.includes(k))
|
||||
.sort();
|
||||
const globalContext = Object.fromEntries(
|
||||
neededKeys.map(k => [k, global[
|
||||
/** @type {keyof typeof global} */ (k)
|
||||
]])
|
||||
);
|
||||
|
||||
// In node <15, console is in vmGlobals.
|
||||
globalContext.console = console;
|
||||
|
||||
/**
|
||||
* @typedef {"amd"
|
||||
* | "bare"
|
||||
* | "cjs"
|
||||
* | "commonjs"
|
||||
* | "es"
|
||||
* | "es6"
|
||||
* | "esm"
|
||||
* | "globals"
|
||||
* | "guess"
|
||||
* | "mjs"
|
||||
* | "module"
|
||||
* | "umd" } SourceFormat
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for how to process code.
|
||||
*
|
||||
* @typedef {object} FromMemOptions
|
||||
* @property {SourceFormat} [format="commonjs"]
|
||||
* What format does the code have? "guess" means to read the closest
|
||||
* package.json file looking for the "type" key.
|
||||
* @property {string} filename What is the fully-qualified synthetic
|
||||
* filename for the code? Most important is the directory, which is used to
|
||||
* find modules that the code import's or require's.
|
||||
* @property {object} [context={}] Variables to make availble in the global
|
||||
* scope while code is being evaluated.
|
||||
* @property {boolean} [includeGlobals=true] Include the typical global
|
||||
* properties that node gives to all modules. (e.g. Buffer, process).
|
||||
* @property {string} [globalExport=null] For type "globals", what name is
|
||||
* exported from the module?
|
||||
* @property {number} [lineOffset=0] Specifies the line number offset that is
|
||||
* displayed in stack traces produced by this script.
|
||||
* @property {number} [columnOffset=0] Specifies the first-line column number
|
||||
* offset that is displayed in stack traces produced by this script.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Treat the given code as a node module as if require() had been called
|
||||
* on a file containing the code.
|
||||
*
|
||||
* @param {string} code Source code in commonjs format.
|
||||
* @param {string} dirname Used for __dirname.
|
||||
* @param {FromMemOptions} options
|
||||
* @returns {object} The module exports from code
|
||||
*/
|
||||
function requireString(code, dirname, options) {
|
||||
// @ts-expect-error This isn't correct.
|
||||
const m = new Module(options.filename, module); // Current module is parent.
|
||||
// This is the function that will be called by `require()` in the parser.
|
||||
m.require = Module.createRequire(options.filename);
|
||||
const script = new vm.Script(code, {
|
||||
filename: options.filename,
|
||||
lineOffset: options.lineOffset,
|
||||
columnOffset: options.columnOffset,
|
||||
});
|
||||
return script.runInNewContext({
|
||||
module: m,
|
||||
exports: m.exports,
|
||||
require: m.require,
|
||||
__dirname: dirname,
|
||||
__filename: options.filename,
|
||||
...options.context,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If the given specifier starts with a ".", path.resolve it to the given
|
||||
* directory. Otherwise, it's a fully-qualified path, a node internal
|
||||
* module name, an npm-provided module name, or a URL.
|
||||
*
|
||||
* @param {string} dirname Owning directory
|
||||
* @param {string} specifier String from the rightmost side of an import statement
|
||||
* @returns {string} Resolved path name or original string
|
||||
*/
|
||||
function resolveIfNeeded(dirname, specifier) {
|
||||
if (specifier.startsWith(".")) {
|
||||
specifier = new URL(specifier, dirname).toString();
|
||||
}
|
||||
return specifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Treat the given code as a node module as if import had been called
|
||||
* on a file containing the code.
|
||||
*
|
||||
* @param {string} code Source code in es6 format.
|
||||
* @param {string} dirname Where the synthetic file would have lived.
|
||||
* @param {FromMemOptions} options
|
||||
* @returns {Promise<unknown>} The module exports from code
|
||||
*/
|
||||
async function importString(code, dirname, options) {
|
||||
if (!vm.SourceTextModule) {
|
||||
throw new Error("Start node with --experimental-vm-modules for this to work");
|
||||
}
|
||||
|
||||
if (!semver.satisfies(process.version, ">=20.8")) {
|
||||
throw new Error("Requires node.js 20.8+ or 21.");
|
||||
}
|
||||
|
||||
const fileUrl = options.filename.startsWith("file:")
|
||||
? options.filename
|
||||
: url.pathToFileURL(options.filename).toString();
|
||||
const dirUrl = dirname.startsWith("file:")
|
||||
? dirname + "/"
|
||||
: url.pathToFileURL(dirname).toString() + "/";
|
||||
|
||||
const mod = new vm.SourceTextModule(code, {
|
||||
identifier: fileUrl,
|
||||
lineOffset: options.lineOffset,
|
||||
columnOffset: options.columnOffset,
|
||||
context: vm.createContext(options.context),
|
||||
initializeImportMeta(meta) {
|
||||
meta.url = fileUrl;
|
||||
},
|
||||
// @ts-expect-error Types in @types/node are wrong.
|
||||
importModuleDynamically(specifier) {
|
||||
return import(resolveIfNeeded(dirUrl, specifier));
|
||||
},
|
||||
});
|
||||
|
||||
await mod.link(async(specifier, referencingModule) => {
|
||||
const resolvedSpecifier = resolveIfNeeded(dirUrl, specifier);
|
||||
const targetModule = await import(resolvedSpecifier);
|
||||
const exports = Object.keys(targetModule);
|
||||
|
||||
// DO NOT change function to () =>, or `this` will be wrong.
|
||||
return new vm.SyntheticModule(exports, function() {
|
||||
for (const e of exports) {
|
||||
this.setExport(e, targetModule[e]);
|
||||
}
|
||||
}, {
|
||||
context: referencingModule.context,
|
||||
});
|
||||
});
|
||||
await mod.evaluate();
|
||||
return mod.namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {"commonjs"|"es"} ModuleType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type Record<string, ModuleType>
|
||||
*/
|
||||
let cache = {};
|
||||
|
||||
/**
|
||||
* Figure out the module type for the given file. If no package.json is
|
||||
* found, default to "commonjs".
|
||||
*
|
||||
* @param {string} filename Fully-qualified filename to start from.
|
||||
* @returns {Promise<ModuleType>}
|
||||
* @throws On invalid package.json
|
||||
*/
|
||||
async function guessModuleType(filename) {
|
||||
const fp = path.parse(filename);
|
||||
switch (fp.ext) {
|
||||
case ".cjs": return "commonjs";
|
||||
case ".mjs": return "es";
|
||||
default:
|
||||
// Fall-through
|
||||
}
|
||||
|
||||
/** @type {ModuleType} */
|
||||
let res = "commonjs";
|
||||
let dir = fp.dir;
|
||||
let prev = undefined;
|
||||
const pending = [];
|
||||
while (dir !== prev) {
|
||||
const cached = cache[dir];
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
pending.push(dir);
|
||||
try {
|
||||
const pkg = await fs.readFile(path.join(dir, "package.json"), "utf8");
|
||||
const pkgj = JSON.parse(pkg);
|
||||
res = (pkgj.type === "module") ? "es" : "commonjs";
|
||||
break;
|
||||
} catch (err) {
|
||||
// If the file just didn't exist, keep going.
|
||||
if (/** @type {NodeJS.ErrnoException} */ (err).code !== "ENOENT") {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
prev = dir;
|
||||
dir = path.dirname(dir);
|
||||
}
|
||||
for (const p of pending) {
|
||||
cache[p] = res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
guessModuleType.clearCache = function clearCache() {
|
||||
cache = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Import or require the given code from memory. Knows about the different
|
||||
* Peggy output formats. Returns the exports of the module.
|
||||
*
|
||||
* @param {string} code Code to import
|
||||
* @param {FromMemOptions} options Options. Most important is filename.
|
||||
* @returns {Promise<unknown>} The evaluated code.
|
||||
*/
|
||||
async function fromMem(code, options) {
|
||||
options = {
|
||||
format: "commonjs",
|
||||
context: {},
|
||||
includeGlobals: true,
|
||||
globalExport: undefined,
|
||||
lineOffset: 0,
|
||||
columnOffset: 0,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (options.includeGlobals) {
|
||||
options.context = {
|
||||
...globalContext,
|
||||
...options.context,
|
||||
};
|
||||
}
|
||||
|
||||
// @ts-expect-error Context is always non-null
|
||||
options.context.global = options.context;
|
||||
// @ts-expect-error Context is always non-null
|
||||
options.context.globalThis = options.context;
|
||||
|
||||
if (!options.filename) {
|
||||
throw new TypeError("filename is required");
|
||||
}
|
||||
if (!options.filename.startsWith("file:")) {
|
||||
// File URLs must be already resolved.
|
||||
options.filename = path.resolve(options.filename);
|
||||
}
|
||||
const dirname = path.dirname(options.filename);
|
||||
|
||||
if (options.format === "guess") {
|
||||
options.format = await guessModuleType(options.filename);
|
||||
}
|
||||
switch (options.format) {
|
||||
case "bare":
|
||||
case "cjs":
|
||||
case "commonjs":
|
||||
case "umd":
|
||||
return requireString(code, dirname, options);
|
||||
case "es":
|
||||
case "es6":
|
||||
case "esm":
|
||||
case "module":
|
||||
case "mjs":
|
||||
// Returns promise
|
||||
return importString(code, dirname, options);
|
||||
// I don't care enough about amd and globals to figure out how to load them.
|
||||
default:
|
||||
throw new Error(`Unsupported output format: "${options.format}"`);
|
||||
}
|
||||
}
|
||||
|
||||
fromMem.guessModuleType = guessModuleType;
|
||||
|
||||
module.exports = fromMem;
|
||||
Reference in New Issue
Block a user