diff --git a/package-lock.json b/package-lock.json index c483f109..d4232beb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^7.1.4", - "minipass": "^4.2.1", + "minipass": "^4.2.4", "path-scurry": "^1.4.0" }, "devDependencies": { @@ -2942,9 +2942,9 @@ "peer": true }, "node_modules/minipass": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.1.tgz", - "integrity": "sha512-KS4CHIsDfOZetnT+u6fwxyFADXLamtkPxkGScmmtTW//MlRrImV+LtbmbJpLQ86Hw7km/utbfEfndhGBrfwvlA==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", + "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==", "engines": { "node": ">=8" } @@ -8584,9 +8584,9 @@ "peer": true }, "minipass": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.1.tgz", - "integrity": "sha512-KS4CHIsDfOZetnT+u6fwxyFADXLamtkPxkGScmmtTW//MlRrImV+LtbmbJpLQ86Hw7km/utbfEfndhGBrfwvlA==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", + "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==" }, "mkdirp": { "version": "2.0.0", diff --git a/package.json b/package.json index 21ad2b8d..16cd230d 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^7.1.4", - "minipass": "^4.2.1", + "minipass": "^4.2.4", "path-scurry": "^1.4.0" }, "devDependencies": { diff --git a/src/index.ts b/src/index.ts index ed539dc7..670087ed 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import { GWOFileTypesTrue, GWOFileTypesUnset, MatchStream, + Result, } from './walker.js' export function globStreamSync( @@ -106,19 +107,64 @@ export async function glob( return new Glob(pattern, options).walk() } +export function globIterate( + pattern: string | string[], + options?: GlobOptionsWithFileTypesUnset | undefined +): AsyncGenerator, void, void> +export function globIterate( + pattern: string | string[], + options: GlobOptionsWithFileTypesTrue +): AsyncGenerator, void, void> +export function globIterate( + pattern: string | string[], + options: GlobOptionsWithFileTypesFalse +): AsyncGenerator, void, void> +export function globIterate( + pattern: string | string[], + options: GlobOptions +): AsyncGenerator, void, void> +export function globIterate( + pattern: string | string[], + options: GlobOptions = {} +) { + return new Glob(pattern, options).iterate() +} + +export function globIterateSync( + pattern: string | string[], + options?: GlobOptionsWithFileTypesUnset | undefined +): Generator, void, void> +export function globIterateSync( + pattern: string | string[], + options: GlobOptionsWithFileTypesTrue +): Generator, void, void> +export function globIterateSync( + pattern: string | string[], + options: GlobOptionsWithFileTypesFalse +): Generator, void, void> +export function globIterateSync( + pattern: string | string[], + options: GlobOptions +): Generator, void, void> +export function globIterateSync( + pattern: string | string[], + options: GlobOptions = {} +) { + return new Glob(pattern, options).iterateSync() +} + /* c8 ignore start */ export { Glob } from './glob.js' export type { GlobOptions } from './glob.js' export { hasMagic } from './has-magic.js' /* c8 ignore stop */ export default Object.assign(glob, { - glob: glob, - sync: globSync, + glob, globSync, - stream: globStream, - streamSync: globStreamSync, globStream, globStreamSync, + globIterate, + globIterateSync, Glob, hasMagic, }) diff --git a/src/walker.ts b/src/walker.ts index 382746c7..16f1749a 100644 --- a/src/walker.ts +++ b/src/walker.ts @@ -74,7 +74,9 @@ const makeIgnore = ( ? new Ignore([ignore], opts) : Array.isArray(ignore) ? new Ignore(ignore, opts) - : ignore + : /* c8 ignore start */ + ignore +/* c8 ignore stop */ /** * basic walking utilities that all the glob walker types use @@ -89,6 +91,7 @@ export abstract class GlobUtil { #onResume: (() => any)[] = [] #ignore?: Ignore #sep: '\\' | '/' + signal?: AbortSignal constructor(patterns: Pattern[], path: Path, opts: O) constructor(patterns: Pattern[], path: Path, opts: O) { @@ -100,7 +103,10 @@ export abstract class GlobUtil { this.#ignore = makeIgnore(opts.ignore, opts) } if (opts.signal) { - opts.signal.addEventListener('abort', () => this.abort()) + this.signal = opts.signal + this.signal.addEventListener('abort', () => { + this.#onResume.length = 0 + }) } } @@ -116,7 +122,9 @@ export abstract class GlobUtil { this.paused = true } resume() { - if (this.aborted) return + /* c8 ignore start */ + if (this.signal?.aborted) return + /* c8 ignore stop */ this.paused = false let fn: (() => any) | undefined = undefined while (!this.paused && (fn = this.#onResume.shift())) { @@ -124,135 +132,46 @@ export abstract class GlobUtil { } } onResume(fn: () => any) { - if (this.aborted) return + if (this.signal?.aborted) return + /* c8 ignore start */ if (!this.paused) fn() + /* c8 ignore stop */ else this.#onResume.push(fn) } - abort() { - this.paused = true - this.aborted = true - } - // do the requisite realpath/stat checking, and return true/false - // to say whether to include the match or filter it out. + // do the requisite realpath/stat checking, and return the path + // to add or undefined to filter it out. async matchCheck(e: Path, ifDir: boolean): Promise { + if (ifDir && this.opts.nodir) return undefined let rpc: Path | undefined if (this.opts.realpath) { - rpc = e.realpathCached() - if (rpc) { - if (this.#ignored(rpc) || (e.isDirectory() && this.opts.nodir)) { - return undefined - } - e = rpc - } - } - if (e.isDirectory() && this.opts.nodir) { - return undefined + rpc = e.realpathCached() || (await e.realpath()) + if (!rpc) return undefined + e = rpc } - const needRealPath = !rpc && this.opts.realpath const needStat = e.isUnknown() - if (needRealPath && needStat) { - const r = await e.realpath().then(e => e?.lstat()) - if ( - !r || - this.#ignored(r) || - (!e.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if (needRealPath) { - const r = await e.realpath() - if ( - !r || - this.#ignored(r) || - (!e.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if (needStat) { - const r = await e.lstat() - if ( - !r || - this.#ignored(r) || - (!r.canReaddir() && ifDir) || - (r.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if ( - this.#ignored(e) || - (!e.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } else { - return e - } + return this.matchCheckTest(needStat ? await e.lstat() : e, ifDir) + } + + matchCheckTest(e: Path | undefined, ifDir: boolean): Path | undefined { + return e && + !this.#ignored(e) && + (!ifDir || e.canReaddir()) && + (!this.opts.nodir || !e.isDirectory()) + ? e + : undefined } matchCheckSync(e: Path, ifDir: boolean): Path | undefined { + if (ifDir && this.opts.nodir) return undefined let rpc: Path | undefined if (this.opts.realpath) { - rpc = e.realpathCached() - if (rpc) { - if (this.#ignored(rpc) || (e.isDirectory() && this.opts.nodir)) { - return undefined - } - e = rpc - } - } - if (e.isDirectory() && this.opts.nodir) { - return undefined + rpc = e.realpathCached() || e.realpathSync() + if (!rpc) return undefined + e = rpc } - const needRealPath = !rpc && this.opts.realpath const needStat = e.isUnknown() - if (needRealPath && needStat) { - const r = e.realpathSync()?.lstatSync() - if ( - !r || - this.#ignored(r) || - (!r.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if (needRealPath) { - const r = e.realpathSync() - if ( - !r || - this.#ignored(r) || - (!r.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if (needStat) { - const r = e.lstatSync() - if ( - !r || - this.#ignored(r) || - (!r.canReaddir() && ifDir) || - (r.isDirectory() && this.opts.nodir) - ) { - return undefined - } - return r - } else if ( - this.#ignored(e) || - (!e.canReaddir() && ifDir) || - (e.isDirectory() && this.opts.nodir) - ) { - return undefined - } else { - return e - } + return this.matchCheckTest(needStat ? e.lstatSync() : e, ifDir) } abstract matchEmit(p: Result): void @@ -265,8 +184,6 @@ export abstract class GlobUtil { // ok, we have what we need! if (this.opts.withFileTypes) { this.matchEmit(e) - } else if (this.opts.nodir && e.isDirectory()) { - return } else if (this.opts.absolute || absolute) { this.matchEmit(e.fullpath() + mark) } else { @@ -276,22 +193,19 @@ export abstract class GlobUtil { } async match(e: Path, absolute: boolean, ifDir: boolean): Promise { - if (this.#ignored(e)) return const p = await this.matchCheck(e, ifDir) if (p) this.matchFinish(p, absolute) } matchSync(e: Path, absolute: boolean, ifDir: boolean): void { - if (this.#ignored(e)) return const p = this.matchCheckSync(e, ifDir) if (p) this.matchFinish(p, absolute) } walkCB(target: Path, patterns: Pattern[], cb: () => any) { - if (this.paused) { - this.onResume(() => this.walkCB(target, patterns, cb)) - return - } + /* c8 ignore start */ + if (this.signal?.aborted) cb() + /* c8 ignore stop */ this.walkCB2(target, patterns, new Processor(this.opts), cb) } @@ -302,6 +216,7 @@ export abstract class GlobUtil { cb: () => any ) { if (this.#childrenIgnored(target)) return cb() + if (this.signal?.aborted) cb() if (this.paused) { this.onResume(() => this.walkCB2(target, patterns, processor, cb)) return @@ -365,10 +280,9 @@ export abstract class GlobUtil { } walkCBSync(target: Path, patterns: Pattern[], cb: () => any) { - if (this.paused) { - this.onResume(() => this.walkCBSync(target, patterns, cb)) - return - } + /* c8 ignore start */ + if (this.signal?.aborted) cb() + /* c8 ignore stop */ this.walkCB2Sync(target, patterns, new Processor(this.opts), cb) } @@ -379,6 +293,7 @@ export abstract class GlobUtil { cb: () => any ) { if (this.#childrenIgnored(target)) return cb() + if (this.signal?.aborted) cb() if (this.paused) { this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb) @@ -457,19 +372,31 @@ export class GlobWalker< } async walk(): Promise> { + if (this.signal?.aborted) throw this.signal.reason const t = this.path.isUnknown() ? await this.path.lstat() : this.path if (t) { - await new Promise(res => { - this.walkCB(t, this.patterns, () => res(this.matches)) + await new Promise((res, rej) => { + this.walkCB(t, this.patterns, () => { + if (this.signal?.aborted) { + rej(this.signal.reason) + } else { + res(this.matches) + } + }) }) } return this.matches } walkSync(): Matches { + if (this.signal?.aborted) throw this.signal.reason const t = this.path.isUnknown() ? this.path.lstatSync() : this.path // nothing for the callback to do, because this never pauses - if (t) this.walkCBSync(t, this.patterns, () => {}) + if (t) { + this.walkCBSync(t, this.patterns, () => { + if (this.signal?.aborted) throw this.signal.reason + }) + } return this.matches } } @@ -488,7 +415,7 @@ export class GlobStream< constructor(patterns: Pattern[], path: Path, opts: O) { super(patterns, path, opts) this.results = new Minipass({ - signal: this.opts.signal, + signal: this.signal, objectMode: true, }) as MatchStream this.results.on('drain', () => this.resume()) diff --git a/test/bash-comparison.ts b/test/bash-comparison.ts index 976e827c..8406dbbc 100644 --- a/test/bash-comparison.ts +++ b/test/bash-comparison.ts @@ -50,7 +50,7 @@ globs.forEach(function (pattern) { }) t.test(pattern + ' sync', async t => { - const matches = cleanResults(glob.sync(pattern)) + const matches = cleanResults(glob.globSync(pattern)) t.same(matches, expect, 'should match shell (sync)') }) }) diff --git a/test/broken-symlink.ts b/test/broken-symlink.ts index 044834ff..b854829a 100644 --- a/test/broken-symlink.ts +++ b/test/broken-symlink.ts @@ -58,7 +58,7 @@ t.test('sync test', t => { t.test(pattern, t => { t.plan(opts.length) for (const opt of opts) { - const res = glob.sync(pattern, opt) + const res = glob.globSync(pattern, opt) t.not(res.indexOf(link), -1, 'opt=' + JSON.stringify(opt)) } }) diff --git a/test/follow.ts b/test/follow.ts index 53d377f6..101b3667 100644 --- a/test/follow.ts +++ b/test/follow.ts @@ -10,8 +10,8 @@ process.chdir(__dirname + '/fixtures') t.test('follow symlinks', async t => { const pattern = 'a/symlink/**' - const syncNoFollow = glob.sync(pattern) - const syncFollow = glob.sync(pattern, { follow: true }) + const syncNoFollow = glob.globSync(pattern) + const syncFollow = glob.globSync(pattern, { follow: true }) const [noFollow, follow] = await Promise.all([ glob(pattern), glob(pattern, { follow: true }), diff --git a/test/ignore.ts b/test/ignore.ts index c6163c9d..86381a0f 100644 --- a/test/ignore.ts +++ b/test/ignore.ts @@ -357,7 +357,7 @@ for (const c of cases) { t.test(name, async t => { const res = await glob(pattern, opt) t.same(res.sort(), expect, 'async') - const resSync = glob.sync(pattern, opt) + const resSync = glob.globSync(pattern, opt) t.same(resSync.sort(), expect, 'sync') }) } @@ -377,7 +377,7 @@ t.test('race condition', async t => { const expect = ignore ? [] : j(['fixtures/a']) t.test(JSON.stringify(opt), async t => { t.plan(2) - t.same(glob.sync(pattern, opt).sort(), expect) + t.same(glob.globSync(pattern, opt).sort(), expect) t.same((await glob(pattern, opt)).sort(), expect) }) } diff --git a/test/mark.ts b/test/mark.ts index 298bd924..620aa2f3 100644 --- a/test/mark.ts +++ b/test/mark.ts @@ -25,7 +25,7 @@ t.test('mark with cwd', async t => { } t.same(res.sort(alphasort), j(expect)) - t.same(glob.sync(pattern, opt).sort(alphasort), j(expect)) + t.same(glob.globSync(pattern, opt).sort(alphasort), j(expect)) }) t.test('mark, with **', async t => { @@ -50,7 +50,7 @@ t.test('mark, with **', async t => { ].sort(alphasort) t.same((await glob(pattern, opt)).sort(alphasort), j(expect), 'async') - t.same(glob.sync(pattern, opt).sort(alphasort), j(expect), 'sync') + t.same(glob.globSync(pattern, opt).sort(alphasort), j(expect), 'sync') }) t.test('mark, no / on pattern', async t => { @@ -71,7 +71,7 @@ t.test('mark, no / on pattern', async t => { } const results = (await glob(pattern, opt)).sort(alphasort) t.same(results, j(expect)) - t.same(glob.sync(pattern, opt).sort(alphasort), j(expect)) + t.same(glob.globSync(pattern, opt).sort(alphasort), j(expect)) }) t.test('mark=false, no / on pattern', async t => { @@ -92,7 +92,7 @@ t.test('mark=false, no / on pattern', async t => { const results = (await glob(pattern)).sort(alphasort) t.same(results, j(expect)) - t.same(glob.sync(pattern).sort(alphasort), j(expect)) + t.same(glob.globSync(pattern).sort(alphasort), j(expect)) }) t.test('mark=true, / on pattern', async t => { @@ -114,7 +114,7 @@ t.test('mark=true, / on pattern', async t => { } const results = (await glob(pattern, opt)).sort(alphasort) t.same(results, j(expect)) - t.same(glob.sync(pattern, opt).sort(alphasort), j(expect)) + t.same(glob.globSync(pattern, opt).sort(alphasort), j(expect)) }) t.test('mark=false, / on pattern', async t => { @@ -135,7 +135,7 @@ t.test('mark=false, / on pattern', async t => { const results = (await glob(pattern)).sort(alphasort) t.same(results, j(expect)) - t.same(glob.sync(pattern).sort(alphasort), j(expect)) + t.same(glob.globSync(pattern).sort(alphasort), j(expect)) }) const cwd = process @@ -149,7 +149,7 @@ for (const mark of [true, false]) { const results = await glob(pattern, { mark }) t.equal(results.length, 1) const res = results[0].replace(/\\/g, '/') - const syncResults = glob.sync(pattern, { mark: mark }) + const syncResults = glob.globSync(pattern, { mark: mark }) const syncRes = syncResults[0].replace(/\\/g, '/') if (mark) { t.equal(res, cwd + '/') @@ -160,3 +160,22 @@ for (const mark of [true, false]) { }) } } + +for (const mark of [true, false]) { + for (const slash of [true, false]) { + t.test('. mark:' + mark + ' slash:' + slash, async t => { + const pattern = '.' + (slash ? '/' : '') + const results = await glob(pattern, { mark }) + t.equal(results.length, 1) + const res = results[0].replace(/\\/g, '/') + const syncResults = glob.globSync(pattern, { mark: mark }) + const syncRes = syncResults[0].replace(/\\/g, '/') + if (mark) { + t.equal(res, './') + } else { + t.equal(res, '') + } + t.equal(syncRes, res, 'sync should match async') + }) + } +} diff --git a/test/match-base.ts b/test/match-base.ts index bd53f83f..1284c762 100644 --- a/test/match-base.ts +++ b/test/match-base.ts @@ -21,7 +21,7 @@ t.test('chdir', async t => { process.chdir(fixtureDir) t.teardown(() => process.chdir(origCwd)) t.same( - glob.sync(pattern, { matchBase: true }).sort(alphasort), + glob.globSync(pattern, { matchBase: true }).sort(alphasort), j(expect) ) t.same( @@ -33,7 +33,7 @@ t.test('chdir', async t => { t.test('cwd', async t => { t.same( glob - .sync(pattern, { matchBase: true, cwd: fixtureDir }) + .globSync(pattern, { matchBase: true, cwd: fixtureDir }) .sort(alphasort), j(expect) ) @@ -47,7 +47,7 @@ t.test('cwd', async t => { t.test('noglobstar', async t => { t.rejects(glob(pattern, { matchBase: true, noglobstar: true })) - t.throws(() => glob.sync(pattern, { matchBase: true, noglobstar: true })) + t.throws(() => glob.globSync(pattern, { matchBase: true, noglobstar: true })) t.end() }) @@ -56,7 +56,7 @@ t.test('pattern includes /', async t => { const expect = ['a/b', 'a/bc'] t.same( glob - .sync(pattern, { matchBase: true, cwd: fixtureDir }) + .globSync(pattern, { matchBase: true, cwd: fixtureDir }) .sort(alphasort), j(expect) ) @@ -73,7 +73,7 @@ t.test('one brace section of pattern includes /', async t => { const exp = ['a', 'a/b', 'a/bc'] t.same( glob - .sync(pattern, { matchBase: true, cwd: fixtureDir }) + .globSync(pattern, { matchBase: true, cwd: fixtureDir }) .sort(alphasort), j(exp) ) @@ -90,7 +90,7 @@ t.test('one array member of pattern includes /', async t => { const exp = expect.concat(['a/b', 'a/bc']).sort() t.same( glob - .sync(pattern, { matchBase: true, cwd: fixtureDir }) + .globSync(pattern, { matchBase: true, cwd: fixtureDir }) .sort(alphasort), j(exp) ) diff --git a/test/nodir.ts b/test/nodir.ts index cd4dfa9b..a6616e79 100644 --- a/test/nodir.ts +++ b/test/nodir.ts @@ -44,7 +44,7 @@ for (const [pattern, options, expectRaw] of cases) { if (process.platform !== 'win32') { } t.test(pattern + ' ' + JSON.stringify(options), async t => { - t.same(glob.sync(pattern, options).sort(), expect, 'sync results') + t.same(glob.globSync(pattern, options).sort(), expect, 'sync results') t.same((await glob(pattern, options)).sort(), expect, 'async results') }) } diff --git a/test/platform.ts b/test/platform.ts index 5c087b32..c1a67b77 100644 --- a/test/platform.ts +++ b/test/platform.ts @@ -1,3 +1,4 @@ +import { resolve } from 'path' import t from 'tap' import { @@ -7,6 +8,9 @@ import { PathScurryWin32, } from 'path-scurry' import { Glob } from '../' +import { glob } from '../dist/cjs' +import {GlobWalker} from '../dist/cjs/walker' +import {Pattern} from '../dist/cjs/pattern' t.test('default platform is process.platform', t => { const g = new Glob('.', {}) @@ -55,3 +59,15 @@ t.test('set scurry, sets nocase and scurry', t => { t.equal(g.nocase, true) t.end() }) + +t.test('instantiate to hit a coverage line', async t => { + const s = new PathScurry(resolve(__dirname, 'fixtures/a/b')) + const p = new Pattern([/./, /./], ['?', '?'], 0, process.platform) + new GlobWalker([p], s.cwd, { + platform: 'win32', + }) + new GlobWalker([p], s.cwd, { + platform: 'linux', + }) + t.pass('this is fine') +}) diff --git a/test/realpath.ts b/test/realpath.ts index f0e9da2f..64a1731d 100644 --- a/test/realpath.ts +++ b/test/realpath.ts @@ -55,7 +55,7 @@ if (process.platform === 'win32') { expect.sort(alphasort) t.test(p + ' ' + JSON.stringify(opt), async t => { opt.realpath = true - t.same(glob.sync(p, opt).sort(alphasort), expect, 'sync') + t.same(glob.globSync(p, opt).sort(alphasort), expect, 'sync') const a = await glob(p, opt) t.same(a.sort(alphasort), expect, 'async') }) @@ -83,13 +83,13 @@ if (process.platform === 'win32') { const expect = ['a/symlink', 'a/symlink/a/b'].sort(alphasort) t.test('setting cwd explicitly', async t => { const opt = { realpath: true, cwd: fixtureDir } - t.same(glob.sync(pattern, opt).sort(alphasort), expect) + t.same(glob.globSync(pattern, opt).sort(alphasort), expect) t.same((await glob(pattern, opt)).sort(alphasort), expect) }) t.test('looking in cwd', async t => { process.chdir(fixtureDir) const opt = { realpath: true } - t.same(glob.sync(pattern, opt).sort(alphasort), expect) + t.same(glob.globSync(pattern, opt).sort(alphasort), expect) t.same((await glob(pattern, opt)).sort(alphasort), expect) }) }) diff --git a/test/signal.ts b/test/signal.ts new file mode 100644 index 00000000..717a45c5 --- /dev/null +++ b/test/signal.ts @@ -0,0 +1,89 @@ +import * as fs from 'fs' +import { resolve } from 'path' +import t from 'tap' +import { glob, globStream, globStreamSync, globSync } from '../' + +const mocks = (ac: AbortController) => { + const fsMock = { + ...fs, + readdirSync: (path: string, options: any) => { + ac.abort(yeet) + return fs.readdirSync(path, options) + }, + } + return { + fs: fsMock, + 'path-scurry': t.mock('path-scurry', { fs: fsMock }), + } +} + +const cwd = resolve(__dirname, 'fixtures/a') + +const yeet = new Error('yeet') + +t.test('pre abort walk', async t => { + const ac = new AbortController() + ac.abort(yeet) + await t.rejects(glob('./**', { cwd, signal: ac.signal }), yeet) +}) + +t.test('mid-abort walk', async t => { + const ac = new AbortController() + const res = glob('./**', { cwd, signal: ac.signal }) + ac.abort(yeet) + await t.rejects(res, yeet) +}) + +t.test('pre abort sync walk', t => { + const ac = new AbortController() + ac.abort(yeet) + t.throws(() => globSync('./**', { cwd, signal: ac.signal })) + t.end() +}) + +t.test('mid-abort sync walk', t => { + const ac = new AbortController() + const { globSync } = t.mock('../', mocks(ac)) + t.throws(() => globSync('./**', { cwd, signal: ac.signal })) + t.end() +}) + +t.test('pre abort stream', t => { + const ac = new AbortController() + ac.abort(yeet) + const s = globStream('./**', { cwd, signal: ac.signal }) + s.on('error', er => { + t.equal(er, yeet) + t.end() + }) +}) + +t.test('mid-abort stream', t => { + const ac = new AbortController() + const s = globStream('./**', { cwd, signal: ac.signal }) + s.on('error', er => { + t.equal(er, yeet) + t.end() + }) + s.once('data', () => ac.abort(yeet)) +}) + +t.test('pre abort sync stream', t => { + const ac = new AbortController() + ac.abort(yeet) + const s = globStreamSync('./**', { cwd, signal: ac.signal }) + s.on('error', er => { + t.equal(er, yeet) + t.end() + }) +}) + +t.test('mid-abort sync stream', t => { + const ac = new AbortController() + const s = globStreamSync('./**', { cwd, signal: ac.signal }) + s.on('error', er => { + t.equal(er, yeet) + t.end() + }) + s.on('data', () => ac.abort(yeet)) +}) diff --git a/test/slash-cwd.ts b/test/slash-cwd.ts index ffb8c82a..dab9e0d2 100644 --- a/test/slash-cwd.ts +++ b/test/slash-cwd.ts @@ -11,6 +11,6 @@ const opt: GlobOptions = { cwd } process.chdir(__dirname + '/..') t.test('slashes only match directories', async t => { - t.same(glob.sync(pattern, opt), expect, 'sync test') + t.same(glob.globSync(pattern, opt), expect, 'sync test') t.same(await glob(pattern, opt), expect, 'async test') }) diff --git a/test/stream.ts b/test/stream.ts index 37ca8072..e808314f 100644 --- a/test/stream.ts +++ b/test/stream.ts @@ -1,7 +1,14 @@ import { resolve, sep } from 'path' import t from 'tap' -import { Glob } from '../' -const fixture = resolve(__dirname, 'fixtures/a') +import { + Glob, + globIterate, + globIterateSync, + globStream, + globStreamSync, +} from '../' +import {glob, globSync} from '../dist/cjs' +const cwd = resolve(__dirname, 'fixtures/a') const j = (a: string[]) => a.map(a => a.split('/').join(sep)) const expect = j([ '', @@ -34,7 +41,7 @@ const expect = j([ t.test('stream', t => { let sync: boolean = true - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const stream = s.stream() const e = new Set(expect) stream.on('data', c => { @@ -61,7 +68,7 @@ t.test('stream', t => { t.test('streamSync', t => { let sync: boolean = true - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const stream = s.streamSync() const e = new Set(expect) stream.on('data', c => { @@ -87,7 +94,7 @@ t.test('streamSync', t => { }) t.test('iterate', async t => { - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const e = new Set(expect) for await (const c of s.iterate()) { t.equal(e.has(c), true, JSON.stringify(c)) @@ -105,7 +112,7 @@ t.test('iterate', async t => { }) t.test('iterateSync', t => { - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const e = new Set(expect) for (const c of s.iterateSync()) { t.equal(e.has(c), true, JSON.stringify(c)) @@ -123,8 +130,29 @@ t.test('iterateSync', t => { t.end() }) +t.test('walk', async t => { + const s = new Glob('./**', { cwd }) + const e = new Set(expect) + const actual = new Set(await s.walk()) + t.same(actual, e) + const d = new Glob('./**', s) + const dactual= new Set(await d.walk()) + t.same(dactual, e) +}) + +t.test('walkSync', t => { + const s = new Glob('./**', { cwd }) + const e = new Set(expect) + const actual = new Set(s.walkSync()) + t.same(actual, e) + const d = new Glob('./**', s) + const dactual= new Set(d.walkSync()) + t.same(dactual, e) + t.end() +}) + t.test('for await', async t => { - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const e = new Set(expect) for await (const c of s) { t.equal(e.has(c), true, JSON.stringify(c)) @@ -142,7 +170,7 @@ t.test('for await', async t => { }) t.test('for of', t => { - const s = new Glob('./**', { cwd: fixture }) + const s = new Glob('./**', { cwd }) const e = new Set(expect) for (const c of s) { t.equal(e.has(c), true, JSON.stringify(c)) @@ -159,3 +187,71 @@ t.test('for of', t => { t.equal(f.size, 0, 'saw all entries') t.end() }) + +t.test('iterate on main', async t => { + const s = globIterate('./**', { cwd }) + const e = new Set(expect) + for await (const c of s) { + t.equal(e.has(c), true, JSON.stringify(c)) + e.delete(c) + } + t.equal(e.size, 0, 'saw all entries') +}) + +t.test('iterateSync on main', t => { + const s = globIterateSync('./**', { cwd }) + const e = new Set(expect) + for (const c of s) { + t.equal(e.has(c), true, JSON.stringify(c)) + e.delete(c) + } + t.equal(e.size, 0, 'saw all entries') + t.end() +}) + +t.test('stream on main', t => { + let sync: boolean = true + const stream = globStream('./**', { cwd }) + const e = new Set(expect) + stream.on('data', c => { + t.equal(e.has(c), true, JSON.stringify(c)) + e.delete(c) + }) + stream.on('end', () => { + t.equal(e.size, 0, 'saw all entries') + t.equal(sync, false, 'did not finish in one tick') + t.end() + }) + sync = false +}) + +t.test('streamSync on main', t => { + let sync: boolean = true + const stream = globStreamSync('./**', { cwd }) + const e = new Set(expect) + stream.on('data', c => { + t.equal(e.has(c), true, JSON.stringify(c)) + e.delete(c) + }) + stream.on('end', () => { + t.equal(e.size, 0, 'saw all entries') + t.equal(sync, true, 'finished synchronously') + t.end() + }) + sync = false +}) + +t.test('walk on main', async t => { + const s = glob('./**', { cwd }) + const e = new Set(expect) + const actual = new Set(await s) + t.same(actual, e) +}) + +t.test('walkSync', t => { + const s = globSync('./**', { cwd }) + const e = new Set(expect) + const actual = new Set(s) + t.same(actual, e) + t.end() +}) diff --git a/test/windows-paths-fs.ts b/test/windows-paths-fs.ts index 52b04437..842343eb 100644 --- a/test/windows-paths-fs.ts +++ b/test/windows-paths-fs.ts @@ -31,7 +31,7 @@ t.test('treat backslash as escape', t => { for (const [pattern, expect] of cases) { t.test(pattern, async t => { t.strictSame( - glob.sync(pattern, { cwd: dir }).map(s => s.replace(/\\/g, '/')), + glob.globSync(pattern, { cwd: dir }).map(s => s.replace(/\\/g, '/')), expect, 'sync' ) @@ -60,7 +60,7 @@ t.test('treat backslash as separator', t => { t.test(pattern, async t => { t.strictSame( glob - .sync(pattern, { cwd: dir, windowsPathsNoEscape: true }) + .globSync(pattern, { cwd: dir, windowsPathsNoEscape: true }) .map(s => s.replace(/\\/g, '/')), expect, 'sync'