UNPKG

node-version-use

Version:

Cross-platform solution for using multiple versions of node. Useful for compatibility testing

221 lines 10.6 kB
"use strict"; 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; }