From f260cb51fa99ac27cf705af5fb3835750783a64d Mon Sep 17 00:00:00 2001 From: chatman-media Date: Fri, 19 Jun 2026 22:57:56 +0700 Subject: [PATCH] fix: forward `windows` option to basename in matchBase `picomatch.matchBase` stopped honoring the `windows` option after the switch from Node's `path.basename` to `utils.basename` (2f25761, "Remove automatic windows detection"). The `posix` argument that `picomatch.test` still passes was dropped from the signature, and `utils.basename(input)` was called without the `{ windows }` flag, so backslash-separated paths were never split into segments. As a result `isMatch('a\\b\\c\\foo.md', '*.md', { matchBase: true, windows: true })` returned `false` even though `utils.basename` already supports `{ windows: true }` (and is tested for it). Restore the `posix` parameter (defaulting to `options.windows`, as in `picomatch.test`) and pass it through to `utils.basename`. --- lib/picomatch.js | 4 ++-- test/options.js | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/picomatch.js b/lib/picomatch.js index fbb8b1ca..448d354b 100644 --- a/lib/picomatch.js +++ b/lib/picomatch.js @@ -157,9 +157,9 @@ picomatch.test = (input, regex, options, { glob, posix } = {}) => { * @api public */ -picomatch.matchBase = (input, glob, options) => { +picomatch.matchBase = (input, glob, options, posix = options && options.windows) => { const regex = glob instanceof RegExp ? glob : picomatch.makeRe(glob, options); - return regex.test(utils.basename(input)); + return regex.test(utils.basename(input, { windows: posix })); }; /** diff --git a/test/options.js b/test/options.js index 8993d181..5d0f98af 100644 --- a/test/options.js +++ b/test/options.js @@ -2,7 +2,7 @@ const assert = require('assert'); const match = require('./support/match'); -const { isMatch } = require('..'); +const { isMatch, matchBase } = require('..'); describe('options', () => { describe('options.matchBase', () => { @@ -15,6 +15,19 @@ describe('options', () => { assert.deepStrictEqual(match(['x/y/acb', 'acb/', 'acb/d/e', 'x/y/acb/d'], 'a?b', { matchBase: true, windows: true }), ['x/y/acb', 'acb/']); }); + it('should match the basename of backslash-separated paths when `options.windows` is true', () => { + assert(isMatch('foo\\bar.js', '*.js', { matchBase: true, windows: true })); + assert(isMatch('a\\b\\c\\d.md', '*.md', { matchBase: true, windows: true })); + assert(isMatch('a\\b\\c\\foo.md', '*.md', { matchBase: true, windows: true })); + assert(isMatch('x\\y\\acb', 'a?b', { matchBase: true, windows: true })); + assert(!isMatch('a\\b\\c\\d.md', '*.js', { matchBase: true, windows: true })); + }); + + it('should pass the `windows` option through `matchBase`', () => { + assert(matchBase('foo\\bar.js', '*.js', { windows: true })); + assert(matchBase('a\\b\\c\\d.md', '*.md', { windows: true })); + }); + it('should work with negation patterns', () => { assert(isMatch('./x/y.js', '*.js', { matchBase: true, windows: true })); assert(!isMatch('./x/y.js', '!*.js', { matchBase: true, windows: true }));