padrone 1.4.0 → 1.6.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/CHANGELOG.md +115 -0
- package/README.md +108 -283
- package/dist/args-Cnq0nwSM.mjs +272 -0
- package/dist/args-Cnq0nwSM.mjs.map +1 -0
- package/dist/codegen/index.d.mts +28 -3
- package/dist/codegen/index.d.mts.map +1 -1
- package/dist/codegen/index.mjs +169 -19
- package/dist/codegen/index.mjs.map +1 -1
- package/dist/commands-B_gufyR9.mjs +514 -0
- package/dist/commands-B_gufyR9.mjs.map +1 -0
- package/dist/{completion.mjs → completion-BEuflbDO.mjs} +86 -108
- package/dist/completion-BEuflbDO.mjs.map +1 -0
- package/dist/docs/index.d.mts +22 -2
- package/dist/docs/index.d.mts.map +1 -1
- package/dist/docs/index.mjs +92 -7
- package/dist/docs/index.mjs.map +1 -1
- package/dist/errors-CL63UOzt.mjs +137 -0
- package/dist/errors-CL63UOzt.mjs.map +1 -0
- package/dist/{formatter-ClUK5hcQ.d.mts → formatter-DrvhDMrq.d.mts} +35 -6
- package/dist/formatter-DrvhDMrq.d.mts.map +1 -0
- package/dist/help-B5Kk83of.mjs +849 -0
- package/dist/help-B5Kk83of.mjs.map +1 -0
- package/dist/index-BaU3X6dY.d.mts +1178 -0
- package/dist/index-BaU3X6dY.d.mts.map +1 -0
- package/dist/index.d.mts +763 -36
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3608 -1534
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-BM-d0nZi.mjs +377 -0
- package/dist/mcp-BM-d0nZi.mjs.map +1 -0
- package/dist/serve-Bk0JUlCj.mjs +402 -0
- package/dist/serve-Bk0JUlCj.mjs.map +1 -0
- package/dist/stream-DC4H8YTx.mjs +77 -0
- package/dist/stream-DC4H8YTx.mjs.map +1 -0
- package/dist/test.d.mts +5 -8
- package/dist/test.d.mts.map +1 -1
- package/dist/test.mjs +5 -27
- package/dist/test.mjs.map +1 -1
- package/dist/{update-check-EbNDkzyV.mjs → update-check-CZ2VqjnV.mjs} +16 -17
- package/dist/update-check-CZ2VqjnV.mjs.map +1 -0
- package/dist/zod.d.mts +32 -0
- package/dist/zod.d.mts.map +1 -0
- package/dist/zod.mjs +50 -0
- package/dist/zod.mjs.map +1 -0
- package/package.json +20 -9
- package/src/cli/completions.ts +14 -11
- package/src/cli/docs.ts +13 -16
- package/src/cli/doctor.ts +213 -24
- package/src/cli/index.ts +28 -82
- package/src/cli/init.ts +12 -10
- package/src/cli/link.ts +22 -18
- package/src/cli/wrap.ts +14 -11
- package/src/codegen/discovery.ts +80 -28
- package/src/codegen/index.ts +2 -1
- package/src/codegen/parsers/bash.ts +179 -0
- package/src/codegen/schema-to-code.ts +2 -1
- package/src/core/args.ts +296 -0
- package/src/core/commands.ts +373 -0
- package/src/core/create.ts +268 -0
- package/src/{runtime.ts → core/default-runtime.ts} +70 -135
- package/src/{errors.ts → core/errors.ts} +22 -0
- package/src/core/exec.ts +259 -0
- package/src/core/interceptors.ts +302 -0
- package/src/{parse.ts → core/parse.ts} +36 -89
- package/src/core/program-methods.ts +301 -0
- package/src/core/results.ts +229 -0
- package/src/core/runtime.ts +246 -0
- package/src/core/validate.ts +247 -0
- package/src/docs/index.ts +124 -11
- package/src/extension/auto-output.ts +95 -0
- package/src/extension/color.ts +38 -0
- package/src/extension/completion.ts +49 -0
- package/src/extension/config.ts +262 -0
- package/src/extension/env.ts +101 -0
- package/src/extension/help.ts +192 -0
- package/src/extension/index.ts +43 -0
- package/src/extension/ink.ts +93 -0
- package/src/extension/interactive.ts +106 -0
- package/src/extension/logger.ts +214 -0
- package/src/extension/man.ts +51 -0
- package/src/extension/mcp.ts +52 -0
- package/src/extension/progress-renderer.ts +338 -0
- package/src/extension/progress.ts +299 -0
- package/src/extension/repl.ts +94 -0
- package/src/extension/serve.ts +48 -0
- package/src/extension/signal.ts +87 -0
- package/src/extension/stdin.ts +62 -0
- package/src/extension/suggestions.ts +114 -0
- package/src/extension/timing.ts +81 -0
- package/src/extension/tracing.ts +175 -0
- package/src/extension/update-check.ts +77 -0
- package/src/extension/utils.ts +51 -0
- package/src/extension/version.ts +63 -0
- package/src/{completion.ts → feature/completion.ts} +130 -57
- package/src/{interactive.ts → feature/interactive.ts} +47 -6
- package/src/feature/mcp.ts +387 -0
- package/src/{repl-loop.ts → feature/repl-loop.ts} +26 -16
- package/src/feature/serve.ts +438 -0
- package/src/feature/test.ts +262 -0
- package/src/{update-check.ts → feature/update-check.ts} +16 -16
- package/src/{wrap.ts → feature/wrap.ts} +27 -27
- package/src/index.ts +120 -11
- package/src/output/colorizer.ts +154 -0
- package/src/{formatter.ts → output/formatter.ts} +281 -135
- package/src/{help.ts → output/help.ts} +62 -15
- package/src/{zod.d.ts → schema/zod.d.ts} +1 -1
- package/src/schema/zod.ts +50 -0
- package/src/test.ts +2 -285
- package/src/types/args-meta.ts +151 -0
- package/src/types/builder.ts +697 -0
- package/src/types/command.ts +157 -0
- package/src/types/index.ts +59 -0
- package/src/types/interceptor.ts +296 -0
- package/src/types/preferences.ts +83 -0
- package/src/types/result.ts +71 -0
- package/src/types/schema.ts +19 -0
- package/src/util/dotenv.ts +244 -0
- package/src/{shell-utils.ts → util/shell-utils.ts} +26 -9
- package/src/util/stream.ts +101 -0
- package/src/{type-helpers.ts → util/type-helpers.ts} +23 -16
- package/src/{type-utils.ts → util/type-utils.ts} +99 -37
- package/src/util/utils.ts +51 -0
- package/src/zod.ts +1 -0
- package/dist/args-CVDbyyzG.mjs +0 -199
- package/dist/args-CVDbyyzG.mjs.map +0 -1
- package/dist/chunk-y_GBKt04.mjs +0 -5
- package/dist/completion.d.mts +0 -64
- package/dist/completion.d.mts.map +0 -1
- package/dist/completion.mjs.map +0 -1
- package/dist/formatter-ClUK5hcQ.d.mts.map +0 -1
- package/dist/help-CcBe91bV.mjs +0 -1254
- package/dist/help-CcBe91bV.mjs.map +0 -1
- package/dist/types-DjIdJN5G.d.mts +0 -1059
- package/dist/types-DjIdJN5G.d.mts.map +0 -1
- package/dist/update-check-EbNDkzyV.mjs.map +0 -1
- package/src/args.ts +0 -461
- package/src/colorizer.ts +0 -41
- package/src/command-utils.ts +0 -532
- package/src/create.ts +0 -1477
- package/src/types.ts +0 -1109
- package/src/utils.ts +0 -140
|
@@ -1,75 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/shell-utils.ts
|
|
4
|
-
/**
|
|
5
|
-
* Detects the current shell from environment variables and process info.
|
|
6
|
-
* @returns The detected shell type, or undefined if unknown
|
|
7
|
-
*/
|
|
8
|
-
function detectShell() {
|
|
9
|
-
if (typeof process === "undefined") return void 0;
|
|
10
|
-
const shellEnv = process.env.SHELL || "";
|
|
11
|
-
if (shellEnv.includes("zsh")) return "zsh";
|
|
12
|
-
if (shellEnv.includes("bash")) return "bash";
|
|
13
|
-
if (shellEnv.includes("fish")) return "fish";
|
|
14
|
-
if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) return "powershell";
|
|
15
|
-
try {
|
|
16
|
-
const ppid = process.ppid;
|
|
17
|
-
if (ppid) {
|
|
18
|
-
const { execSync } = __require("node:child_process");
|
|
19
|
-
const processName = execSync(`ps -p ${ppid} -o comm=`, {
|
|
20
|
-
encoding: "utf-8",
|
|
21
|
-
stdio: [
|
|
22
|
-
"pipe",
|
|
23
|
-
"pipe",
|
|
24
|
-
"ignore"
|
|
25
|
-
]
|
|
26
|
-
}).trim();
|
|
27
|
-
if (processName.includes("zsh")) return "zsh";
|
|
28
|
-
if (processName.includes("bash")) return "bash";
|
|
29
|
-
if (processName.includes("fish")) return "fish";
|
|
30
|
-
}
|
|
31
|
-
} catch {}
|
|
32
|
-
}
|
|
33
|
-
function getRcFile(shell, home) {
|
|
34
|
-
const { homedir } = __require("node:os");
|
|
35
|
-
const { join } = __require("node:path");
|
|
36
|
-
const h = home ?? homedir();
|
|
37
|
-
switch (shell) {
|
|
38
|
-
case "bash": return join(h, ".bashrc");
|
|
39
|
-
case "zsh": return join(h, ".zshrc");
|
|
40
|
-
case "fish": return join(h, ".config", "fish", "config.fish");
|
|
41
|
-
case "powershell": return process.env.PROFILE || join(h, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
42
|
-
default: return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function escapeRegExp(str) {
|
|
46
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Writes a snippet to a shell config file using begin/end markers for idempotency.
|
|
50
|
-
* If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.
|
|
51
|
-
*/
|
|
52
|
-
function writeToRcFile(rcFile, snippet, beginMarker, endMarker) {
|
|
53
|
-
const { existsSync, mkdirSync, readFileSync, writeFileSync } = __require("node:fs");
|
|
54
|
-
const { dirname } = __require("node:path");
|
|
55
|
-
const existing = existsSync(rcFile) ? readFileSync(rcFile, "utf-8") : "";
|
|
56
|
-
if (existing.includes(beginMarker)) {
|
|
57
|
-
const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`);
|
|
58
|
-
writeFileSync(rcFile, existing.replace(pattern, snippet));
|
|
59
|
-
return {
|
|
60
|
-
file: rcFile,
|
|
61
|
-
updated: true
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
mkdirSync(dirname(rcFile), { recursive: true });
|
|
65
|
-
writeFileSync(rcFile, `${existing}${existing.length > 0 && !existing.endsWith("\n") ? "\n" : ""}\n${snippet}\n`);
|
|
66
|
-
return {
|
|
67
|
-
file: rcFile,
|
|
68
|
-
updated: false
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
//#region src/completion.ts
|
|
1
|
+
import { a as getJsonSchema, d as detectShell, i as extractSchemaMetadata, m as writeToRcFile, p as getRcFile } from "./args-Cnq0nwSM.mjs";
|
|
2
|
+
//#region src/feature/completion.ts
|
|
73
3
|
/**
|
|
74
4
|
* Collects all commands from a program recursively.
|
|
75
5
|
*/
|
|
@@ -92,35 +22,55 @@ function extractArguments(cmd) {
|
|
|
92
22
|
try {
|
|
93
23
|
const argsMeta = cmd.meta?.fields;
|
|
94
24
|
const { aliases } = extractSchemaMetadata(cmd.argsSchema, argsMeta, cmd.meta?.autoAlias);
|
|
95
|
-
const
|
|
96
|
-
for (const [
|
|
97
|
-
const jsonSchema = cmd.argsSchema
|
|
25
|
+
const argToAlias = {};
|
|
26
|
+
for (const [aliasName, argName] of Object.entries(aliases)) if (!argToAlias[argName]) argToAlias[argName] = aliasName;
|
|
27
|
+
const jsonSchema = getJsonSchema(cmd.argsSchema);
|
|
98
28
|
if (jsonSchema.type === "object" && jsonSchema.properties) for (const [key, prop] of Object.entries(jsonSchema.properties)) {
|
|
99
|
-
const
|
|
29
|
+
const enumValues = prop.enum ?? prop.items?.enum;
|
|
30
|
+
const optMeta = argsMeta?.[key];
|
|
100
31
|
argList.push({
|
|
101
32
|
name: key,
|
|
102
|
-
alias,
|
|
103
|
-
isBoolean: prop?.type === "boolean"
|
|
33
|
+
alias: argToAlias[key],
|
|
34
|
+
isBoolean: prop?.type === "boolean",
|
|
35
|
+
enum: enumValues,
|
|
36
|
+
description: optMeta?.description ?? prop.description
|
|
104
37
|
});
|
|
105
38
|
}
|
|
106
39
|
} catch {}
|
|
107
40
|
return argList;
|
|
108
41
|
}
|
|
109
42
|
/**
|
|
43
|
+
* Collects unique args across all commands, preserving first-seen enum values.
|
|
44
|
+
*/
|
|
45
|
+
function collectUniqueArgs(program, commands) {
|
|
46
|
+
const seen = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const cmd of [program, ...commands]) for (const arg of extractArguments(cmd)) if (!seen.has(arg.name)) seen.set(arg.name, arg);
|
|
48
|
+
return seen;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
110
51
|
* Generates a Bash completion script for the program.
|
|
111
52
|
*/
|
|
112
53
|
function generateBashCompletion(program) {
|
|
113
54
|
const programName = program.name;
|
|
114
55
|
const commands = collectAllCommands(program);
|
|
115
56
|
const commandNames = commands.map((c) => c.name).join(" ");
|
|
57
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
116
58
|
const allArguments = /* @__PURE__ */ new Set();
|
|
117
59
|
allArguments.add("--help");
|
|
118
60
|
allArguments.add("--version");
|
|
119
|
-
for (const
|
|
61
|
+
for (const arg of uniqueArgs.values()) {
|
|
120
62
|
allArguments.add(`--${arg.name}`);
|
|
121
|
-
if (arg.alias) allArguments.add(
|
|
63
|
+
if (arg.alias) allArguments.add(`--${arg.alias}`);
|
|
122
64
|
}
|
|
123
65
|
const argsList = Array.from(allArguments).join(" ");
|
|
66
|
+
const enumCases = [];
|
|
67
|
+
for (const arg of uniqueArgs.values()) {
|
|
68
|
+
if (!arg.enum || arg.enum.length === 0) continue;
|
|
69
|
+
const values = arg.enum.join(" ");
|
|
70
|
+
const patterns = [`--${arg.name}`];
|
|
71
|
+
if (arg.alias) patterns.push(`--${arg.alias}`);
|
|
72
|
+
enumCases.push(` ${patterns.join("|")}) COMPREPLY=($(compgen -W "${values}" -- "$cur")); return 0 ;;`);
|
|
73
|
+
}
|
|
124
74
|
return `###-begin-${programName}-completion-###
|
|
125
75
|
#
|
|
126
76
|
# ${programName} command completion script
|
|
@@ -144,8 +94,13 @@ if type complete &>/dev/null; then
|
|
|
144
94
|
|
|
145
95
|
local commands="${commandNames}"
|
|
146
96
|
local args="${argsList}"
|
|
97
|
+
${enumCases.length > 0 ? `
|
|
98
|
+
# Complete option values
|
|
99
|
+
case "$prev" in
|
|
100
|
+
${enumCases.join("\n")}
|
|
101
|
+
esac
|
|
147
102
|
|
|
148
|
-
# Complete args when current word starts with -
|
|
103
|
+
` : "\n"} # Complete args when current word starts with -
|
|
149
104
|
if [[ "$cur" == -* ]]; then
|
|
150
105
|
COMPREPLY=($(compgen -W "$args" -- "$cur"))
|
|
151
106
|
return 0
|
|
@@ -197,13 +152,12 @@ function generateZshCompletion(program) {
|
|
|
197
152
|
const argumentCompletions = [];
|
|
198
153
|
argumentCompletions.push(" '--help[Show help information]'");
|
|
199
154
|
argumentCompletions.push(" '--version[Show version number]'");
|
|
200
|
-
const
|
|
201
|
-
for (const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
else argumentCompletions.push(` '--${arg.name}[${escapedDesc}]'`);
|
|
155
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
156
|
+
for (const arg of uniqueArgs.values()) {
|
|
157
|
+
const escapedDesc = (arg.description || "").replace(/'/g, "'\\''").replace(/\[/g, "\\[").replace(/\]/g, "\\]");
|
|
158
|
+
const valueAction = arg.enum?.length ? `: :(${arg.enum.join(" ")})` : "";
|
|
159
|
+
if (arg.alias) argumentCompletions.push(` {--${arg.alias},--${arg.name}}'[${escapedDesc}]${valueAction}'`);
|
|
160
|
+
else argumentCompletions.push(` '--${arg.name}[${escapedDesc}]${valueAction}'`);
|
|
207
161
|
}
|
|
208
162
|
return `#compdef ${programName}
|
|
209
163
|
###-begin-${programName}-completion-###
|
|
@@ -268,13 +222,12 @@ function generateFishCompletion(program) {
|
|
|
268
222
|
lines.push("# Global arguments");
|
|
269
223
|
lines.push(`complete -c ${programName} -l help -d 'Show help information'`);
|
|
270
224
|
lines.push(`complete -c ${programName} -l version -d 'Show version number'`);
|
|
271
|
-
const
|
|
272
|
-
for (const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
else lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'`);
|
|
225
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
226
|
+
for (const arg of uniqueArgs.values()) {
|
|
227
|
+
const escapedDesc = (arg.description || "").replace(/'/g, "\\'");
|
|
228
|
+
const valueFlag = arg.enum?.length ? ` -xa '${arg.enum.join(" ")}'` : "";
|
|
229
|
+
if (arg.alias) lines.push(`complete -c ${programName} -l ${arg.name} -s ${arg.alias} -d '${escapedDesc}'${valueFlag}`);
|
|
230
|
+
else lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'${valueFlag}`);
|
|
278
231
|
}
|
|
279
232
|
lines.push(`###-end-${programName}-completion-###`);
|
|
280
233
|
return lines.join("\n");
|
|
@@ -284,6 +237,32 @@ function generateFishCompletion(program) {
|
|
|
284
237
|
*/
|
|
285
238
|
function generatePowerShellCompletion(program) {
|
|
286
239
|
const programName = program.name;
|
|
240
|
+
const commands = collectAllCommands(program);
|
|
241
|
+
const uniqueArgs = collectUniqueArgs(program, commands);
|
|
242
|
+
const commandNames = commands.map((c) => `'${c.name}'`).join(", ");
|
|
243
|
+
const argNames = ["'--help'", "'--version'"];
|
|
244
|
+
for (const arg of uniqueArgs.values()) {
|
|
245
|
+
argNames.push(`'--${arg.name}'`);
|
|
246
|
+
if (arg.alias) argNames.push(`'--${arg.alias}'`);
|
|
247
|
+
}
|
|
248
|
+
const enumCases = [];
|
|
249
|
+
for (const arg of uniqueArgs.values()) {
|
|
250
|
+
if (!arg.enum || arg.enum.length === 0) continue;
|
|
251
|
+
const values = arg.enum.map((v) => `'${v}'`).join(", ");
|
|
252
|
+
const patterns = [`'--${arg.name}'`];
|
|
253
|
+
if (arg.alias) patterns.push(`'--${arg.alias}'`);
|
|
254
|
+
enumCases.push(` ${patterns.join(", ")} { @(${values}) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
255
|
+
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
256
|
+
}; return }`);
|
|
257
|
+
}
|
|
258
|
+
const enumBlock = enumCases.length > 0 ? `
|
|
259
|
+
# Complete option values
|
|
260
|
+
$prevWord = $commandAst.CommandElements | Select-Object -Last 2 | Select-Object -First 1
|
|
261
|
+
switch ($prevWord) {
|
|
262
|
+
${enumCases.join("\n")}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
` : "\n";
|
|
287
266
|
return `###-begin-${programName}-completion-###
|
|
288
267
|
#
|
|
289
268
|
# ${programName} command completion script for PowerShell
|
|
@@ -294,10 +273,9 @@ function generatePowerShellCompletion(program) {
|
|
|
294
273
|
Register-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {
|
|
295
274
|
param($wordToComplete, $commandAst, $cursorPosition)
|
|
296
275
|
|
|
297
|
-
$commands = @(${
|
|
298
|
-
$args = @(
|
|
299
|
-
|
|
300
|
-
if ($wordToComplete -like '-*') {
|
|
276
|
+
$commands = @(${commandNames})
|
|
277
|
+
$args = @(${argNames.join(", ")})
|
|
278
|
+
${enumBlock} if ($wordToComplete -like '-*') {
|
|
301
279
|
$args | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
|
302
280
|
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
|
303
281
|
}
|
|
@@ -348,10 +326,10 @@ ${programName} completion powershell >> $PROFILE`;
|
|
|
348
326
|
* Generates the completion output with automatic shell detection.
|
|
349
327
|
* If shell is not specified, detects the current shell and provides instructions.
|
|
350
328
|
*/
|
|
351
|
-
function generateCompletionOutput(program, shell) {
|
|
329
|
+
async function generateCompletionOutput(program, shell) {
|
|
352
330
|
const programName = program.name;
|
|
353
331
|
if (shell) return generateCompletion(program, shell);
|
|
354
|
-
const detectedShell = detectShell();
|
|
332
|
+
const detectedShell = await detectShell();
|
|
355
333
|
if (detectedShell) return `# Detected shell: ${detectedShell}
|
|
356
334
|
#
|
|
357
335
|
${getCompletionInstallInstructions(programName, detectedShell)}
|
|
@@ -380,10 +358,10 @@ ${generateCompletion(program, detectedShell)}`;
|
|
|
380
358
|
* Sets up shell completions by writing an eval snippet to the appropriate shell config file.
|
|
381
359
|
* Uses marker comments for idempotency — re-running replaces the existing block.
|
|
382
360
|
*/
|
|
383
|
-
function setupCompletions(programName, shell) {
|
|
384
|
-
const { existsSync, mkdirSync, writeFileSync } =
|
|
385
|
-
const { join } =
|
|
386
|
-
const { homedir } =
|
|
361
|
+
async function setupCompletions(programName, shell) {
|
|
362
|
+
const { existsSync, mkdirSync, writeFileSync } = await import("node:fs");
|
|
363
|
+
const { join } = await import("node:path");
|
|
364
|
+
const { homedir } = await import("node:os");
|
|
387
365
|
const beginMarker = `###-begin-${programName}-completion-###`;
|
|
388
366
|
const endMarker = `###-end-${programName}-completion-###`;
|
|
389
367
|
const snippet = buildSetupSnippet(programName, shell, beginMarker, endMarker);
|
|
@@ -398,7 +376,7 @@ function setupCompletions(programName, shell) {
|
|
|
398
376
|
updated: existed
|
|
399
377
|
};
|
|
400
378
|
}
|
|
401
|
-
const rcFile = getRcFile(shell);
|
|
379
|
+
const rcFile = await getRcFile(shell);
|
|
402
380
|
if (!rcFile) throw new Error(`Could not determine config file for ${shell}.`);
|
|
403
381
|
return writeToRcFile(rcFile, snippet, beginMarker, endMarker);
|
|
404
382
|
}
|
|
@@ -412,6 +390,6 @@ function buildSetupSnippet(programName, shell, beginMarker, endMarker) {
|
|
|
412
390
|
}
|
|
413
391
|
}
|
|
414
392
|
//#endregion
|
|
415
|
-
export { detectShell,
|
|
393
|
+
export { detectShell, generateCompletionOutput, setupCompletions };
|
|
416
394
|
|
|
417
|
-
//# sourceMappingURL=completion.mjs.map
|
|
395
|
+
//# sourceMappingURL=completion-BEuflbDO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"completion-BEuflbDO.mjs","names":[],"sources":["../src/feature/completion.ts"],"sourcesContent":["import { extractSchemaMetadata, getJsonSchema } from '../core/args.ts';\nimport type { AnyPadroneCommand } from '../types/index.ts';\nimport { detectShell, getRcFile, type ShellType, writeToRcFile } from '../util/shell-utils.ts';\n\nexport { detectShell, escapeRegExp, getRcFile, type ShellType, writeToRcFile } from '../util/shell-utils.ts';\n\n/**\n * Collects all commands from a program recursively.\n */\nfunction collectAllCommands(cmd: AnyPadroneCommand): AnyPadroneCommand[] {\n const result: AnyPadroneCommand[] = [];\n\n if (cmd.commands) {\n for (const subcmd of cmd.commands) {\n if (!subcmd.hidden) {\n result.push(subcmd);\n result.push(...collectAllCommands(subcmd));\n }\n }\n }\n\n return result;\n}\n\ninterface ExtractedArg {\n name: string;\n alias?: string;\n isBoolean: boolean;\n enum?: string[];\n description?: string;\n}\n\n/**\n * Extracts all argument names from a command's schema.\n */\nfunction extractArguments(cmd: AnyPadroneCommand): ExtractedArg[] {\n const argList: ExtractedArg[] = [];\n\n if (!cmd.argsSchema) return argList;\n\n try {\n const argsMeta = cmd.meta?.fields;\n const { aliases } = extractSchemaMetadata(cmd.argsSchema, argsMeta, cmd.meta?.autoAlias);\n\n // Build reverse map: argName → aliasName\n const argToAlias: Record<string, string> = {};\n for (const [aliasName, argName] of Object.entries(aliases)) {\n if (!argToAlias[argName]) argToAlias[argName] = aliasName;\n }\n\n const jsonSchema = getJsonSchema(cmd.argsSchema) as Record<string, any>;\n\n if (jsonSchema.type === 'object' && jsonSchema.properties) {\n for (const [key, prop] of Object.entries(jsonSchema.properties as Record<string, any>)) {\n const enumValues = (prop.enum ?? prop.items?.enum) as string[] | undefined;\n const optMeta = argsMeta?.[key];\n argList.push({\n name: key,\n alias: argToAlias[key],\n isBoolean: prop?.type === 'boolean',\n enum: enumValues,\n description: optMeta?.description ?? prop.description,\n });\n }\n }\n } catch {\n // Ignore schema parsing errors\n }\n\n return argList;\n}\n\n/**\n * Collects unique args across all commands, preserving first-seen enum values.\n */\nfunction collectUniqueArgs(program: AnyPadroneCommand, commands: AnyPadroneCommand[]): Map<string, ExtractedArg> {\n const seen = new Map<string, ExtractedArg>();\n\n for (const cmd of [program, ...commands]) {\n for (const arg of extractArguments(cmd)) {\n if (!seen.has(arg.name)) {\n seen.set(arg.name, arg);\n }\n }\n }\n\n return seen;\n}\n\n/**\n * Generates a Bash completion script for the program.\n */\nexport function generateBashCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n const commandNames = commands.map((c) => c.name).join(' ');\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n // Collect all option names\n const allArguments = new Set<string>();\n allArguments.add('--help');\n allArguments.add('--version');\n\n for (const arg of uniqueArgs.values()) {\n allArguments.add(`--${arg.name}`);\n if (arg.alias) allArguments.add(`--${arg.alias}`);\n }\n\n const argsList = Array.from(allArguments).join(' ');\n\n // Build case branches for options with enum values\n const enumCases: string[] = [];\n for (const arg of uniqueArgs.values()) {\n if (!arg.enum || arg.enum.length === 0) continue;\n const values = arg.enum.join(' ');\n const patterns = [`--${arg.name}`];\n if (arg.alias) patterns.push(`--${arg.alias}`);\n enumCases.push(` ${patterns.join('|')}) COMPREPLY=($(compgen -W \"${values}\" -- \"$cur\")); return 0 ;;`);\n }\n\n const enumBlock =\n enumCases.length > 0\n ? `\n # Complete option values\n case \"$prev\" in\n${enumCases.join('\\n')}\n esac\n\n`\n : '\\n';\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script\n#\n# Installation: ${programName} completion >> ~/.bashrc (or ~/.zshrc)\n# Or, maybe: ${programName} completion > /usr/local/etc/bash_completion.d/${programName}\n#\n\nif type complete &>/dev/null; then\n _${programName}_completion() {\n local cur prev words cword\n if type _get_comp_words_by_ref &>/dev/null; then\n _get_comp_words_by_ref -n = -n @ -n : -w words -i cword\n else\n cword=\"$COMP_CWORD\"\n words=(\"\\${COMP_WORDS[@]}\")\n fi\n\n cur=\"\\${words[cword]}\"\n prev=\"\\${words[cword-1]}\"\n\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n${enumBlock} # Complete args when current word starts with -\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$args\" -- \"$cur\"))\n return 0\n fi\n\n # Complete commands\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n }\n complete -o bashdefault -o default -o nospace -F _${programName}_completion ${programName}\nelif type compdef &>/dev/null; then\n _${programName}_completion() {\n local si=$IFS\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n compadd -- \\${=args}\n else\n compadd -- \\${=commands}\n fi\n IFS=$si\n }\n compdef _${programName}_completion ${programName}\nelif type compctl &>/dev/null; then\n _${programName}_completion() {\n local commands=\"${commandNames}\"\n local args=\"${argsList}\"\n\n if [[ \"\\${words[CURRENT]}\" == -* ]]; then\n reply=(\\${=args})\n else\n reply=(\\${=commands})\n fi\n }\n compctl -K _${programName}_completion ${programName}\nfi\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Zsh completion script for the program.\n */\nexport function generateZshCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n // Generate command completions with descriptions\n const commandCompletions = commands\n .map((cmd) => {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/:/g, '\\\\:');\n return ` '${cmd.name}:${escapedDesc}'`;\n })\n .join('\\n');\n\n // Collect all args with descriptions and enum values\n const argumentCompletions: string[] = [];\n argumentCompletions.push(\" '--help[Show help information]'\");\n argumentCompletions.push(\" '--version[Show version number]'\");\n\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n for (const arg of uniqueArgs.values()) {\n const desc = arg.description || '';\n const escapedDesc = desc.replace(/'/g, \"'\\\\''\").replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]');\n\n // Zsh action spec for enum values: :label:(val1 val2 val3)\n const valueAction = arg.enum?.length ? `: :(${arg.enum.join(' ')})` : '';\n\n if (arg.alias) {\n argumentCompletions.push(` {--${arg.alias},--${arg.name}}'[${escapedDesc}]${valueAction}'`);\n } else {\n argumentCompletions.push(` '--${arg.name}[${escapedDesc}]${valueAction}'`);\n }\n }\n\n return `#compdef ${programName}\n###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for Zsh\n#\n# Installation: ${programName} completion >> ~/.zshrc\n# Or: ${programName} completion > ~/.zsh/completions/_${programName}\n#\n\n_${programName}() {\n local -a commands\n local -a args\n\n commands=(\n${commandCompletions}\n )\n\n args=(\n${argumentCompletions.join('\\n')}\n )\n\n _arguments -s \\\\\n $args \\\\\n '1: :->command' \\\\\n '*::arg:->args'\n\n case \"$state\" in\n command)\n _describe 'command' commands\n ;;\n esac\n}\n\n_${programName}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a Fish completion script for the program.\n */\nexport function generateFishCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n\n const lines: string[] = [\n `###-begin-${programName}-completion-###`,\n '#',\n `# ${programName} command completion script for Fish`,\n '#',\n `# Installation: ${programName} completion > ~/.config/fish/completions/${programName}.fish`,\n '#',\n '',\n `# Clear existing completions`,\n `complete -c ${programName} -e`,\n '',\n '# Commands',\n ];\n\n for (const cmd of commands) {\n const desc = cmd.description || cmd.title || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n lines.push(`complete -c ${programName} -n \"__fish_use_subcommand\" -a \"${cmd.name}\" -d '${escapedDesc}'`);\n }\n\n lines.push('');\n lines.push('# Global arguments');\n lines.push(`complete -c ${programName} -l help -d 'Show help information'`);\n lines.push(`complete -c ${programName} -l version -d 'Show version number'`);\n\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n for (const arg of uniqueArgs.values()) {\n const desc = arg.description || '';\n const escapedDesc = desc.replace(/'/g, \"\\\\'\");\n // Fish: -xa 'val1 val2' provides exclusive value completions\n const valueFlag = arg.enum?.length ? ` -xa '${arg.enum.join(' ')}'` : '';\n\n if (arg.alias) {\n lines.push(`complete -c ${programName} -l ${arg.name} -s ${arg.alias} -d '${escapedDesc}'${valueFlag}`);\n } else {\n lines.push(`complete -c ${programName} -l ${arg.name} -d '${escapedDesc}'${valueFlag}`);\n }\n }\n\n lines.push(`###-end-${programName}-completion-###`);\n\n return lines.join('\\n');\n}\n\n/**\n * Generates a PowerShell completion script for the program.\n */\nexport function generatePowerShellCompletion(program: AnyPadroneCommand): string {\n const programName = program.name;\n const commands = collectAllCommands(program);\n const uniqueArgs = collectUniqueArgs(program, commands);\n\n const commandNames = commands.map((c) => `'${c.name}'`).join(', ');\n\n // Collect all option names\n const argNames: string[] = [\"'--help'\", \"'--version'\"];\n for (const arg of uniqueArgs.values()) {\n argNames.push(`'--${arg.name}'`);\n if (arg.alias) argNames.push(`'--${arg.alias}'`);\n }\n\n // Build switch cases for option value completion\n const enumCases: string[] = [];\n for (const arg of uniqueArgs.values()) {\n if (!arg.enum || arg.enum.length === 0) continue;\n const values = arg.enum.map((v) => `'${v}'`).join(', ');\n const patterns = [`'--${arg.name}'`];\n if (arg.alias) patterns.push(`'--${arg.alias}'`);\n enumCases.push(` ${patterns.join(', ')} { @(${values}) | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }; return }`);\n }\n\n const enumBlock =\n enumCases.length > 0\n ? `\n # Complete option values\n $prevWord = $commandAst.CommandElements | Select-Object -Last 2 | Select-Object -First 1\n switch ($prevWord) {\n${enumCases.join('\\n')}\n }\n\n`\n : '\\n';\n\n return `###-begin-${programName}-completion-###\n#\n# ${programName} command completion script for PowerShell\n#\n# Installation: ${programName} completion >> $PROFILE\n#\n\nRegister-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {\n param($wordToComplete, $commandAst, $cursorPosition)\n\n $commands = @(${commandNames})\n $args = @(${argNames.join(', ')})\n${enumBlock} if ($wordToComplete -like '-*') {\n $args | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n } else {\n $commands | Where-Object { $_ -like \"$wordToComplete*\" } | ForEach-Object {\n [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)\n }\n }\n}\n###-end-${programName}-completion-###`;\n}\n\n/**\n * Generates a completion script for the specified shell.\n */\nexport function generateCompletion(program: AnyPadroneCommand, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return generateBashCompletion(program);\n case 'zsh':\n return generateZshCompletion(program);\n case 'fish':\n return generateFishCompletion(program);\n case 'powershell':\n return generatePowerShellCompletion(program);\n default:\n throw new Error(`Unsupported shell: ${shell}`);\n }\n}\n\n/**\n * Gets the installation instructions for a shell completion script.\n */\nexport function getCompletionInstallInstructions(programName: string, shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return `# Add to ~/.bashrc:\n${programName} completion bash >> ~/.bashrc\n\n# Or install system-wide:\n${programName} completion bash > /usr/local/etc/bash_completion.d/${programName}`;\n\n case 'zsh':\n return `# Add to ~/.zshrc:\n${programName} completion zsh >> ~/.zshrc\n\n# Or add to completions directory:\n${programName} completion zsh > ~/.zsh/completions/_${programName}`;\n\n case 'fish':\n return `# Install to Fish completions:\n${programName} completion fish > ~/.config/fish/completions/${programName}.fish`;\n\n case 'powershell':\n return `# Add to PowerShell profile:\n${programName} completion powershell >> $PROFILE`;\n\n default:\n return `# Run: ${programName} completion <shell>\n# Supported shells: bash, zsh, fish, powershell`;\n }\n}\n\n/**\n * Generates the completion output with automatic shell detection.\n * If shell is not specified, detects the current shell and provides instructions.\n */\nexport async function generateCompletionOutput(program: AnyPadroneCommand, shell?: ShellType): Promise<string> {\n const programName = program.name;\n\n if (shell) {\n return generateCompletion(program, shell);\n }\n\n // Auto-detect shell and provide instructions\n const detectedShell = await detectShell();\n\n if (detectedShell) {\n const instructions = getCompletionInstallInstructions(programName, detectedShell);\n const script = generateCompletion(program, detectedShell);\n\n return `# Detected shell: ${detectedShell}\n#\n${instructions}\n#\n# Or evaluate directly (temporary, for current session only):\n# eval \"$(${programName} completion ${detectedShell})\"\n\n${script}`;\n }\n\n // Could not detect shell - provide usage info\n return `# Shell auto-detection failed.\n#\n# Usage: ${programName} completion <shell>\n#\n# Supported shells:\n# bash - Bash completion script\n# zsh - Zsh completion script\n# fish - Fish completion script\n# powershell - PowerShell completion script\n#\n# Example:\n# ${programName} completion bash >> ~/.bashrc\n# ${programName} completion zsh >> ~/.zshrc\n# ${programName} completion fish > ~/.config/fish/completions/${programName}.fish\n# ${programName} completion powershell >> $PROFILE`;\n}\n\nexport interface SetupCompletionsResult {\n /** The file that was written to. */\n file: string;\n /** Whether an existing completion block was replaced (true) or a new one was appended (false). */\n updated: boolean;\n}\n\n/**\n * Sets up shell completions by writing an eval snippet to the appropriate shell config file.\n * Uses marker comments for idempotency — re-running replaces the existing block.\n */\nexport async function setupCompletions(programName: string, shell: ShellType): Promise<SetupCompletionsResult> {\n const { existsSync, mkdirSync, writeFileSync } = await import('node:fs');\n const { join } = await import('node:path');\n const { homedir } = await import('node:os');\n\n const beginMarker = `###-begin-${programName}-completion-###`;\n const endMarker = `###-end-${programName}-completion-###`;\n const snippet = buildSetupSnippet(programName, shell, beginMarker, endMarker);\n\n if (shell === 'fish') {\n const completionsDir = join(homedir(), '.config', 'fish', 'completions');\n const filePath = join(completionsDir, `${programName}.fish`);\n mkdirSync(completionsDir, { recursive: true });\n const existed = existsSync(filePath);\n writeFileSync(filePath, `${snippet}\\n`);\n return { file: filePath, updated: existed };\n }\n\n const rcFile = await getRcFile(shell);\n if (!rcFile) {\n throw new Error(`Could not determine config file for ${shell}.`);\n }\n\n return writeToRcFile(rcFile, snippet, beginMarker, endMarker);\n}\n\nfunction buildSetupSnippet(programName: string, shell: ShellType, beginMarker: string, endMarker: string): string {\n const evalCmd = `${programName} completion ${shell}`;\n\n switch (shell) {\n case 'bash':\n case 'zsh':\n return `${beginMarker}\\neval \"$(${evalCmd})\"\\n${endMarker}`;\n case 'fish':\n return `${beginMarker}\\n${evalCmd} | source\\n${endMarker}`;\n case 'powershell':\n return `${beginMarker}\\n${evalCmd} | Invoke-Expression\\n${endMarker}`;\n }\n}\n"],"mappings":"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"}
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as HelpInfo } from "../formatter-
|
|
1
|
+
import { r as HelpInfo } from "../formatter-DrvhDMrq.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/docs/index.d.ts
|
|
4
4
|
type DocsFormat = 'markdown' | 'html' | 'man' | 'json';
|
|
@@ -29,6 +29,26 @@ type DocsResult = {
|
|
|
29
29
|
* Accepts either a PadroneProgram (from createPadrone()) or a raw AnyPadroneCommand.
|
|
30
30
|
*/
|
|
31
31
|
declare function generateDocs(program: object, options?: DocsOptions): DocsResult;
|
|
32
|
+
type SetupManPagesResult = {
|
|
33
|
+
/** Directory where man pages were written. */dir: string; /** Man page files that were written. */
|
|
34
|
+
written: string[]; /** Whether existing pages were overwritten (true) or newly created (false). */
|
|
35
|
+
updated: boolean;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Installs man pages for a Padrone CLI program into the local man directory.
|
|
39
|
+
* Generates man pages for all commands and writes them to `~/.local/share/man/man1/`.
|
|
40
|
+
*
|
|
41
|
+
* After installation, `man <program>` and `man <program>-<subcommand>` should work
|
|
42
|
+
* (assuming `~/.local/share/man` is in `MANPATH` or `manpath` picks it up).
|
|
43
|
+
*/
|
|
44
|
+
declare function setupManPages(program: object): Promise<SetupManPagesResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Removes installed man pages for a Padrone CLI program.
|
|
47
|
+
*/
|
|
48
|
+
declare function removeManPages(program: object): Promise<{
|
|
49
|
+
dir: string;
|
|
50
|
+
removed: string[];
|
|
51
|
+
}>;
|
|
32
52
|
//#endregion
|
|
33
|
-
export { DocsFormat, DocsOptions, DocsPage, DocsResult, generateDocs };
|
|
53
|
+
export { DocsFormat, DocsOptions, DocsPage, DocsResult, SetupManPagesResult, generateDocs, removeManPages, setupManPages };
|
|
34
54
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/docs/index.ts"],"mappings":";;;KAWY,UAAA;AAAA,KAEA,WAAA;EAFA,6CAIV,MAAA,GAAS,UAAA;EAET,MAAA,WANoB;EAQpB,aAAA,YANqB;EAQrB,WAAA,IAAe,IAAA,EAAM,QAAA,EAAU,KAAA,aAAkB,MAAA,mBANxC;EAQT,SAAA,YAFiD;EAIjD,MAAA;AAAA;AAAA,KAGU,QAAA;EAbD,8EAeT,IAAA,UAXA;EAaA,OAAA,UAXqB;EAarB,OAAA;AAAA;AAAA,KAGU,UAAA;EAdV,2BAgBA,KAAA,EAAO,QAAA,IAdD;EAgBN,OAAA,YAbU;EAeV,OAAA;EAEA,MAAA;IAAU,IAAA;IAAc,KAAA,EAAO,KAAA;EAAA;AAAA;;AARjC;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/docs/index.ts"],"mappings":";;;KAWY,UAAA;AAAA,KAEA,WAAA;EAFA,6CAIV,MAAA,GAAS,UAAA;EAET,MAAA,WANoB;EAQpB,aAAA,YANqB;EAQrB,WAAA,IAAe,IAAA,EAAM,QAAA,EAAU,KAAA,aAAkB,MAAA,mBANxC;EAQT,SAAA,YAFiD;EAIjD,MAAA;AAAA;AAAA,KAGU,QAAA;EAbD,8EAeT,IAAA,UAXA;EAaA,OAAA,UAXqB;EAarB,OAAA;AAAA;AAAA,KAGU,UAAA;EAdV,2BAgBA,KAAA,EAAO,QAAA,IAdD;EAgBN,OAAA,YAbU;EAeV,OAAA;EAEA,MAAA;IAAU,IAAA;IAAc,KAAA,EAAO,KAAA;EAAA;AAAA;;AARjC;;;iBAigBgB,YAAA,CAAa,OAAA,UAAiB,OAAA,GAAS,WAAA,GAAmB,UAAA;AAAA,KAoF9D,mBAAA;EAnlBH,8CAqlBP,GAAA,UAjlBA;EAmlBA,OAAA,YAjlBU;EAmlBV,OAAA;AAAA;;;AA1FF;;;;;iBAqHsB,aAAA,CAAc,OAAA,WAAkB,OAAA,CAAQ,mBAAA;;;;iBA+BxC,cAAA,CAAe,OAAA,WAAkB,OAAA;EAAU,GAAA;EAAa,OAAA;AAAA"}
|
package/dist/docs/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as getCommand } from "../commands-B_gufyR9.mjs";
|
|
2
|
+
import { n as getHelpInfo } from "../help-B5Kk83of.mjs";
|
|
2
3
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { dirname, join, resolve } from "node:path";
|
|
4
5
|
//#region src/docs/index.ts
|
|
@@ -122,6 +123,14 @@ function generateMarkdownPage(info, depth, frontmatterFn) {
|
|
|
122
123
|
lines.push(usageParts.join(" "));
|
|
123
124
|
lines.push("```");
|
|
124
125
|
lines.push("");
|
|
126
|
+
if (info.examples?.length) {
|
|
127
|
+
lines.push("## Examples");
|
|
128
|
+
lines.push("");
|
|
129
|
+
lines.push("```");
|
|
130
|
+
for (const ex of info.examples) lines.push(`$ ${ex}`);
|
|
131
|
+
lines.push("```");
|
|
132
|
+
lines.push("");
|
|
133
|
+
}
|
|
125
134
|
if (info.subcommands?.length) {
|
|
126
135
|
const visibleSubs = info.subcommands.filter((s) => !s.hidden);
|
|
127
136
|
if (visibleSubs.length > 0) {
|
|
@@ -170,6 +179,10 @@ function generateHtmlPage(info, depth) {
|
|
|
170
179
|
if (info.usage.hasArguments) usageParts.push("[options]");
|
|
171
180
|
sections.push(" <h2>Usage</h2>");
|
|
172
181
|
sections.push(` <pre><code>${escapeHtml(usageParts.join(" "))}</code></pre>`);
|
|
182
|
+
if (info.examples?.length) {
|
|
183
|
+
sections.push(" <h2>Examples</h2>");
|
|
184
|
+
sections.push(` <pre><code>${info.examples.map((ex) => `$ ${escapeHtml(ex)}`).join("\n")}</code></pre>`);
|
|
185
|
+
}
|
|
173
186
|
if (info.subcommands?.length) {
|
|
174
187
|
const visibleSubs = info.subcommands.filter((s) => !s.hidden);
|
|
175
188
|
if (visibleSubs.length > 0) {
|
|
@@ -249,6 +262,13 @@ function generateManPage(info, _depth, programName) {
|
|
|
249
262
|
lines.push(".SH DESCRIPTION");
|
|
250
263
|
lines.push(escapeMan(info.description));
|
|
251
264
|
}
|
|
265
|
+
if (info.examples?.length) {
|
|
266
|
+
lines.push(".SH EXAMPLES");
|
|
267
|
+
for (const ex of info.examples) {
|
|
268
|
+
lines.push(".PP");
|
|
269
|
+
lines.push(`.nf\n$ ${escapeMan(ex)}\n.fi`);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
252
272
|
if (info.subcommands?.length) {
|
|
253
273
|
const visibleSubs = info.subcommands.filter((s) => !s.hidden);
|
|
254
274
|
if (visibleSubs.length > 0) {
|
|
@@ -321,17 +341,13 @@ function generateMarkdownIndex(rootInfo, allInfos) {
|
|
|
321
341
|
}
|
|
322
342
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
323
343
|
}
|
|
324
|
-
function resolveCommand(programOrCommand) {
|
|
325
|
-
if (commandSymbol in programOrCommand) return programOrCommand[commandSymbol];
|
|
326
|
-
return programOrCommand;
|
|
327
|
-
}
|
|
328
344
|
/**
|
|
329
345
|
* Generate documentation for a Padrone CLI program or command tree.
|
|
330
346
|
* Accepts either a PadroneProgram (from createPadrone()) or a raw AnyPadroneCommand.
|
|
331
347
|
*/
|
|
332
348
|
function generateDocs(program, options = {}) {
|
|
333
349
|
const { format = "markdown", output, includeHidden = false, frontmatter, overwrite = true, dryRun = false } = options;
|
|
334
|
-
const cmd =
|
|
350
|
+
const cmd = getCommand(program);
|
|
335
351
|
const allInfos = collectAllHelpInfo(cmd, includeHidden);
|
|
336
352
|
const rootInfo = allInfos[0];
|
|
337
353
|
const programName = cmd.name || "program";
|
|
@@ -399,7 +415,76 @@ function generateDocs(program, options = {}) {
|
|
|
399
415
|
}
|
|
400
416
|
return result;
|
|
401
417
|
}
|
|
418
|
+
/**
|
|
419
|
+
* Returns the local man page directory for the given section.
|
|
420
|
+
* Uses `~/.local/share/man/man<section>` (XDG convention).
|
|
421
|
+
*/
|
|
422
|
+
async function getManPageDir(section = 1) {
|
|
423
|
+
const { homedir } = await import("node:os");
|
|
424
|
+
return join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), "man", `man${section}`);
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Converts a command name to a man page filename.
|
|
428
|
+
* "myapp" → "myapp.1", "myapp deploy" → "myapp-deploy.1"
|
|
429
|
+
*/
|
|
430
|
+
function manPageFilename(commandName, section = 1) {
|
|
431
|
+
return `${commandName.replace(/\s+/g, "-")}.${section}`;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Installs man pages for a Padrone CLI program into the local man directory.
|
|
435
|
+
* Generates man pages for all commands and writes them to `~/.local/share/man/man1/`.
|
|
436
|
+
*
|
|
437
|
+
* After installation, `man <program>` and `man <program>-<subcommand>` should work
|
|
438
|
+
* (assuming `~/.local/share/man` is in `MANPATH` or `manpath` picks it up).
|
|
439
|
+
*/
|
|
440
|
+
async function setupManPages(program) {
|
|
441
|
+
const cmd = getCommand(program);
|
|
442
|
+
const allInfos = collectAllHelpInfo(cmd, false);
|
|
443
|
+
const programName = cmd.name || "program";
|
|
444
|
+
const manDir = await getManPageDir(1);
|
|
445
|
+
mkdirSync(manDir, { recursive: true });
|
|
446
|
+
const written = [];
|
|
447
|
+
let updated = false;
|
|
448
|
+
for (let i = 0; i < allInfos.length; i++) {
|
|
449
|
+
const info = allInfos[i];
|
|
450
|
+
const depth = i === 0 ? 0 : info.name.split(/\s+/).length;
|
|
451
|
+
const filename = manPageFilename(info.name === "<root>" || !info.name ? programName : info.name);
|
|
452
|
+
const fullPath = join(manDir, filename);
|
|
453
|
+
if (existsSync(fullPath)) updated = true;
|
|
454
|
+
writeFileSync(fullPath, generateManPage(info, depth, programName), "utf-8");
|
|
455
|
+
written.push(filename);
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
dir: manDir,
|
|
459
|
+
written,
|
|
460
|
+
updated
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Removes installed man pages for a Padrone CLI program.
|
|
465
|
+
*/
|
|
466
|
+
async function removeManPages(program) {
|
|
467
|
+
const { unlinkSync } = await import("node:fs");
|
|
468
|
+
const cmd = getCommand(program);
|
|
469
|
+
const allInfos = collectAllHelpInfo(cmd, false);
|
|
470
|
+
const programName = cmd.name || "program";
|
|
471
|
+
const manDir = await getManPageDir(1);
|
|
472
|
+
const removed = [];
|
|
473
|
+
for (let i = 0; i < allInfos.length; i++) {
|
|
474
|
+
const info = allInfos[i];
|
|
475
|
+
const filename = manPageFilename(info.name === "<root>" || !info.name ? programName : info.name);
|
|
476
|
+
const fullPath = join(manDir, filename);
|
|
477
|
+
if (existsSync(fullPath)) {
|
|
478
|
+
unlinkSync(fullPath);
|
|
479
|
+
removed.push(filename);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return {
|
|
483
|
+
dir: manDir,
|
|
484
|
+
removed
|
|
485
|
+
};
|
|
486
|
+
}
|
|
402
487
|
//#endregion
|
|
403
|
-
export { generateDocs };
|
|
488
|
+
export { generateDocs, removeManPages, setupManPages };
|
|
404
489
|
|
|
405
490
|
//# sourceMappingURL=index.mjs.map
|