From ed22d659f242ed5b8518b9d971b50887607dd867 Mon Sep 17 00:00:00 2001 From: Casey Holzer Date: Tue, 31 Mar 2026 14:49:16 -0600 Subject: [PATCH 1/3] feat: add min-release-age-exclude with glob support --- lib/commands/install.js | 1 + lib/commands/outdated.js | 1 + lib/commands/query.js | 2 + node_modules/npm-pick-manifest/lib/index.js | 13 ++++- tap-snapshots/test/lib/docs.js.test.cjs | 52 +++++++++++++++++-- workspaces/arborist/lib/query-selector-all.js | 10 +++- .../arborist/test/query-selector-all.js | 17 ++++++ .../config/lib/definitions/definitions.js | 19 +++++++ workspaces/config/test/index.js | 22 ++++++++ 9 files changed, 131 insertions(+), 6 deletions(-) diff --git a/lib/commands/install.js b/lib/commands/install.js index 5970fddfdfe4f..f4829abea9743 100644 --- a/lib/commands/install.js +++ b/lib/commands/install.js @@ -31,6 +31,7 @@ class Install extends ArboristWorkspaceCmd { 'audit', 'before', 'min-release-age', + 'min-release-age-exclude', 'bin-links', 'fund', 'dry-run', diff --git a/lib/commands/outdated.js b/lib/commands/outdated.js index e6f2cd006b60f..4c98e7597ad13 100644 --- a/lib/commands/outdated.js +++ b/lib/commands/outdated.js @@ -31,6 +31,7 @@ class Outdated extends ArboristWorkspaceCmd { 'global', 'workspace', 'before', + 'min-release-age-exclude', ] #tree diff --git a/lib/commands/query.js b/lib/commands/query.js index 5e70e25f32e62..cb8ed78454d85 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -49,6 +49,8 @@ class Query extends BaseCommand { 'include-workspace-root', 'package-lock-only', 'expect-results', + 'before', + 'min-release-age-exclude', ] constructor (...args) { diff --git a/node_modules/npm-pick-manifest/lib/index.js b/node_modules/npm-pick-manifest/lib/index.js index 985c78df7a9bf..6edee42b964eb 100644 --- a/node_modules/npm-pick-manifest/lib/index.js +++ b/node_modules/npm-pick-manifest/lib/index.js @@ -2,6 +2,7 @@ const npa = require('npm-package-arg') const semver = require('semver') +const { minimatch } = require('minimatch') const { checkEngine } = require('npm-install-checks') const normalizeBin = require('npm-normalize-package-bin') @@ -21,6 +22,13 @@ const avoidSemverOpt = { includePrerelease: true, loose: true } const shouldAvoid = (ver, avoid) => avoid && semver.satisfies(ver, avoid, avoidSemverOpt) +const shouldBypassBefore = (name, exclude) => { + const patterns = Array.isArray(exclude) ? exclude : [exclude] + return patterns + .filter(pattern => typeof pattern === 'string' && pattern) + .some(pattern => minimatch(name, pattern)) +} + const decorateAvoid = (result, avoid) => result && shouldAvoid(result.version, avoid) ? { ...result, _shouldAvoid: true } @@ -35,6 +43,7 @@ const pickManifest = (packument, wanted, opts) => { includeStaged = false, avoid = null, avoidStrict = false, + minReleaseAgeExclude = opts['min-release-age-exclude'], } = opts const { name, time: verTimes } = packument @@ -84,7 +93,9 @@ const pickManifest = (packument, wanted, opts) => { const restricted = (packument.policyRestrictions && packument.policyRestrictions.versions) || {} - const time = before && verTimes ? +(new Date(before)) : Infinity + const time = before && verTimes && !shouldBypassBefore(name, minReleaseAgeExclude) + ? +(new Date(before)) + : Infinity const spec = npa.resolve(name, wanted || defaultTag) const type = spec.type const distTags = packument['dist-tags'] || {} diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index 2f8891f886263..22203a9c81d08 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -1151,6 +1151,19 @@ This config cannot be used with: \`before\` This value is not exported to the environment for child processes. +#### \`min-release-age-exclude\` + +* Default: +* Type: String (can be set multiple times) + +Exclude package names from \`min-release-age\` and \`before\` publish-time +filtering. + +Values can be exact package names (\`left-pad\`) or glob patterns +(\`@myorg/*\`). + +This value is not exported to the environment for child processes. + #### \`name\` * Default: null @@ -2350,6 +2363,7 @@ Array [ "maxsockets", "message", "min-release-age", + "min-release-age-exclude", "node-gyp", "node-options", "noproxy", @@ -2508,6 +2522,7 @@ Array [ "maxsockets", "message", "min-release-age", + "min-release-age-exclude", "node-gyp", "noproxy", "offline", @@ -2675,6 +2690,7 @@ Object { "logColor": false, "maxSockets": 15, "message": "%s", + "minReleaseAgeExclude": Array [], "name": null, "nodeBin": "{NODE}", "nodeGyp": "{CWD}/node_modules/node-gyp/bin/node-gyp.js", @@ -3948,8 +3964,10 @@ Options: [--include [--include ...]] [--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] [--foreground-scripts] [--ignore-scripts] [--allow-git ] -[--no-audit] [--before |--min-release-age ] [--no-bin-links] -[--no-fund] [--dry-run] [--cpu ] [--os ] [--libc ] +[--no-audit] [--before |--min-release-age ] +[--min-release-age-exclude [--min-release-age-exclude ...]] +[--no-bin-links] [--no-fund] [--dry-run] [--cpu ] [--os ] +[--libc ] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -4007,6 +4025,9 @@ Options: --min-release-age If set, npm will build the npm tree such that only versions that were + --min-release-age-exclude + Exclude package names from \`min-release-age\` and \`before\` publish-time + --bin-links Tells npm to create symlinks (or \`.cmd\` shims on Windows) for package @@ -4066,6 +4087,7 @@ aliases: add, i, in, ins, inst, insta, instal, isnt, isnta, isntal, isntall #### \`audit\` #### \`before\` #### \`min-release-age\` +#### \`min-release-age-exclude\` #### \`bin-links\` #### \`fund\` #### \`dry-run\` @@ -4189,8 +4211,10 @@ Options: [--include [--include ...]] [--strict-peer-deps] [--prefer-dedupe] [--no-package-lock] [--package-lock-only] [--foreground-scripts] [--ignore-scripts] [--allow-git ] -[--no-audit] [--before |--min-release-age ] [--no-bin-links] -[--no-fund] [--dry-run] [--cpu ] [--os ] [--libc ] +[--no-audit] [--before |--min-release-age ] +[--min-release-age-exclude [--min-release-age-exclude ...]] +[--no-bin-links] [--no-fund] [--dry-run] [--cpu ] [--os ] +[--libc ] [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--install-links] @@ -4248,6 +4272,9 @@ Options: --min-release-age If set, npm will build the npm tree such that only versions that were + --min-release-age-exclude + Exclude package names from \`min-release-age\` and \`before\` publish-time + --bin-links Tells npm to create symlinks (or \`.cmd\` shims on Windows) for package @@ -4307,6 +4334,7 @@ alias: it #### \`audit\` #### \`before\` #### \`min-release-age\` +#### \`min-release-age-exclude\` #### \`bin-links\` #### \`fund\` #### \`dry-run\` @@ -4739,6 +4767,7 @@ Options: [-a|--all] [--json] [-l|--long] [-p|--parseable] [-g|--global] [-w|--workspace [-w|--workspace ...]] [--before |--min-release-age ] +[--min-release-age-exclude [--min-release-age-exclude ...]] -a|--all When running \`npm outdated\` and \`npm ls\`, setting \`--all\` will show @@ -4761,6 +4790,9 @@ Options: --before If passed to \`npm install\`, will rebuild the npm tree such that only + --min-release-age-exclude + Exclude package names from \`min-release-age\` and \`before\` publish-time + Run "npm help outdated" for more info @@ -4776,6 +4808,7 @@ npm outdated [ ...] #### \`workspace\` #### \`before\` #### \`min-release-age\` +#### \`min-release-age-exclude\` ` exports[`test/lib/docs.js TAP usage owner > must match snapshot 1`] = ` @@ -5132,6 +5165,8 @@ Options: [-w|--workspace [-w|--workspace ...]] [--workspaces] [--include-workspace-root] [--package-lock-only] [--expect-results|--expect-result-count ] +[--before |--min-release-age ] +[--min-release-age-exclude [--min-release-age-exclude ...]] -g|--global Operates in "global" mode, so that packages are installed into the @@ -5151,6 +5186,12 @@ Options: --expect-results Tells npm whether or not to expect results from the command. + --before + If passed to \`npm install\`, will rebuild the npm tree such that only + + --min-release-age-exclude + Exclude package names from \`min-release-age\` and \`before\` publish-time + Run "npm help query" for more info @@ -5165,6 +5206,9 @@ npm query #### \`package-lock-only\` #### \`expect-results\` #### \`expect-result-count\` +#### \`before\` +#### \`min-release-age\` +#### \`min-release-age-exclude\` ` exports[`test/lib/docs.js TAP usage rebuild > must match snapshot 1`] = ` diff --git a/workspaces/arborist/lib/query-selector-all.js b/workspaces/arborist/lib/query-selector-all.js index 626af0c908e9c..6ddd9809170bf 100644 --- a/workspaces/arborist/lib/query-selector-all.js +++ b/workspaces/arborist/lib/query-selector-all.js @@ -870,9 +870,17 @@ const combinators = { }, } +const shouldBypassBefore = (name, exclude) => { + const patterns = Array.isArray(exclude) ? exclude : [exclude] + return patterns + .filter(pattern => typeof pattern === 'string' && pattern) + .some(pattern => minimatch(name, pattern)) +} + // get a list of available versions of a package filtered to respect --before // NOTE: this runs over each node and should not throw const getPackageVersions = async (name, opts) => { + const minReleaseAgeExclude = opts.minReleaseAgeExclude ?? opts['min-release-age-exclude'] let packument try { packument = await pacote.packument(name, { @@ -890,7 +898,7 @@ const getPackageVersions = async (name, opts) => { // if the packument has a time property, and the user passed a before flag, then // we filter this list down to only those versions that existed before the specified date - if (packument.time && opts.before) { + if (packument.time && opts.before && !shouldBypassBefore(name, minReleaseAgeExclude)) { candidates = candidates.filter((version) => { // this version isn't found in the times at all, drop it if (!packument.time[version]) { diff --git a/workspaces/arborist/test/query-selector-all.js b/workspaces/arborist/test/query-selector-all.js index 70f14c302c1c6..60c4301e99c8a 100644 --- a/workspaces/arborist/test/query-selector-all.js +++ b/workspaces/arborist/test/query-selector-all.js @@ -393,6 +393,9 @@ t.test('query-selector-all', async t => { : options.before title += ` before ${friendlyTime}` } + if (options.minReleaseAgeExclude) { + title += ` exclude ${JSON.stringify(options.minReleaseAgeExclude)}` + } t.test(title, async t => { const res = await querySelectorAll(tree, selector, options) t.same( @@ -865,6 +868,20 @@ t.test('query-selector-all', async t => { [':outdated(out-of-range)', [ 'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday ], { before: yesterday }], + [':outdated(out-of-range)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday + 'bar@1.4.0', // excluded from --before filter + ], { + before: yesterday, + minReleaseAgeExclude: ['bar'], + }], + [':outdated(out-of-range)', [ + 'dash-separated-pkg@1.0.0', // 2.0.0 is available, out-of-range and published yesterday + 'bar@1.4.0', // excluded from --before filter by glob + ], { + before: yesterday, + minReleaseAgeExclude: ['ba*'], + }], [':outdated(nonsense)', [], { before: yesterday }], // again, no results here ever // vuln pseudo diff --git a/workspaces/config/lib/definitions/definitions.js b/workspaces/config/lib/definitions/definitions.js index 7c5b2ce170d89..f19eac37ff40f 100644 --- a/workspaces/config/lib/definitions/definitions.js +++ b/workspaces/config/lib/definitions/definitions.js @@ -1382,6 +1382,25 @@ const definitions = { } }, }), + 'min-release-age-exclude': new Definition('min-release-age-exclude', { + default: [], + hint: '', + type: [String, Array], + envExport: false, + description: ` + Exclude package names from \`min-release-age\` and \`before\` publish-time + filtering. + + Values can be exact package names (\`left-pad\`) or glob patterns + (\`@myorg/*\`). + `, + flatten: (key, obj, flatOptions) => { + const patterns = Array.isArray(obj[key]) + ? obj[key] + : obj[key] ? [obj[key]] : [] + flatOptions.minReleaseAgeExclude = patterns.filter(Boolean) + }, + }), 'node-gyp': new Definition('node-gyp', { default: (() => { try { diff --git a/workspaces/config/test/index.js b/workspaces/config/test/index.js index fea502d38f767..d685537cce1d9 100644 --- a/workspaces/config/test/index.js +++ b/workspaces/config/test/index.js @@ -1868,3 +1868,25 @@ t.test('before and min-release-age', async t => { // Simple gut check to make sure we didn't do + instead of - t.ok(config.flat.before < Date.now(), 'before date is in the past not the future') }) + +t.test('min-release-age-exclude flattens to list', async t => { + const path = t.testdir() + const config = new Config({ + npmPath: `${path}/npm`, + env: {}, + argv: [ + process.execPath, + __filename, + '--min-release-age-exclude', + '@myorg/*', + '--min-release-age-exclude', + 'left-pad', + ], + cwd: path, + definitions, + shorthands, + flatten, + }) + await config.load() + t.same(config.flat.minReleaseAgeExclude, ['@myorg/*', 'left-pad']) +}) From dfb8c33f02f16f05beb011cf13a2ac5bb438930a Mon Sep 17 00:00:00 2001 From: Casey Holzer Date: Wed, 1 Apr 2026 13:46:52 -0600 Subject: [PATCH 2/3] fix: address review feedback for min-release-age-exclude --- node_modules/npm-pick-manifest/lib/index.js | 2 ++ workspaces/arborist/lib/query-selector-all.js | 10 ++------- .../arborist/test/query-selector-all.js | 21 +++++++++++++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/node_modules/npm-pick-manifest/lib/index.js b/node_modules/npm-pick-manifest/lib/index.js index 6edee42b964eb..4e8de5bbef8a6 100644 --- a/node_modules/npm-pick-manifest/lib/index.js +++ b/node_modules/npm-pick-manifest/lib/index.js @@ -228,3 +228,5 @@ module.exports = (packument, wanted, opts = {}) => { defaultTag, }) } + +module.exports.shouldBypassBefore = shouldBypassBefore diff --git a/workspaces/arborist/lib/query-selector-all.js b/workspaces/arborist/lib/query-selector-all.js index 6ddd9809170bf..7456c8469c53e 100644 --- a/workspaces/arborist/lib/query-selector-all.js +++ b/workspaces/arborist/lib/query-selector-all.js @@ -6,6 +6,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const { log } = require('proc-log') const { minimatch } = require('minimatch') const npa = require('npm-package-arg') +const { shouldBypassBefore } = require('npm-pick-manifest') const pacote = require('pacote') const semver = require('semver') const npmFetch = require('npm-registry-fetch') @@ -870,17 +871,10 @@ const combinators = { }, } -const shouldBypassBefore = (name, exclude) => { - const patterns = Array.isArray(exclude) ? exclude : [exclude] - return patterns - .filter(pattern => typeof pattern === 'string' && pattern) - .some(pattern => minimatch(name, pattern)) -} - // get a list of available versions of a package filtered to respect --before // NOTE: this runs over each node and should not throw const getPackageVersions = async (name, opts) => { - const minReleaseAgeExclude = opts.minReleaseAgeExclude ?? opts['min-release-age-exclude'] + const minReleaseAgeExclude = opts.minReleaseAgeExclude let packument try { packument = await pacote.packument(name, { diff --git a/workspaces/arborist/test/query-selector-all.js b/workspaces/arborist/test/query-selector-all.js index 60c4301e99c8a..4f33bdd9cedb1 100644 --- a/workspaces/arborist/test/query-selector-all.js +++ b/workspaces/arborist/test/query-selector-all.js @@ -1140,3 +1140,24 @@ t.test('linked strategy: :root > * excludes transitive deps and store nodes', as 'nopt@7.2.1', ], ':root * should return all descendants including transitive deps') }) + +t.test('shouldBypassBefore with scoped package patterns', async t => { + const { shouldBypassBefore } = require('npm-pick-manifest') + + t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/*']), true, + 'scoped glob @myorg/* matches @myorg/foo') + t.equal(shouldBypassBefore('@myorg/bar', ['@myorg/*']), true, + 'scoped glob @myorg/* matches @myorg/bar') + t.equal(shouldBypassBefore('@other/foo', ['@myorg/*']), false, + 'scoped glob @myorg/* does not match @other/foo') + t.equal(shouldBypassBefore('unscoped', ['@myorg/*']), false, + 'scoped glob @myorg/* does not match unscoped package') + t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/foo']), true, + 'exact scoped name matches') + t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/bar']), false, + 'exact scoped name does not match different package') + t.equal(shouldBypassBefore('@myorg/foo', []), false, + 'empty exclude list matches nothing') + t.equal(shouldBypassBefore('@myorg/foo', undefined), false, + 'undefined exclude list matches nothing') +}) From 6619fc1fb09b6245d72e5077b5bcf05bc5fd5316 Mon Sep 17 00:00:00 2001 From: Casey Holzer Date: Wed, 1 Apr 2026 14:08:24 -0600 Subject: [PATCH 3/3] fix: improve min-release-age-exclude implementation --- lib/commands/query.js | 1 + node_modules/npm-pick-manifest/lib/index.js | 9 ++++++--- tap-snapshots/test/lib/docs.js.test.cjs | 3 +++ workspaces/arborist/lib/query-selector-all.js | 4 ++-- .../arborist/test/query-selector-all.js | 20 +++++++++---------- 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/commands/query.js b/lib/commands/query.js index cb8ed78454d85..63bd00c3206b3 100644 --- a/lib/commands/query.js +++ b/lib/commands/query.js @@ -50,6 +50,7 @@ class Query extends BaseCommand { 'package-lock-only', 'expect-results', 'before', + 'min-release-age', 'min-release-age-exclude', ] diff --git a/node_modules/npm-pick-manifest/lib/index.js b/node_modules/npm-pick-manifest/lib/index.js index 4e8de5bbef8a6..0f950f0731b2b 100644 --- a/node_modules/npm-pick-manifest/lib/index.js +++ b/node_modules/npm-pick-manifest/lib/index.js @@ -22,7 +22,10 @@ const avoidSemverOpt = { includePrerelease: true, loose: true } const shouldAvoid = (ver, avoid) => avoid && semver.satisfies(ver, avoid, avoidSemverOpt) -const shouldBypassBefore = (name, exclude) => { +const isExcludedFromTimeFilter = (name, exclude) => { + if (!exclude) { + return false + } const patterns = Array.isArray(exclude) ? exclude : [exclude] return patterns .filter(pattern => typeof pattern === 'string' && pattern) @@ -93,7 +96,7 @@ const pickManifest = (packument, wanted, opts) => { const restricted = (packument.policyRestrictions && packument.policyRestrictions.versions) || {} - const time = before && verTimes && !shouldBypassBefore(name, minReleaseAgeExclude) + const time = before && verTimes && !isExcludedFromTimeFilter(name, minReleaseAgeExclude) ? +(new Date(before)) : Infinity const spec = npa.resolve(name, wanted || defaultTag) @@ -229,4 +232,4 @@ module.exports = (packument, wanted, opts = {}) => { }) } -module.exports.shouldBypassBefore = shouldBypassBefore +module.exports.isExcludedFromTimeFilter = isExcludedFromTimeFilter diff --git a/tap-snapshots/test/lib/docs.js.test.cjs b/tap-snapshots/test/lib/docs.js.test.cjs index 22203a9c81d08..f40fbd5bc921b 100644 --- a/tap-snapshots/test/lib/docs.js.test.cjs +++ b/tap-snapshots/test/lib/docs.js.test.cjs @@ -5189,6 +5189,9 @@ Options: --before If passed to \`npm install\`, will rebuild the npm tree such that only + --min-release-age + If set, npm will build the npm tree such that only versions that were + --min-release-age-exclude Exclude package names from \`min-release-age\` and \`before\` publish-time diff --git a/workspaces/arborist/lib/query-selector-all.js b/workspaces/arborist/lib/query-selector-all.js index 7456c8469c53e..9b13abfb58fe8 100644 --- a/workspaces/arborist/lib/query-selector-all.js +++ b/workspaces/arborist/lib/query-selector-all.js @@ -6,7 +6,7 @@ const localeCompare = require('@isaacs/string-locale-compare')('en') const { log } = require('proc-log') const { minimatch } = require('minimatch') const npa = require('npm-package-arg') -const { shouldBypassBefore } = require('npm-pick-manifest') +const { isExcludedFromTimeFilter } = require('npm-pick-manifest') const pacote = require('pacote') const semver = require('semver') const npmFetch = require('npm-registry-fetch') @@ -892,7 +892,7 @@ const getPackageVersions = async (name, opts) => { // if the packument has a time property, and the user passed a before flag, then // we filter this list down to only those versions that existed before the specified date - if (packument.time && opts.before && !shouldBypassBefore(name, minReleaseAgeExclude)) { + if (packument.time && opts.before && !isExcludedFromTimeFilter(name, minReleaseAgeExclude)) { candidates = candidates.filter((version) => { // this version isn't found in the times at all, drop it if (!packument.time[version]) { diff --git a/workspaces/arborist/test/query-selector-all.js b/workspaces/arborist/test/query-selector-all.js index 4f33bdd9cedb1..4b55f18c41845 100644 --- a/workspaces/arborist/test/query-selector-all.js +++ b/workspaces/arborist/test/query-selector-all.js @@ -1141,23 +1141,23 @@ t.test('linked strategy: :root > * excludes transitive deps and store nodes', as ], ':root * should return all descendants including transitive deps') }) -t.test('shouldBypassBefore with scoped package patterns', async t => { - const { shouldBypassBefore } = require('npm-pick-manifest') +t.test('isExcludedFromTimeFilter with scoped package patterns', async t => { + const { isExcludedFromTimeFilter } = require('npm-pick-manifest') - t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/*']), true, + t.equal(isExcludedFromTimeFilter('@myorg/foo', ['@myorg/*']), true, 'scoped glob @myorg/* matches @myorg/foo') - t.equal(shouldBypassBefore('@myorg/bar', ['@myorg/*']), true, + t.equal(isExcludedFromTimeFilter('@myorg/bar', ['@myorg/*']), true, 'scoped glob @myorg/* matches @myorg/bar') - t.equal(shouldBypassBefore('@other/foo', ['@myorg/*']), false, + t.equal(isExcludedFromTimeFilter('@other/foo', ['@myorg/*']), false, 'scoped glob @myorg/* does not match @other/foo') - t.equal(shouldBypassBefore('unscoped', ['@myorg/*']), false, + t.equal(isExcludedFromTimeFilter('unscoped', ['@myorg/*']), false, 'scoped glob @myorg/* does not match unscoped package') - t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/foo']), true, + t.equal(isExcludedFromTimeFilter('@myorg/foo', ['@myorg/foo']), true, 'exact scoped name matches') - t.equal(shouldBypassBefore('@myorg/foo', ['@myorg/bar']), false, + t.equal(isExcludedFromTimeFilter('@myorg/foo', ['@myorg/bar']), false, 'exact scoped name does not match different package') - t.equal(shouldBypassBefore('@myorg/foo', []), false, + t.equal(isExcludedFromTimeFilter('@myorg/foo', []), false, 'empty exclude list matches nothing') - t.equal(shouldBypassBefore('@myorg/foo', undefined), false, + t.equal(isExcludedFromTimeFilter('@myorg/foo', undefined), false, 'undefined exclude list matches nothing') })