diff --git a/lib/cli/src/latest_version.js b/lib/cli/src/latest_version.js index b351f4fceb0..72e452e642d 100644 --- a/lib/cli/src/latest_version.js +++ b/lib/cli/src/latest_version.js @@ -1,11 +1,38 @@ import { spawn } from 'cross-spawn'; import { satisfies } from 'semver'; +/** + * Get latest version of the package available on npmjs.com. + * If constraint is set then it returns a version satisfying it, otherwise the latest version available is returned. + * + * @param {Object} npmOptions Object containing a `useYarn: boolean` attribute + * @param {string} packageName Name of the package + * @param {Object} constraint Version range to use to constraint the returned version + * @return {Promise} Promise resolved with a version + */ export function latestVersion(npmOptions, packageName, constraint) { - const packageManager = npmOptions.useYarn ? 'yarn' : 'npm'; + const getPackageVersions = npmOptions.useYarn + ? spawnVersionsWithYarn(packageName, constraint) + : spawnVersionsWithNpm(packageName, constraint); + + return getPackageVersions.then(versions => { + if (!constraint) return versions; + + return versions.reverse().find(version => satisfies(version, constraint)); + }); +} + +/** + * Get latest version(s) of the package available on npmjs.com using NPM + * + * @param {string} packageName Name of the package + * @param {Object} constraint Version range to use to constraint the returned version + * @returns {Promise>} versions Promise resolved with a version or an array of versions + */ +function spawnVersionsWithNpm(packageName, constraint) { return new Promise((resolve, reject) => { const command = spawn( - packageManager, + 'npm', ['info', packageName, constraint ? 'versions' : 'version', '--json', '--silent'], { cwd: process.cwd(), @@ -16,39 +43,57 @@ export function latestVersion(npmOptions, packageName, constraint) { } ); - const processResult = result => { - if (!constraint) return result; - - return result.reverse().find(version => satisfies(version, constraint)); - }; - command.stdout.on('data', data => { try { const info = JSON.parse(data); if (info.error) { - // npm error reject(new Error(info.error.summary)); - } else if (info.type === 'inspect') { - // yarn success - resolve(processResult(info.data)); } else { - // npm success - resolve(processResult(info)); + resolve(info); } } catch (e) { - // yarn info output - } - }); - - command.stderr.on('data', data => { - try { - // yarn error - const info = JSON.parse(data); - if (info.type === 'error') { - reject(new Error(info.data)); - } - } catch (e) { - // package manager unstructured info/warnings output + reject(new Error(`Unable to find versions of ${packageName} using npm`)); + } + }); + }); +} + +/** + * Get latest version(s) of the package available on npmjs.com using Yarn + * + * @param {string} packageName Name of the package + * @param {Object} constraint Version range to use to constraint the returned version + * @returns {Promise>} versions Promise resolved with a version or an array of versions + */ +function spawnVersionsWithYarn(packageName, constraint) { + return new Promise((resolve, reject) => { + const command = spawn( + 'yarn', + ['info', packageName, constraint ? 'versions' : 'version', '--json', '--silent'], + { + cwd: process.cwd(), + env: process.env, + stdio: 'pipe', + encoding: 'utf-8', + silent: true, + } + ); + + command.stdout.on('data', data => { + try { + const info = JSON.parse(data); + if (info.type === 'inspect') { + resolve(info.data); + } + } catch (e) { + reject(new Error(`Unable to find versions of ${packageName} using yarn`)); + } + }); + + command.stderr.on('data', data => { + const info = JSON.parse(data); + if (info.type === 'error') { + reject(new Error(info.data)); } }); });