From 047e847be6380296be980b4062e41651ac44382a Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sat, 5 Mar 2022 12:07:23 +0800 Subject: [PATCH 1/3] Add `last N node versions` (with major) support --- grammar.w3c-ebnf | 3 +++ index.js | 21 +++++++++++++++++++++ test/node.test.js | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/grammar.w3c-ebnf b/grammar.w3c-ebnf index ddd7c3e5..9c9497e4 100644 --- a/grammar.w3c-ebnf +++ b/grammar.w3c-ebnf @@ -46,6 +46,8 @@ LastBrowsers ::= 'last' Space+ Digit+ Space+ (BrowserName Space+)? ('major' Spac LastElectron ::= 'last' Space+ Digit+ Space+ 'electron' Space+ ('major' Space+)? VersionKeyword +LastNode ::= 'last' Space+ Digit+ Space+ 'node' Space+ ('major' Space+)? VersionKeyword + Unreleased ::= 'unreleased' Space+ ((BrowserName | 'electron') Space+)? VersionKeyword Years ::= 'last' Space+ Numeric Space+ 'year' 's'? @@ -96,6 +98,7 @@ Dead ::= 'dead' QueryAtom ::= LastBrowsers | LastElectron + | LastNode | Unreleased | Years | Since diff --git a/index.js b/index.js index baefcb45..713cbcae 100644 --- a/index.js +++ b/index.js @@ -716,6 +716,19 @@ var QUERIES = [ }) } }, + { + regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i, + select: function (context, versions) { + return getMajorVersions( + jsReleases.map(function (release) { + return release.version + }), + versions + ).map(function (version) { + return 'node ' + version + }) + } + }, { regexp: /^last\s+(\d+)\s+(\w+)\s+major\s+versions?$/i, select: function (context, versions, name) { @@ -738,6 +751,14 @@ var QUERIES = [ }) } }, + { + regexp: /^last\s+(\d+)\s+node\s+versions?$/i, + select: function (context, versions) { + return jsReleases.slice(-versions).map(function (release) { + return 'node ' + release.version + }) + } + }, { regexp: /^last\s+(\d+)\s+(\w+)\s+versions?$/i, select: function (context, versions, name) { diff --git a/test/node.test.js b/test/node.test.js index f5ec89cb..53ac5a6e 100644 --- a/test/node.test.js +++ b/test/node.test.js @@ -343,4 +343,12 @@ test('supports range selection', () => { ) }) +test('supports last versions for Node.js', () => { + is(browserslist('last 2 node versions').length >= 1, true) +}) + +test('supports last major versions for Node.js', () => { + is(browserslist('last 2 node major versions').length >= 1, true) +}) + test.run() From 4e355c4121a9270104b2e62f14f20189dabd9b2f Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sat, 5 Mar 2022 23:45:19 +0800 Subject: [PATCH 2/3] Update tests --- index.d.ts | 2 ++ index.js | 52 ++++++++++++++++------------------------------- test/node.test.js | 26 ++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/index.d.ts b/index.d.ts index 4ca9cd93..bea42704 100644 --- a/index.d.ts +++ b/index.d.ts @@ -102,6 +102,8 @@ declare namespace browserslist { | undefined } + let nodeVersions: string[] + interface Usage { [version: string]: number } diff --git a/index.js b/index.js index 713cbcae..8c09141c 100644 --- a/index.js +++ b/index.js @@ -19,8 +19,8 @@ function isVersionsMatch(versionA, versionB) { function isEolReleased(name) { var version = name.slice(1) - return jsReleases.some(function (i) { - return isVersionsMatch(i.version, version) + return browserslist.nodeVersions.some(function (i) { + return isVersionsMatch(i, version) }) } @@ -617,11 +617,8 @@ browserslist.coverage = function (browsers, stats) { } function nodeQuery(context, version) { - var nodeReleases = jsReleases.filter(function (i) { - return i.name === 'nodejs' - }) - var matched = nodeReleases.filter(function (i) { - return isVersionsMatch(i.version, version) + var matched = browserslist.nodeVersions.filter(function (i) { + return isVersionsMatch(i, version) }) if (matched.length === 0) { if (context.ignoreUnknownVersions) { @@ -630,7 +627,7 @@ function nodeQuery(context, version) { throw new BrowserslistError('Unknown version ' + version + ' of Node.js') } } - return ['node ' + matched[matched.length - 1].version] + return ['node ' + matched[matched.length - 1]] } function sinceQuery(context, year, month, date) { @@ -719,14 +716,11 @@ var QUERIES = [ { regexp: /^last\s+(\d+)\s+node\s+major\s+versions?$/i, select: function (context, versions) { - return getMajorVersions( - jsReleases.map(function (release) { - return release.version - }), - versions - ).map(function (version) { - return 'node ' + version - }) + return getMajorVersions(browserslist.nodeVersions, versions).map( + function (version) { + return 'node ' + version + } + ) } }, { @@ -754,8 +748,8 @@ var QUERIES = [ { regexp: /^last\s+(\d+)\s+node\s+versions?$/i, select: function (context, versions) { - return jsReleases.slice(-versions).map(function (release) { - return 'node ' + release.version + return browserslist.nodeVersions.slice(-versions).map(function (version) { + return 'node ' + version }) } }, @@ -1001,14 +995,7 @@ var QUERIES = [ { regexp: /^node\s+([\d.]+)\s*-\s*([\d.]+)$/i, select: function (context, from, to) { - var nodeVersions = jsReleases - .filter(function (i) { - return i.name === 'nodejs' - }) - .map(function (i) { - return i.version - }) - return nodeVersions + return browserslist.nodeVersions .filter(semverFilterLoose('>=', from)) .filter(semverFilterLoose('<=', to)) .map(function (v) { @@ -1043,14 +1030,7 @@ var QUERIES = [ { regexp: /^node\s*(>=?|<=?)\s*([\d.]+)$/i, select: function (context, sign, version) { - var nodeVersions = jsReleases - .filter(function (i) { - return i.name === 'nodejs' - }) - .map(function (i) { - return i.version - }) - return nodeVersions + return browserslist.nodeVersions .filter(generateSemverFilter(sign, version)) .map(function (v) { return 'node ' + v @@ -1246,6 +1226,10 @@ var QUERIES = [ } browserslist.versionAliases.op_mob['59'] = '58' + + browserslist.nodeVersions = jsReleases.map(function (release) { + return release.version + }) })() module.exports = browserslist diff --git a/test/node.test.js b/test/node.test.js index 53ac5a6e..05083623 100644 --- a/test/node.test.js +++ b/test/node.test.js @@ -345,10 +345,36 @@ test('supports range selection', () => { test('supports last versions for Node.js', () => { is(browserslist('last 2 node versions').length >= 1, true) + + browserslist.nodeVersions = ['16.0.0', '16.1.0', '17.0.0', '17.1.0'] + equal(browserslist('last 3 node versions'), [ + 'node 17.1.0', + 'node 17.0.0', + 'node 16.1.0' + ]) }) test('supports last major versions for Node.js', () => { is(browserslist('last 2 node major versions').length >= 1, true) + + browserslist.nodeVersions = [ + '14.0.0', + '14.1.0', + '15.0.0', + '15.1.0', + '16.0.0', + '16.1.0', + '17.0.0', + '17.1.0' + ] + equal(browserslist('last 3 node major versions'), [ + 'node 17.1.0', + 'node 17.0.0', + 'node 16.1.0', + 'node 16.0.0', + 'node 15.1.0', + 'node 15.0.0' + ]) }) test.run() From 4a1f103b41f6a1c5daa45a09ff752d8bd9f1e570 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sun, 6 Mar 2022 09:04:40 +0800 Subject: [PATCH 3/3] Update docs --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 6afe049d..7060180b 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,8 @@ You can specify the browser and Node.js versions by queries (case insensitive): * Node.js versions: * `node 10` and `node 10.4`: selects latest Node.js `10.x.x` or `10.4.x` release. + * `last 2 node versions`: select 2 latest Node.js releases. + * `last 2 node major versions`: select 2 latest major-version Node.js releases. * `current node`: Node.js version used by Browserslist right now. * `maintained node versions`: all Node.js versions, which are [still maintained] by Node.js Foundation.