@zenfs/core 2.5.1 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node/promises.js +19 -11
- package/dist/node/sync.js +19 -11
- package/dist/utils.js +9 -4
- package/package.json +1 -1
- package/tests/common/glob.test.ts +135 -0
package/dist/node/promises.js
CHANGED
|
@@ -898,25 +898,33 @@ export async function statfs(path, opts) {
|
|
|
898
898
|
export function glob(pattern, opt) {
|
|
899
899
|
pattern = Array.isArray(pattern) ? pattern : [pattern];
|
|
900
900
|
const { cwd = '/', withFileTypes = false, exclude = () => false } = opt || {};
|
|
901
|
-
|
|
902
|
-
const
|
|
901
|
+
const normalizedPatterns = pattern.map(p => p.replace(/^\/+/g, ''));
|
|
902
|
+
const hasGlobStar = normalizedPatterns.some(p => p.includes('**'));
|
|
903
|
+
const patternBases = normalizedPatterns.map(p => {
|
|
904
|
+
const firstGlob = p.search(/[*?[\]{]/);
|
|
905
|
+
if (firstGlob === -1)
|
|
906
|
+
return p;
|
|
907
|
+
const lastSlash = p.lastIndexOf('/', firstGlob);
|
|
908
|
+
return lastSlash === -1 ? '' : p.slice(0, lastSlash);
|
|
909
|
+
});
|
|
910
|
+
const regexPatterns = normalizedPatterns.map(globToRegex);
|
|
903
911
|
async function* recursiveList(dir) {
|
|
904
912
|
const entries = await readdir(dir, { withFileTypes, encoding: 'utf8' });
|
|
905
913
|
for (const entry of entries) {
|
|
906
|
-
const fullPath = withFileTypes ?
|
|
914
|
+
const fullPath = join(dir, withFileTypes ? entry.name : entry);
|
|
907
915
|
if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
|
|
908
916
|
continue;
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
917
|
+
const relativePath = fullPath.replace(/^\/+/g, '');
|
|
918
|
+
if ((await stat(fullPath)).isDirectory()) {
|
|
919
|
+
if (hasGlobStar || patternBases.some(base => relativePath === base || base.startsWith(relativePath + '/'))) {
|
|
920
|
+
yield* recursiveList(fullPath);
|
|
921
|
+
}
|
|
914
922
|
}
|
|
915
|
-
if (regexPatterns.some(
|
|
916
|
-
yield withFileTypes ? entry :
|
|
923
|
+
if (regexPatterns.some(rx => rx.test(relativePath))) {
|
|
924
|
+
yield withFileTypes ? entry : relativePath;
|
|
917
925
|
}
|
|
918
926
|
}
|
|
919
927
|
}
|
|
920
|
-
return recursiveList(cwd);
|
|
928
|
+
return recursiveList(cwd instanceof URL ? cwd.pathname : cwd);
|
|
921
929
|
}
|
|
922
930
|
glob;
|
package/dist/node/sync.js
CHANGED
|
@@ -656,27 +656,35 @@ export function statfsSync(path, options) {
|
|
|
656
656
|
export function globSync(pattern, options = {}) {
|
|
657
657
|
pattern = Array.isArray(pattern) ? pattern : [pattern];
|
|
658
658
|
const { cwd = '/', withFileTypes = false, exclude = () => false } = options;
|
|
659
|
-
|
|
660
|
-
const
|
|
659
|
+
const normalizedPatterns = pattern.map(p => p.replace(/^\/+/g, ''));
|
|
660
|
+
const hasGlobStar = normalizedPatterns.some(p => p.includes('**'));
|
|
661
|
+
const patternBases = normalizedPatterns.map(p => {
|
|
662
|
+
const firstGlob = p.search(/[*?[\]{]/);
|
|
663
|
+
if (firstGlob === -1)
|
|
664
|
+
return p;
|
|
665
|
+
const lastSlash = p.lastIndexOf('/', firstGlob);
|
|
666
|
+
return lastSlash === -1 ? '' : p.slice(0, lastSlash);
|
|
667
|
+
});
|
|
668
|
+
const regexPatterns = normalizedPatterns.map(globToRegex);
|
|
661
669
|
const results = [];
|
|
662
670
|
function recursiveList(dir) {
|
|
663
671
|
const entries = readdirSync(dir, { withFileTypes, encoding: 'utf8' });
|
|
664
672
|
for (const entry of entries) {
|
|
665
|
-
const fullPath = withFileTypes ?
|
|
673
|
+
const fullPath = join(dir, withFileTypes ? entry.name : entry);
|
|
666
674
|
if (typeof exclude != 'function' ? exclude.some(p => matchesGlob(p, fullPath)) : exclude((withFileTypes ? entry : fullPath)))
|
|
667
675
|
continue;
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
676
|
+
const relativePath = fullPath.replace(/^\/+/g, '');
|
|
677
|
+
if (statSync(fullPath).isDirectory()) {
|
|
678
|
+
if (hasGlobStar || patternBases.some(base => relativePath === base || base.startsWith(relativePath + '/'))) {
|
|
679
|
+
recursiveList(fullPath);
|
|
680
|
+
}
|
|
673
681
|
}
|
|
674
|
-
if (regexPatterns.some(
|
|
675
|
-
results.push(withFileTypes ? entry :
|
|
682
|
+
if (regexPatterns.some(rx => rx.test(relativePath))) {
|
|
683
|
+
results.push(withFileTypes ? entry : relativePath);
|
|
676
684
|
}
|
|
677
685
|
}
|
|
678
686
|
}
|
|
679
|
-
recursiveList(cwd);
|
|
687
|
+
recursiveList(cwd instanceof URL ? cwd.pathname : cwd);
|
|
680
688
|
return results;
|
|
681
689
|
}
|
|
682
690
|
globSync;
|
package/dist/utils.js
CHANGED
|
@@ -97,11 +97,16 @@ export function normalizeOptions(options, encoding = 'utf8', flag, mode = 0) {
|
|
|
97
97
|
* @internal
|
|
98
98
|
*/
|
|
99
99
|
export function globToRegex(pattern) {
|
|
100
|
+
const GLOBSTAR = '\0GS\0';
|
|
101
|
+
const STAR = '\0S\0';
|
|
100
102
|
pattern = pattern
|
|
101
|
-
.replace(
|
|
102
|
-
.replace(
|
|
103
|
-
.replace(
|
|
104
|
-
.replace(/\?/g, '.')
|
|
103
|
+
.replace(/\*\*/g, GLOBSTAR)
|
|
104
|
+
.replace(/\*/g, STAR)
|
|
105
|
+
.replace(/[.+^$(){}|[\]\\]/g, '\\$&')
|
|
106
|
+
.replace(/\?/g, '.')
|
|
107
|
+
.replaceAll('/' + GLOBSTAR + '/', '(?:/.*)?/')
|
|
108
|
+
.replaceAll(GLOBSTAR, '.*')
|
|
109
|
+
.replaceAll(STAR, '[^/]*');
|
|
105
110
|
return new RegExp(`^${pattern}$`);
|
|
106
111
|
}
|
|
107
112
|
export async function waitOnline(worker) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { suite, test } from 'node:test';
|
|
4
|
+
import { fs } from '../common.js';
|
|
5
|
+
|
|
6
|
+
// Set up a directory structure for glob tests
|
|
7
|
+
fs.mkdirSync('/glob');
|
|
8
|
+
fs.mkdirSync('/glob/sub');
|
|
9
|
+
fs.mkdirSync('/glob/sub/deep');
|
|
10
|
+
fs.writeFileSync('/glob/a.txt', 'a');
|
|
11
|
+
fs.writeFileSync('/glob/b.txt', 'b');
|
|
12
|
+
fs.writeFileSync('/glob/c.js', 'c');
|
|
13
|
+
fs.writeFileSync('/glob/sub/d.txt', 'd');
|
|
14
|
+
fs.writeFileSync('/glob/sub/e.js', 'e');
|
|
15
|
+
fs.writeFileSync('/glob/sub/deep/f.txt', 'f');
|
|
16
|
+
|
|
17
|
+
suite('globSync', () => {
|
|
18
|
+
test('wildcard in root', () => {
|
|
19
|
+
const results = fs.globSync('glob/*');
|
|
20
|
+
assert(results.includes('glob/a.txt'), 'should include glob/a.txt');
|
|
21
|
+
assert(results.includes('glob/b.txt'), 'should include glob/b.txt');
|
|
22
|
+
assert(results.includes('glob/c.js'), 'should include glob/c.js');
|
|
23
|
+
assert(results.includes('glob/sub'), 'should include glob/sub');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('wildcard with absolute path pattern', () => {
|
|
27
|
+
const results = fs.globSync('/glob/*');
|
|
28
|
+
assert(results.includes('glob/a.txt'), 'should include glob/a.txt');
|
|
29
|
+
assert(results.includes('glob/b.txt'), 'should include glob/b.txt');
|
|
30
|
+
assert(results.includes('glob/c.js'), 'should include glob/c.js');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('wildcard with extension filter', () => {
|
|
34
|
+
const results = fs.globSync('/glob/*.txt');
|
|
35
|
+
assert(results.includes('glob/a.txt'));
|
|
36
|
+
assert(results.includes('glob/b.txt'));
|
|
37
|
+
assert(!results.includes('glob/c.js'), 'should not include .js files');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('nested path wildcard', () => {
|
|
41
|
+
const results = fs.globSync('/glob/sub/*');
|
|
42
|
+
assert(results.includes('glob/sub/d.txt'));
|
|
43
|
+
assert(results.includes('glob/sub/e.js'));
|
|
44
|
+
assert(!results.includes('glob/a.txt'), 'should not include files from parent');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('globstar (**)', () => {
|
|
48
|
+
const results = fs.globSync('/glob/**/*.txt');
|
|
49
|
+
assert(results.includes('glob/a.txt'));
|
|
50
|
+
assert(results.includes('glob/b.txt'));
|
|
51
|
+
assert(results.includes('glob/sub/d.txt'));
|
|
52
|
+
assert(results.includes('glob/sub/deep/f.txt'));
|
|
53
|
+
assert(!results.includes('glob/c.js'), 'should not include .js files');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('question mark wildcard', () => {
|
|
57
|
+
const results = fs.globSync('/glob/?.txt');
|
|
58
|
+
assert(results.includes('glob/a.txt'));
|
|
59
|
+
assert(results.includes('glob/b.txt'));
|
|
60
|
+
assert(!results.includes('glob/c.js'));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test('multiple patterns', () => {
|
|
64
|
+
const results = fs.globSync(['/glob/*.txt', '/glob/*.js']);
|
|
65
|
+
assert(results.includes('glob/a.txt'));
|
|
66
|
+
assert(results.includes('glob/c.js'));
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('no matches returns empty', () => {
|
|
70
|
+
const results = fs.globSync('/glob/*.xyz');
|
|
71
|
+
assert.equal(results.length, 0);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test('withFileTypes option', () => {
|
|
75
|
+
const results = fs.globSync('/glob/*.txt', { withFileTypes: true });
|
|
76
|
+
assert(results.length > 0, 'should have results');
|
|
77
|
+
assert(typeof results[0] === 'object' && 'name' in results[0], 'results should be Dirent objects');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('exclude option with function', () => {
|
|
81
|
+
const results = fs.globSync('/glob/*', { exclude: path => typeof path === 'string' && path.endsWith('.js') });
|
|
82
|
+
assert(!results.includes('glob/c.js'), 'should exclude .js files');
|
|
83
|
+
assert(results.includes('glob/a.txt'), 'should still include .txt files');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
await suite('promises.glob', () => {
|
|
88
|
+
test('wildcard in root', async () => {
|
|
89
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/*'));
|
|
90
|
+
assert(results.includes('glob/a.txt'));
|
|
91
|
+
assert(results.includes('glob/b.txt'));
|
|
92
|
+
assert(results.includes('glob/c.js'));
|
|
93
|
+
assert(results.includes('glob/sub'));
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('wildcard with absolute path pattern', async () => {
|
|
97
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/*'));
|
|
98
|
+
assert(results.includes('glob/a.txt'));
|
|
99
|
+
assert(results.includes('glob/b.txt'));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('wildcard with extension filter', async () => {
|
|
103
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/*.txt'));
|
|
104
|
+
assert(results.includes('glob/a.txt'));
|
|
105
|
+
assert(results.includes('glob/b.txt'));
|
|
106
|
+
assert(!results.includes('glob/c.js'));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test('nested path wildcard', async () => {
|
|
110
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/sub/*'));
|
|
111
|
+
assert(results.includes('glob/sub/d.txt'));
|
|
112
|
+
assert(results.includes('glob/sub/e.js'));
|
|
113
|
+
assert(!results.includes('glob/a.txt'));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('globstar (**)', async () => {
|
|
117
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/**/*.txt'));
|
|
118
|
+
assert(results.includes('glob/a.txt'));
|
|
119
|
+
assert(results.includes('glob/b.txt'));
|
|
120
|
+
assert(results.includes('glob/sub/d.txt'));
|
|
121
|
+
assert(results.includes('glob/sub/deep/f.txt'));
|
|
122
|
+
assert(!results.includes('glob/c.js'));
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('multiple patterns', async () => {
|
|
126
|
+
const results = await Array.fromAsync(fs.promises.glob(['/glob/*.txt', '/glob/*.js']));
|
|
127
|
+
assert(results.includes('glob/a.txt'));
|
|
128
|
+
assert(results.includes('glob/c.js'));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('no matches returns empty', async () => {
|
|
132
|
+
const results = await Array.fromAsync(fs.promises.glob('/glob/*.xyz'));
|
|
133
|
+
assert.equal(results.length, 0);
|
|
134
|
+
});
|
|
135
|
+
});
|