From 0f7cb92492418078705d5d7bd65858fa9c8d65bd Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Tue, 16 Jul 2024 14:01:49 -0700 Subject: [PATCH] feat: add `engines` and `cwd` options --- bin/nv | 7 +++- index.js | 17 +++++++++ test/cli.js | 58 ++++++++++++++++++++++++++++++ test/fixtures/engines/package.json | 5 +++ test/index.js | 56 +++++++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/engines/package.json diff --git a/bin/nv b/bin/nv index 5aa94c0..7f915f9 100755 --- a/bin/nv +++ b/bin/nv @@ -22,9 +22,14 @@ require('yargs') type: 'boolean', description: 'show version number only' }) + yargs.option('engines', { + type: 'string', + description: 'read the value of `engines.node`. if a value is provided, and it satisfies, the version is shown; if not, the max satisfying version is shown' + }) }, handler: (argv) => { nv(argv.versions, { + engines: argv.engines, mirror: argv.mirror }) .then(result => { @@ -41,7 +46,7 @@ require('yargs') }) }).catch(e => { console.error(e) - process.exitCode = e.code || 1 + process.exitCode ||= e.code || 1 }) } }) diff --git a/index.js b/index.js index c5672bf..bffaf1c 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,7 @@ 'use strict' +const { readFile } = require('fs/promises') +const { join } = require('path') + const got = require('got') const semver = require('semver') const _cache = new Map() @@ -8,6 +11,8 @@ module.exports = async function (alias = 'lts_active', opts = {}) { const cache = opts.cache || _cache const mirror = opts.mirror || 'https://nodejs.org/dist/' const latestOfMajorOnly = opts.latestOfMajorOnly || false + const engines = opts.engines + const cwd = opts.cwd || process.cwd() const a = Array.isArray(alias) ? alias : [alias] const versions = await getLatestVersionsByCodename(now, cache, mirror) @@ -25,6 +30,18 @@ module.exports = async function (alias = 'lts_active', opts = {}) { return m }, {}) + if (typeof engines === 'string' || engines === true) { + const { engines: { node } = { node: '*' } } = JSON.parse(await readFile(join(cwd, 'package.json'), 'utf8')) + + m = Object.fromEntries(Object.entries(m).filter(([version]) => semver.satisfies(version, node))) + + const matching = Object.entries(m).filter(([version]) => semver.satisfies(version, engines)) + + if (matching.length > 0) { + m = Object.fromEntries(matching) + } + } + // If only latest major is true, filter out all but latest if (latestOfMajorOnly) { const vers = Object.values(m).reduce((latestMajor, v) => { diff --git a/test/cli.js b/test/cli.js index de8fb85..96d0d6d 100644 --- a/test/cli.js +++ b/test/cli.js @@ -40,4 +40,62 @@ suite('nv cli', () => { assert(semver.valid(r)) }) }) + + test('works with `--engines`', () => { + const result = execFileSync(nv, ['ls', '8.x', '--only-version', '--engines=">=8"'], { cwd: path.join(__dirname, 'fixtures', 'engines') }) + .toString().trim().split('\n') + + assert.deepEqual(result, [ + '8.10.0', + '8.11.0', + '8.11.1', + '8.11.2', + '8.11.3', + '8.11.4', + '8.12.0', + '8.13.0', + '8.14.0', + '8.14.1', + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + + const result2 = execFileSync(nv, ['ls', '8.x', '--only-version', '--engines=">=8.15"'], { cwd: path.join(__dirname, 'fixtures', 'engines') }) + .toString().trim().split('\n') + + assert.deepEqual(result2, [ + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + + const result3 = execFileSync(nv, ['ls', '8.x', '--only-version', '--engines'], { cwd: path.join(__dirname, 'fixtures', 'engines') }) + .toString().trim().split('\n') + + assert.deepEqual(result3, [ + '8.10.0', + '8.11.0', + '8.11.1', + '8.11.2', + '8.11.3', + '8.11.4', + '8.12.0', + '8.13.0', + '8.14.0', + '8.14.1', + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + }) }) diff --git a/test/fixtures/engines/package.json b/test/fixtures/engines/package.json new file mode 100644 index 0000000..0a6e7f7 --- /dev/null +++ b/test/fixtures/engines/package.json @@ -0,0 +1,5 @@ +{ + "engines": { + "node": "^8.10" + } +} diff --git a/test/index.js b/test/index.js index 208374a..7951b3e 100644 --- a/test/index.js +++ b/test/index.js @@ -1,6 +1,7 @@ 'use strict' const { suite, test } = require('mocha') const assert = require('assert') +const path = require('path') const nv = require('..') // 2019-02-07T16:15:49.683Z @@ -182,4 +183,59 @@ suite('nv', () => { const versions = await nv('0.8.0', { now }) assert.strictEqual(versions[0].codename, null) }) + + test('engines option', async () => { + const versions = await nv('8.x', { now, cwd: path.join(__dirname, 'fixtures', 'engines'), engines: '>=8' }) + + assert.deepEqual(versions.map(x => x.version), [ + '8.10.0', + '8.11.0', + '8.11.1', + '8.11.2', + '8.11.3', + '8.11.4', + '8.12.0', + '8.13.0', + '8.14.0', + '8.14.1', + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + + const versions2 = await nv('8.x', { now, cwd: path.join(__dirname, 'fixtures', 'engines'), engines: '>=8.15' }) + + assert.deepEqual(versions2.map(x => x.version), [ + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + + const versions3 = await nv('8.x', { now, cwd: path.join(__dirname, 'fixtures', 'engines'), engines: true }) + + assert.deepEqual(versions3.map(x => x.version), [ + '8.10.0', + '8.11.0', + '8.11.1', + '8.11.2', + '8.11.3', + '8.11.4', + '8.12.0', + '8.13.0', + '8.14.0', + '8.14.1', + '8.15.0', + '8.15.1', + '8.16.0', + '8.16.1', + '8.16.2', + '8.17.0' + ]) + }) })