node-version-use
Version:
Cross-platform solution for using multiple versions of node. Useful for compatibility testing
221 lines • 10.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return worker;
}
});
var _crossspawncb = /*#__PURE__*/ _interop_require_default(require("cross-spawn-cb"));
var _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
var _noderesolveversions = /*#__PURE__*/ _interop_require_default(require("node-resolve-versions"));
var _nodeversionutils = require("node-version-utils");
var _path = /*#__PURE__*/ _interop_require_default(require("path"));
var _queuecb = /*#__PURE__*/ _interop_require_default(require("queue-cb"));
var _resolvebinsync = /*#__PURE__*/ _interop_require_default(require("resolve-bin-sync"));
var _spawnstreaming = /*#__PURE__*/ _interop_require_default(require("spawn-streaming"));
var _spawnterm = require("spawn-term");
var _compatts = require("./compat.js");
var _constantsts = require("./constants.js");
var _loadNodeVersionInstallts = /*#__PURE__*/ _interop_require_default(require("./lib/loadNodeVersionInstall.js"));
var _resolveSystemBinaryts = require("./lib/resolveSystemBinary.js");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
var _process_env_OSTYPE;
var isWindows = process.platform === 'win32' || /^(msys|cygwin)$/.test((_process_env_OSTYPE = process.env.OSTYPE) !== null && _process_env_OSTYPE !== void 0 ? _process_env_OSTYPE : '');
var NODE = isWindows ? 'node.exe' : 'node';
// Parse npm-generated .cmd wrapper to extract the JS script path
function parseNpmCmdWrapper(cmdPath) {
try {
var content = _fs.default.readFileSync(cmdPath, 'utf8');
// Match: "%_prog%" "%dp0%\node_modules\...\cli.js" %*
// or: "%_prog%" "%dp0%\path\to\script.js" %*
var match = content.match(/"%_prog%"\s+"?%dp0%\\([^"]+)"?\s+%\*/);
if (match) {
var relativePath = match[1];
var cmdDir = _path.default.dirname(cmdPath);
return _path.default.join(cmdDir, relativePath);
}
} catch (_e) {
// ignore
}
return null;
}
// On Windows, resolve npm bin commands to their JS entry points to bypass .cmd wrappers
// This fixes issues with nvm-windows where .cmd wrappers use symlinked node.exe directly
function resolveCommand(command, args) {
if (!isWindows) return {
command: command,
args: args
};
// Case 1: Command is a .cmd file path
if ((0, _compatts.stringEndsWith)(command.toLowerCase(), '.cmd')) {
var scriptPath = parseNpmCmdWrapper(command);
if (scriptPath) {
return {
command: NODE,
args: [
scriptPath
].concat(args)
};
}
}
// Case 2: Try to resolve the command as an npm package bin from node_modules
try {
var binPath = (0, _resolvebinsync.default)(command);
return {
command: NODE,
args: [
binPath
].concat(args)
};
} catch (_e) {
// Not an npm package bin, use original command
}
return {
command: command,
args: args
};
}
function worker(versionExpression, command, args, options, callback) {
// Handle "system" as a special version that uses system binaries directly
if (versionExpression === 'system') {
runWithSystemBinaries(command, args, options, callback);
return;
}
// Load node-version-install lazily
(0, _loadNodeVersionInstallts.default)(function(loadErr, installVersion) {
if (loadErr) return callback(loadErr);
(0, _noderesolveversions.default)(versionExpression, options, function(err, result) {
var versions = result;
if (err) return callback(err);
if (!versions || !versions.length) {
callback(new Error("No versions found from expression: ".concat(versionExpression)));
return;
}
var installOptions = (0, _compatts.objectAssign)({
storagePath: _constantsts.storagePath
}, options);
var streamingOptions = options;
var results = [];
var queue = new _queuecb.default(1);
// Create session once for all processes (only if multiple versions)
var interactive = options.interactive !== false;
var session = versions.length >= 2 && process.stdout.isTTY && typeof _spawnterm.createSession === 'function' && !streamingOptions.streaming ? (0, _spawnterm.createSession)({
header: "".concat(command, " ").concat(args.join(' ')),
showStatusBar: true,
interactive: interactive
}) : null;
versions.forEach(function(version, index) {
return queue.defer(function(cb) {
return installVersion === null || installVersion === void 0 ? void 0 : installVersion(version, installOptions, function(err, installs) {
var next = function next(err, res) {
if (!session && !options.silent) console.log('==============');
if (err && err.message.indexOf('ExperimentalWarning') >= 0) {
res = err;
err = undefined;
}
results.push({
install: install,
command: command,
version: version,
error: err !== null && err !== void 0 ? err : undefined,
result: res
});
cb();
};
var install = installs && installs.length === 1 ? installs[0] : null;
if (err || !install) {
var error = err || new Error("Unexpected version results for version ".concat(version, ". Install ").concat(JSON.stringify(installs)));
results.push({
install: install,
command: command,
version: version,
error: error,
result: undefined
});
return cb();
}
var spawnOptions = (0, _nodeversionutils.spawnOptions)(install.installPath, options);
var prefix = install.version;
// On Windows, resolve npm bin commands to bypass .cmd wrappers
var resolved = resolveCommand(command, args);
// Show command when running single version (no terminal session, unless silent)
if (!session && !options.silent) console.log("".concat(index > 0 ? '\n' : '').concat(version));
if (!session && !options.silent) console.log('--------------');
if (!session && !options.silent) console.log("$ ".concat((0, _spawnterm.formatArguments)([
resolved.command
].concat(resolved.args)).join(' ')));
if ((versions === null || versions === void 0 ? void 0 : versions.length) < 2) (0, _crossspawncb.default)(resolved.command, resolved.args, spawnOptions, next);
else if (session) session.spawn(resolved.command, resolved.args, spawnOptions, {
group: prefix,
expanded: streamingOptions.expanded
}, next);
else (0, _spawnstreaming.default)(resolved.command, resolved.args, spawnOptions, {
prefix: process.stdout.isTTY ? prefix : undefined
}, next);
});
});
});
queue.await(function(err) {
if (session) {
session.waitAndClose(function() {
err ? callback(err) : callback(undefined, results);
});
} else {
err ? callback(err) : callback(undefined, results);
}
});
});
});
}
/**
* Run command using system binaries (bypassing nvu version management)
* This handles the "system" version specifier
*/ function runWithSystemBinaries(command, args, options, callback) {
// Find the system binary for the command
var systemBinary = (0, _resolveSystemBinaryts.resolveSystemBinary)(command);
if (!systemBinary) {
callback(new Error("System ".concat(command, " not found in PATH")));
return;
}
// Create spawn options with PATH excluding ~/.nvu/bin
// This ensures any child processes also use system binaries
var cleanPath = (0, _resolveSystemBinaryts.getPathWithoutNvuBin)();
var spawnOptions = (0, _compatts.objectAssign)({}, options);
spawnOptions.env = (0, _compatts.objectAssign)({}, process.env);
spawnOptions.env.PATH = cleanPath;
spawnOptions.stdio = options.stdio || 'inherit';
// On Windows, resolve npm bin commands to bypass .cmd wrappers
var resolved = resolveCommand(command, args);
// For system, use the resolved system binary path
var finalCommand = resolved.command === command ? systemBinary : resolved.command;
var finalArgs = resolved.command === command ? args : resolved.args;
if (!options.silent) {
console.log("$ ".concat((0, _spawnterm.formatArguments)([
finalCommand
].concat(finalArgs)).join(' ')));
}
(0, _crossspawncb.default)(finalCommand, finalArgs, spawnOptions, function(err, res) {
if (err && err.message && err.message.indexOf('ExperimentalWarning') >= 0) {
res = err;
err = undefined;
}
var result = {
install: null,
command: command,
version: 'system',
error: err,
result: res
};
callback(err, [
result
]);
});
}
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }