From aae20ef9bbfe4faede6e65dfc52d65a5f2abb048 Mon Sep 17 00:00:00 2001 From: Beth Griggs Date: Wed, 7 Oct 2026 14:36:36 +0100 Subject: [PATCH] feat: add && syntax for AND conditions in skip entries Allows combining multiple match conditions with && in a single string, so a skip only applies when all parts match. For example: "skip": ["win32", "aix && >=26"] Previously only OR logic was possible (array items are OR'd). The new syntax works with any existing condition type: semver ranges, platform, arch, platform-arch combos, distro, endian, and fips. Assisted-by: IBM Bob Signed-off-by: Beth Griggs --- lib/match-conditions.js | 6 ++++++ test/test-match-conditions.js | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/lib/match-conditions.js b/lib/match-conditions.js index 3e98e1587..bbc835620 100644 --- a/lib/match-conditions.js +++ b/lib/match-conditions.js @@ -50,6 +50,12 @@ export class ConditionMatcher { } isStringMatch(conditions) { + // "a && b" — split on && and require every part to match. + if (conditions.includes('&&')) { + const parts = conditions.split('&&').map((s) => s.trim()); + if (parts.some((part) => part === '')) return false; + return parts.every((part) => this.isStringMatch(part)); + } if ( semver.validRange(conditions) && semver.satisfies(this.semVersion, conditions) diff --git a/test/test-match-conditions.js b/test/test-match-conditions.js index a710e3190..197553a8b 100644 --- a/test/test-match-conditions.js +++ b/test/test-match-conditions.js @@ -128,5 +128,41 @@ test('isMatch', (t) => { t.ok(isMatch(true), 'true is matched'); t.notOk(isMatch(false), 'false is not matched'); t.notOk(isMatch(123), 'invalid input is not matched'); + t.ok(isMatch('darwin && v5'), 'isMatch delegates && string to isStringMatch'); + t.notOk( + isMatch('darwin && hurd'), + 'isMatch delegates partial && string -> false' + ); + t.end(); +}); + +test('isStringMatch - && malformed', (t) => { + t.notOk( + testMatcher.isStringMatch('darwin &&'), + 'trailing && produces empty part -> false' + ); + t.notOk( + testMatcher.isStringMatch('&& darwin'), + 'leading && produces empty part -> false' + ); + t.notOk(testMatcher.isStringMatch('&&'), 'bare && -> false'); + t.notOk( + testMatcher.isStringMatch('darwin && && v5'), + 'repeated && produces empty middle part -> false' + ); + t.end(); +}); + +test('isStringMatch - && syntax with semver range: aix && >=26', (t) => { + const testMatcher = new ConditionMatcher({ + version: 'v26.0.0', + platform: 'aix', + arch: 'ppc64', + distro: '', + release: '', + endian: 'big', + fips: '' + }); + t.ok(testMatcher.isStringMatch('aix && >=26'), 'aix + v26 -> true'); t.end(); });