Initial commit
This commit is contained in:
23
node_modules/node-retrieve-globals/.github/workflows/ci.yml
generated
vendored
Normal file
23
node_modules/node-retrieve-globals/.github/workflows/ci.yml
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- "gh-pages"
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
|
||||
node: ["16", "18", "20"]
|
||||
name: Node.js ${{ matrix.node }} on ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
# cache: npm
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
env:
|
||||
YARN_GPG: no
|
21
node_modules/node-retrieve-globals/LICENSE
generated
vendored
Normal file
21
node_modules/node-retrieve-globals/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Zach Leatherman @zachleat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
91
node_modules/node-retrieve-globals/README.md
generated
vendored
Normal file
91
node_modules/node-retrieve-globals/README.md
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
# node-retrieve-globals
|
||||
|
||||
Execute a string of JavaScript using Node.js and return the global variable values and functions.
|
||||
|
||||
* Supported on Node.js 16 and newer.
|
||||
* Uses `var`, `let`, `const`, `function`, Array and Object [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).
|
||||
* Async-only as of v5.0.
|
||||
* Can return any valid JS data type (including functions).
|
||||
* Can provide an external data object as context to the local execution scope
|
||||
* Transforms ESM import statements to work with current CommonJS limitations in Node’s `vm`.
|
||||
* Uses [Node’s `vm` module to execute JavaScript](https://nodejs.org/api/vm.html#vmruninthiscontextcode-options)
|
||||
* ⚠️ The `node:vm` module is not a security mechanism. Do not use it to run untrusted code.
|
||||
* `codeGeneration` (e.g. `eval`) is disabled by default; use `setCreateContextOptions({codeGeneration: { strings: true, wasm: true } })` to re-enable.
|
||||
* Works _with or without_ `--experimental-vm-modules` flag (for `vm.Module` support). _(v5.0.0 and newer)_
|
||||
* Future-friendly feature tests for when `vm.Module` is stable and `--experimental-vm-modules` is no longer necessary. _(v5.0.0 and newer)_
|
||||
* In use on:
|
||||
* [JavaScript in Eleventy Front Matter](https://www.11ty.dev/docs/data-frontmatter-customize/#example-use-javascript-in-your-front-matter) (and [Demo](https://github.com/11ty/demo-eleventy-js-front-matter))
|
||||
* [WebC’s `<script webc:setup>`](https://www.11ty.dev/docs/languages/webc/#using-javascript-to-setup-your-component-webcsetup)
|
||||
|
||||
## Installation
|
||||
|
||||
Available on [npm](https://www.npmjs.com/package/node-retrieve-globals)
|
||||
|
||||
```
|
||||
npm install node-retrieve-globals
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Works from Node.js with ESM and CommonJS:
|
||||
|
||||
```js
|
||||
import { RetrieveGlobals } from "node-retrieve-globals";
|
||||
// const { RetrieveGlobals } = await import("node-retrieve-globals");
|
||||
```
|
||||
|
||||
And then:
|
||||
|
||||
```js
|
||||
let code = `var a = 1;
|
||||
const b = "hello";
|
||||
|
||||
function hello() {}`;
|
||||
|
||||
let vm = new RetrieveGlobals(code);
|
||||
|
||||
await vm.getGlobalContext();
|
||||
```
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ a: 1, b: "hello", hello: function hello() {} }
|
||||
```
|
||||
|
||||
### Pass in your own Data and reference it in the JavaScript code
|
||||
|
||||
```js
|
||||
let code = `let ref = myData;`;
|
||||
|
||||
let vm = new RetrieveGlobals(code);
|
||||
|
||||
await vm.getGlobalContext({ myData: "hello" });
|
||||
```
|
||||
|
||||
Returns:
|
||||
|
||||
```js
|
||||
{ ref: "hello" }
|
||||
```
|
||||
|
||||
### Advanced options
|
||||
|
||||
```js
|
||||
// Defaults shown
|
||||
let options = {
|
||||
reuseGlobal: false, // re-use Node.js `global`, important if you want `console.log` to log to your console as expected.
|
||||
dynamicImport: false, // allows `import()`
|
||||
addRequire: false, // allows `require()`
|
||||
experimentalModuleApi: false, // uses Module#_compile instead of `vm` (you probably don’t want this and it is bypassed by default when vm.Module is supported)
|
||||
};
|
||||
|
||||
await vm.getGlobalContext({}, options);
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
* `v6.0.0` Changes `import` and `require` to be project relative (not relative to this package on the file system).
|
||||
* `v5.0.0` Removes sync API, swap to async-only. Better compatibility with `--experimental-vm-modules` Node flag.
|
||||
* `v4.0.0` Swap to use `Module._compile` as a workaround for #2 (Node regression with experimental modules API in Node v20.10+)
|
||||
* `v3.0.0` ESM-only package. Node 16+
|
30
node_modules/node-retrieve-globals/package.json
generated
vendored
Normal file
30
node_modules/node-retrieve-globals/package.json
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "node-retrieve-globals",
|
||||
"version": "6.0.0",
|
||||
"description": "Execute a string of JavaScript using Node.js and return the global variable values and functions.",
|
||||
"type": "module",
|
||||
"main": "retrieveGlobals.js",
|
||||
"scripts": {
|
||||
"test": "npx ava && cross-env NODE_OPTIONS='--experimental-vm-modules' npx ava"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zachleat/node-retrieve-globals.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Zach Leatherman",
|
||||
"email": "zachleatherman@gmail.com",
|
||||
"url": "https://zachleat.com/"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@zachleat/noop": "^1.0.3",
|
||||
"ava": "^6.1.2",
|
||||
"cross-env": "^7.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": "^8.1.3",
|
||||
"acorn-walk": "^8.3.2",
|
||||
"esm-import-transformer": "^3.0.2"
|
||||
}
|
||||
}
|
374
node_modules/node-retrieve-globals/retrieveGlobals.js
generated
vendored
Normal file
374
node_modules/node-retrieve-globals/retrieveGlobals.js
generated
vendored
Normal file
@@ -0,0 +1,374 @@
|
||||
import vm from "vm";
|
||||
import * as acorn from "acorn";
|
||||
import * as walk from "acorn-walk";
|
||||
import { ImportTransformer } from "esm-import-transformer";
|
||||
import { createRequire, Module } from "module";
|
||||
|
||||
import { getWorkingDirectory } from "./util/getWorkingDirectory.js";
|
||||
import { isSupported } from "./util/vmModules.js";
|
||||
|
||||
const IS_VM_MODULES_SUPPORTED = isSupported();
|
||||
|
||||
// `import` and `require` should both be relative to working directory (not this file)
|
||||
const WORKING_DIRECTORY = getWorkingDirectory();
|
||||
|
||||
// TODO (feature) option to change `require` home base
|
||||
const customRequire = createRequire(WORKING_DIRECTORY);
|
||||
|
||||
class RetrieveGlobals {
|
||||
constructor(code, options) {
|
||||
this.originalCode = code;
|
||||
|
||||
// backwards compat
|
||||
if(typeof options === "string") {
|
||||
options = {
|
||||
filePath: options
|
||||
};
|
||||
}
|
||||
|
||||
this.options = Object.assign({
|
||||
filePath: null,
|
||||
transformEsmImports: false,
|
||||
}, options);
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
// Override: no code transformations if vm.Module works
|
||||
this.options.transformEsmImports = false;
|
||||
}
|
||||
|
||||
// set defaults
|
||||
let acornOptions = {};
|
||||
if(IS_VM_MODULES_SUPPORTED || this.options.transformEsmImports) {
|
||||
acornOptions.sourceType = "module";
|
||||
}
|
||||
|
||||
this.setAcornOptions(acornOptions);
|
||||
this.setCreateContextOptions();
|
||||
|
||||
// transform `import ___ from ___` to `const ___ = await import(___)` to emulate *some* import syntax.
|
||||
// Doesn’t currently work with aliases (mod as name) or namespaced imports (* as name).
|
||||
if(this.options.transformEsmImports) {
|
||||
this.code = this.transformer.transformToDynamicImport();
|
||||
} else {
|
||||
this.code = this.originalCode;
|
||||
}
|
||||
}
|
||||
|
||||
get transformer() {
|
||||
if(!this._transformer) {
|
||||
this._transformer = new ImportTransformer(this.originalCode);
|
||||
}
|
||||
return this._transformer;
|
||||
}
|
||||
|
||||
setAcornOptions(acornOptions) {
|
||||
this.acornOptions = Object.assign({
|
||||
ecmaVersion: "latest",
|
||||
}, acornOptions );
|
||||
}
|
||||
|
||||
setCreateContextOptions(contextOptions) {
|
||||
this.createContextOptions = Object.assign({
|
||||
codeGeneration: {
|
||||
strings: false,
|
||||
wasm: false,
|
||||
}
|
||||
}, contextOptions );
|
||||
}
|
||||
|
||||
static _getProxiedContext(context = {}, options = {}) {
|
||||
return new Proxy(context, {
|
||||
get(target, propertyName) {
|
||||
if(Reflect.has(target, propertyName)) {
|
||||
return Reflect.get(target, propertyName);
|
||||
}
|
||||
|
||||
if(options.reuseGlobal && Reflect.has(global, propertyName)) {
|
||||
return global[propertyName];
|
||||
}
|
||||
if(options.addRequire && propertyName === "require") {
|
||||
return customRequire;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// We prune function and variable declarations that aren’t globally declared
|
||||
// (our acorn walker could be improved to skip non-global declarations, but this method is easier for now)
|
||||
static _getGlobalVariablesReturnString(names, mode = "cjs") {
|
||||
let s = [`let __globals = {};`];
|
||||
for(let name of names) {
|
||||
s.push(`if( typeof ${name} !== "undefined") { __globals.${name} = ${name}; }`);
|
||||
}
|
||||
return `${s.join("\n")};${mode === "esm" ? "\nexport default __globals;" : "return __globals;"}`
|
||||
}
|
||||
|
||||
_setContextPrototype(context) {
|
||||
// Context will fail isPlainObject and won’t be merged in the data cascade properly without this prototype set
|
||||
// See https://github.com/11ty/eleventy-utils/blob/main/src/IsPlainObject.js
|
||||
if(!context || typeof context !== "object" || Array.isArray(context)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Object.getPrototypeOf(context).isPrototypeOf(Object.create({}))) {
|
||||
Object.setPrototypeOf(context, Object.prototype);
|
||||
|
||||
// Go deep
|
||||
for(let key in context) {
|
||||
this._setContextPrototype(context[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_getCode(code, options) {
|
||||
let { async: isAsync, globalNames, experimentalModuleApi, data } = Object.assign({
|
||||
async: true
|
||||
}, options);
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
return `${code}
|
||||
|
||||
${globalNames ? RetrieveGlobals._getGlobalVariablesReturnString(globalNames, "esm") : ""}`;
|
||||
}
|
||||
|
||||
let prefix = [];
|
||||
let argKeys = "";
|
||||
let argValues = "";
|
||||
|
||||
// Don’t use this when vm.Module is stable (or if the code doesn’t have any imports!)
|
||||
if(experimentalModuleApi) {
|
||||
prefix = "module.exports = ";
|
||||
|
||||
if(typeof data === "object") {
|
||||
let dataKeys = Object.keys(data);
|
||||
if(dataKeys) {
|
||||
argKeys = `{${dataKeys.join(",")}}`;
|
||||
argValues = JSON.stringify(data, function replacer(key, value) {
|
||||
if(typeof value === "function") {
|
||||
throw new Error(`When using \`experimentalModuleApi\`, context data must be JSON.stringify friendly. The "${key}" property was type \`function\`.`);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return `${prefix}(${isAsync ? "async " : ""}function(${argKeys}) {
|
||||
${code}
|
||||
${globalNames ? RetrieveGlobals._getGlobalVariablesReturnString(globalNames, "cjs") : ""}
|
||||
})(${argValues});`;
|
||||
}
|
||||
|
||||
getGlobalNames(parsedAst) {
|
||||
let globalNames = new Set();
|
||||
|
||||
let types = {
|
||||
FunctionDeclaration(node) {
|
||||
globalNames.add(node.id.name);
|
||||
},
|
||||
VariableDeclarator(node) {
|
||||
// destructuring assignment Array
|
||||
if(node.id.type === "ArrayPattern") {
|
||||
for(let prop of node.id.elements) {
|
||||
if(prop.type === "Identifier") {
|
||||
globalNames.add(prop.name);
|
||||
}
|
||||
}
|
||||
} else if(node.id.type === "ObjectPattern") {
|
||||
// destructuring assignment Object
|
||||
for(let prop of node.id.properties) {
|
||||
if(prop.type === "Property") {
|
||||
globalNames.add(prop.value.name);
|
||||
}
|
||||
}
|
||||
} else if(node.id.name) {
|
||||
globalNames.add(node.id.name);
|
||||
}
|
||||
},
|
||||
// if imports aren’t being transformed to variables assignment, we need those too
|
||||
ImportSpecifier(node) {
|
||||
globalNames.add(node.imported.name);
|
||||
}
|
||||
};
|
||||
|
||||
walk.simple(parsedAst, types);
|
||||
|
||||
return globalNames;
|
||||
}
|
||||
|
||||
_getParseError(code, err) {
|
||||
// Acorn parsing error on script
|
||||
let metadata = [];
|
||||
if(this.options.filePath) {
|
||||
metadata.push(`file: ${this.options.filePath}`);
|
||||
}
|
||||
if(err?.loc?.line) {
|
||||
metadata.push(`line: ${err.loc.line}`);
|
||||
}
|
||||
if(err?.loc?.column) {
|
||||
metadata.push(`column: ${err.loc.column}`);
|
||||
}
|
||||
|
||||
return new Error(`Had trouble parsing with "acorn"${metadata.length ? ` (${metadata.join(", ")})` : ""}:
|
||||
Message: ${err.message}
|
||||
|
||||
${code}`);
|
||||
}
|
||||
|
||||
async _getGlobalContext(data, options) {
|
||||
let {
|
||||
async: isAsync,
|
||||
reuseGlobal,
|
||||
dynamicImport,
|
||||
addRequire,
|
||||
experimentalModuleApi,
|
||||
} = Object.assign({
|
||||
// defaults
|
||||
async: true,
|
||||
|
||||
reuseGlobal: false,
|
||||
|
||||
// adds support for `require`
|
||||
addRequire: false,
|
||||
|
||||
// allows dynamic import in `vm` (requires --experimental-vm-modules in Node v20.10+)
|
||||
// https://github.com/nodejs/node/issues/51154
|
||||
// TODO Another workaround possibility: We could use `import` outside of `vm` and inject the dependencies into context `data`
|
||||
dynamicImport: false,
|
||||
|
||||
// Use Module._compile instead of vm
|
||||
// Workaround for: https://github.com/zachleat/node-retrieve-globals/issues/2
|
||||
// Warning: This method requires input `data` to be JSON stringify friendly.
|
||||
// Don’t use this if vm.Module is supported
|
||||
// Don’t use this if the code does not contain `import`s
|
||||
experimentalModuleApi: !IS_VM_MODULES_SUPPORTED && this.transformer.hasImports(),
|
||||
}, options);
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
// Override: don’t use this when modules are allowed.
|
||||
experimentalModuleApi = false;
|
||||
}
|
||||
|
||||
// These options are already supported by Module._compile
|
||||
if(experimentalModuleApi) {
|
||||
addRequire = false;
|
||||
dynamicImport = false;
|
||||
}
|
||||
|
||||
if(reuseGlobal || addRequire) {
|
||||
// Re-use the parent `global` https://nodejs.org/api/globals.html
|
||||
data = RetrieveGlobals._getProxiedContext(data || {}, {
|
||||
reuseGlobal,
|
||||
addRequire,
|
||||
});
|
||||
}
|
||||
|
||||
if(!data) {
|
||||
data = {};
|
||||
}
|
||||
|
||||
let context;
|
||||
if(experimentalModuleApi || vm.isContext(data)) {
|
||||
context = data;
|
||||
} else {
|
||||
context = vm.createContext(data, this.createContextOptions);
|
||||
}
|
||||
|
||||
let parseCode;
|
||||
let globalNames;
|
||||
|
||||
try {
|
||||
parseCode = this._getCode(this.code, {
|
||||
async: isAsync,
|
||||
});
|
||||
|
||||
let parsedAst = acorn.parse(parseCode, this.acornOptions);
|
||||
globalNames = this.getGlobalNames(parsedAst);
|
||||
} catch(e) {
|
||||
throw this._getParseError(parseCode, e);
|
||||
}
|
||||
|
||||
try {
|
||||
let execCode = this._getCode(this.code, {
|
||||
async: isAsync,
|
||||
globalNames,
|
||||
experimentalModuleApi,
|
||||
data: context,
|
||||
});
|
||||
|
||||
if(experimentalModuleApi) {
|
||||
let m = new Module();
|
||||
m._compile(execCode, WORKING_DIRECTORY);
|
||||
return m.exports;
|
||||
}
|
||||
|
||||
let execOptions = {};
|
||||
if(dynamicImport) {
|
||||
// Warning: this option is part of the experimental modules API
|
||||
execOptions.importModuleDynamically = (specifier) => import(specifier);
|
||||
}
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
// options.initializeImportMeta
|
||||
let m = new vm.SourceTextModule(execCode, {
|
||||
context,
|
||||
initializeImportMeta: (meta, module) => {
|
||||
meta.url = this.options.filePath || WORKING_DIRECTORY || module.identifier;
|
||||
},
|
||||
...execOptions,
|
||||
});
|
||||
|
||||
// Thank you! https://stackoverflow.com/a/73282303/16711
|
||||
await m.link(async (specifier, referencingModule) => {
|
||||
const mod = await import(specifier);
|
||||
const exportNames = Object.keys(mod);
|
||||
return new vm.SyntheticModule(
|
||||
exportNames,
|
||||
function () {
|
||||
exportNames.forEach(key => {
|
||||
this.setExport(key, mod[key])
|
||||
});
|
||||
},
|
||||
{
|
||||
identifier: specifier,
|
||||
context: referencingModule.context
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
await m.evaluate();
|
||||
|
||||
// TODO (feature) incorporate other esm `exports` here
|
||||
return m.namespace.default;
|
||||
}
|
||||
|
||||
return vm.runInContext(execCode, context, execOptions);
|
||||
} catch(e) {
|
||||
let type = "cjs";
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
type = "esm";
|
||||
} else if(experimentalModuleApi) {
|
||||
type = "cjs-experimental";
|
||||
}
|
||||
|
||||
throw new Error(`Had trouble executing Node script (type: ${type}):
|
||||
Message: ${e.message}
|
||||
|
||||
${this.code}`);
|
||||
}
|
||||
}
|
||||
|
||||
async getGlobalContext(data, options) {
|
||||
let ret = await this._getGlobalContext(data, Object.assign({
|
||||
// whether or not the target code is executed asynchronously
|
||||
// note that vm.Module will always be async-friendly
|
||||
async: true,
|
||||
}, options));
|
||||
|
||||
this._setContextPrototype(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
export { RetrieveGlobals };
|
270
node_modules/node-retrieve-globals/test/test.js
generated
vendored
Normal file
270
node_modules/node-retrieve-globals/test/test.js
generated
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
import test from "ava";
|
||||
import { RetrieveGlobals } from "../retrieveGlobals.js";
|
||||
import { isSupported } from "../util/vmModules.js";
|
||||
import { getWorkingDirectory } from "../util/getWorkingDirectory.js";
|
||||
|
||||
const IS_VM_MODULES_SUPPORTED = isSupported();
|
||||
|
||||
test("var", async t => {
|
||||
let vm = new RetrieveGlobals(`var a = 1;`);
|
||||
t.deepEqual(await vm.getGlobalContext(), { a: 1 });
|
||||
});
|
||||
|
||||
test("isPlainObject", async t => {
|
||||
// from eleventy-utils
|
||||
function isPlainObject(value) {
|
||||
if (value === null || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
let proto = Object.getPrototypeOf(value);
|
||||
return !proto || proto === Object.prototype;
|
||||
};
|
||||
|
||||
let vm = new RetrieveGlobals("var a = 1;");
|
||||
t.true(isPlainObject(await vm.getGlobalContext()));
|
||||
});
|
||||
|
||||
test("isPlainObject deep", async t => {
|
||||
// from eleventy-utils
|
||||
function isPlainObject(value) {
|
||||
if (value === null || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
let proto = Object.getPrototypeOf(value);
|
||||
return !proto || proto === Object.prototype;
|
||||
};
|
||||
|
||||
let vm = new RetrieveGlobals("var a = { b: 1, c: { d: {} } };");
|
||||
let obj = await vm.getGlobalContext();
|
||||
t.true(isPlainObject(obj.a.c));
|
||||
t.true(isPlainObject(obj.a.c.d));
|
||||
});
|
||||
|
||||
test("isPlainObject deep circular", async t => {
|
||||
// from eleventy-utils
|
||||
function isPlainObject(value) {
|
||||
if (value === null || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
let proto = Object.getPrototypeOf(value);
|
||||
return !proto || proto === Object.prototype;
|
||||
};
|
||||
|
||||
let vm = new RetrieveGlobals(`
|
||||
var a = { a: 1 };
|
||||
var b = { b: a };
|
||||
a.b = b;
|
||||
`);
|
||||
let obj = await vm.getGlobalContext();
|
||||
t.true(isPlainObject(obj.a.b));
|
||||
t.true(isPlainObject(obj.b.b));
|
||||
});
|
||||
|
||||
|
||||
test("var with data", async t => {
|
||||
let vm = new RetrieveGlobals("var a = b;");
|
||||
t.deepEqual(await vm.getGlobalContext({ b: 2 }), { a: 2 });
|
||||
});
|
||||
|
||||
test("let with data", async t => {
|
||||
let vm = new RetrieveGlobals("let a = b;");
|
||||
t.deepEqual(await vm.getGlobalContext({ b: 2 }), { a: 2 });
|
||||
});
|
||||
|
||||
test("const with data", async t => {
|
||||
let vm = new RetrieveGlobals("const a = b;");
|
||||
t.deepEqual(await vm.getGlobalContext({ b: 2 }), { a: 2 });
|
||||
});
|
||||
|
||||
test("function", async t => {
|
||||
let vm = new RetrieveGlobals("function testFunction() {}");
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.true(typeof ret.testFunction === "function");
|
||||
});
|
||||
|
||||
test("async let", async t => {
|
||||
let vm = new RetrieveGlobals(`let b = await Promise.resolve(1);`);
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.deepEqual(ret, { b: 1 });
|
||||
});
|
||||
|
||||
test("destructured assignment via object", async t => {
|
||||
let vm = new RetrieveGlobals(`const { a } = { a: 1 };`);
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.is(typeof ret.a, "number");
|
||||
t.is(ret.a, 1);
|
||||
});
|
||||
|
||||
test("destructured assignment via Array", async t => {
|
||||
let vm = new RetrieveGlobals(`const [a, b] = [1, 2];`);
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.is(typeof ret.a, "number");
|
||||
t.is(typeof ret.b, "number");
|
||||
t.is(ret.a, 1);
|
||||
t.is(ret.b, 2);
|
||||
});
|
||||
|
||||
test("global: same console.log", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = console.log`);
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
reuseGlobal: false
|
||||
});
|
||||
t.not(ret.b, console.log);
|
||||
|
||||
let ret2 = await vm.getGlobalContext(undefined, {
|
||||
reuseGlobal: true
|
||||
});
|
||||
t.is(ret2.b, console.log);
|
||||
});
|
||||
|
||||
test("global: Same URL", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = URL;`);
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
reuseGlobal: true
|
||||
});
|
||||
t.is(ret.b, URL);
|
||||
});
|
||||
|
||||
test("return array", async t => {
|
||||
let vm = new RetrieveGlobals("let b = [1,2,3];");
|
||||
let globals = await vm.getGlobalContext();
|
||||
t.true(Array.isArray(globals.b));
|
||||
t.deepEqual(globals.b, [1,2,3]);
|
||||
});
|
||||
|
||||
test("`require` Compatibility", async t => {
|
||||
let vm = new RetrieveGlobals(`const { noop } = require("@zachleat/noop");
|
||||
const b = 1;`);
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
addRequire: true,
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
t.is(ret.b, 1);
|
||||
});
|
||||
|
||||
// Works with --experimental-vm-modules, remove this when modules are stable
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
test("dynamic import (no code transformation) (requires --experimental-vm-modules in Node v20.10)", async t => {
|
||||
let vm = new RetrieveGlobals(`const { noop } = await import("@zachleat/noop");`);
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
dynamicImport: true
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
});
|
||||
}
|
||||
|
||||
test("dynamic import (no code transformation) (experimentalModuleApi explicit true)", async t => {
|
||||
let vm = new RetrieveGlobals(`const { noop } = await import("@zachleat/noop");`);
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
dynamicImport: true, // irrelevant for fallback case, important for --experimental-vm-modules support case
|
||||
experimentalModuleApi: true, // Needs to be true here because there are no top level `import`
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
});
|
||||
|
||||
// This would require --experimental-vm-modules in Node v20.10, but instead falls back to `experimentalModuleApi` automatically
|
||||
test("ESM import", async t => {
|
||||
let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";
|
||||
const b = 1;`, {
|
||||
transformEsmImports: true,
|
||||
});
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
// experimentalModuleApi: true, // implied
|
||||
dynamicImport: true,
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
t.is(ret.b, 1);
|
||||
});
|
||||
|
||||
// This would require --experimental-vm-modules in Node v20.10, but instead falls back to `experimentalModuleApi` automatically
|
||||
test("ESM import (experimentalModuleApi implied true)", async t => {
|
||||
let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";
|
||||
const b = 1;`, {
|
||||
transformEsmImports: true,
|
||||
});
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
// experimentalModuleApi: true,
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
t.is(ret.b, 1);
|
||||
});
|
||||
|
||||
// This would require --experimental-vm-modules in Node v20.10, but instead falls back to `experimentalModuleApi` automatically
|
||||
test("ESM import (experimentalModuleApi explicit true)", async t => {
|
||||
// let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";
|
||||
let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";
|
||||
const b = 1;`, {
|
||||
transformEsmImports: true, // overridden to false when --experimental-vm-modules
|
||||
});
|
||||
let ret = await vm.getGlobalContext(undefined, {
|
||||
experimentalModuleApi: true, // overridden to false when --experimental-vm-modules
|
||||
});
|
||||
t.is(typeof ret.noop, "function");
|
||||
t.is(ret.b, 1);
|
||||
});
|
||||
|
||||
// This does not require --experimental-vm-modules in Node v20.10+ as it has no imports
|
||||
test("No imports, with data", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = inputData;`, {
|
||||
transformEsmImports: true,
|
||||
});
|
||||
let ret = await vm.getGlobalContext({ inputData: "hi" }, {
|
||||
// experimentalModuleApi: true, // implied false
|
||||
});
|
||||
|
||||
t.is(ret.b, "hi");
|
||||
});
|
||||
|
||||
// This does not require --experimental-vm-modules in Node v20.10+ as it has no imports
|
||||
test("No imports, with JSON unfriendly data", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = fn;`, {
|
||||
transformEsmImports: true,
|
||||
});
|
||||
let ret = await vm.getGlobalContext({ fn: function() {} }, {
|
||||
// experimentalModuleApi: true, // implied false
|
||||
});
|
||||
t.is(typeof ret.b, "function");
|
||||
});
|
||||
|
||||
// This requires --experimental-vm-modules in Node v20.10+ and uses the experimentalModuleApi because it has imports
|
||||
test("With imports, with JSON unfriendly data", async t => {
|
||||
let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";
|
||||
const b = fn;`, {
|
||||
transformEsmImports: true,
|
||||
});
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
// Works fine with --experimental-vm-modules
|
||||
let ret = await vm.getGlobalContext({ fn: function() {} }, {
|
||||
// experimentalModuleApi: true, // implied false
|
||||
});
|
||||
t.is(typeof ret.b, "function");
|
||||
} else {
|
||||
// This throws if --experimental-vm-modules not set
|
||||
await t.throwsAsync(async () => {
|
||||
let ret = await vm.getGlobalContext({ fn: function() {} }, {
|
||||
// experimentalModuleApi: true, // implied true
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(IS_VM_MODULES_SUPPORTED) {
|
||||
test("import.meta.url works", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = import.meta.url;`, {
|
||||
filePath: import.meta.url
|
||||
});
|
||||
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.is(ret.b, import.meta.url);
|
||||
});
|
||||
|
||||
test("import.meta.url has the current working directory (if not passed via filePath)", async t => {
|
||||
let vm = new RetrieveGlobals(`const b = import.meta.url;`, {
|
||||
// filePath: import.meta.url
|
||||
});
|
||||
|
||||
let ret = await vm.getGlobalContext();
|
||||
t.is(ret.b, getWorkingDirectory());
|
||||
});
|
||||
}
|
18
node_modules/node-retrieve-globals/util/getWorkingDirectory.js
generated
vendored
Normal file
18
node_modules/node-retrieve-globals/util/getWorkingDirectory.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
function addTrailingSlash(path) {
|
||||
if(path.endsWith("/")) {
|
||||
return path;
|
||||
}
|
||||
return path + "/";
|
||||
}
|
||||
|
||||
|
||||
function getWorkingDirectory() {
|
||||
// Trailing slash required
|
||||
// `import` and `require` should both be relative to working directory (not this file)
|
||||
return addTrailingSlash(pathToFileURL(path.resolve(".")).toString());
|
||||
}
|
||||
|
||||
export { getWorkingDirectory };
|
23
node_modules/node-retrieve-globals/util/vmModules.js
generated
vendored
Normal file
23
node_modules/node-retrieve-globals/util/vmModules.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import vm from "vm";
|
||||
|
||||
function isSupported() {
|
||||
// node --experimental-vm-modules …
|
||||
if(process.execArgv.find(entry => entry == "--experimental-vm-modules")) {
|
||||
return true;
|
||||
}
|
||||
// NODE_OPTIONS='--experimental-vm-modules' node …
|
||||
if((process.env?.NODE_OPTIONS || "").split(" ").find(entry => entry == "--experimental-vm-modules")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Feature test for a future when --experimental-vm-modules is not needed
|
||||
// and vm.Module is stable:
|
||||
try {
|
||||
new vm.SourceTextModule(`/* hi */`);
|
||||
return true;
|
||||
} catch(e) {}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
export { isSupported };
|
Reference in New Issue
Block a user