politty 0.1.2 → 0.2.1

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.
@@ -424,7 +424,7 @@ function generateZshScript(command, programName, includeDescriptions) {
424
424
 
425
425
  ${collectSubcommandFunctions(command, programName, includeDescriptions).join("\n")}
426
426
 
427
- _${programName} "$@"
427
+ compdef _${programName} ${programName}
428
428
  `;
429
429
  }
430
430
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["extractFields","generateOptionCompletions","generateSubcommandCompletions","z","arg","defineCommand"],"sources":["../../src/completion/extractor.ts","../../src/completion/bash.ts","../../src/completion/fish.ts","../../src/completion/zsh.ts","../../src/completion/index.ts"],"sourcesContent":["/**\n * Extract completion data from commands\n */\n\nimport { extractFields, type ResolvedFieldMeta } from \"../core/schema-extractor.js\";\nimport type { AnyCommand } from \"../types.js\";\nimport type { CompletableOption, CompletableSubcommand, CompletionData } from \"./types.js\";\n\n/**\n * Convert a resolved field to a completable option\n */\nfunction fieldToOption(field: ResolvedFieldMeta): CompletableOption {\n return {\n name: field.name,\n cliName: field.cliName,\n alias: field.alias,\n description: field.description,\n // Booleans are flags that don't require a value\n takesValue: field.type !== \"boolean\",\n valueType: field.type,\n required: field.required,\n };\n}\n\n/**\n * Extract options from a command's args schema\n */\nfunction extractOptions(command: AnyCommand): CompletableOption[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields\n .filter((field) => !field.positional) // Only include flags/options, not positionals\n .map(fieldToOption);\n}\n\n/**\n * Extract positional arguments from a command\n */\nexport function extractPositionals(command: AnyCommand): ResolvedFieldMeta[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields.filter((field) => field.positional);\n}\n\n/**\n * Extract a completable subcommand from a command\n */\nfunction extractSubcommand(name: string, command: AnyCommand): CompletableSubcommand {\n const subcommands: CompletableSubcommand[] = [];\n\n // Extract subcommands recursively (only sync subcommands for now)\n if (command.subCommands) {\n for (const [subName, subCommand] of Object.entries(command.subCommands)) {\n // Skip async subcommands as we can't inspect them statically\n if (typeof subCommand === \"function\") {\n // For async subcommands, add a placeholder\n subcommands.push({\n name: subName,\n description: \"(lazy loaded)\",\n subcommands: [],\n options: [],\n });\n } else {\n subcommands.push(extractSubcommand(subName, subCommand));\n }\n }\n }\n\n return {\n name,\n description: command.description,\n subcommands,\n options: extractOptions(command),\n };\n}\n\n/**\n * Extract completion data from a command tree\n */\nexport function extractCompletionData(command: AnyCommand, programName: string): CompletionData {\n const rootSubcommand = extractSubcommand(programName, command);\n\n return {\n command: rootSubcommand,\n programName,\n // Global options are the options defined on the root command\n globalOptions: rootSubcommand.options,\n };\n}\n","/**\n * Bash completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Generate option completions for bash\n */\nfunction generateOptionCompletions(options: CompletableOption[]): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n completions.push(`--${opt.cliName}`);\n if (opt.alias) {\n completions.push(`-${opt.alias}`);\n }\n }\n\n return completions;\n}\n\n/**\n * Generate subcommand completions for bash\n */\nfunction generateSubcommandCompletions(subcommands: CompletableSubcommand[]): string[] {\n return subcommands.map((sub) => sub.name);\n}\n\n/**\n * Generate the bash completion script\n */\nfunction generateBashScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const allOptions = collectAllOptions(command);\n\n const optionList = generateOptionCompletions(allOptions).join(\" \");\n const subcommandList = generateSubcommandCompletions(command.subcommands).join(\" \");\n\n // Build subcommand-specific completions\n const subcommandCases = buildSubcommandCases(command.subcommands, includeDescriptions);\n\n return `# Bash completion for ${programName}\n# Generated by politty\n\n_${programName}_completions() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"${subcommandList}\"\n local global_opts=\"${optionList}\"\n\n # Handle subcommand-specific completions\n local cmd_index=1\n local cmd=\"\"\n\n # Find the subcommand\n for ((i=1; i < cword; i++)); do\n case \"\\${words[i]}\" in\n -*)\n # Skip options and their values\n if [[ \"\\${words[i]}\" == *=* ]]; then\n continue\n fi\n # Check if next word is the option's value\n local opt=\"\\${words[i]}\"\n case \"$opt\" in\n ${\n allOptions\n .filter((o) => o.takesValue)\n .map((o) => `--${o.cliName}|-${o.alias || \"\"}`)\n .join(\"|\") || \"--*\"\n }\n ((i++))\n ;;\n esac\n ;;\n *)\n # Found a subcommand\n cmd=\"\\${words[i]}\"\n cmd_index=$i\n break\n ;;\n esac\n done\n\n # Subcommand-specific completions\n case \"$cmd\" in\n${subcommandCases}\n *)\n # Root level completions\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$global_opts\" -- \"$cur\"))\n else\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n fi\n ;;\n esac\n\n return 0\n}\n\n# Register the completion function\ncomplete -F _${programName}_completions ${programName}\n`;\n}\n\n/**\n * Build case statements for subcommand-specific completions\n */\nfunction buildSubcommandCases(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n let cases = \"\";\n\n for (const sub of subcommands) {\n const options = generateOptionCompletions(sub.options).join(\" \");\n const nestedSubcommands = generateSubcommandCompletions(sub.subcommands).join(\" \");\n const completions = [options, nestedSubcommands].filter(Boolean).join(\" \");\n\n cases += ` ${sub.name})\\n`;\n cases += ` COMPREPLY=($(compgen -W \"${completions}\" -- \"$cur\"))\\n`;\n cases += ` ;;\\n`;\n\n // Add nested subcommand cases if any\n if (sub.subcommands.length > 0) {\n const nestedCases = buildSubcommandCases(sub.subcommands, includeDescriptions);\n if (nestedCases) {\n cases += nestedCases;\n }\n }\n }\n\n return cases;\n}\n\n/**\n * Collect all options from a command tree\n */\nfunction collectAllOptions(command: CompletableSubcommand): CompletableOption[] {\n const options = [...command.options];\n\n for (const sub of command.subcommands) {\n options.push(...collectAllOptions(sub));\n }\n\n // Deduplicate by name\n const seen = new Set<string>();\n return options.filter((opt) => {\n if (seen.has(opt.name)) {\n return false;\n }\n seen.add(opt.name);\n return true;\n });\n}\n\n/**\n * Generate bash completion script for a command\n */\nexport function generateBashCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateBashScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"bash\",\n installInstructions: `# To enable completions, add the following to your ~/.bashrc:\n\n# Option 1: Source directly\neval \"$(${options.programName} completion bash)\"\n\n# Option 2: Save to a file\n${options.programName} completion bash > ~/.local/share/bash-completion/completions/${options.programName}\n\n# Then reload your shell or run:\nsource ~/.bashrc`,\n };\n}\n","/**\n * Fish completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in fish completion descriptions\n */\nfunction escapeForFish(str: string): string {\n return str.replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate completion entries for options\n */\nfunction generateOptionCompletions(\n options: CompletableOption[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition if specified\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Add long option\n cmd += ` -l ${opt.cliName}`;\n\n // Add short option if exists\n if (opt.alias) {\n cmd += ` -s ${opt.alias}`;\n }\n\n // Add flag for options that take values\n if (opt.takesValue) {\n cmd += \" -r\"; // Require argument\n } else {\n cmd += \" -f\"; // No argument (flag)\n }\n\n // Add description\n if (includeDescriptions && opt.description) {\n cmd += ` -d '${escapeForFish(opt.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate completion entries for subcommands\n */\nfunction generateSubcommandCompletions(\n subcommands: CompletableSubcommand[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const sub of subcommands) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Subcommands are exclusive (no prefix)\n cmd += ` -f -a ${sub.name}`;\n\n // Add description\n if (includeDescriptions && sub.description) {\n cmd += ` -d '${escapeForFish(sub.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate helper functions for fish\n */\nfunction generateHelperFunctions(programName: string): string {\n return `# Helper function to check if using subcommand\nfunction __fish_use_subcommand_${programName}\n set -l cmd (commandline -opc)\n if test (count $cmd) -eq 1\n return 0\n end\n return 1\nend\n\n# Helper function to check current subcommand\nfunction __fish_${programName}_using_command\n set -l cmd (commandline -opc)\n if contains -- $argv[1] $cmd\n return 0\n end\n return 1\nend\n`;\n}\n\n/**\n * Recursively generate completions for a command and its subcommands\n */\nfunction generateCommandCompletions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentCommands: string[] = [],\n): string[] {\n const completions: string[] = [];\n\n // Build condition for this level\n const optionCondition =\n parentCommands.length === 0\n ? \"\"\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n const subcommandCondition =\n parentCommands.length === 0\n ? `__fish_use_subcommand_${programName}`\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n // Add option completions\n completions.push(\n ...generateOptionCompletions(\n command.options,\n programName,\n optionCondition,\n includeDescriptions,\n ),\n );\n\n // Add subcommand completions\n if (command.subcommands.length > 0) {\n completions.push(\n ...generateSubcommandCompletions(\n command.subcommands,\n programName,\n subcommandCondition,\n includeDescriptions,\n ),\n );\n\n // Recursively add completions for subcommands\n for (const sub of command.subcommands) {\n completions.push(\n ...generateCommandCompletions(sub, programName, includeDescriptions, [\n ...parentCommands,\n sub.name,\n ]),\n );\n }\n }\n\n return completions;\n}\n\n/**\n * Generate the fish completion script\n */\nfunction generateFishScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const helpers = generateHelperFunctions(programName);\n const completions = generateCommandCompletions(command, programName, includeDescriptions);\n\n // Add built-in options (help and version)\n const builtinCompletions = [\n `complete -c ${programName} -l help -s h -d 'Show help information'`,\n `complete -c ${programName} -l version -d 'Show version information'`,\n ];\n\n return `# Fish completion for ${programName}\n# Generated by politty\n\n${helpers}\n\n# Clear existing completions\ncomplete -e -c ${programName}\n\n# Built-in options\n${builtinCompletions.join(\"\\n\")}\n\n# Command-specific completions\n${completions.join(\"\\n\")}\n`;\n}\n\n/**\n * Generate fish completion script for a command\n */\nexport function generateFishCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateFishScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"fish\",\n installInstructions: `# To enable completions, run one of the following:\n\n# Option 1: Source directly\n${options.programName} completion fish | source\n\n# Option 2: Save to the fish completions directory\n${options.programName} completion fish > ~/.config/fish/completions/${options.programName}.fish\n\n# The completion will be available immediately in new shell sessions.\n# To use in the current session, run:\nsource ~/.config/fish/completions/${options.programName}.fish`,\n };\n}\n","/**\n * Zsh completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in zsh completion descriptions\n */\nfunction escapeForZsh(str: string): string {\n return str.replace(/'/g, \"''\").replace(/\\[/g, \"\\\\[\").replace(/\\]/g, \"\\\\]\");\n}\n\n/**\n * Generate option specs for zsh _arguments\n */\nfunction generateOptionSpecs(options: CompletableOption[], includeDescriptions: boolean): string[] {\n const specs: string[] = [];\n\n for (const opt of options) {\n const desc = includeDescriptions && opt.description ? escapeForZsh(opt.description) : \"\";\n const valueSpec = opt.takesValue ? \":\" : \"\";\n\n // Long option\n if (desc) {\n specs.push(`'--${opt.cliName}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'--${opt.cliName}${valueSpec}'`);\n }\n\n // Short option (alias)\n if (opt.alias) {\n if (desc) {\n specs.push(`'-${opt.alias}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'-${opt.alias}${valueSpec}'`);\n }\n }\n }\n\n return specs;\n}\n\n/**\n * Generate subcommand descriptions for zsh\n */\nfunction generateSubcommandDescriptions(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n const lines = subcommands.map((sub) => {\n const desc = includeDescriptions && sub.description ? escapeForZsh(sub.description) : sub.name;\n return `'${sub.name}:${desc}'`;\n });\n\n return lines.join(\"\\n \");\n}\n\n/**\n * Generate a zsh function for a subcommand\n */\nfunction generateSubcommandFunction(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string {\n const currentPath = [...parentPath, command.name];\n const funcName =\n parentPath.length === 0\n ? `_${programName}`\n : `_${programName}_${currentPath.slice(1).join(\"_\")}`;\n\n const optionSpecs = generateOptionSpecs(command.options, includeDescriptions);\n const hasSubcommands = command.subcommands.length > 0;\n\n let func = `${funcName}() {\\n`;\n func += ` local -a args\\n`;\n\n if (hasSubcommands) {\n const subcommandDesc = generateSubcommandDescriptions(command.subcommands, includeDescriptions);\n func += ` local -a subcommands\\n`;\n func += ` subcommands=(\\n`;\n func += ` ${subcommandDesc}\\n`;\n func += ` )\\n\\n`;\n }\n\n func += ` args=(\\n`;\n\n if (hasSubcommands) {\n func += ` '1:command:->command'\\n`;\n func += ` '*::arg:->args'\\n`;\n }\n\n for (const spec of optionSpecs) {\n func += ` ${spec}\\n`;\n }\n\n func += ` )\\n\\n`;\n\n func += ` _arguments -s -S $args\\n\\n`;\n\n if (hasSubcommands) {\n func += ` case \"$state\" in\\n`;\n func += ` command)\\n`;\n func += ` _describe -t commands 'command' subcommands\\n`;\n func += ` ;;\\n`;\n func += ` args)\\n`;\n func += ` case $words[1] in\\n`;\n\n for (const sub of command.subcommands) {\n const subFuncName = `_${programName}_${[...currentPath.slice(1), sub.name].join(\"_\")}`;\n func += ` ${sub.name})\\n`;\n func += ` ${subFuncName}\\n`;\n func += ` ;;\\n`;\n }\n\n func += ` esac\\n`;\n func += ` ;;\\n`;\n func += ` esac\\n`;\n }\n\n func += `}\\n`;\n\n return func;\n}\n\n/**\n * Collect all subcommand functions recursively\n */\nfunction collectSubcommandFunctions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string[] {\n const functions: string[] = [];\n\n // Generate function for this command\n functions.push(generateSubcommandFunction(command, programName, includeDescriptions, parentPath));\n\n // Generate functions for subcommands\n const currentPath = parentPath.length === 0 ? [command.name] : [...parentPath, command.name];\n\n for (const sub of command.subcommands) {\n functions.push(\n ...collectSubcommandFunctions(sub, programName, includeDescriptions, currentPath),\n );\n }\n\n return functions;\n}\n\n/**\n * Generate the zsh completion script\n */\nfunction generateZshScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const functions = collectSubcommandFunctions(command, programName, includeDescriptions);\n\n return `#compdef ${programName}\n\n# Zsh completion for ${programName}\n# Generated by politty\n\n${functions.join(\"\\n\")}\n\n_${programName} \"$@\"\n`;\n}\n\n/**\n * Generate zsh completion script for a command\n */\nexport function generateZshCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateZshScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"zsh\",\n installInstructions: `# To enable completions, add the following to your ~/.zshrc:\n\n# Option 1: Source directly (add before compinit)\neval \"$(${options.programName} completion zsh)\"\n\n# Option 2: Save to a file in your fpath\n${options.programName} completion zsh > ~/.zsh/completions/_${options.programName}\n\n# Make sure your fpath includes the completions directory:\n# fpath=(~/.zsh/completions $fpath)\n# autoload -Uz compinit && compinit\n\n# Then reload your shell or run:\nsource ~/.zshrc`,\n };\n}\n","/**\n * Shell completion generation module\n *\n * Provides utilities to generate shell completion scripts for bash, zsh, and fish.\n *\n * @example\n * ```typescript\n * import { generateCompletion, createCompletionCommand } from \"politty/completion\";\n *\n * // Generate completion script directly\n * const result = generateCompletion(myCommand, {\n * shell: \"bash\",\n * programName: \"mycli\"\n * });\n * console.log(result.script);\n *\n * // Or add a completion subcommand to your CLI\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(myCommand, \"mycli\")\n * }\n * });\n * ```\n */\n\nimport { z } from \"zod\";\nimport { arg } from \"../core/arg-registry.js\";\nimport { defineCommand } from \"../core/command.js\";\nimport type { AnyCommand, Command } from \"../types.js\";\nimport { generateBashCompletion } from \"./bash.js\";\nimport { generateFishCompletion } from \"./fish.js\";\nimport type { CompletionOptions, CompletionResult, ShellType } from \"./types.js\";\nimport { generateZshCompletion } from \"./zsh.js\";\n\n// Re-export types\n// Re-export extractor\nexport { extractCompletionData, extractPositionals } from \"./extractor.js\";\nexport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionData,\n CompletionGenerator,\n CompletionOptions,\n CompletionResult,\n ShellType,\n} from \"./types.js\";\n\n/**\n * Generate completion script for the specified shell\n */\nexport function generateCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n switch (options.shell) {\n case \"bash\":\n return generateBashCompletion(command, options);\n case \"zsh\":\n return generateZshCompletion(command, options);\n case \"fish\":\n return generateFishCompletion(command, options);\n default:\n throw new Error(`Unsupported shell: ${options.shell}`);\n }\n}\n\n/**\n * Get the list of supported shells\n */\nexport function getSupportedShells(): ShellType[] {\n return [\"bash\", \"zsh\", \"fish\"];\n}\n\n/**\n * Detect the current shell from environment\n */\nexport function detectShell(): ShellType | null {\n const shell = process.env.SHELL || \"\";\n const shellName = shell.split(\"/\").pop()?.toLowerCase() || \"\";\n\n if (shellName.includes(\"bash\")) {\n return \"bash\";\n }\n if (shellName.includes(\"zsh\")) {\n return \"zsh\";\n }\n if (shellName.includes(\"fish\")) {\n return \"fish\";\n }\n\n return null;\n}\n\n/**\n * Schema for the completion command arguments\n */\nconst completionArgsSchema = z.object({\n shell: arg(\n z\n .enum([\"bash\", \"zsh\", \"fish\"])\n .optional()\n .describe(\"Shell type (auto-detected if not specified)\"),\n {\n positional: true,\n description: \"Shell type (bash, zsh, or fish)\",\n placeholder: \"SHELL\",\n },\n ),\n instructions: arg(z.boolean().default(false), {\n alias: \"i\",\n description: \"Show installation instructions\",\n }),\n});\n\ntype CompletionArgs = z.infer<typeof completionArgsSchema>;\n\n/**\n * Create a completion subcommand for your CLI\n *\n * This creates a ready-to-use subcommand that generates completion scripts.\n *\n * @example\n * ```typescript\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(mainCommand, \"mycli\")\n * }\n * });\n * ```\n */\nexport function createCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Command<typeof completionArgsSchema, CompletionArgs, any> {\n return defineCommand({\n name: \"completion\",\n description: \"Generate shell completion script\",\n args: completionArgsSchema,\n run(args) {\n // Detect shell if not specified\n const shellType = args.shell || detectShell();\n\n if (!shellType) {\n console.error(\"Could not detect shell type. Please specify one of: bash, zsh, fish\");\n process.exitCode = 1;\n return;\n }\n\n const result = generateCompletion(rootCommand, {\n shell: shellType,\n programName,\n includeDescriptions: true,\n });\n\n if (args.instructions) {\n console.log(result.installInstructions);\n } else {\n console.log(result.script);\n }\n },\n });\n}\n\n/**\n * Helper to add completion command to an existing command's subCommands\n *\n * @example\n * ```typescript\n * const command = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * ...withCompletionCommand(command, \"mycli\"),\n * // other subcommands\n * }\n * });\n * ```\n */\nexport function withCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n): { completion: ReturnType<typeof createCompletionCommand> } {\n return {\n completion: createCompletionCommand(rootCommand, programName),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["extractFields","generateOptionCompletions","generateSubcommandCompletions","z","arg","defineCommand"],"sources":["../../src/completion/extractor.ts","../../src/completion/bash.ts","../../src/completion/fish.ts","../../src/completion/zsh.ts","../../src/completion/index.ts"],"sourcesContent":["/**\n * Extract completion data from commands\n */\n\nimport { extractFields, type ResolvedFieldMeta } from \"../core/schema-extractor.js\";\nimport type { AnyCommand } from \"../types.js\";\nimport type { CompletableOption, CompletableSubcommand, CompletionData } from \"./types.js\";\n\n/**\n * Convert a resolved field to a completable option\n */\nfunction fieldToOption(field: ResolvedFieldMeta): CompletableOption {\n return {\n name: field.name,\n cliName: field.cliName,\n alias: field.alias,\n description: field.description,\n // Booleans are flags that don't require a value\n takesValue: field.type !== \"boolean\",\n valueType: field.type,\n required: field.required,\n };\n}\n\n/**\n * Extract options from a command's args schema\n */\nfunction extractOptions(command: AnyCommand): CompletableOption[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields\n .filter((field) => !field.positional) // Only include flags/options, not positionals\n .map(fieldToOption);\n}\n\n/**\n * Extract positional arguments from a command\n */\nexport function extractPositionals(command: AnyCommand): ResolvedFieldMeta[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields.filter((field) => field.positional);\n}\n\n/**\n * Extract a completable subcommand from a command\n */\nfunction extractSubcommand(name: string, command: AnyCommand): CompletableSubcommand {\n const subcommands: CompletableSubcommand[] = [];\n\n // Extract subcommands recursively (only sync subcommands for now)\n if (command.subCommands) {\n for (const [subName, subCommand] of Object.entries(command.subCommands)) {\n // Skip async subcommands as we can't inspect them statically\n if (typeof subCommand === \"function\") {\n // For async subcommands, add a placeholder\n subcommands.push({\n name: subName,\n description: \"(lazy loaded)\",\n subcommands: [],\n options: [],\n });\n } else {\n subcommands.push(extractSubcommand(subName, subCommand));\n }\n }\n }\n\n return {\n name,\n description: command.description,\n subcommands,\n options: extractOptions(command),\n };\n}\n\n/**\n * Extract completion data from a command tree\n */\nexport function extractCompletionData(command: AnyCommand, programName: string): CompletionData {\n const rootSubcommand = extractSubcommand(programName, command);\n\n return {\n command: rootSubcommand,\n programName,\n // Global options are the options defined on the root command\n globalOptions: rootSubcommand.options,\n };\n}\n","/**\n * Bash completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Generate option completions for bash\n */\nfunction generateOptionCompletions(options: CompletableOption[]): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n completions.push(`--${opt.cliName}`);\n if (opt.alias) {\n completions.push(`-${opt.alias}`);\n }\n }\n\n return completions;\n}\n\n/**\n * Generate subcommand completions for bash\n */\nfunction generateSubcommandCompletions(subcommands: CompletableSubcommand[]): string[] {\n return subcommands.map((sub) => sub.name);\n}\n\n/**\n * Generate the bash completion script\n */\nfunction generateBashScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const allOptions = collectAllOptions(command);\n\n const optionList = generateOptionCompletions(allOptions).join(\" \");\n const subcommandList = generateSubcommandCompletions(command.subcommands).join(\" \");\n\n // Build subcommand-specific completions\n const subcommandCases = buildSubcommandCases(command.subcommands, includeDescriptions);\n\n return `# Bash completion for ${programName}\n# Generated by politty\n\n_${programName}_completions() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"${subcommandList}\"\n local global_opts=\"${optionList}\"\n\n # Handle subcommand-specific completions\n local cmd_index=1\n local cmd=\"\"\n\n # Find the subcommand\n for ((i=1; i < cword; i++)); do\n case \"\\${words[i]}\" in\n -*)\n # Skip options and their values\n if [[ \"\\${words[i]}\" == *=* ]]; then\n continue\n fi\n # Check if next word is the option's value\n local opt=\"\\${words[i]}\"\n case \"$opt\" in\n ${\n allOptions\n .filter((o) => o.takesValue)\n .map((o) => `--${o.cliName}|-${o.alias || \"\"}`)\n .join(\"|\") || \"--*\"\n }\n ((i++))\n ;;\n esac\n ;;\n *)\n # Found a subcommand\n cmd=\"\\${words[i]}\"\n cmd_index=$i\n break\n ;;\n esac\n done\n\n # Subcommand-specific completions\n case \"$cmd\" in\n${subcommandCases}\n *)\n # Root level completions\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$global_opts\" -- \"$cur\"))\n else\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n fi\n ;;\n esac\n\n return 0\n}\n\n# Register the completion function\ncomplete -F _${programName}_completions ${programName}\n`;\n}\n\n/**\n * Build case statements for subcommand-specific completions\n */\nfunction buildSubcommandCases(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n let cases = \"\";\n\n for (const sub of subcommands) {\n const options = generateOptionCompletions(sub.options).join(\" \");\n const nestedSubcommands = generateSubcommandCompletions(sub.subcommands).join(\" \");\n const completions = [options, nestedSubcommands].filter(Boolean).join(\" \");\n\n cases += ` ${sub.name})\\n`;\n cases += ` COMPREPLY=($(compgen -W \"${completions}\" -- \"$cur\"))\\n`;\n cases += ` ;;\\n`;\n\n // Add nested subcommand cases if any\n if (sub.subcommands.length > 0) {\n const nestedCases = buildSubcommandCases(sub.subcommands, includeDescriptions);\n if (nestedCases) {\n cases += nestedCases;\n }\n }\n }\n\n return cases;\n}\n\n/**\n * Collect all options from a command tree\n */\nfunction collectAllOptions(command: CompletableSubcommand): CompletableOption[] {\n const options = [...command.options];\n\n for (const sub of command.subcommands) {\n options.push(...collectAllOptions(sub));\n }\n\n // Deduplicate by name\n const seen = new Set<string>();\n return options.filter((opt) => {\n if (seen.has(opt.name)) {\n return false;\n }\n seen.add(opt.name);\n return true;\n });\n}\n\n/**\n * Generate bash completion script for a command\n */\nexport function generateBashCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateBashScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"bash\",\n installInstructions: `# To enable completions, add the following to your ~/.bashrc:\n\n# Option 1: Source directly\neval \"$(${options.programName} completion bash)\"\n\n# Option 2: Save to a file\n${options.programName} completion bash > ~/.local/share/bash-completion/completions/${options.programName}\n\n# Then reload your shell or run:\nsource ~/.bashrc`,\n };\n}\n","/**\n * Fish completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in fish completion descriptions\n */\nfunction escapeForFish(str: string): string {\n return str.replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate completion entries for options\n */\nfunction generateOptionCompletions(\n options: CompletableOption[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition if specified\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Add long option\n cmd += ` -l ${opt.cliName}`;\n\n // Add short option if exists\n if (opt.alias) {\n cmd += ` -s ${opt.alias}`;\n }\n\n // Add flag for options that take values\n if (opt.takesValue) {\n cmd += \" -r\"; // Require argument\n } else {\n cmd += \" -f\"; // No argument (flag)\n }\n\n // Add description\n if (includeDescriptions && opt.description) {\n cmd += ` -d '${escapeForFish(opt.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate completion entries for subcommands\n */\nfunction generateSubcommandCompletions(\n subcommands: CompletableSubcommand[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const sub of subcommands) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Subcommands are exclusive (no prefix)\n cmd += ` -f -a ${sub.name}`;\n\n // Add description\n if (includeDescriptions && sub.description) {\n cmd += ` -d '${escapeForFish(sub.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate helper functions for fish\n */\nfunction generateHelperFunctions(programName: string): string {\n return `# Helper function to check if using subcommand\nfunction __fish_use_subcommand_${programName}\n set -l cmd (commandline -opc)\n if test (count $cmd) -eq 1\n return 0\n end\n return 1\nend\n\n# Helper function to check current subcommand\nfunction __fish_${programName}_using_command\n set -l cmd (commandline -opc)\n if contains -- $argv[1] $cmd\n return 0\n end\n return 1\nend\n`;\n}\n\n/**\n * Recursively generate completions for a command and its subcommands\n */\nfunction generateCommandCompletions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentCommands: string[] = [],\n): string[] {\n const completions: string[] = [];\n\n // Build condition for this level\n const optionCondition =\n parentCommands.length === 0\n ? \"\"\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n const subcommandCondition =\n parentCommands.length === 0\n ? `__fish_use_subcommand_${programName}`\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n // Add option completions\n completions.push(\n ...generateOptionCompletions(\n command.options,\n programName,\n optionCondition,\n includeDescriptions,\n ),\n );\n\n // Add subcommand completions\n if (command.subcommands.length > 0) {\n completions.push(\n ...generateSubcommandCompletions(\n command.subcommands,\n programName,\n subcommandCondition,\n includeDescriptions,\n ),\n );\n\n // Recursively add completions for subcommands\n for (const sub of command.subcommands) {\n completions.push(\n ...generateCommandCompletions(sub, programName, includeDescriptions, [\n ...parentCommands,\n sub.name,\n ]),\n );\n }\n }\n\n return completions;\n}\n\n/**\n * Generate the fish completion script\n */\nfunction generateFishScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const helpers = generateHelperFunctions(programName);\n const completions = generateCommandCompletions(command, programName, includeDescriptions);\n\n // Add built-in options (help and version)\n const builtinCompletions = [\n `complete -c ${programName} -l help -s h -d 'Show help information'`,\n `complete -c ${programName} -l version -d 'Show version information'`,\n ];\n\n return `# Fish completion for ${programName}\n# Generated by politty\n\n${helpers}\n\n# Clear existing completions\ncomplete -e -c ${programName}\n\n# Built-in options\n${builtinCompletions.join(\"\\n\")}\n\n# Command-specific completions\n${completions.join(\"\\n\")}\n`;\n}\n\n/**\n * Generate fish completion script for a command\n */\nexport function generateFishCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateFishScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"fish\",\n installInstructions: `# To enable completions, run one of the following:\n\n# Option 1: Source directly\n${options.programName} completion fish | source\n\n# Option 2: Save to the fish completions directory\n${options.programName} completion fish > ~/.config/fish/completions/${options.programName}.fish\n\n# The completion will be available immediately in new shell sessions.\n# To use in the current session, run:\nsource ~/.config/fish/completions/${options.programName}.fish`,\n };\n}\n","/**\n * Zsh completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in zsh completion descriptions\n */\nfunction escapeForZsh(str: string): string {\n return str.replace(/'/g, \"''\").replace(/\\[/g, \"\\\\[\").replace(/\\]/g, \"\\\\]\");\n}\n\n/**\n * Generate option specs for zsh _arguments\n */\nfunction generateOptionSpecs(options: CompletableOption[], includeDescriptions: boolean): string[] {\n const specs: string[] = [];\n\n for (const opt of options) {\n const desc = includeDescriptions && opt.description ? escapeForZsh(opt.description) : \"\";\n const valueSpec = opt.takesValue ? \":\" : \"\";\n\n // Long option\n if (desc) {\n specs.push(`'--${opt.cliName}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'--${opt.cliName}${valueSpec}'`);\n }\n\n // Short option (alias)\n if (opt.alias) {\n if (desc) {\n specs.push(`'-${opt.alias}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'-${opt.alias}${valueSpec}'`);\n }\n }\n }\n\n return specs;\n}\n\n/**\n * Generate subcommand descriptions for zsh\n */\nfunction generateSubcommandDescriptions(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n const lines = subcommands.map((sub) => {\n const desc = includeDescriptions && sub.description ? escapeForZsh(sub.description) : sub.name;\n return `'${sub.name}:${desc}'`;\n });\n\n return lines.join(\"\\n \");\n}\n\n/**\n * Generate a zsh function for a subcommand\n */\nfunction generateSubcommandFunction(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string {\n const currentPath = [...parentPath, command.name];\n const funcName =\n parentPath.length === 0\n ? `_${programName}`\n : `_${programName}_${currentPath.slice(1).join(\"_\")}`;\n\n const optionSpecs = generateOptionSpecs(command.options, includeDescriptions);\n const hasSubcommands = command.subcommands.length > 0;\n\n let func = `${funcName}() {\\n`;\n func += ` local -a args\\n`;\n\n if (hasSubcommands) {\n const subcommandDesc = generateSubcommandDescriptions(command.subcommands, includeDescriptions);\n func += ` local -a subcommands\\n`;\n func += ` subcommands=(\\n`;\n func += ` ${subcommandDesc}\\n`;\n func += ` )\\n\\n`;\n }\n\n func += ` args=(\\n`;\n\n if (hasSubcommands) {\n func += ` '1:command:->command'\\n`;\n func += ` '*::arg:->args'\\n`;\n }\n\n for (const spec of optionSpecs) {\n func += ` ${spec}\\n`;\n }\n\n func += ` )\\n\\n`;\n\n func += ` _arguments -s -S $args\\n\\n`;\n\n if (hasSubcommands) {\n func += ` case \"$state\" in\\n`;\n func += ` command)\\n`;\n func += ` _describe -t commands 'command' subcommands\\n`;\n func += ` ;;\\n`;\n func += ` args)\\n`;\n func += ` case $words[1] in\\n`;\n\n for (const sub of command.subcommands) {\n const subFuncName = `_${programName}_${[...currentPath.slice(1), sub.name].join(\"_\")}`;\n func += ` ${sub.name})\\n`;\n func += ` ${subFuncName}\\n`;\n func += ` ;;\\n`;\n }\n\n func += ` esac\\n`;\n func += ` ;;\\n`;\n func += ` esac\\n`;\n }\n\n func += `}\\n`;\n\n return func;\n}\n\n/**\n * Collect all subcommand functions recursively\n */\nfunction collectSubcommandFunctions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string[] {\n const functions: string[] = [];\n\n // Generate function for this command\n functions.push(generateSubcommandFunction(command, programName, includeDescriptions, parentPath));\n\n // Generate functions for subcommands\n const currentPath = parentPath.length === 0 ? [command.name] : [...parentPath, command.name];\n\n for (const sub of command.subcommands) {\n functions.push(\n ...collectSubcommandFunctions(sub, programName, includeDescriptions, currentPath),\n );\n }\n\n return functions;\n}\n\n/**\n * Generate the zsh completion script\n */\nfunction generateZshScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const functions = collectSubcommandFunctions(command, programName, includeDescriptions);\n\n return `#compdef ${programName}\n\n# Zsh completion for ${programName}\n# Generated by politty\n\n${functions.join(\"\\n\")}\n\ncompdef _${programName} ${programName}\n`;\n}\n\n/**\n * Generate zsh completion script for a command\n */\nexport function generateZshCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateZshScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"zsh\",\n installInstructions: `# To enable completions, add the following to your ~/.zshrc:\n\n# Option 1: Source directly (add before compinit)\neval \"$(${options.programName} completion zsh)\"\n\n# Option 2: Save to a file in your fpath\n${options.programName} completion zsh > ~/.zsh/completions/_${options.programName}\n\n# Make sure your fpath includes the completions directory:\n# fpath=(~/.zsh/completions $fpath)\n# autoload -Uz compinit && compinit\n\n# Then reload your shell or run:\nsource ~/.zshrc`,\n };\n}\n","/**\n * Shell completion generation module\n *\n * Provides utilities to generate shell completion scripts for bash, zsh, and fish.\n *\n * @example\n * ```typescript\n * import { generateCompletion, createCompletionCommand } from \"politty/completion\";\n *\n * // Generate completion script directly\n * const result = generateCompletion(myCommand, {\n * shell: \"bash\",\n * programName: \"mycli\"\n * });\n * console.log(result.script);\n *\n * // Or add a completion subcommand to your CLI\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(myCommand, \"mycli\")\n * }\n * });\n * ```\n */\n\nimport { z } from \"zod\";\nimport { arg } from \"../core/arg-registry.js\";\nimport { defineCommand } from \"../core/command.js\";\nimport type { AnyCommand, Command } from \"../types.js\";\nimport { generateBashCompletion } from \"./bash.js\";\nimport { generateFishCompletion } from \"./fish.js\";\nimport type { CompletionOptions, CompletionResult, ShellType } from \"./types.js\";\nimport { generateZshCompletion } from \"./zsh.js\";\n\n// Re-export types\n// Re-export extractor\nexport { extractCompletionData, extractPositionals } from \"./extractor.js\";\nexport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionData,\n CompletionGenerator,\n CompletionOptions,\n CompletionResult,\n ShellType,\n} from \"./types.js\";\n\n/**\n * Generate completion script for the specified shell\n */\nexport function generateCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n switch (options.shell) {\n case \"bash\":\n return generateBashCompletion(command, options);\n case \"zsh\":\n return generateZshCompletion(command, options);\n case \"fish\":\n return generateFishCompletion(command, options);\n default:\n throw new Error(`Unsupported shell: ${options.shell}`);\n }\n}\n\n/**\n * Get the list of supported shells\n */\nexport function getSupportedShells(): ShellType[] {\n return [\"bash\", \"zsh\", \"fish\"];\n}\n\n/**\n * Detect the current shell from environment\n */\nexport function detectShell(): ShellType | null {\n const shell = process.env.SHELL || \"\";\n const shellName = shell.split(\"/\").pop()?.toLowerCase() || \"\";\n\n if (shellName.includes(\"bash\")) {\n return \"bash\";\n }\n if (shellName.includes(\"zsh\")) {\n return \"zsh\";\n }\n if (shellName.includes(\"fish\")) {\n return \"fish\";\n }\n\n return null;\n}\n\n/**\n * Schema for the completion command arguments\n */\nconst completionArgsSchema = z.object({\n shell: arg(\n z\n .enum([\"bash\", \"zsh\", \"fish\"])\n .optional()\n .describe(\"Shell type (auto-detected if not specified)\"),\n {\n positional: true,\n description: \"Shell type (bash, zsh, or fish)\",\n placeholder: \"SHELL\",\n },\n ),\n instructions: arg(z.boolean().default(false), {\n alias: \"i\",\n description: \"Show installation instructions\",\n }),\n});\n\ntype CompletionArgs = z.infer<typeof completionArgsSchema>;\n\n/**\n * Create a completion subcommand for your CLI\n *\n * This creates a ready-to-use subcommand that generates completion scripts.\n *\n * @example\n * ```typescript\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(mainCommand, \"mycli\")\n * }\n * });\n * ```\n */\nexport function createCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Command<typeof completionArgsSchema, CompletionArgs, any> {\n return defineCommand({\n name: \"completion\",\n description: \"Generate shell completion script\",\n args: completionArgsSchema,\n run(args) {\n // Detect shell if not specified\n const shellType = args.shell || detectShell();\n\n if (!shellType) {\n console.error(\"Could not detect shell type. Please specify one of: bash, zsh, fish\");\n process.exitCode = 1;\n return;\n }\n\n const result = generateCompletion(rootCommand, {\n shell: shellType,\n programName,\n includeDescriptions: true,\n });\n\n if (args.instructions) {\n console.log(result.installInstructions);\n } else {\n console.log(result.script);\n }\n },\n });\n}\n\n/**\n * Helper to add completion command to an existing command's subCommands\n *\n * @example\n * ```typescript\n * const command = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * ...withCompletionCommand(command, \"mycli\"),\n * // other subcommands\n * }\n * });\n * ```\n */\nexport function withCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n): { completion: ReturnType<typeof createCompletionCommand> } {\n return {\n completion: createCompletionCommand(rootCommand, programName),\n };\n}\n"],"mappings":"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"}
@@ -423,7 +423,7 @@ function generateZshScript(command, programName, includeDescriptions) {
423
423
 
424
424
  ${collectSubcommandFunctions(command, programName, includeDescriptions).join("\n")}
425
425
 
426
- _${programName} "$@"
426
+ compdef _${programName} ${programName}
427
427
  `;
428
428
  }
429
429
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["generateOptionCompletions","generateSubcommandCompletions"],"sources":["../../src/completion/extractor.ts","../../src/completion/bash.ts","../../src/completion/fish.ts","../../src/completion/zsh.ts","../../src/completion/index.ts"],"sourcesContent":["/**\n * Extract completion data from commands\n */\n\nimport { extractFields, type ResolvedFieldMeta } from \"../core/schema-extractor.js\";\nimport type { AnyCommand } from \"../types.js\";\nimport type { CompletableOption, CompletableSubcommand, CompletionData } from \"./types.js\";\n\n/**\n * Convert a resolved field to a completable option\n */\nfunction fieldToOption(field: ResolvedFieldMeta): CompletableOption {\n return {\n name: field.name,\n cliName: field.cliName,\n alias: field.alias,\n description: field.description,\n // Booleans are flags that don't require a value\n takesValue: field.type !== \"boolean\",\n valueType: field.type,\n required: field.required,\n };\n}\n\n/**\n * Extract options from a command's args schema\n */\nfunction extractOptions(command: AnyCommand): CompletableOption[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields\n .filter((field) => !field.positional) // Only include flags/options, not positionals\n .map(fieldToOption);\n}\n\n/**\n * Extract positional arguments from a command\n */\nexport function extractPositionals(command: AnyCommand): ResolvedFieldMeta[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields.filter((field) => field.positional);\n}\n\n/**\n * Extract a completable subcommand from a command\n */\nfunction extractSubcommand(name: string, command: AnyCommand): CompletableSubcommand {\n const subcommands: CompletableSubcommand[] = [];\n\n // Extract subcommands recursively (only sync subcommands for now)\n if (command.subCommands) {\n for (const [subName, subCommand] of Object.entries(command.subCommands)) {\n // Skip async subcommands as we can't inspect them statically\n if (typeof subCommand === \"function\") {\n // For async subcommands, add a placeholder\n subcommands.push({\n name: subName,\n description: \"(lazy loaded)\",\n subcommands: [],\n options: [],\n });\n } else {\n subcommands.push(extractSubcommand(subName, subCommand));\n }\n }\n }\n\n return {\n name,\n description: command.description,\n subcommands,\n options: extractOptions(command),\n };\n}\n\n/**\n * Extract completion data from a command tree\n */\nexport function extractCompletionData(command: AnyCommand, programName: string): CompletionData {\n const rootSubcommand = extractSubcommand(programName, command);\n\n return {\n command: rootSubcommand,\n programName,\n // Global options are the options defined on the root command\n globalOptions: rootSubcommand.options,\n };\n}\n","/**\n * Bash completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Generate option completions for bash\n */\nfunction generateOptionCompletions(options: CompletableOption[]): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n completions.push(`--${opt.cliName}`);\n if (opt.alias) {\n completions.push(`-${opt.alias}`);\n }\n }\n\n return completions;\n}\n\n/**\n * Generate subcommand completions for bash\n */\nfunction generateSubcommandCompletions(subcommands: CompletableSubcommand[]): string[] {\n return subcommands.map((sub) => sub.name);\n}\n\n/**\n * Generate the bash completion script\n */\nfunction generateBashScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const allOptions = collectAllOptions(command);\n\n const optionList = generateOptionCompletions(allOptions).join(\" \");\n const subcommandList = generateSubcommandCompletions(command.subcommands).join(\" \");\n\n // Build subcommand-specific completions\n const subcommandCases = buildSubcommandCases(command.subcommands, includeDescriptions);\n\n return `# Bash completion for ${programName}\n# Generated by politty\n\n_${programName}_completions() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"${subcommandList}\"\n local global_opts=\"${optionList}\"\n\n # Handle subcommand-specific completions\n local cmd_index=1\n local cmd=\"\"\n\n # Find the subcommand\n for ((i=1; i < cword; i++)); do\n case \"\\${words[i]}\" in\n -*)\n # Skip options and their values\n if [[ \"\\${words[i]}\" == *=* ]]; then\n continue\n fi\n # Check if next word is the option's value\n local opt=\"\\${words[i]}\"\n case \"$opt\" in\n ${\n allOptions\n .filter((o) => o.takesValue)\n .map((o) => `--${o.cliName}|-${o.alias || \"\"}`)\n .join(\"|\") || \"--*\"\n }\n ((i++))\n ;;\n esac\n ;;\n *)\n # Found a subcommand\n cmd=\"\\${words[i]}\"\n cmd_index=$i\n break\n ;;\n esac\n done\n\n # Subcommand-specific completions\n case \"$cmd\" in\n${subcommandCases}\n *)\n # Root level completions\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$global_opts\" -- \"$cur\"))\n else\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n fi\n ;;\n esac\n\n return 0\n}\n\n# Register the completion function\ncomplete -F _${programName}_completions ${programName}\n`;\n}\n\n/**\n * Build case statements for subcommand-specific completions\n */\nfunction buildSubcommandCases(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n let cases = \"\";\n\n for (const sub of subcommands) {\n const options = generateOptionCompletions(sub.options).join(\" \");\n const nestedSubcommands = generateSubcommandCompletions(sub.subcommands).join(\" \");\n const completions = [options, nestedSubcommands].filter(Boolean).join(\" \");\n\n cases += ` ${sub.name})\\n`;\n cases += ` COMPREPLY=($(compgen -W \"${completions}\" -- \"$cur\"))\\n`;\n cases += ` ;;\\n`;\n\n // Add nested subcommand cases if any\n if (sub.subcommands.length > 0) {\n const nestedCases = buildSubcommandCases(sub.subcommands, includeDescriptions);\n if (nestedCases) {\n cases += nestedCases;\n }\n }\n }\n\n return cases;\n}\n\n/**\n * Collect all options from a command tree\n */\nfunction collectAllOptions(command: CompletableSubcommand): CompletableOption[] {\n const options = [...command.options];\n\n for (const sub of command.subcommands) {\n options.push(...collectAllOptions(sub));\n }\n\n // Deduplicate by name\n const seen = new Set<string>();\n return options.filter((opt) => {\n if (seen.has(opt.name)) {\n return false;\n }\n seen.add(opt.name);\n return true;\n });\n}\n\n/**\n * Generate bash completion script for a command\n */\nexport function generateBashCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateBashScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"bash\",\n installInstructions: `# To enable completions, add the following to your ~/.bashrc:\n\n# Option 1: Source directly\neval \"$(${options.programName} completion bash)\"\n\n# Option 2: Save to a file\n${options.programName} completion bash > ~/.local/share/bash-completion/completions/${options.programName}\n\n# Then reload your shell or run:\nsource ~/.bashrc`,\n };\n}\n","/**\n * Fish completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in fish completion descriptions\n */\nfunction escapeForFish(str: string): string {\n return str.replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate completion entries for options\n */\nfunction generateOptionCompletions(\n options: CompletableOption[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition if specified\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Add long option\n cmd += ` -l ${opt.cliName}`;\n\n // Add short option if exists\n if (opt.alias) {\n cmd += ` -s ${opt.alias}`;\n }\n\n // Add flag for options that take values\n if (opt.takesValue) {\n cmd += \" -r\"; // Require argument\n } else {\n cmd += \" -f\"; // No argument (flag)\n }\n\n // Add description\n if (includeDescriptions && opt.description) {\n cmd += ` -d '${escapeForFish(opt.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate completion entries for subcommands\n */\nfunction generateSubcommandCompletions(\n subcommands: CompletableSubcommand[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const sub of subcommands) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Subcommands are exclusive (no prefix)\n cmd += ` -f -a ${sub.name}`;\n\n // Add description\n if (includeDescriptions && sub.description) {\n cmd += ` -d '${escapeForFish(sub.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate helper functions for fish\n */\nfunction generateHelperFunctions(programName: string): string {\n return `# Helper function to check if using subcommand\nfunction __fish_use_subcommand_${programName}\n set -l cmd (commandline -opc)\n if test (count $cmd) -eq 1\n return 0\n end\n return 1\nend\n\n# Helper function to check current subcommand\nfunction __fish_${programName}_using_command\n set -l cmd (commandline -opc)\n if contains -- $argv[1] $cmd\n return 0\n end\n return 1\nend\n`;\n}\n\n/**\n * Recursively generate completions for a command and its subcommands\n */\nfunction generateCommandCompletions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentCommands: string[] = [],\n): string[] {\n const completions: string[] = [];\n\n // Build condition for this level\n const optionCondition =\n parentCommands.length === 0\n ? \"\"\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n const subcommandCondition =\n parentCommands.length === 0\n ? `__fish_use_subcommand_${programName}`\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n // Add option completions\n completions.push(\n ...generateOptionCompletions(\n command.options,\n programName,\n optionCondition,\n includeDescriptions,\n ),\n );\n\n // Add subcommand completions\n if (command.subcommands.length > 0) {\n completions.push(\n ...generateSubcommandCompletions(\n command.subcommands,\n programName,\n subcommandCondition,\n includeDescriptions,\n ),\n );\n\n // Recursively add completions for subcommands\n for (const sub of command.subcommands) {\n completions.push(\n ...generateCommandCompletions(sub, programName, includeDescriptions, [\n ...parentCommands,\n sub.name,\n ]),\n );\n }\n }\n\n return completions;\n}\n\n/**\n * Generate the fish completion script\n */\nfunction generateFishScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const helpers = generateHelperFunctions(programName);\n const completions = generateCommandCompletions(command, programName, includeDescriptions);\n\n // Add built-in options (help and version)\n const builtinCompletions = [\n `complete -c ${programName} -l help -s h -d 'Show help information'`,\n `complete -c ${programName} -l version -d 'Show version information'`,\n ];\n\n return `# Fish completion for ${programName}\n# Generated by politty\n\n${helpers}\n\n# Clear existing completions\ncomplete -e -c ${programName}\n\n# Built-in options\n${builtinCompletions.join(\"\\n\")}\n\n# Command-specific completions\n${completions.join(\"\\n\")}\n`;\n}\n\n/**\n * Generate fish completion script for a command\n */\nexport function generateFishCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateFishScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"fish\",\n installInstructions: `# To enable completions, run one of the following:\n\n# Option 1: Source directly\n${options.programName} completion fish | source\n\n# Option 2: Save to the fish completions directory\n${options.programName} completion fish > ~/.config/fish/completions/${options.programName}.fish\n\n# The completion will be available immediately in new shell sessions.\n# To use in the current session, run:\nsource ~/.config/fish/completions/${options.programName}.fish`,\n };\n}\n","/**\n * Zsh completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in zsh completion descriptions\n */\nfunction escapeForZsh(str: string): string {\n return str.replace(/'/g, \"''\").replace(/\\[/g, \"\\\\[\").replace(/\\]/g, \"\\\\]\");\n}\n\n/**\n * Generate option specs for zsh _arguments\n */\nfunction generateOptionSpecs(options: CompletableOption[], includeDescriptions: boolean): string[] {\n const specs: string[] = [];\n\n for (const opt of options) {\n const desc = includeDescriptions && opt.description ? escapeForZsh(opt.description) : \"\";\n const valueSpec = opt.takesValue ? \":\" : \"\";\n\n // Long option\n if (desc) {\n specs.push(`'--${opt.cliName}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'--${opt.cliName}${valueSpec}'`);\n }\n\n // Short option (alias)\n if (opt.alias) {\n if (desc) {\n specs.push(`'-${opt.alias}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'-${opt.alias}${valueSpec}'`);\n }\n }\n }\n\n return specs;\n}\n\n/**\n * Generate subcommand descriptions for zsh\n */\nfunction generateSubcommandDescriptions(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n const lines = subcommands.map((sub) => {\n const desc = includeDescriptions && sub.description ? escapeForZsh(sub.description) : sub.name;\n return `'${sub.name}:${desc}'`;\n });\n\n return lines.join(\"\\n \");\n}\n\n/**\n * Generate a zsh function for a subcommand\n */\nfunction generateSubcommandFunction(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string {\n const currentPath = [...parentPath, command.name];\n const funcName =\n parentPath.length === 0\n ? `_${programName}`\n : `_${programName}_${currentPath.slice(1).join(\"_\")}`;\n\n const optionSpecs = generateOptionSpecs(command.options, includeDescriptions);\n const hasSubcommands = command.subcommands.length > 0;\n\n let func = `${funcName}() {\\n`;\n func += ` local -a args\\n`;\n\n if (hasSubcommands) {\n const subcommandDesc = generateSubcommandDescriptions(command.subcommands, includeDescriptions);\n func += ` local -a subcommands\\n`;\n func += ` subcommands=(\\n`;\n func += ` ${subcommandDesc}\\n`;\n func += ` )\\n\\n`;\n }\n\n func += ` args=(\\n`;\n\n if (hasSubcommands) {\n func += ` '1:command:->command'\\n`;\n func += ` '*::arg:->args'\\n`;\n }\n\n for (const spec of optionSpecs) {\n func += ` ${spec}\\n`;\n }\n\n func += ` )\\n\\n`;\n\n func += ` _arguments -s -S $args\\n\\n`;\n\n if (hasSubcommands) {\n func += ` case \"$state\" in\\n`;\n func += ` command)\\n`;\n func += ` _describe -t commands 'command' subcommands\\n`;\n func += ` ;;\\n`;\n func += ` args)\\n`;\n func += ` case $words[1] in\\n`;\n\n for (const sub of command.subcommands) {\n const subFuncName = `_${programName}_${[...currentPath.slice(1), sub.name].join(\"_\")}`;\n func += ` ${sub.name})\\n`;\n func += ` ${subFuncName}\\n`;\n func += ` ;;\\n`;\n }\n\n func += ` esac\\n`;\n func += ` ;;\\n`;\n func += ` esac\\n`;\n }\n\n func += `}\\n`;\n\n return func;\n}\n\n/**\n * Collect all subcommand functions recursively\n */\nfunction collectSubcommandFunctions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string[] {\n const functions: string[] = [];\n\n // Generate function for this command\n functions.push(generateSubcommandFunction(command, programName, includeDescriptions, parentPath));\n\n // Generate functions for subcommands\n const currentPath = parentPath.length === 0 ? [command.name] : [...parentPath, command.name];\n\n for (const sub of command.subcommands) {\n functions.push(\n ...collectSubcommandFunctions(sub, programName, includeDescriptions, currentPath),\n );\n }\n\n return functions;\n}\n\n/**\n * Generate the zsh completion script\n */\nfunction generateZshScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const functions = collectSubcommandFunctions(command, programName, includeDescriptions);\n\n return `#compdef ${programName}\n\n# Zsh completion for ${programName}\n# Generated by politty\n\n${functions.join(\"\\n\")}\n\n_${programName} \"$@\"\n`;\n}\n\n/**\n * Generate zsh completion script for a command\n */\nexport function generateZshCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateZshScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"zsh\",\n installInstructions: `# To enable completions, add the following to your ~/.zshrc:\n\n# Option 1: Source directly (add before compinit)\neval \"$(${options.programName} completion zsh)\"\n\n# Option 2: Save to a file in your fpath\n${options.programName} completion zsh > ~/.zsh/completions/_${options.programName}\n\n# Make sure your fpath includes the completions directory:\n# fpath=(~/.zsh/completions $fpath)\n# autoload -Uz compinit && compinit\n\n# Then reload your shell or run:\nsource ~/.zshrc`,\n };\n}\n","/**\n * Shell completion generation module\n *\n * Provides utilities to generate shell completion scripts for bash, zsh, and fish.\n *\n * @example\n * ```typescript\n * import { generateCompletion, createCompletionCommand } from \"politty/completion\";\n *\n * // Generate completion script directly\n * const result = generateCompletion(myCommand, {\n * shell: \"bash\",\n * programName: \"mycli\"\n * });\n * console.log(result.script);\n *\n * // Or add a completion subcommand to your CLI\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(myCommand, \"mycli\")\n * }\n * });\n * ```\n */\n\nimport { z } from \"zod\";\nimport { arg } from \"../core/arg-registry.js\";\nimport { defineCommand } from \"../core/command.js\";\nimport type { AnyCommand, Command } from \"../types.js\";\nimport { generateBashCompletion } from \"./bash.js\";\nimport { generateFishCompletion } from \"./fish.js\";\nimport type { CompletionOptions, CompletionResult, ShellType } from \"./types.js\";\nimport { generateZshCompletion } from \"./zsh.js\";\n\n// Re-export types\n// Re-export extractor\nexport { extractCompletionData, extractPositionals } from \"./extractor.js\";\nexport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionData,\n CompletionGenerator,\n CompletionOptions,\n CompletionResult,\n ShellType,\n} from \"./types.js\";\n\n/**\n * Generate completion script for the specified shell\n */\nexport function generateCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n switch (options.shell) {\n case \"bash\":\n return generateBashCompletion(command, options);\n case \"zsh\":\n return generateZshCompletion(command, options);\n case \"fish\":\n return generateFishCompletion(command, options);\n default:\n throw new Error(`Unsupported shell: ${options.shell}`);\n }\n}\n\n/**\n * Get the list of supported shells\n */\nexport function getSupportedShells(): ShellType[] {\n return [\"bash\", \"zsh\", \"fish\"];\n}\n\n/**\n * Detect the current shell from environment\n */\nexport function detectShell(): ShellType | null {\n const shell = process.env.SHELL || \"\";\n const shellName = shell.split(\"/\").pop()?.toLowerCase() || \"\";\n\n if (shellName.includes(\"bash\")) {\n return \"bash\";\n }\n if (shellName.includes(\"zsh\")) {\n return \"zsh\";\n }\n if (shellName.includes(\"fish\")) {\n return \"fish\";\n }\n\n return null;\n}\n\n/**\n * Schema for the completion command arguments\n */\nconst completionArgsSchema = z.object({\n shell: arg(\n z\n .enum([\"bash\", \"zsh\", \"fish\"])\n .optional()\n .describe(\"Shell type (auto-detected if not specified)\"),\n {\n positional: true,\n description: \"Shell type (bash, zsh, or fish)\",\n placeholder: \"SHELL\",\n },\n ),\n instructions: arg(z.boolean().default(false), {\n alias: \"i\",\n description: \"Show installation instructions\",\n }),\n});\n\ntype CompletionArgs = z.infer<typeof completionArgsSchema>;\n\n/**\n * Create a completion subcommand for your CLI\n *\n * This creates a ready-to-use subcommand that generates completion scripts.\n *\n * @example\n * ```typescript\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(mainCommand, \"mycli\")\n * }\n * });\n * ```\n */\nexport function createCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Command<typeof completionArgsSchema, CompletionArgs, any> {\n return defineCommand({\n name: \"completion\",\n description: \"Generate shell completion script\",\n args: completionArgsSchema,\n run(args) {\n // Detect shell if not specified\n const shellType = args.shell || detectShell();\n\n if (!shellType) {\n console.error(\"Could not detect shell type. Please specify one of: bash, zsh, fish\");\n process.exitCode = 1;\n return;\n }\n\n const result = generateCompletion(rootCommand, {\n shell: shellType,\n programName,\n includeDescriptions: true,\n });\n\n if (args.instructions) {\n console.log(result.installInstructions);\n } else {\n console.log(result.script);\n }\n },\n });\n}\n\n/**\n * Helper to add completion command to an existing command's subCommands\n *\n * @example\n * ```typescript\n * const command = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * ...withCompletionCommand(command, \"mycli\"),\n * // other subcommands\n * }\n * });\n * ```\n */\nexport function withCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n): { completion: ReturnType<typeof createCompletionCommand> } {\n return {\n completion: createCompletionCommand(rootCommand, programName),\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["generateOptionCompletions","generateSubcommandCompletions"],"sources":["../../src/completion/extractor.ts","../../src/completion/bash.ts","../../src/completion/fish.ts","../../src/completion/zsh.ts","../../src/completion/index.ts"],"sourcesContent":["/**\n * Extract completion data from commands\n */\n\nimport { extractFields, type ResolvedFieldMeta } from \"../core/schema-extractor.js\";\nimport type { AnyCommand } from \"../types.js\";\nimport type { CompletableOption, CompletableSubcommand, CompletionData } from \"./types.js\";\n\n/**\n * Convert a resolved field to a completable option\n */\nfunction fieldToOption(field: ResolvedFieldMeta): CompletableOption {\n return {\n name: field.name,\n cliName: field.cliName,\n alias: field.alias,\n description: field.description,\n // Booleans are flags that don't require a value\n takesValue: field.type !== \"boolean\",\n valueType: field.type,\n required: field.required,\n };\n}\n\n/**\n * Extract options from a command's args schema\n */\nfunction extractOptions(command: AnyCommand): CompletableOption[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields\n .filter((field) => !field.positional) // Only include flags/options, not positionals\n .map(fieldToOption);\n}\n\n/**\n * Extract positional arguments from a command\n */\nexport function extractPositionals(command: AnyCommand): ResolvedFieldMeta[] {\n if (!command.args) {\n return [];\n }\n\n const extracted = extractFields(command.args);\n return extracted.fields.filter((field) => field.positional);\n}\n\n/**\n * Extract a completable subcommand from a command\n */\nfunction extractSubcommand(name: string, command: AnyCommand): CompletableSubcommand {\n const subcommands: CompletableSubcommand[] = [];\n\n // Extract subcommands recursively (only sync subcommands for now)\n if (command.subCommands) {\n for (const [subName, subCommand] of Object.entries(command.subCommands)) {\n // Skip async subcommands as we can't inspect them statically\n if (typeof subCommand === \"function\") {\n // For async subcommands, add a placeholder\n subcommands.push({\n name: subName,\n description: \"(lazy loaded)\",\n subcommands: [],\n options: [],\n });\n } else {\n subcommands.push(extractSubcommand(subName, subCommand));\n }\n }\n }\n\n return {\n name,\n description: command.description,\n subcommands,\n options: extractOptions(command),\n };\n}\n\n/**\n * Extract completion data from a command tree\n */\nexport function extractCompletionData(command: AnyCommand, programName: string): CompletionData {\n const rootSubcommand = extractSubcommand(programName, command);\n\n return {\n command: rootSubcommand,\n programName,\n // Global options are the options defined on the root command\n globalOptions: rootSubcommand.options,\n };\n}\n","/**\n * Bash completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Generate option completions for bash\n */\nfunction generateOptionCompletions(options: CompletableOption[]): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n completions.push(`--${opt.cliName}`);\n if (opt.alias) {\n completions.push(`-${opt.alias}`);\n }\n }\n\n return completions;\n}\n\n/**\n * Generate subcommand completions for bash\n */\nfunction generateSubcommandCompletions(subcommands: CompletableSubcommand[]): string[] {\n return subcommands.map((sub) => sub.name);\n}\n\n/**\n * Generate the bash completion script\n */\nfunction generateBashScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const allOptions = collectAllOptions(command);\n\n const optionList = generateOptionCompletions(allOptions).join(\" \");\n const subcommandList = generateSubcommandCompletions(command.subcommands).join(\" \");\n\n // Build subcommand-specific completions\n const subcommandCases = buildSubcommandCases(command.subcommands, includeDescriptions);\n\n return `# Bash completion for ${programName}\n# Generated by politty\n\n_${programName}_completions() {\n local cur prev words cword\n _init_completion || return\n\n local commands=\"${subcommandList}\"\n local global_opts=\"${optionList}\"\n\n # Handle subcommand-specific completions\n local cmd_index=1\n local cmd=\"\"\n\n # Find the subcommand\n for ((i=1; i < cword; i++)); do\n case \"\\${words[i]}\" in\n -*)\n # Skip options and their values\n if [[ \"\\${words[i]}\" == *=* ]]; then\n continue\n fi\n # Check if next word is the option's value\n local opt=\"\\${words[i]}\"\n case \"$opt\" in\n ${\n allOptions\n .filter((o) => o.takesValue)\n .map((o) => `--${o.cliName}|-${o.alias || \"\"}`)\n .join(\"|\") || \"--*\"\n }\n ((i++))\n ;;\n esac\n ;;\n *)\n # Found a subcommand\n cmd=\"\\${words[i]}\"\n cmd_index=$i\n break\n ;;\n esac\n done\n\n # Subcommand-specific completions\n case \"$cmd\" in\n${subcommandCases}\n *)\n # Root level completions\n if [[ \"$cur\" == -* ]]; then\n COMPREPLY=($(compgen -W \"$global_opts\" -- \"$cur\"))\n else\n COMPREPLY=($(compgen -W \"$commands\" -- \"$cur\"))\n fi\n ;;\n esac\n\n return 0\n}\n\n# Register the completion function\ncomplete -F _${programName}_completions ${programName}\n`;\n}\n\n/**\n * Build case statements for subcommand-specific completions\n */\nfunction buildSubcommandCases(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n let cases = \"\";\n\n for (const sub of subcommands) {\n const options = generateOptionCompletions(sub.options).join(\" \");\n const nestedSubcommands = generateSubcommandCompletions(sub.subcommands).join(\" \");\n const completions = [options, nestedSubcommands].filter(Boolean).join(\" \");\n\n cases += ` ${sub.name})\\n`;\n cases += ` COMPREPLY=($(compgen -W \"${completions}\" -- \"$cur\"))\\n`;\n cases += ` ;;\\n`;\n\n // Add nested subcommand cases if any\n if (sub.subcommands.length > 0) {\n const nestedCases = buildSubcommandCases(sub.subcommands, includeDescriptions);\n if (nestedCases) {\n cases += nestedCases;\n }\n }\n }\n\n return cases;\n}\n\n/**\n * Collect all options from a command tree\n */\nfunction collectAllOptions(command: CompletableSubcommand): CompletableOption[] {\n const options = [...command.options];\n\n for (const sub of command.subcommands) {\n options.push(...collectAllOptions(sub));\n }\n\n // Deduplicate by name\n const seen = new Set<string>();\n return options.filter((opt) => {\n if (seen.has(opt.name)) {\n return false;\n }\n seen.add(opt.name);\n return true;\n });\n}\n\n/**\n * Generate bash completion script for a command\n */\nexport function generateBashCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateBashScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"bash\",\n installInstructions: `# To enable completions, add the following to your ~/.bashrc:\n\n# Option 1: Source directly\neval \"$(${options.programName} completion bash)\"\n\n# Option 2: Save to a file\n${options.programName} completion bash > ~/.local/share/bash-completion/completions/${options.programName}\n\n# Then reload your shell or run:\nsource ~/.bashrc`,\n };\n}\n","/**\n * Fish completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in fish completion descriptions\n */\nfunction escapeForFish(str: string): string {\n return str.replace(/'/g, \"\\\\'\").replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Generate completion entries for options\n */\nfunction generateOptionCompletions(\n options: CompletableOption[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const opt of options) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition if specified\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Add long option\n cmd += ` -l ${opt.cliName}`;\n\n // Add short option if exists\n if (opt.alias) {\n cmd += ` -s ${opt.alias}`;\n }\n\n // Add flag for options that take values\n if (opt.takesValue) {\n cmd += \" -r\"; // Require argument\n } else {\n cmd += \" -f\"; // No argument (flag)\n }\n\n // Add description\n if (includeDescriptions && opt.description) {\n cmd += ` -d '${escapeForFish(opt.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate completion entries for subcommands\n */\nfunction generateSubcommandCompletions(\n subcommands: CompletableSubcommand[],\n programName: string,\n condition: string,\n includeDescriptions: boolean,\n): string[] {\n const completions: string[] = [];\n\n for (const sub of subcommands) {\n let cmd = `complete -c ${programName}`;\n\n // Add condition\n if (condition) {\n cmd += ` -n '${condition}'`;\n }\n\n // Subcommands are exclusive (no prefix)\n cmd += ` -f -a ${sub.name}`;\n\n // Add description\n if (includeDescriptions && sub.description) {\n cmd += ` -d '${escapeForFish(sub.description)}'`;\n }\n\n completions.push(cmd);\n }\n\n return completions;\n}\n\n/**\n * Generate helper functions for fish\n */\nfunction generateHelperFunctions(programName: string): string {\n return `# Helper function to check if using subcommand\nfunction __fish_use_subcommand_${programName}\n set -l cmd (commandline -opc)\n if test (count $cmd) -eq 1\n return 0\n end\n return 1\nend\n\n# Helper function to check current subcommand\nfunction __fish_${programName}_using_command\n set -l cmd (commandline -opc)\n if contains -- $argv[1] $cmd\n return 0\n end\n return 1\nend\n`;\n}\n\n/**\n * Recursively generate completions for a command and its subcommands\n */\nfunction generateCommandCompletions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentCommands: string[] = [],\n): string[] {\n const completions: string[] = [];\n\n // Build condition for this level\n const optionCondition =\n parentCommands.length === 0\n ? \"\"\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n const subcommandCondition =\n parentCommands.length === 0\n ? `__fish_use_subcommand_${programName}`\n : `__fish_${programName}_using_command ${parentCommands[parentCommands.length - 1]}`;\n\n // Add option completions\n completions.push(\n ...generateOptionCompletions(\n command.options,\n programName,\n optionCondition,\n includeDescriptions,\n ),\n );\n\n // Add subcommand completions\n if (command.subcommands.length > 0) {\n completions.push(\n ...generateSubcommandCompletions(\n command.subcommands,\n programName,\n subcommandCondition,\n includeDescriptions,\n ),\n );\n\n // Recursively add completions for subcommands\n for (const sub of command.subcommands) {\n completions.push(\n ...generateCommandCompletions(sub, programName, includeDescriptions, [\n ...parentCommands,\n sub.name,\n ]),\n );\n }\n }\n\n return completions;\n}\n\n/**\n * Generate the fish completion script\n */\nfunction generateFishScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const helpers = generateHelperFunctions(programName);\n const completions = generateCommandCompletions(command, programName, includeDescriptions);\n\n // Add built-in options (help and version)\n const builtinCompletions = [\n `complete -c ${programName} -l help -s h -d 'Show help information'`,\n `complete -c ${programName} -l version -d 'Show version information'`,\n ];\n\n return `# Fish completion for ${programName}\n# Generated by politty\n\n${helpers}\n\n# Clear existing completions\ncomplete -e -c ${programName}\n\n# Built-in options\n${builtinCompletions.join(\"\\n\")}\n\n# Command-specific completions\n${completions.join(\"\\n\")}\n`;\n}\n\n/**\n * Generate fish completion script for a command\n */\nexport function generateFishCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateFishScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"fish\",\n installInstructions: `# To enable completions, run one of the following:\n\n# Option 1: Source directly\n${options.programName} completion fish | source\n\n# Option 2: Save to the fish completions directory\n${options.programName} completion fish > ~/.config/fish/completions/${options.programName}.fish\n\n# The completion will be available immediately in new shell sessions.\n# To use in the current session, run:\nsource ~/.config/fish/completions/${options.programName}.fish`,\n };\n}\n","/**\n * Zsh completion script generator\n */\n\nimport type { AnyCommand } from \"../types.js\";\nimport { extractCompletionData } from \"./extractor.js\";\nimport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionOptions,\n CompletionResult,\n} from \"./types.js\";\n\n/**\n * Escape a string for use in zsh completion descriptions\n */\nfunction escapeForZsh(str: string): string {\n return str.replace(/'/g, \"''\").replace(/\\[/g, \"\\\\[\").replace(/\\]/g, \"\\\\]\");\n}\n\n/**\n * Generate option specs for zsh _arguments\n */\nfunction generateOptionSpecs(options: CompletableOption[], includeDescriptions: boolean): string[] {\n const specs: string[] = [];\n\n for (const opt of options) {\n const desc = includeDescriptions && opt.description ? escapeForZsh(opt.description) : \"\";\n const valueSpec = opt.takesValue ? \":\" : \"\";\n\n // Long option\n if (desc) {\n specs.push(`'--${opt.cliName}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'--${opt.cliName}${valueSpec}'`);\n }\n\n // Short option (alias)\n if (opt.alias) {\n if (desc) {\n specs.push(`'-${opt.alias}[${desc}]${valueSpec}'`);\n } else {\n specs.push(`'-${opt.alias}${valueSpec}'`);\n }\n }\n }\n\n return specs;\n}\n\n/**\n * Generate subcommand descriptions for zsh\n */\nfunction generateSubcommandDescriptions(\n subcommands: CompletableSubcommand[],\n includeDescriptions: boolean,\n): string {\n if (subcommands.length === 0) {\n return \"\";\n }\n\n const lines = subcommands.map((sub) => {\n const desc = includeDescriptions && sub.description ? escapeForZsh(sub.description) : sub.name;\n return `'${sub.name}:${desc}'`;\n });\n\n return lines.join(\"\\n \");\n}\n\n/**\n * Generate a zsh function for a subcommand\n */\nfunction generateSubcommandFunction(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string {\n const currentPath = [...parentPath, command.name];\n const funcName =\n parentPath.length === 0\n ? `_${programName}`\n : `_${programName}_${currentPath.slice(1).join(\"_\")}`;\n\n const optionSpecs = generateOptionSpecs(command.options, includeDescriptions);\n const hasSubcommands = command.subcommands.length > 0;\n\n let func = `${funcName}() {\\n`;\n func += ` local -a args\\n`;\n\n if (hasSubcommands) {\n const subcommandDesc = generateSubcommandDescriptions(command.subcommands, includeDescriptions);\n func += ` local -a subcommands\\n`;\n func += ` subcommands=(\\n`;\n func += ` ${subcommandDesc}\\n`;\n func += ` )\\n\\n`;\n }\n\n func += ` args=(\\n`;\n\n if (hasSubcommands) {\n func += ` '1:command:->command'\\n`;\n func += ` '*::arg:->args'\\n`;\n }\n\n for (const spec of optionSpecs) {\n func += ` ${spec}\\n`;\n }\n\n func += ` )\\n\\n`;\n\n func += ` _arguments -s -S $args\\n\\n`;\n\n if (hasSubcommands) {\n func += ` case \"$state\" in\\n`;\n func += ` command)\\n`;\n func += ` _describe -t commands 'command' subcommands\\n`;\n func += ` ;;\\n`;\n func += ` args)\\n`;\n func += ` case $words[1] in\\n`;\n\n for (const sub of command.subcommands) {\n const subFuncName = `_${programName}_${[...currentPath.slice(1), sub.name].join(\"_\")}`;\n func += ` ${sub.name})\\n`;\n func += ` ${subFuncName}\\n`;\n func += ` ;;\\n`;\n }\n\n func += ` esac\\n`;\n func += ` ;;\\n`;\n func += ` esac\\n`;\n }\n\n func += `}\\n`;\n\n return func;\n}\n\n/**\n * Collect all subcommand functions recursively\n */\nfunction collectSubcommandFunctions(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n parentPath: string[] = [],\n): string[] {\n const functions: string[] = [];\n\n // Generate function for this command\n functions.push(generateSubcommandFunction(command, programName, includeDescriptions, parentPath));\n\n // Generate functions for subcommands\n const currentPath = parentPath.length === 0 ? [command.name] : [...parentPath, command.name];\n\n for (const sub of command.subcommands) {\n functions.push(\n ...collectSubcommandFunctions(sub, programName, includeDescriptions, currentPath),\n );\n }\n\n return functions;\n}\n\n/**\n * Generate the zsh completion script\n */\nfunction generateZshScript(\n command: CompletableSubcommand,\n programName: string,\n includeDescriptions: boolean,\n): string {\n const functions = collectSubcommandFunctions(command, programName, includeDescriptions);\n\n return `#compdef ${programName}\n\n# Zsh completion for ${programName}\n# Generated by politty\n\n${functions.join(\"\\n\")}\n\ncompdef _${programName} ${programName}\n`;\n}\n\n/**\n * Generate zsh completion script for a command\n */\nexport function generateZshCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n const data = extractCompletionData(command, options.programName);\n const includeDescriptions = options.includeDescriptions ?? true;\n\n const script = generateZshScript(data.command, options.programName, includeDescriptions);\n\n return {\n script,\n shell: \"zsh\",\n installInstructions: `# To enable completions, add the following to your ~/.zshrc:\n\n# Option 1: Source directly (add before compinit)\neval \"$(${options.programName} completion zsh)\"\n\n# Option 2: Save to a file in your fpath\n${options.programName} completion zsh > ~/.zsh/completions/_${options.programName}\n\n# Make sure your fpath includes the completions directory:\n# fpath=(~/.zsh/completions $fpath)\n# autoload -Uz compinit && compinit\n\n# Then reload your shell or run:\nsource ~/.zshrc`,\n };\n}\n","/**\n * Shell completion generation module\n *\n * Provides utilities to generate shell completion scripts for bash, zsh, and fish.\n *\n * @example\n * ```typescript\n * import { generateCompletion, createCompletionCommand } from \"politty/completion\";\n *\n * // Generate completion script directly\n * const result = generateCompletion(myCommand, {\n * shell: \"bash\",\n * programName: \"mycli\"\n * });\n * console.log(result.script);\n *\n * // Or add a completion subcommand to your CLI\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(myCommand, \"mycli\")\n * }\n * });\n * ```\n */\n\nimport { z } from \"zod\";\nimport { arg } from \"../core/arg-registry.js\";\nimport { defineCommand } from \"../core/command.js\";\nimport type { AnyCommand, Command } from \"../types.js\";\nimport { generateBashCompletion } from \"./bash.js\";\nimport { generateFishCompletion } from \"./fish.js\";\nimport type { CompletionOptions, CompletionResult, ShellType } from \"./types.js\";\nimport { generateZshCompletion } from \"./zsh.js\";\n\n// Re-export types\n// Re-export extractor\nexport { extractCompletionData, extractPositionals } from \"./extractor.js\";\nexport type {\n CompletableOption,\n CompletableSubcommand,\n CompletionData,\n CompletionGenerator,\n CompletionOptions,\n CompletionResult,\n ShellType,\n} from \"./types.js\";\n\n/**\n * Generate completion script for the specified shell\n */\nexport function generateCompletion(\n command: AnyCommand,\n options: CompletionOptions,\n): CompletionResult {\n switch (options.shell) {\n case \"bash\":\n return generateBashCompletion(command, options);\n case \"zsh\":\n return generateZshCompletion(command, options);\n case \"fish\":\n return generateFishCompletion(command, options);\n default:\n throw new Error(`Unsupported shell: ${options.shell}`);\n }\n}\n\n/**\n * Get the list of supported shells\n */\nexport function getSupportedShells(): ShellType[] {\n return [\"bash\", \"zsh\", \"fish\"];\n}\n\n/**\n * Detect the current shell from environment\n */\nexport function detectShell(): ShellType | null {\n const shell = process.env.SHELL || \"\";\n const shellName = shell.split(\"/\").pop()?.toLowerCase() || \"\";\n\n if (shellName.includes(\"bash\")) {\n return \"bash\";\n }\n if (shellName.includes(\"zsh\")) {\n return \"zsh\";\n }\n if (shellName.includes(\"fish\")) {\n return \"fish\";\n }\n\n return null;\n}\n\n/**\n * Schema for the completion command arguments\n */\nconst completionArgsSchema = z.object({\n shell: arg(\n z\n .enum([\"bash\", \"zsh\", \"fish\"])\n .optional()\n .describe(\"Shell type (auto-detected if not specified)\"),\n {\n positional: true,\n description: \"Shell type (bash, zsh, or fish)\",\n placeholder: \"SHELL\",\n },\n ),\n instructions: arg(z.boolean().default(false), {\n alias: \"i\",\n description: \"Show installation instructions\",\n }),\n});\n\ntype CompletionArgs = z.infer<typeof completionArgsSchema>;\n\n/**\n * Create a completion subcommand for your CLI\n *\n * This creates a ready-to-use subcommand that generates completion scripts.\n *\n * @example\n * ```typescript\n * const mainCommand = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * completion: createCompletionCommand(mainCommand, \"mycli\")\n * }\n * });\n * ```\n */\nexport function createCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Command<typeof completionArgsSchema, CompletionArgs, any> {\n return defineCommand({\n name: \"completion\",\n description: \"Generate shell completion script\",\n args: completionArgsSchema,\n run(args) {\n // Detect shell if not specified\n const shellType = args.shell || detectShell();\n\n if (!shellType) {\n console.error(\"Could not detect shell type. Please specify one of: bash, zsh, fish\");\n process.exitCode = 1;\n return;\n }\n\n const result = generateCompletion(rootCommand, {\n shell: shellType,\n programName,\n includeDescriptions: true,\n });\n\n if (args.instructions) {\n console.log(result.installInstructions);\n } else {\n console.log(result.script);\n }\n },\n });\n}\n\n/**\n * Helper to add completion command to an existing command's subCommands\n *\n * @example\n * ```typescript\n * const command = defineCommand({\n * name: \"mycli\",\n * subCommands: {\n * ...withCompletionCommand(command, \"mycli\"),\n * // other subcommands\n * }\n * });\n * ```\n */\nexport function withCompletionCommand(\n rootCommand: AnyCommand,\n programName: string,\n): { completion: ReturnType<typeof createCompletionCommand> } {\n return {\n completion: createCompletionCommand(rootCommand, programName),\n };\n}\n"],"mappings":"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"}
@@ -113,32 +113,33 @@ function formatOptionFlags(opt) {
113
113
  * - Displays multiple env vars as comma-separated list
114
114
  *
115
115
  * @example
116
- * | Option | Alias | Description | Default | Env |
117
- * |--------|-------|-------------|---------|-----|
118
- * | `--dry-run` | `-d` | Dry run mode | `false` | - |
119
- * | `--port <PORT>` | - | Server port | - | `PORT`, `SERVER_PORT` |
116
+ * | Option | Alias | Description | Required | Default | Env |
117
+ * |--------|-------|-------------|----------|---------|-----|
118
+ * | `--dry-run` | `-d` | Dry run mode | No | `false` | - |
119
+ * | `--port <PORT>` | - | Server port | Yes | - | `PORT`, `SERVER_PORT` |
120
120
  */
121
121
  function renderOptionsTable(info) {
122
122
  if (info.options.length === 0) return "";
123
123
  const hasEnv = info.options.some((opt) => opt.env);
124
124
  const lines = [];
125
125
  if (hasEnv) {
126
- lines.push("| Option | Alias | Description | Default | Env |");
127
- lines.push("|--------|-------|-------------|---------|-----|");
126
+ lines.push("| Option | Alias | Description | Required | Default | Env |");
127
+ lines.push("|--------|-------|-------------|----------|---------|-----|");
128
128
  } else {
129
- lines.push("| Option | Alias | Description | Default |");
130
- lines.push("|--------|-------|-------------|---------|");
129
+ lines.push("| Option | Alias | Description | Required | Default |");
130
+ lines.push("|--------|-------|-------------|----------|---------|");
131
131
  }
132
132
  for (const opt of info.options) {
133
133
  const placeholder = opt.placeholder ?? opt.cliName.toUpperCase().replace(/-/g, "_");
134
134
  const optionName = opt.type === "boolean" ? `\`--${opt.cliName}\`` : `\`--${opt.cliName} <${placeholder}>\``;
135
135
  const alias = opt.alias ? `\`-${opt.alias}\`` : "-";
136
136
  const desc = escapeTableCell$2(opt.description ?? "");
137
+ const required = opt.required ? "Yes" : "No";
137
138
  const defaultVal = formatDefaultValue$1(opt.defaultValue);
138
139
  if (hasEnv) {
139
140
  const envNames = opt.env ? Array.isArray(opt.env) ? opt.env.map((e) => `\`${e}\``).join(", ") : `\`${opt.env}\`` : "-";
140
- lines.push(`| ${optionName} | ${alias} | ${desc} | ${defaultVal} | ${envNames} |`);
141
- } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${defaultVal} |`);
141
+ lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} | ${envNames} |`);
142
+ } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} |`);
142
143
  }
143
144
  return lines.join("\n");
144
145
  }
@@ -151,7 +152,7 @@ function renderOptionsTable(info) {
151
152
  *
152
153
  * @example
153
154
  * - `-d`, `--dry-run` - Dry run mode (default: false)
154
- * - `--port <PORT>` - Server port [env: PORT, SERVER_PORT]
155
+ * - `--port <PORT>` - Server port (required) [env: PORT, SERVER_PORT]
155
156
  */
156
157
  function renderOptionsList(info) {
157
158
  if (info.options.length === 0) return "";
@@ -159,9 +160,10 @@ function renderOptionsList(info) {
159
160
  for (const opt of info.options) {
160
161
  const flags = formatOptionFlags(opt);
161
162
  const desc = opt.description ? ` - ${opt.description}` : "";
163
+ const required = opt.required ? " (required)" : "";
162
164
  const defaultVal = opt.defaultValue !== void 0 ? ` (default: ${JSON.stringify(opt.defaultValue)})` : "";
163
165
  const envInfo = formatEnvInfo(opt.env);
164
- lines.push(`- ${flags}${desc}${defaultVal}${envInfo}`);
166
+ lines.push(`- ${flags}${desc}${required}${defaultVal}${envInfo}`);
165
167
  }
166
168
  return lines.join("\n");
167
169
  }
@@ -215,22 +217,23 @@ function renderOptionsTableFromArray(options) {
215
217
  const hasEnv = options.some((opt) => opt.env);
216
218
  const lines = [];
217
219
  if (hasEnv) {
218
- lines.push("| Option | Alias | Description | Default | Env |");
219
- lines.push("|--------|-------|-------------|---------|-----|");
220
+ lines.push("| Option | Alias | Description | Required | Default | Env |");
221
+ lines.push("|--------|-------|-------------|----------|---------|-----|");
220
222
  } else {
221
- lines.push("| Option | Alias | Description | Default |");
222
- lines.push("|--------|-------|-------------|---------|");
223
+ lines.push("| Option | Alias | Description | Required | Default |");
224
+ lines.push("|--------|-------|-------------|----------|---------|");
223
225
  }
224
226
  for (const opt of options) {
225
227
  const placeholder = opt.placeholder ?? opt.cliName.toUpperCase().replace(/-/g, "_");
226
228
  const optionName = opt.type === "boolean" ? `\`--${opt.cliName}\`` : `\`--${opt.cliName} <${placeholder}>\``;
227
229
  const alias = opt.alias ? `\`-${opt.alias}\`` : "-";
228
230
  const desc = escapeTableCell$2(opt.description ?? "");
231
+ const required = opt.required ? "Yes" : "No";
229
232
  const defaultVal = formatDefaultValue$1(opt.defaultValue);
230
233
  if (hasEnv) {
231
234
  const envNames = opt.env ? Array.isArray(opt.env) ? opt.env.map((e) => `\`${e}\``).join(", ") : `\`${opt.env}\`` : "-";
232
- lines.push(`| ${optionName} | ${alias} | ${desc} | ${defaultVal} | ${envNames} |`);
233
- } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${defaultVal} |`);
235
+ lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} | ${envNames} |`);
236
+ } else lines.push(`| ${optionName} | ${alias} | ${desc} | ${required} | ${defaultVal} |`);
234
237
  }
