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

module-from-string

Package Overview
Dependencies
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

module-from-string - npm Package Compare versions

Comparing version 3.1.4 to 3.2.0-0

103

__tests__/cjs/import.test.ts
import path from 'path'
import { importFromString, importFromStringSync } from '../../src/index'
describe('importFromString', () => {
let importFromStringFn: typeof importFromString | typeof importFromStringSync
const testImport = (): void => {
it('should work with named export', async () => {
const res = await importFromString("export const greet = 'hi'")
const res = await importFromStringFn("export const greet = 'hi'")
expect(res.greet).toBe('hi')

@@ -11,3 +13,3 @@ })

it('should work with default export', async () => {
const res = await importFromString("export default 'hi'")
const res = await importFromStringFn("export default 'hi'")
expect(res.default).toBe('hi')

@@ -18,3 +20,3 @@ })

const modulePath = './fixtures/namedExport.js'
const res = await importFromString(`export { greet } from '${modulePath}'`)
const res = await importFromStringFn(`export { greet } from '${modulePath}'`)
expect(res.greet).toBe('hi')

@@ -25,3 +27,3 @@ })

const modulePath = './cjs/fixtures/defaultExport.js'
const res = await importFromString(`import greet from '${modulePath}'; export default greet`, {
const res = await importFromStringFn(`import greet from '${modulePath}';export default greet`, {
dirname: path.dirname(__dirname)

@@ -34,3 +36,3 @@ })

const modulePath = path.join(__dirname, 'fixtures/namedExport.js')
const res = await importFromString(`export { greet } from '${modulePath}'`)
const res = await importFromStringFn(`export { greet } from '${modulePath}'`)
expect(res.greet).toBe('hi')

@@ -44,3 +46,3 @@ })

`
const res = await importFromString(code)
const res = await importFromStringFn(code)
expect(res.default).toMatchInlineSnapshot(`

@@ -55,62 +57,55 @@ "var Greet = /* @__PURE__ */ ((Greet2) => {

it('should work if transformOption is provided', async () => {
const res = await importFromString("export const greet: () => string = () => 'hi'", {
transformOptions: { loader: 'ts' }
})
expect(res.greet()).toBe('hi')
it('should be able to access __dirname and __filename', () => {
const res = importFromStringSync(`
export const dirname = __dirname
export const filename = __filename
`)
expect(res.dirname).toBe(__dirname)
expect(res.filename).toMatch(__dirname)
})
})
describe('importFromStringSync', () => {
it('should work with named export', () => {
const res = importFromStringSync("export const greet = 'hi'")
it('should have access the global object', async () => {
const res = await importFromStringFn('export const { greet } = global', {
globals: { greet: 'hi' }
})
expect(res.greet).toBe('hi')
})
it('should work with default export', () => {
const res = importFromStringSync("export default 'hi'")
expect(res.default).toBe('hi')
it('should work with current global', async () => {
const res = await importFromStringFn('export default new Error()', {
useCurrentGlobal: true
})
expect(res.default).toBeInstanceOf(Error)
})
it('should work with relative path import', () => {
const modulePath = './fixtures/namedExport.js'
const res = importFromStringSync(`export { greet } from '${modulePath}'`)
expect(res.greet).toBe('hi')
})
it('should resolve correctly if option `dirname` is provided', () => {
const modulePath = './cjs/fixtures/defaultExport.js'
const res = importFromStringSync(`import greet from '${modulePath}'; export default greet`, {
dirname: path.dirname(__dirname)
it('should work if transformOption is provided', async () => {
const res = await importFromStringFn("export const greet: () => string = () => 'hi'", {
transformOptions: { loader: 'ts' }
})
expect(res.default).toBe('hi')
expect(res.greet()).toBe('hi')
})
it('should work with absolute path import', () => {
const modulePath = path.join(__dirname, 'fixtures/namedExport.js')
const res = importFromStringSync(`export { greet } from '${modulePath}'`)
expect(res.greet).toBe('hi')
it('should be able to override default shims', async () => {
const relativeModulePath = './fixtures/namedExport.js'
const modulePath = path.join(__dirname, relativeModulePath)
const res = await importFromStringFn(
`export default import.meta.resolve("${relativeModulePath}")`,
{
transformOptions: {
banner: 'var import_meta_resolve = require.resolve;'
}
}
)
expect(res.default).toBe(modulePath)
})
}
it('should work with import external module', () => {
const code = `import { transformSync } from 'esbuild'
const { code } = transformSync('enum Greet { Hi }', { loader: 'ts' })
export default code
`
const res = importFromStringSync(code)
expect(res.default).toMatchInlineSnapshot(`
"var Greet = /* @__PURE__ */ ((Greet2) => {
Greet2[Greet2[\\"Hi\\"] = 0] = \\"Hi\\";
return Greet2;
})(Greet || {});
"
`)
})
describe('importFromString', () => {
importFromStringFn = importFromString
testImport()
})
it('should work if transformOption is provided', () => {
const res = importFromStringSync("export const greet: () => string = () => 'hi'", {
transformOptions: { loader: 'ts' }
})
expect(res.greet()).toBe('hi')
})
describe('importFromStringSync', () => {
importFromStringFn = importFromStringSync
testImport()
})

@@ -15,3 +15,3 @@ import path from 'path'

it('should work with relative path import', () => {
it('should work with relative path require', () => {
const modulePath = './fixtures/defaultExport.js'

@@ -30,3 +30,3 @@ const res = requireFromString(`module.exports = require('${modulePath}')`)

it('should work with absolute path import', () => {
it('should work with absolute path require', () => {
const modulePath = path.join(__dirname, 'fixtures/defaultExport.js')

@@ -58,1 +58,15 @@ const res = requireFromString(`module.exports = require('${modulePath}')`)

})
it('should have access the global object', () => {
const res = requireFromString('module.exports = global.hi', {
globals: { hi: 'hi' }
})
expect(res).toBe('hi')
})
it('should work with current global', () => {
const res = requireFromString('module.exports = new Error()', {
useCurrentGlobal: true
})
expect(res).toBeInstanceOf(Error)
})

@@ -5,3 +5,3 @@ import path from 'path'

const __dirname = path.dirname(fileURLToPath(new URL(import.meta.url)))
const __dirname = path.dirname(fileURLToPath(import.meta.url))

@@ -60,2 +60,30 @@ describe('importFromString', () => {

it('should be able to access __dirname and __filename', () => {
const res = importFromStringSync(`
export const dirname = __dirname
export const filename = __filename
`)
expect(res.dirname).toBe(__dirname)
expect(res.filename).toMatch(__dirname)
})
it('should be able to access import.meta.url', async () => {
const res = await importFromString('export const { url } = import.meta')
expect(res.url).toMatch(`file://${__dirname}`)
})
it('should have access the global object', async () => {
const res = await importFromString('export const { greet } = global', {
globals: { greet: 'hi' }
})
expect(res.greet).toBe('hi')
})
it('should work with current global', async () => {
const res = await importFromString('export default new Error()', {
useCurrentGlobal: true
})
expect(res.default).toBeInstanceOf(Error)
})
it('should work if transformOption is provided', async () => {

@@ -67,7 +95,2 @@ const res = await importFromString("export default function(): string { return 'hi' }", {

})
it('should be able to access import.meta.url', async () => {
const res = await importFromString('export const { url } = import.meta')
expect(res.url).toMatch(`file://${__dirname}`)
})
})

@@ -74,0 +97,0 @@

@@ -18,3 +18,3 @@ import path from 'path'

it('should work with relative path import', () => {
it('should work with relative path require', () => {
const modulePath = '../cjs/fixtures/defaultExport.js'

@@ -33,3 +33,3 @@ const res = requireFromString(`module.exports = require('${modulePath}')`)

it('should work with absolute path import', () => {
it('should work with absolute path require', () => {
const modulePath = path.join(__dirname, '../cjs/fixtures/defaultExport.js')

@@ -61,1 +61,15 @@ const res = requireFromString(`module.exports = require('${modulePath}')`)

})
it('should have access the global object', () => {
const res = requireFromString('module.exports = global.hi', {
globals: { hi: 'hi' }
})
expect(res).toBe('hi')
})
it('should work with current global', () => {
const res = requireFromString('module.exports = new Error()', {
useCurrentGlobal: true
})
expect(res).toBeInstanceOf(Error)
})
module.exports = {
extends: ['./node_modules/ts-standardx/.eslintrc.js'],
ignorePatterns: ['dist/*']
ignorePatterns: ['dist/**/*'],
overrides: [
{
files: ['src/**/*.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'off'
}
}
]
}

@@ -0,1 +1,3 @@

/// <reference types="node" />
import { Context } from 'vm';
import { TransformOptions } from 'esbuild';

@@ -5,5 +7,7 @@

dirname?: string;
globals?: Record<string, unknown>;
globals?: Context;
useCurrentGlobal?: boolean;
}
declare const requireFromString: (code: string, { dirname, globals }?: Options) => any;
declare const requireFromString: (code: string, { dirname, globals, useCurrentGlobal }?: Options) => any;
declare const createRequireFromString: (options?: Options | undefined) => (code: string) => any;

@@ -13,5 +17,7 @@ interface ImportOptions extends Options {

}
declare const importFromString: (code: string, { dirname, globals, transformOptions }?: ImportOptions) => Promise<any>;
declare const importFromStringSync: (code: string, { dirname, globals, transformOptions }?: ImportOptions) => any;
declare const importFromString: (code: string, { transformOptions, ...commonOptions }?: ImportOptions) => Promise<any>;
declare const createImportFromString: (options?: ImportOptions | undefined) => (code: string) => Promise<any>;
declare const importFromStringSync: (code: string, { transformOptions, ...commonOptions }?: ImportOptions) => any;
declare const createImportFromStringSync: (options?: ImportOptions | undefined) => (code: string) => any;
export { ImportOptions, Options, importFromString, importFromStringSync, requireFromString };
export { ImportOptions, Options, createImportFromString, createImportFromStringSync, createRequireFromString, importFromString, importFromStringSync, requireFromString };

@@ -21,15 +21,24 @@ "use strict";

var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
Object.defineProperty(exports, "__esModule", { value: true });
var module$1 = require("module");
var path = require("path");
var vm = require("vm");
var nanoid = require("nanoid");
var url = require("url");
var esbuild = require("esbuild");
function _interopDefaultLegacy(e) {
return e && typeof e === "object" && "default" in e ? e : { "default": e };
}
var path__default = /* @__PURE__ */ _interopDefaultLegacy(path);
var vm__default = /* @__PURE__ */ _interopDefaultLegacy(vm);
var url__default = /* @__PURE__ */ _interopDefaultLegacy(url);
const module$1 = require("module");
const path = require("path");
const vm = require("vm");
const nanoid = require("nanoid");
const url = require("url");
const esbuild = require("esbuild");
const async = require("nanoid/async");
const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
const vm__default = /* @__PURE__ */ _interopDefaultLegacy(vm);
const isInESModuleScope = () => {

@@ -42,11 +51,12 @@ try {

};
const isVMModuleAvailable = () => vm__default["default"].Module !== void 0;
const isVMModuleAvailable = () => vm__default.default.Module !== void 0;
const FILE_URL_SCHEME = "file:";
const fileURLToPath = (value) => value.startsWith(FILE_URL_SCHEME) ? url__default["default"].fileURLToPath(value) : value;
const pathToFileURL = (value) => (value.startsWith(FILE_URL_SCHEME) ? new URL(value) : url__default["default"].pathToFileURL(value)).href;
const FUNCTION_NAMES = [
const isFileURL = (value) => value.startsWith(FILE_URL_SCHEME);
const fileURLStringToPath = (value) => isFileURL(value) ? url.fileURLToPath(value) : value;
const pathToFileURLString = (value) => (isFileURL(value) ? new url.URL(value) : url.pathToFileURL(value)).toString();
const internalFunctionNames = [
"getCallerDirname",
"requireFromString",
"importFromStringSync",
"importFromString",
"importFromStringSync",
"processTicksAndRejections"

@@ -59,15 +69,24 @@ ];

const functionName = callSite.getFunctionName();
return functionName === null || !FUNCTION_NAMES.includes(functionName);
return functionName === null || !internalFunctionNames.includes(functionName);
});
Error.prepareStackTrace = __prepareStackTrace;
const callerFilename = callSites[0].getFileName();
return path__default["default"].dirname(callerFilename === null ? process.argv[1] : fileURLToPath(callerFilename));
return path.dirname(callerFilename === null ? process.argv[1] : fileURLStringToPath(callerFilename));
};
const resolveModuleSpecifier = (specifier, dirname) => {
const specifierPath = fileURLToPath(specifier);
return specifierPath.startsWith(".") || path__default["default"].isAbsolute(specifierPath) ? path__default["default"].resolve(dirname, specifierPath) : specifier;
const createGlobalProxy = (contextObject) => new Proxy(contextObject, {
get: (target, propKey) => {
if (propKey in target) {
return target[propKey];
} else {
return Reflect.get(global, propKey);
}
}
});
const resolveModuleSpecifier = (specifier, dirname2) => {
const specifierPath = fileURLStringToPath(specifier);
return specifierPath.startsWith(".") || path.isAbsolute(specifierPath) ? path.resolve(dirname2, specifierPath) : specifier;
};
const requireFromString = (code, { dirname = getCallerDirname(), globals } = {}) => {
const requireFromString = (code, { dirname = getCallerDirname(), globals, useCurrentGlobal = false } = {}) => {
var _a;
const moduleFilename = path__default["default"].join(dirname, `${nanoid.nanoid()}.js`);
const moduleFilename = path.join(dirname, `${nanoid.nanoid()}.js`);
const mainModule = isInESModuleScope() ? void 0 : require.main;

@@ -79,3 +98,3 @@ const contextModule = new module$1.Module(moduleFilename, mainModule);

contextModule.require = module$1.createRequire(moduleFilename);
vm__default["default"].runInNewContext(code, __spreadValues({
const contextObject = __spreadValues({
__dirname: contextModule.path,

@@ -86,3 +105,7 @@ __filename: contextModule.filename,

require: contextModule.require
}, globals), {
}, globals);
const context = vm.createContext(useCurrentGlobal ? createGlobalProxy(contextObject) : contextObject);
context.global = context;
vm.runInContext(code, context, {
filename: moduleFilename,
async importModuleDynamically(specifier) {

@@ -95,4 +118,6 @@ return await import(resolveModuleSpecifier(specifier, contextModule.path));

};
const IMPORT_META_URL_SHIM = "var import_meta_url = require('url').pathToFileURL(__filename).toString();";
const IMPORT_META_RESOLVE_SHIM = `var import_meta_resolve = () => {
const createRequireFromString = (options) => (code) => requireFromString(code, options);
const USE_STRICT = '"use strict";';
const IMPORT_META_URL_SHIM = 'var import_meta_url = require("url").pathToFileURL(__filename).toString();';
const IMPORT_META_RESOLVE_SHIM = `function import_meta_resolve() {
throw new Error(

@@ -103,8 +128,10 @@ \`'import.meta.resolve' is not supported

);
};`;
}`;
const getCommonJS = (transformOptions) => {
var _a;
return __spreadProps(__spreadValues({}, transformOptions), {
banner: `${(transformOptions == null ? void 0 : transformOptions.banner) === void 0 ? "" : `${transformOptions.banner}
`}${IMPORT_META_URL_SHIM}
${IMPORT_META_RESOLVE_SHIM}`,
banner: `${USE_STRICT}
${IMPORT_META_URL_SHIM}
${IMPORT_META_RESOLVE_SHIM}
${(_a = transformOptions == null ? void 0 : transformOptions.banner) != null ? _a : ""}`,
define: __spreadValues({

@@ -118,9 +145,10 @@ "import.meta.url": "import_meta_url",

const ERR_REQUIRE_ESM = "ERR_REQUIRE_ESM";
const importFromString = async (code, { dirname = getCallerDirname(), globals, transformOptions } = {}) => {
const importFromString = async (code, _a = {}) => {
var _b = _a, { transformOptions } = _b, commonOptions = __objRest(_b, ["transformOptions"]);
if (!isVMModuleAvailable()) {
const { code: transformedCode2 } = await esbuild.transform(code, getCommonJS(transformOptions));
try {
return requireFromString(transformedCode2, { dirname, globals });
return requireFromString(transformedCode2, commonOptions);
} catch (err) {
if (err.code === ERR_REQUIRE_ESM) {
if (err != null && err.code === ERR_REQUIRE_ESM) {
throw new Error(`'import' statement of ES modules is not supported

@@ -132,15 +160,23 @@ Enable '--experimental-vm-modules' CLI option or replace it with dynamic 'import()' expression.`);

}
const { code: transformedCode = void 0 } = transformOptions === void 0 ? {} : await esbuild.transform(code, __spreadValues({
format: "esm"
}, transformOptions));
const moduleFilename = path__default["default"].join(dirname, `${nanoid.nanoid()}.js`);
const moduleFileURL = pathToFileURL(moduleFilename);
const context = vm__default["default"].createContext(__spreadValues({
__IMPORTS__: {}
}, globals));
const vmModule = new vm__default["default"].SourceTextModule(transformedCode != null ? transformedCode : code, {
identifier: moduleFileURL,
let transformedCode;
if (transformOptions !== void 0) {
({ code: transformedCode } = await esbuild.transform(code, __spreadValues({
format: "esm"
}, transformOptions)));
}
const { dirname = getCallerDirname(), globals, useCurrentGlobal = false } = commonOptions;
const moduleFilename = path.join(dirname, `${await async.nanoid()}.js`);
const moduleFileURLString = pathToFileURLString(moduleFilename);
const contextObject = __spreadValues({
__IMPORTS__: {},
__dirname: dirname,
__filename: moduleFilename
}, globals);
const context = vm.createContext(useCurrentGlobal ? createGlobalProxy(contextObject) : contextObject);
context.global = context;
const vmModule = new vm__default.default.SourceTextModule(transformedCode != null ? transformedCode : code, {
identifier: moduleFileURLString,
context,
initializeImportMeta(meta) {
meta.url = moduleFileURL;
meta.url = moduleFileURLString;
},

@@ -155,6 +191,6 @@ async importModuleDynamically(specifier) {

context.__IMPORTS__[specifier] = targetModule;
const exportedNames = Object.getOwnPropertyNames(targetModule);
const exportedNames = Object.keys(targetModule);
const targetModuleContent = `${exportedNames.includes("default") ? `export default __IMPORTS__['${specifier}'].default;
` : ""}export const { ${exportedNames.filter((exportedName) => exportedName !== "default").join(", ")} } = __IMPORTS__['${specifier}'];`;
return new vm__default["default"].SourceTextModule(targetModuleContent, {
return new vm__default.default.SourceTextModule(targetModuleContent, {
identifier: resolvedSpecifier,

@@ -168,8 +204,10 @@ context

};
const importFromStringSync = (code, { dirname = getCallerDirname(), globals, transformOptions } = {}) => {
const createImportFromString = (options) => async (code) => await importFromString(code, options);
const importFromStringSync = (code, _c = {}) => {
var _d = _c, { transformOptions } = _d, commonOptions = __objRest(_d, ["transformOptions"]);
const { code: transformedCode } = esbuild.transformSync(code, getCommonJS(transformOptions));
try {
return requireFromString(transformedCode, { dirname, globals });
return requireFromString(transformedCode, commonOptions);
} catch (err) {
if (err.code === ERR_REQUIRE_ESM) {
if (err != null && err.code === ERR_REQUIRE_ESM) {
throw new Error(`'import' statement of ES modules is not supported

@@ -181,4 +219,8 @@ Use asynchronous function 'importFromString' instead or replace it with dynamic 'import()' expression.`);

};
const createImportFromStringSync = (options) => (code) => importFromStringSync(code, options);
exports.createImportFromString = createImportFromString;
exports.createImportFromStringSync = createImportFromStringSync;
exports.createRequireFromString = createRequireFromString;
exports.importFromString = importFromString;
exports.importFromStringSync = importFromStringSync;
exports.requireFromString = requireFromString;
{
"name": "module-from-string",
"version": "3.1.4",
"version": "3.2.0-0",
"description": "Load module from string using require or import.",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

Sorry, the diff of this file is not supported yet

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