|
1 |
| -import bunxSpec from "./bunx"; |
2 |
| -import { npmSearchGenerator } from "./npm"; |
3 |
| -import npxSpec, { npxSuggestions } from "./npx"; |
4 |
| -import pnpxSpec from "./pnpx"; |
| 1 | +import { npxSuggestions } from "./npx"; |
5 | 2 |
|
6 |
| -// Helper to coerce a Fig.Spec into a Fig.Subcommand when possible |
7 |
| -const toSubcommand = (spec: Fig.Spec): Fig.Subcommand | null => { |
8 |
| - if (typeof spec === "function") { |
9 |
| - // eslint-disable-next-line @typescript-eslint/no-explicit-any |
10 |
| - const res = (spec as any)(); |
11 |
| - if (res && typeof res === "object" && "versionedSpecPath" in res) |
12 |
| - return null; |
13 |
| - return res as Fig.Subcommand; |
14 |
| - } |
15 |
| - return spec as Fig.Subcommand; |
16 |
| -}; |
17 |
| - |
18 |
| -const npxCmd = toSubcommand(npxSpec); |
19 |
| -const bunxCmd = toSubcommand(bunxSpec); |
20 |
| -const pnpxCmd = toSubcommand(pnpxSpec); |
21 |
| - |
22 |
| -const mergedSubcommands: Fig.Subcommand[] = [ |
23 |
| - ...(npxCmd?.subcommands ?? []), |
24 |
| - ...(bunxCmd?.subcommands ?? []), |
25 |
| - ...(pnpxCmd?.subcommands ?? []), |
26 |
| -]; |
27 |
| - |
28 |
| -const mergedOptions: Fig.Option[] = [ |
29 |
| - ...(npxCmd?.options ?? []), |
30 |
| - ...(bunxCmd?.options ?? []), |
31 |
| - ...(pnpxCmd?.options ?? []), |
32 |
| -].filter((opt, idx, arr) => { |
33 |
| - const key = Array.isArray(opt.name) ? opt.name.join("|") : String(opt.name); |
34 |
| - return ( |
35 |
| - idx === |
36 |
| - arr.findIndex((o) => { |
37 |
| - const k = Array.isArray(o.name) ? o.name.join("|") : String(o.name); |
38 |
| - return k === key; |
39 |
| - }) |
40 |
| - ); |
| 3 | +// Merge curated lists (currently only npx exports suggestions). |
| 4 | +// If bunx/pnpx add their own in the future, they can be merged here too. |
| 5 | +const curatedSuggestions: Fig.Suggestion[] = ( |
| 6 | + npxSuggestions as Fig.Suggestion[] |
| 7 | +).map((s) => { |
| 8 | + if (typeof s === "string") return { name: s, loadSpec: s }; |
| 9 | + const name = Array.isArray(s.name) ? s.name[0] : s.name; |
| 10 | + return { ...s, ...(name && { loadSpec: name }) }; |
41 | 11 | });
|
42 | 12 |
|
43 | 13 | const completionSpec: Fig.Spec = {
|
44 | 14 | name: "nlx",
|
45 | 15 | description: "Download & execute a package binary with the correct agent",
|
46 |
| - subcommands: mergedSubcommands, |
47 |
| - args: [ |
48 |
| - { |
49 |
| - name: "commandOrPackage", |
50 |
| - description: "Package name (and optional subcommand) to execute", |
51 |
| - isOptional: true, |
52 |
| - generators: npmSearchGenerator, |
53 |
| - suggestions: npxSuggestions, |
54 |
| - }, |
55 |
| - { |
56 |
| - name: "args", |
57 |
| - isOptional: true, |
58 |
| - isVariadic: true, |
59 |
| - description: "Arguments passed to the executed binary", |
| 16 | + args: { |
| 17 | + name: "command", |
| 18 | + isCommand: true, |
| 19 | + description: "The package binary to run (e.g. vitest, tsc, prisma, next)", |
| 20 | + // Prefer curated CLI list, but also surface local node_modules/.bin executables |
| 21 | + generators: { |
| 22 | + script: [ |
| 23 | + "bash", |
| 24 | + "-c", |
| 25 | + "until [[ -d node_modules/ ]] || [[ $PWD = '/' ]]; do cd ..; done; ls -1 node_modules/.bin/", |
| 26 | + ], |
| 27 | + postProcess: function (out) { |
| 28 | + const curated = curatedSuggestions.reduce((acc, cur) => { |
| 29 | + const name = |
| 30 | + typeof cur === "string" |
| 31 | + ? cur |
| 32 | + : Array.isArray(cur.name) |
| 33 | + ? cur.name[0] |
| 34 | + : cur.name; |
| 35 | + return name ? acc.concat(name) : acc; |
| 36 | + }, [] as string[]); |
| 37 | + return out |
| 38 | + .split("\\n") |
| 39 | + .filter((name) => !!name && !curated.includes(name)) |
| 40 | + .map((name) => ({ |
| 41 | + name, |
| 42 | + icon: "fig://icon?type=command", |
| 43 | + loadSpec: name, |
| 44 | + })); |
| 45 | + }, |
60 | 46 | },
|
61 |
| - ], |
| 47 | + suggestions: curatedSuggestions, |
| 48 | + isOptional: true, |
| 49 | + }, |
62 | 50 | options: [
|
63 |
| - ...mergedOptions, |
64 | 51 | {
|
65 | 52 | name: "-C",
|
66 | 53 | description: "Change directory before running the command",
|
|
0 commit comments