235
238
  return lines.join("\n");
236
239
  }
@@ -243,9 +246,10 @@ function renderOptionsListFromArray(options) {
243
246
  for (const opt of options) {
244
247
  const flags = formatOptionFlags(opt);
245
248
  const desc = opt.description ? ` - ${opt.description}` : "";
249
+ const required = opt.required ? " (required)" : "";
246
250
  const defaultVal = opt.defaultValue !== void 0 ? ` (default: ${JSON.stringify(opt.defaultValue)})` : "";
247
251
  const envInfo = formatEnvInfo(opt.env);
248
- lines.push(`- ${flags}${desc}${defaultVal}${envInfo}`);
252
+ lines.push(`- ${flags}${desc}${required}${defaultVal}${envInfo}`);
249
253
  }
250
254
  return lines.join("\n");
251
255
  }
@@ -320,6 +324,7 @@ function renderSubcommandsTableFromArray(subcommands, info, generateAnchors = tr
320
324
  function renderExamplesDefault(examples, results, opts) {
321
325
  if (examples.length === 0) return "";
322
326
  const showOutput = opts?.showOutput ?? true;
327
+ const prefix = opts?.commandPrefix ? `${opts.commandPrefix} ` : "";
323
328
  const lines = [];
324
329
  for (let i = 0; i < examples.length; i++) {
325
330
  const example = examples[i];
@@ -328,7 +333,7 @@ function renderExamplesDefault(examples, results, opts) {
328
333
  lines.push(`**${example.desc}**`);
329
334
  lines.push("");
330
335
  lines.push("```bash");
331
- lines.push(`$ ${example.cmd}`);
336
+ lines.push(`$ ${prefix}${example.cmd}`);
332
337
  if (showOutput) {
333
338
  if (result) {
334
339
  if (result.stdout) lines.push(result.stdout);
@@ -438,7 +443,10 @@ function createCommandRenderer(options = {}) {
438
443
  if (info.examples && info.examples.length > 0) {
439
444
  const renderEx = (examples, results, opts) => {
440
445
  const withHeading = opts?.withHeading ?? true;
441
- const content = renderExamplesDefault(examples, results, opts);
446
+ const content = renderExamplesDefault(examples, results, {
447
+ commandPrefix: info.fullCommandPath,
448
+ ...opts
449
+ });
442
450
  return withHeading ? `**Examples**\n\n${content}` : content;
443
451
  };
444
452
  const context = {
@@ -672,7 +680,7 @@ async function executeSingleExample(example, rootCommand, commandPath) {
672
680
  collector.start();
673
681
  let success = true;
674
682
  try {
675
- const { runCommand } = await Promise.resolve().then(() => require("../runner-BkhekqT9.cjs"));
683
+ const { runCommand } = await Promise.resolve().then(() => require("../runner-DdljTA5L.cjs"));
676
684
  const result = await runCommand(rootCommand, argv);
677
685
  success = result.success;
678
686
  if (!result.success && result.error) console.error(result.error.message);
@@ -1280,6 +1288,10 @@ function renderFilteredTable(options, columns) {
1280
1288
  headerCells.push("Description");
1281
1289
  separatorCells.push("-----------");
1282
1290
  break;
1291
+ case "required":
1292
+ headerCells.push("Required");
1293
+ separatorCells.push("--------");
1294
+ break;
1283
1295
  case "default":
1284
1296
  headerCells.push("Default");
1285
1297
  separatorCells.push("-------");
@@ -1306,6 +1318,9 @@ function renderFilteredTable(options, columns) {
1306
1318
  case "description":
1307
1319
  cells.push(escapeTableCell$1(opt.description ?? ""));
1308
1320
  break;
1321
+ case "required":
1322
+ cells.push(opt.required ? "Yes" : "No");
1323
+ break;
1309
1324
  case "default":
1310
1325
  cells.push(formatDefaultValue(opt.defaultValue));
1311
1326
  break;