path: add matchGlob
method
PR-URL: https://github.com/nodejs/node/pull/52881 Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
This commit is contained in:
parent
78ea6cee1b
commit
92a25abca9
@ -279,6 +279,29 @@ path.format({
|
||||
// Returns: 'C:\\path\\dir\\file.txt'
|
||||
```
|
||||
|
||||
## `path.matchesGlob(path, pattern)`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
* `path` {string} The path to glob-match against.
|
||||
* `pattern` {string} The glob to check the path against.
|
||||
* Returns: {boolean} Whether or not the `path` matched the `pattern`.
|
||||
|
||||
The `path.matchesGlob()` method determines if `path` matches the `pattern`.
|
||||
|
||||
For example:
|
||||
|
||||
```js
|
||||
path.matchesGlob('/foo/bar', '/foo/*'); // true
|
||||
path.matchesGlob('/foo/bar*', 'foo/bird'); // false
|
||||
```
|
||||
|
||||
A [`TypeError`][] is thrown if `path` or `pattern` are not strings.
|
||||
|
||||
## `path.isAbsolute(path)`
|
||||
|
||||
<!-- YAML
|
||||
|
32
lib/path.js
32
lib/path.js
@ -47,7 +47,15 @@ const {
|
||||
validateString,
|
||||
} = require('internal/validators');
|
||||
|
||||
const {
|
||||
getLazy,
|
||||
emitExperimentalWarning,
|
||||
} = require('internal/util');
|
||||
|
||||
const lazyMinimatch = getLazy(() => require('internal/deps/minimatch/index'));
|
||||
|
||||
const platformIsWin32 = (process.platform === 'win32');
|
||||
const platformIsOSX = (process.platform === 'darwin');
|
||||
|
||||
function isPathSeparator(code) {
|
||||
return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;
|
||||
@ -153,6 +161,22 @@ function _format(sep, pathObject) {
|
||||
return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;
|
||||
}
|
||||
|
||||
function glob(path, pattern, windows) {
|
||||
emitExperimentalWarning('glob');
|
||||
validateString(path, 'path');
|
||||
validateString(pattern, 'pattern');
|
||||
return lazyMinimatch().minimatch(path, pattern, {
|
||||
__proto__: null,
|
||||
nocase: platformIsOSX || platformIsWin32,
|
||||
windowsPathsNoEscape: true,
|
||||
nonegate: true,
|
||||
nocomment: true,
|
||||
optimizationLevel: 2,
|
||||
platform: windows ? 'win32' : 'posix',
|
||||
nocaseMagicOnly: true,
|
||||
});
|
||||
}
|
||||
|
||||
const win32 = {
|
||||
/**
|
||||
* path.resolve([from ...], to)
|
||||
@ -1065,6 +1089,10 @@ const win32 = {
|
||||
return ret;
|
||||
},
|
||||
|
||||
matchesGlob(path, pattern) {
|
||||
return glob(path, pattern, true);
|
||||
},
|
||||
|
||||
sep: '\\',
|
||||
delimiter: ';',
|
||||
win32: null,
|
||||
@ -1530,6 +1558,10 @@ const posix = {
|
||||
return ret;
|
||||
},
|
||||
|
||||
matchesGlob(path, pattern) {
|
||||
return glob(path, pattern, false);
|
||||
},
|
||||
|
||||
sep: '/',
|
||||
delimiter: ':',
|
||||
win32: null,
|
||||
|
44
test/parallel/test-path-glob.js
Normal file
44
test/parallel/test-path-glob.js
Normal file
@ -0,0 +1,44 @@
|
||||
'use strict';
|
||||
|
||||
require('../common');
|
||||
const assert = require('assert');
|
||||
const path = require('path');
|
||||
|
||||
const globs = {
|
||||
win32: [
|
||||
['foo\\bar\\baz', 'foo\\[bcr]ar\\baz', true], // Matches 'bar' or 'car' in 'foo\\bar'
|
||||
['foo\\bar\\baz', 'foo\\[!bcr]ar\\baz', false], // Matches anything except 'bar' or 'car' in 'foo\\bar'
|
||||
['foo\\bar\\baz', 'foo\\[bc-r]ar\\baz', true], // Matches 'bar' or 'car' using range in 'foo\\bar'
|
||||
['foo\\bar\\baz', 'foo\\*\\!bar\\*\\baz', false], // Matches anything with 'foo' and 'baz' but not 'bar' in between
|
||||
['foo\\bar1\\baz', 'foo\\bar[0-9]\\baz', true], // Matches 'bar' followed by any digit in 'foo\\bar1'
|
||||
['foo\\bar5\\baz', 'foo\\bar[0-9]\\baz', true], // Matches 'bar' followed by any digit in 'foo\\bar5'
|
||||
['foo\\barx\\baz', 'foo\\bar[a-z]\\baz', true], // Matches 'bar' followed by any lowercase letter in 'foo\\barx'
|
||||
['foo\\bar\\baz\\boo', 'foo\\[bc-r]ar\\baz\\*', true], // Matches 'bar' or 'car' in 'foo\\bar'
|
||||
['foo\\bar\\baz', 'foo/**', true], // Matches anything in 'foo'
|
||||
['foo\\bar\\baz', '*', false], // No match
|
||||
],
|
||||
posix: [
|
||||
['foo/bar/baz', 'foo/[bcr]ar/baz', true], // Matches 'bar' or 'car' in 'foo/bar'
|
||||
['foo/bar/baz', 'foo/[!bcr]ar/baz', false], // Matches anything except 'bar' or 'car' in 'foo/bar'
|
||||
['foo/bar/baz', 'foo/[bc-r]ar/baz', true], // Matches 'bar' or 'car' using range in 'foo/bar'
|
||||
['foo/bar/baz', 'foo/*/!bar/*/baz', false], // Matches anything with 'foo' and 'baz' but not 'bar' in between
|
||||
['foo/bar1/baz', 'foo/bar[0-9]/baz', true], // Matches 'bar' followed by any digit in 'foo/bar1'
|
||||
['foo/bar5/baz', 'foo/bar[0-9]/baz', true], // Matches 'bar' followed by any digit in 'foo/bar5'
|
||||
['foo/barx/baz', 'foo/bar[a-z]/baz', true], // Matches 'bar' followed by any lowercase letter in 'foo/barx'
|
||||
['foo/bar/baz/boo', 'foo/[bc-r]ar/baz/*', true], // Matches 'bar' or 'car' in 'foo/bar'
|
||||
['foo/bar/baz', 'foo/**', true], // Matches anything in 'foo'
|
||||
['foo/bar/baz', '*', false], // No match
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
for (const [platform, platformGlobs] of Object.entries(globs)) {
|
||||
for (const [pathStr, glob, expected] of platformGlobs) {
|
||||
const actual = path[platform].matchesGlob(pathStr, glob);
|
||||
assert.strictEqual(actual, expected, `Expected ${pathStr} to ` + (expected ? '' : 'not ') + `match ${glob} on ${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Test for non-string input
|
||||
assert.throws(() => path.matchesGlob(123, 'foo/bar/baz'), /.*must be of type string.*/);
|
||||
assert.throws(() => path.matchesGlob('foo/bar/baz', 123), /.*must be of type string.*/);
|
Loading…
x
Reference in New Issue
Block a user