Skip to content

Commit ae0144c

Browse files
committed
which() can return all results
1 parent 9bb5946 commit ae0144c

2 files changed

Lines changed: 65 additions & 18 deletions

File tree

src/plumbing/which.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { assert, assertEquals } from "deno/testing/asserts.ts"
2+
import { isArray } from "is-what"
3+
import which from "./which.ts"
4+
5+
Deno.test("which('ls')", async () => {
6+
const foo = await which('ls')
7+
assert(!isArray(foo))
8+
assert(foo)
9+
})
10+
11+
Deno.test("which('kill-port')", async () => {
12+
const foo = await which('kill-port')
13+
assert(!isArray(foo))
14+
assert(foo)
15+
16+
const bar = await which('kill-port', { providers: false })
17+
assertEquals(bar, undefined)
18+
})
19+
20+
Deno.test("which('nvim')", async () => {
21+
const foo = await which('kill-port', { all: true })
22+
assert(isArray(foo))
23+
assert(foo.length)
24+
})

src/plumbing/which.ts

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,53 @@ export type WhichResult = PackageRequirement & {
66
shebang: string[]
77
}
88

9-
export default async function(arg0: string, opts = { providers: true }): Promise<WhichResult | undefined> {
9+
10+
export default async function which(arg0: string, opts?: { providers?: boolean }): Promise<WhichResult | undefined>;
11+
export default async function which(arg0: string, opts: { providers?: boolean, all: false }): Promise<WhichResult | undefined>;
12+
export default async function which(arg0: string, opts: { providers?: boolean, all: true }): Promise<WhichResult[]>;
13+
export default async function which(arg0: string, opts_?: { providers?: boolean, all?: boolean }) {
14+
15+
const opts = { providers: opts_?.providers ?? true, all: opts_?.all ?? false }
16+
17+
const rv: WhichResult[] = []
18+
for await (const result of _which(arg0, opts)) {
19+
if (opts.all) {
20+
rv.push(result)
21+
} else {
22+
return result
23+
}
24+
}
25+
if (!opts.all && rv.length == 0) {
26+
return
27+
} else {
28+
return rv
29+
}
30+
}
31+
32+
async function *_which(arg0: string, opts: { providers: boolean }): AsyncGenerator<WhichResult> {
1033
arg0 = arg0.trim()
1134
/// sanitize and reject anything with path components
1235
if (!arg0 || arg0.includes("/")) return
1336

1437
const pantry = usePantry()
15-
let found: { project: string, constraint: semver.Range, shebang: string[] } | undefined
38+
let found: WhichResult[] = []
1639
const promises: Promise<void>[] = []
1740

1841
for await (const entry of pantry.ls()) {
19-
if (found) break
42+
if (found.length) {
43+
for (const f of found) yield f
44+
found = []
45+
}
2046
const p = pantry.project(entry).provides().then(providers => {
2147
for (const provider of providers) {
22-
if (found) {
23-
return
24-
} else if (provider == arg0) {
48+
if (provider == arg0) {
2549
const constraint = new semver.Range("*")
26-
found = {...entry, constraint, shebang: [provider] }
50+
found.push({...entry, constraint, shebang: [provider] })
2751
} else if (arg0.startsWith(provider)) {
2852
// eg. `node^16` symlink
2953
try {
3054
const constraint = new semver.Range(arg0.substring(provider.length))
31-
found = {...entry, constraint, shebang: [provider] }
55+
found.push({...entry, constraint, shebang: [provider] })
3256
} catch {
3357
// not a valid semver range; fallthrough
3458
}
@@ -46,35 +70,34 @@ export default async function(arg0: string, opts = { providers: true }): Promise
4670
match = arg0.match(rx)
4771
if (match) {
4872
const constraint = new semver.Range(`~${match[1]}`)
49-
found = {...entry, constraint, shebang: [arg0] }
73+
found.push({...entry, constraint, shebang: [arg0] })
5074
}
5175
}
5276
}
5377
}).swallow(PantryError)
78+
5479
promises.push(p)
5580

5681
if (opts.providers) {
5782
const pp = pantry.project(entry).provider().then(f => {
5883
if (!f) return
5984
const rv = f(arg0)
60-
if (rv) found = {
85+
if (rv) found.push({
6186
...entry,
6287
constraint: new semver.Range('*'),
6388
shebang: [...rv, arg0]
64-
}
89+
})
6590
})
6691
promises.push(pp)
6792
}
6893
}
6994

70-
if (!found) {
71-
// if we didn’t find anything yet then we have to wait on the promises
72-
// otherwise we can ignore them
73-
await Promise.all(promises)
74-
}
95+
// if we didn’t find anything yet then we have to wait on the promises
96+
// otherwise we can ignore them
97+
await Promise.all(promises)
7598

76-
if (found) {
77-
return found
99+
for (const f of found) {
100+
yield f
78101
}
79102
}
80103

0 commit comments

Comments
 (0)