Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

node-retrieve-globals

Package Overview
Dependencies
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

node-retrieve-globals - npm Package Compare versions

Comparing version 3.0.1 to 4.0.0

4

package.json
{
"name": "node-retrieve-globals",
"version": "3.0.1",
"version": "4.0.0",
"description": "Execute a string of JavaScript using Node.js and return the global variable values and functions.",

@@ -27,4 +27,4 @@ "type": "module",

"acorn-walk": "^8.2.0",
"esm-import-transformer": "^3.0.0"
"esm-import-transformer": "^3.0.2"
}
}

@@ -5,3 +5,3 @@ # node-retrieve-globals

* Supported on Node.js 14 and newer.
* 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).

@@ -8,0 +8,0 @@ * Async-friendly but synchronous methods are available.

@@ -5,3 +5,7 @@ import vm from "vm";

import { ImportTransformer } from "esm-import-transformer";
import { createRequire, Module } from "module";
// TODO option to change `require` home base
const customRequire = createRequire(import.meta.url);
class RetrieveGlobals {

@@ -36,4 +40,3 @@ constructor(code, options) {

if(this.options.transformEsmImports) {
let it = new ImportTransformer(this.originalCode);
this.code = it.transformToDynamicImport();
this.code = this.transformer.transformToDynamicImport();
} else {

@@ -44,2 +47,9 @@ this.code = this.originalCode;

get transformer() {
if(!this._transformer) {
this._transformer = new ImportTransformer(this.originalCode);
}
return this._transformer;
}
setAcornOptions(acornOptions) {

@@ -60,3 +70,3 @@ this.acornOptions = Object.assign({

static _getProxiedContext(context = {}) {
static _getProxiedContext(context = {}, options = {}) {
return new Proxy(context, {

@@ -68,4 +78,8 @@ get(target, propertyName) {

// Re-use the parent `global` https://nodejs.org/api/globals.html
return global[propertyName] || undefined;
if(options.reuseGlobal && Reflect.has(global, propertyName)) {
return global[propertyName];
}
if(options.addRequire && propertyName === "require") {
return customRequire;
}
}

@@ -103,10 +117,34 @@ });

static _getCode(code, options) {
let { async: isAsync, globalNames } = Object.assign({
let { async: isAsync, globalNames, experimentalModuleApi, data } = Object.assign({
async: true
}, options);
return `(${isAsync ? "async " : ""}function() {
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;
});
}
}
}
let finalCode = `${prefix}(${isAsync ? "async " : ""}function(${argKeys}) {
${code}
${globalNames ? RetrieveGlobals._getGlobalVariablesReturnString(globalNames) : ""}
})();`;
})(${argValues});`;
return finalCode;
}

@@ -119,11 +157,37 @@

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.
// Only use this if the code has `import`:
experimentalModuleApi: this.transformer.hasImports(),
}, options);
if(reuseGlobal) {
data = RetrieveGlobals._getProxiedContext(data || {});
// these things 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,
});
} else {

@@ -134,3 +198,3 @@ data = data || {};

let context;
if(vm.isContext(data)) {
if(experimentalModuleApi || vm.isContext(data)) {
context = data;

@@ -146,3 +210,3 @@ } else {

parseCode = RetrieveGlobals._getCode(this.code, {
async: isAsync
async: isAsync,
}, this.cache);

@@ -201,2 +265,4 @@

globalNames,
experimentalModuleApi,
data: context,
});

@@ -213,2 +279,7 @@

if(experimentalModuleApi) {
let m = new Module();
m._compile(execCode, import.meta.url);
return m.exports;
}
return vm.runInContext(execCode, context, execOptions);

@@ -215,0 +286,0 @@ } catch(e) {

@@ -103,11 +103,2 @@ import test from "ava";

test("dynamic import", 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("global: same console.log", async t => {

@@ -141,2 +132,30 @@ let vm = new RetrieveGlobals(`const b = console.log`);

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);
});
// TODO we detect `await import()` and use `experimentalModuleApi: true`
test.skip("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, {
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 => {

@@ -148,6 +167,69 @@ let vm = new RetrieveGlobals(`import { noop } from "@zachleat/noop";

let ret = await vm.getGlobalContext(undefined, {
dynamicImport: true
// 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";
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 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,
});
await t.throwsAsync(async () => {
let ret = await vm.getGlobalContext({ fn: function() {} }, {
// experimentalModuleApi: true, // implied true
});
});
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc