apisurf
Version:
Analyze API surface changes between npm package versions to catch breaking changes
103 lines (102 loc) • 3.59 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
import * as vm from 'vm';
/**
* Load and execute a CommonJS module in a sandboxed VM environment
*/
export function loadModuleWithVM(modulePath, packageName, version) {
try {
// Create a sandbox with proper Node.js environment
const sandbox = {
require: (id) => {
// Use Node.js standard require resolution from the module's directory
// This will now work properly since we have installed dependencies
try {
// Special handling for object-assign which React 17 uses
if (id === 'object-assign') {
return Object.assign;
}
if (id.startsWith('.')) {
// Relative requires
const resolvedPath = path.resolve(path.dirname(modulePath), id);
return require(resolvedPath);
}
else {
// Package requires - resolve from the module's location
return require(require.resolve(id, { paths: [path.dirname(modulePath)] }));
}
}
catch (error) {
// If resolution still fails, return empty object to prevent crashes
return {};
}
},
module: { exports: {} },
exports: {},
__filename: modulePath,
__dirname: path.dirname(modulePath),
process: {
env: { NODE_ENV: 'development' },
versions: process.versions,
platform: process.platform
},
console: {
log: () => { },
warn: () => { },
error: () => { },
info: () => { },
debug: () => { }
},
Buffer,
setTimeout,
clearTimeout,
setInterval,
clearInterval,
setImmediate,
clearImmediate,
global: {},
Object,
Array,
String,
Number,
Boolean,
Function,
Error,
Date,
RegExp,
Math,
JSON,
Symbol,
Promise,
Map,
Set,
WeakMap,
WeakSet,
Proxy,
Reflect,
undefined: undefined,
null: null
};
// Make sure exports and module.exports point to the same object
sandbox.module.exports = sandbox.exports;
// Set up global references
sandbox.global = sandbox;
sandbox.globalThis = sandbox;
// Create VM context
const context = vm.createContext(sandbox);
// Read the module source
const moduleSource = fs.readFileSync(modulePath, 'utf8');
// Execute the module in the sandbox
vm.runInContext(moduleSource, context, {
filename: modulePath,
timeout: 10000 // 10 second timeout to prevent infinite loops
});
// Return the exports (prefer module.exports over exports)
return sandbox.module.exports || sandbox.exports;
}
catch (error) {
const packageInfo = packageName ? `${packageName}@${version}` : 'unknown package';
console.warn(`VM execution failed while parsing ${packageInfo} at ${modulePath}:`, error);
return null;
}
}