Skip to content

Commit 5699f06

Browse files
committed
refactor(nlx): use npx suggestions as main source
1 parent 0a0e758 commit 5699f06

File tree

1 file changed

+42
-55
lines changed

1 file changed

+42
-55
lines changed

src/nlx.ts

Lines changed: 42 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,53 @@
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";
52

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 }) };
4111
});
4212

4313
const completionSpec: Fig.Spec = {
4414
name: "nlx",
4515
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+
},
6046
},
61-
],
47+
suggestions: curatedSuggestions,
48+
isOptional: true,
49+
},
6250
options: [
63-
...mergedOptions,
6451
{
6552
name: "-C",
6653
description: "Change directory before running the command",

0 commit comments

Comments
 (0)