Skip to content

Commit cb91348

Browse files
committed
chore: release version 0.1.0-beta.1
1 parent 72d3a8a commit cb91348

8 files changed

Lines changed: 233 additions & 91 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ All notable changes to Rush-FS are documented here. The format is based on [Keep
1414

1515
- **Package name:** The main npm package is now **`@rush-fs/core`** (scoped). Install with `pnpm add @rush-fs/core` or `npm i @rush-fs/core`, and import with `import { readdir, readFile, ... } from '@rush-fs/core'`.
1616
- **Migration from `rush-fs`:** If you were using the old unscoped package `rush-fs`, replace it with `@rush-fs/core` in `package.json` and in all imports. The API is unchanged; only the package name and version differ. The old `rush-fs` package may be deprecated on npm in a separate step; prefer `@rush-fs/core` for new installs.
17+
- **glob:** `gitIgnore` option now defaults to **`false`** to align with Node.js `fs.globSync` (no .gitignore filtering by default).
18+
19+
### Fixed
20+
21+
- **glob:** Patterns with a path prefix (e.g. `.dir/**/*.txt` or `src/**/*.ts`) now work when used without an explicit `cwd`; the prefix is used as the search root, matching Node.js behavior.
22+
- **glob:** Recursive pattern `**/*.ext` with `cwd` now correctly recurses into subdirectories.
1723

1824
## [0.0.5]
1925

@@ -36,8 +42,8 @@ All notable changes to Rush-FS are documented here. The format is based on [Keep
3642

3743
---
3844

39-
[Unreleased]: https://github.com/CoderSerio/rush-fs/compare/v0.1.0-beta.0...HEAD
40-
[0.1.0-beta.0]: https://github.com/CoderSerio/rush-fs/compare/v0.0.5...v0.1.0-beta.0
45+
[Unreleased]: https://github.com/CoderSerio/rush-fs/compare/v0.1.0-beta.1...HEAD
46+
[0.1.0]: https://github.com/CoderSerio/rush-fs/compare/v0.0.5...v0.1.0-beta.1
4147
[0.0.5]: https://github.com/CoderSerio/rush-fs/compare/v0.0.4...v0.0.5
4248
[0.0.4]: https://github.com/CoderSerio/rush-fs/compare/v0.0.3...v0.0.4
4349
[0.0.3]: https://github.com/CoderSerio/rush-fs/releases/tag/v0.0.3

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
authors = []
44
edition = "2021"
55
name = "rush_fs"
6-
version = "0.1.0-beta.0"
6+
version = "0.1.0-beta.1"
77

88
[lib]
99
crate-type = ["cdylib"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ We are rewriting `fs` APIs one by one.
446446
withFileTypes?: boolean; //
447447
exclude?: string[]; //
448448
concurrency?: number; //
449-
gitIgnore?: boolean; //
449+
gitIgnore?: boolean; // default false (align with Node.js fs.globSync)
450450
};
451451
```
452452

README.zh-CN.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
与 Node.js <code>fs</code> API 对齐,可无痛替换现有项目中的 fs;在海量文件操作场景下获得数倍于内置 fs 的性能,由 Rust 驱动。
1717
</p>
1818

19-
<p align="center"><strong>⚠️ Alpha:</strong>当前为 <strong>alpha</strong> 版本,在 0.1.0 正式版前 API 与行为可能变更。</p>
20-
</div>
21-
2219
## 安装
2320

2421
```bash
@@ -447,7 +444,7 @@ graph TD
447444
withFileTypes?: boolean; //
448445
exclude?: string[]; //
449446
concurrency?: number; //
450-
gitIgnore?: boolean; //
447+
gitIgnore?: boolean; // 默认 false,与 Node.js fs.globSync 一致
451448
};
452449
```
453450

__test__/glob.spec.ts

Lines changed: 113 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,19 @@ test('globSync: should support exclude option', (t) => {
6161
t.true(filteredFiles.length < allFiles.length)
6262
})
6363

64-
test('globSync: should respect gitIgnore (default: true)', (t) => {
65-
// When gitIgnore: true (default), files in .gitignore are excluded.
66-
// When gitIgnore: false, they are included.
67-
const ignoredFiles = globSync('target/**/*.d', { cwd: CWD })
68-
const includedFiles = globSync('target/**/*.d', { cwd: CWD, gitIgnore: false })
69-
70-
if (includedFiles.length > 0) {
71-
t.true(ignoredFiles.length < includedFiles.length, 'Should find fewer files when respecting gitignore')
64+
test('globSync: gitIgnore option (default: false, align with Node)', (t) => {
65+
// Node.js fs.globSync does not respect .gitignore by default. When gitIgnore: true,
66+
// rush-fs excludes files matching .gitignore. Only assert when this repo has
67+
// .gitignore rules that affect target/**/*.d.
68+
const defaultFiles = globSync('target/**/*.d', { cwd: CWD })
69+
const withGitIgnore = globSync('target/**/*.d', { cwd: CWD, gitIgnore: true })
70+
71+
if (defaultFiles.length > 0 && withGitIgnore.length < defaultFiles.length) {
72+
t.pass('gitIgnore: true reduced results as expected')
73+
} else if (defaultFiles.length > 0) {
74+
t.pass('No .gitignore effect on target/**/*.d in this repo')
7275
} else {
73-
t.pass('Target directory empty or not present, skipping gitIgnore comparison')
76+
t.pass('Target directory empty or not present')
7477
}
7578
})
7679

@@ -156,24 +159,22 @@ test('globSync: dir-matching result should have isDirectory()=true with withFile
156159

157160
test('dual-run: globSync "src/*" should match node:fs.globSync behavior for directories', (t) => {
158161
const base = makeDirFixture()
159-
// node:fs.globSync v22.0.0 起稳定,对齐其目录匹配行为
162+
// node:fs.globSync is stable since v22; align directory matching behavior
160163
const nodeResults: string[] = []
161164
try {
162-
// @ts-ignore - globSync 在旧版 Node 可能不存在
165+
// @ts-expect-error globSync may be missing on older Node
163166
const nodeGlob = nodeFs.globSync as ((p: string, o: object) => string[]) | undefined
164167
if (typeof nodeGlob !== 'function') {
165168
t.pass('node:fs.globSync not available, skipping dual-run comparison')
166169
return
167170
}
168171
nodeResults.push(...nodeGlob('src/*', { cwd: base }))
169172
} catch {
170-
// 旧版 Node.js 不支持 fs.globSync,跳过对比
171173
t.pass('node:fs.globSync not available, skipping dual-run comparison')
172174
return
173175
}
174176
const hyperResults = globSync('src/*', { cwd: base }).map((r) => r.replace(/\\/g, '/'))
175177
const nodeNorm = nodeResults.map((r) => r.replace(/\\/g, '/'))
176-
// 检查 node.js 返回的目录条目我们也有
177178
const nodeDirs = nodeNorm.filter((n) => {
178179
try {
179180
return nodeFs.statSync(join(base, n)).isDirectory()
@@ -185,3 +186,102 @@ test('dual-run: globSync "src/*" should match node:fs.globSync behavior for dire
185186
t.true(hyperResults.includes(d), `should include directory '${d}' as node:fs does`)
186187
}
187188
})
189+
190+
// ===== Node-aligned behavior: path-prefix pattern, ** recursion =====
191+
192+
test('globSync: pattern with path prefix (e.g. .dir/**/*.txt) without cwd should find files', (t) => {
193+
const base = makeDirFixture()
194+
const hiddenDir = join(base, '.rush-fs-glob-check')
195+
nodeFs.mkdirSync(hiddenDir, { recursive: true })
196+
nodeFs.writeFileSync(join(hiddenDir, 'a.txt'), '')
197+
nodeFs.writeFileSync(join(hiddenDir, 'b.txt'), '')
198+
199+
const results = globSync('.rush-fs-glob-check/**/*.txt', { cwd: base })
200+
const names = results.map((r) => r.replace(/\\/g, '/'))
201+
t.true(
202+
names.length >= 2,
203+
`expected at least 2 .txt under .rush-fs-glob-check, got ${names.length}: ${names.join(', ')}`,
204+
)
205+
t.true(names.some((n) => n.endsWith('a.txt')))
206+
t.true(names.some((n) => n.endsWith('b.txt')))
207+
})
208+
209+
test('globSync: **/*.txt with cwd should recurse into subdirectories', (t) => {
210+
const base = makeDirFixture()
211+
nodeFs.writeFileSync(join(base, 'root-only.txt'), '')
212+
nodeFs.mkdirSync(join(base, 'sub'), { recursive: true })
213+
nodeFs.writeFileSync(join(base, 'sub', 'nested.txt'), '')
214+
215+
const results = globSync('**/*.txt', { cwd: base })
216+
const names = results.map((r) => r.replace(/\\/g, '/'))
217+
t.true(names.length >= 2, `expected at least 2 .txt (root + sub), got ${names.length}: ${names.join(', ')}`)
218+
t.true(names.some((n) => n === 'root-only.txt' || n.endsWith('/root-only.txt')))
219+
t.true(
220+
names.some((n) => n.endsWith('nested.txt')),
221+
`should include sub/nested.txt, got: ${names.join(', ')}`,
222+
)
223+
})
224+
225+
// Dual-run: align with node:fs.globSync when available (Node 22+)
226+
function getNodeGlobSync(): ((p: string, o: { cwd: string }) => string[]) | undefined {
227+
const g = (nodeFs as { globSync?: (p: string, o: { cwd: string }) => string[] }).globSync
228+
return typeof g === 'function' ? g : undefined
229+
}
230+
231+
test('dual-run: path-prefix pattern .dir/**/*.txt matches node:fs.globSync', (t) => {
232+
const base = makeDirFixture()
233+
const hiddenDir = join(base, '.rush-fs-glob-check')
234+
nodeFs.mkdirSync(hiddenDir, { recursive: true })
235+
nodeFs.writeFileSync(join(hiddenDir, 'a.txt'), '')
236+
nodeFs.writeFileSync(join(hiddenDir, 'b.txt'), '')
237+
238+
const hyper = globSync('.rush-fs-glob-check/**/*.txt', { cwd: base })
239+
.map((r) => r.replace(/\\/g, '/'))
240+
.sort()
241+
const nodeGlob = getNodeGlobSync()
242+
if (!nodeGlob) {
243+
t.pass('node:fs.globSync not available')
244+
return
245+
}
246+
let nodeResults: string[] = []
247+
try {
248+
nodeResults = nodeGlob('.rush-fs-glob-check/**/*.txt', { cwd: base })
249+
.map((r) => r.replace(/\\/g, '/'))
250+
.sort()
251+
} catch {
252+
t.pass('node:fs.globSync threw, skipping')
253+
return
254+
}
255+
t.true(
256+
hyper.length >= 2,
257+
`rush-fs: expected >= 2, got ${hyper.length} (run 'pnpm build' if path-prefix fix not in binary)`,
258+
)
259+
t.deepEqual(hyper.sort(), nodeResults.sort(), 'path-prefix pattern results should match Node')
260+
})
261+
262+
test('dual-run: **/*.txt recursion matches node:fs.globSync', (t) => {
263+
const base = makeDirFixture()
264+
nodeFs.writeFileSync(join(base, 'root-only.txt'), '')
265+
nodeFs.mkdirSync(join(base, 'sub'), { recursive: true })
266+
nodeFs.writeFileSync(join(base, 'sub', 'nested.txt'), '')
267+
268+
const hyper = globSync('**/*.txt', { cwd: base })
269+
.map((r) => r.replace(/\\/g, '/'))
270+
.sort()
271+
const nodeGlob = getNodeGlobSync()
272+
if (!nodeGlob) {
273+
t.pass('node:fs.globSync not available')
274+
return
275+
}
276+
let nodeResults: string[] = []
277+
try {
278+
nodeResults = nodeGlob('**/*.txt', { cwd: base })
279+
.map((r) => r.replace(/\\/g, '/'))
280+
.sort()
281+
} catch {
282+
t.pass('node:fs.globSync threw, skipping')
283+
return
284+
}
285+
t.true(hyper.length >= 2, `rush-fs: expected >= 2, got ${hyper.length}`)
286+
t.deepEqual(hyper.sort(), nodeResults.sort(), '**/*.txt recursive results should match Node')
287+
})

0 commit comments

Comments
 (0)