@gunshi/plugin-completion 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -9
- package/lib/index.js +122 -15
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ This completion plugin is powered by [`@bomb.sh/tab`](https://github.com/bombshe
|
|
|
13
13
|
<!-- eslint-disable markdown/no-missing-label-refs -->
|
|
14
14
|
|
|
15
15
|
> [!WARNING]
|
|
16
|
-
> This package
|
|
16
|
+
> This package supports Node.js and Bun runtimes only. Deno support is not available yet.
|
|
17
17
|
|
|
18
18
|
<!-- eslint-enable markdown/no-missing-label-refs -->
|
|
19
19
|
|
|
@@ -122,14 +122,8 @@ This section provides detailed instructions for setting up shell completions in
|
|
|
122
122
|
|
|
123
123
|
### Prerequisites
|
|
124
124
|
|
|
125
|
-
Shell completion requires
|
|
126
|
-
|
|
127
|
-
<!-- eslint-disable markdown/no-missing-label-refs -->
|
|
128
|
-
|
|
129
|
-
> [!WARNING]
|
|
130
|
-
> This package support Node.js runtime only. Deno and Bun support are coming soon.
|
|
131
|
-
|
|
132
|
-
<!-- eslint-enable markdown/no-missing-label-refs -->
|
|
125
|
+
Shell completion requires your CLI command to be executable from the generated completion script.
|
|
126
|
+
The plugin currently supports completion script generation for Node.js, Bun source execution, and Bun single-file executables.
|
|
133
127
|
|
|
134
128
|
### Setup by Shell
|
|
135
129
|
|
package/lib/index.js
CHANGED
|
@@ -266,14 +266,126 @@ const pluginId = namespacedId("completion");
|
|
|
266
266
|
* @author kazuya kawaguchi (a.k.a. kazupon)
|
|
267
267
|
* @license MIT
|
|
268
268
|
*/
|
|
269
|
+
function getRuntimeGlobals() {
|
|
270
|
+
return globalThis;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Detect the active JavaScript runtime.
|
|
274
|
+
*
|
|
275
|
+
* @returns The detected runtime name
|
|
276
|
+
*/
|
|
269
277
|
function detectRuntime() {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
278
|
+
return detectRuntimeFromGlobals(getRuntimeGlobals());
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Detect the active JavaScript runtime from globals.
|
|
282
|
+
*
|
|
283
|
+
* @param globals - Runtime globals to inspect
|
|
284
|
+
* @returns The detected runtime name
|
|
285
|
+
*/
|
|
286
|
+
function detectRuntimeFromGlobals(globals) {
|
|
287
|
+
if (globals.Bun !== void 0) return "bun";
|
|
288
|
+
if (globals.Deno !== void 0) return "deno";
|
|
289
|
+
if (globals.process !== void 0 && globals.process.release?.name === "node") return "node";
|
|
273
290
|
return "unknown";
|
|
274
291
|
}
|
|
275
|
-
|
|
276
|
-
|
|
292
|
+
/**
|
|
293
|
+
* Quote a shell command part when needed.
|
|
294
|
+
*
|
|
295
|
+
* This protects the command part when the generated completion script later
|
|
296
|
+
* evaluates the assembled command string. Callers that embed the quoted result
|
|
297
|
+
* into another shell string still need to escape that outer string.
|
|
298
|
+
*
|
|
299
|
+
* @param value - The command part to quote
|
|
300
|
+
* @returns The shell-safe command part
|
|
301
|
+
*/
|
|
302
|
+
function shellQuote(value) {
|
|
303
|
+
if (value.length === 0) return "''";
|
|
304
|
+
if (/^[\w%+,./:=@-]+$/.test(value)) return value;
|
|
305
|
+
return `'${value.replaceAll(`'`, `'\\''`)}'`;
|
|
306
|
+
}
|
|
307
|
+
function escapeDoubleQuotedShellString(value) {
|
|
308
|
+
return value.replaceAll(/[$`"\\]/g, "\\$&");
|
|
309
|
+
}
|
|
310
|
+
function basename(path) {
|
|
311
|
+
const slash = path.lastIndexOf("/");
|
|
312
|
+
const backslash = path.lastIndexOf("\\");
|
|
313
|
+
return path.slice(Math.max(slash, backslash) + 1);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Check if the entry is a Bun virtual entry.
|
|
317
|
+
*
|
|
318
|
+
* @param entry - The entry to check
|
|
319
|
+
* @returns Whether the entry is a Bun virtual entry
|
|
320
|
+
*
|
|
321
|
+
* Bun compiled executables may surface internal virtual paths in `process.argv`
|
|
322
|
+
* instead of the original source entry. These markers are intentionally private
|
|
323
|
+
* to keep the single-binary check heuristic rather than a public contract.
|
|
324
|
+
*
|
|
325
|
+
* @see https://github.com/oven-sh/bun/blob/main/src/standalone_graph/StandaloneModuleGraph.rs#L44-L70
|
|
326
|
+
* @see https://github.com/oven-sh/bun/blob/main/test/regression/issue/22157.test.ts#L47-L55
|
|
327
|
+
*/
|
|
328
|
+
function isBunVirtualEntry(entry) {
|
|
329
|
+
return entry?.startsWith("/$bunfs/") === true || entry?.startsWith("B:\\~BUN\\") === true || entry?.startsWith("B:/~BUN/") === true;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Check if the executable is a likely Bun single binary.
|
|
333
|
+
*
|
|
334
|
+
* @param execPath - The executable path
|
|
335
|
+
* @param entry - The entry to check
|
|
336
|
+
* @returns Whether the executable is a likely Bun single binary
|
|
337
|
+
*
|
|
338
|
+
* Bun documents `bun build --compile` as producing a single-file executable,
|
|
339
|
+
* but it does not expose a stable "compiled executable" runtime flag.
|
|
340
|
+
* Prefer calling the current executable when `process.execPath` is no longer
|
|
341
|
+
* the Bun launcher, because the shell completion script needs to re-enter the
|
|
342
|
+
* compiled CLI rather than the original source file.
|
|
343
|
+
*
|
|
344
|
+
* @see https://bun.com/docs/bundler/executables
|
|
345
|
+
* @see https://github.com/oven-sh/bun/issues/14676
|
|
346
|
+
*/
|
|
347
|
+
function isLikelyBunSingleBinary(execPath, entry) {
|
|
348
|
+
const name = basename(execPath).toLowerCase();
|
|
349
|
+
if (name !== "bun" && name !== "bun.exe") return true;
|
|
350
|
+
return isBunVirtualEntry(entry);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Resolve executable command parts for Node.js source execution.
|
|
354
|
+
*
|
|
355
|
+
* @param process - Node-compatible process global
|
|
356
|
+
* @returns Executable command parts
|
|
357
|
+
*/
|
|
358
|
+
function resolveNodeExecParts(process) {
|
|
359
|
+
const entry = process.argv[1];
|
|
360
|
+
return [
|
|
361
|
+
process.execPath,
|
|
362
|
+
...process.execArgv ?? [],
|
|
363
|
+
...entry ? [entry] : []
|
|
364
|
+
];
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Resolve executable command parts for Bun source and compiled execution.
|
|
368
|
+
*
|
|
369
|
+
* @param process - Bun process global
|
|
370
|
+
* @returns Executable command parts
|
|
371
|
+
*/
|
|
372
|
+
function resolveBunExecParts(process) {
|
|
373
|
+
const entry = process.argv[1];
|
|
374
|
+
if (isLikelyBunSingleBinary(process.execPath, entry)) return [process.execPath];
|
|
375
|
+
return [
|
|
376
|
+
process.execPath,
|
|
377
|
+
...process.execArgv ?? [],
|
|
378
|
+
...entry ? [entry] : []
|
|
379
|
+
];
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Join executable command parts into a shell-safe command string.
|
|
383
|
+
*
|
|
384
|
+
* @param parts - Executable command parts
|
|
385
|
+
* @returns The executable command string
|
|
386
|
+
*/
|
|
387
|
+
function joinExecParts(parts) {
|
|
388
|
+
return escapeDoubleQuotedShellString(parts.map(shellQuote).join(" "));
|
|
277
389
|
}
|
|
278
390
|
/**
|
|
279
391
|
* Quote the exec command for the current runtime.
|
|
@@ -281,17 +393,12 @@ function quoteIfNeeded(path) {
|
|
|
281
393
|
* @returns The quoted exec command string
|
|
282
394
|
*/
|
|
283
395
|
function quoteExec() {
|
|
396
|
+
const globals = getRuntimeGlobals();
|
|
284
397
|
switch (detectRuntime()) {
|
|
285
|
-
case "node":
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const quotedProcessArgs = processArgs.map(quoteIfNeeded);
|
|
290
|
-
return `${quotedExecPath} ${globalThis.process.execArgv.map(quoteIfNeeded).join(" ")} ${quotedProcessArgs[0]}`;
|
|
291
|
-
}
|
|
292
|
-
case "deno": throw new Error("deno not implemented yet, welcome contributions :)");
|
|
293
|
-
case "bun": throw new Error("bun not implemented yet, welcome contributions :)");
|
|
294
|
-
default: throw new Error("Unsupported your javascript runtime for completion script generation.");
|
|
398
|
+
case "node": return joinExecParts(resolveNodeExecParts(globals.process));
|
|
399
|
+
case "deno": throw new Error("Deno runtime is not supported for completion script generation yet.");
|
|
400
|
+
case "bun": return joinExecParts(resolveBunExecParts(globals.process));
|
|
401
|
+
default: throw new Error("Unsupported JavaScript runtime for completion script generation.");
|
|
295
402
|
}
|
|
296
403
|
}
|
|
297
404
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gunshi/plugin-completion",
|
|
3
3
|
"description": "completion plugin for gunshi",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.33.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "kazuya kawaguchi",
|
|
7
7
|
"email": "kawakazu80@gmail.com"
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@bomb.sh/tab": "^0.0.15",
|
|
56
|
-
"@gunshi/plugin": "0.
|
|
56
|
+
"@gunshi/plugin": "0.33.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@gunshi/plugin-i18n": "0.
|
|
59
|
+
"@gunshi/plugin-i18n": "0.33.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/node": "^25.6.2",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
"tsdown": "0.21.0",
|
|
69
69
|
"typedoc": "^0.28.19",
|
|
70
70
|
"typedoc-plugin-markdown": "^4.11.0",
|
|
71
|
-
"@gunshi/shared": "0.
|
|
72
|
-
"@gunshi/plugin-i18n": "0.
|
|
71
|
+
"@gunshi/shared": "0.33.0",
|
|
72
|
+
"@gunshi/plugin-i18n": "0.33.0"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"build": "tsdown",
|