politty 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -473,12 +473,12 @@ source ~/.zshrc`
473
473
  * console.log(result.script);
474
474
  *
475
475
  * // Or add a completion subcommand to your CLI
476
- * const mainCommand = defineCommand({
477
- * name: "mycli",
478
- * subCommands: {
479
- * completion: createCompletionCommand(myCommand, "mycli")
480
- * }
481
- * });
476
+ * const mainCommand = withCompletionCommand(
477
+ * defineCommand({
478
+ * name: "mycli",
479
+ * subCommands: { ... },
480
+ * }),
481
+ * );
482
482
  * ```
483
483
  */
484
484
  /**
@@ -540,12 +540,13 @@ const completionArgsSchema = zod.z.object({
540
540
  * const mainCommand = defineCommand({
541
541
  * name: "mycli",
542
542
  * subCommands: {
543
- * completion: createCompletionCommand(mainCommand, "mycli")
543
+ * completion: createCompletionCommand(mainCommand)
544
544
  * }
545
545
  * });
546
546
  * ```
547
547
  */
548
548
  function createCompletionCommand(rootCommand, programName) {
549
+ const resolvedProgramName = programName ?? rootCommand.name;
549
550
  return require_command.defineCommand({
550
551
  name: "completion",
551
552
  description: "Generate shell completion script",
@@ -559,7 +560,7 @@ function createCompletionCommand(rootCommand, programName) {
559
560
  }
560
561
  const result = generateCompletion(rootCommand, {
561
562
  shell: shellType,
562
- programName,
563
+ programName: resolvedProgramName,
563
564
  includeDescriptions: true
564
565
  });
565
566
  if (args.instructions) console.log(result.installInstructions);
@@ -568,21 +569,32 @@ function createCompletionCommand(rootCommand, programName) {
568
569
  });
569
570
  }
570
571
  /**
571
- * Helper to add completion command to an existing command's subCommands
572
+ * Wrap a command with a completion subcommand
573
+ *
574
+ * This avoids circular references that occur when a command references itself
575
+ * in its subCommands (e.g., for completion generation).
576
+ *
577
+ * @param command - The command to wrap
578
+ * @param programName - Override the program name (defaults to command.name)
579
+ * @returns A new command with the completion subcommand added
572
580
  *
573
581
  * @example
574
582
  * ```typescript
575
- * const command = defineCommand({
576
- * name: "mycli",
577
- * subCommands: {
578
- * ...withCompletionCommand(command, "mycli"),
579
- * // other subcommands
580
- * }
581
- * });
583
+ * const mainCommand = withCompletionCommand(
584
+ * defineCommand({
585
+ * name: "mycli",
586
+ * subCommands: { ... },
587
+ * }),
588
+ * );
582
589
  * ```
583
590
  */
584
- function withCompletionCommand(rootCommand, programName) {
585
- return { completion: createCompletionCommand(rootCommand, programName) };
591
+ function withCompletionCommand(command, programName) {
592
+ const wrappedCommand = { ...command };
593
+ wrappedCommand.subCommands = {
594
+ ...command.subCommands,
595
+ completion: createCompletionCommand(wrappedCommand, programName)
596
+ };
597
+ return wrappedCommand;
586
598
  }
587
599
 
588
600
  //#endregion
@@ -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\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":";;;;;;;;;;;;;AAWA,SAAS,cAAc,OAA6C;AAClE,QAAO;EACL,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,OAAO,MAAM;EACb,aAAa,MAAM;EAEnB,YAAY,MAAM,SAAS;EAC3B,WAAW,MAAM;EACjB,UAAU,MAAM;EACjB;;;;;AAMH,SAAS,eAAe,SAA0C;AAChE,KAAI,CAAC,QAAQ,KACX,QAAO,EAAE;AAIX,QADkBA,uCAAc,QAAQ,KAAK,CAC5B,OACd,QAAQ,UAAU,CAAC,MAAM,WAAW,CACpC,IAAI,cAAc;;;;;AAMvB,SAAgB,mBAAmB,SAA0C;AAC3E,KAAI,CAAC,QAAQ,KACX,QAAO,EAAE;AAIX,QADkBA,uCAAc,QAAQ,KAAK,CAC5B,OAAO,QAAQ,UAAU,MAAM,WAAW;;;;;AAM7D,SAAS,kBAAkB,MAAc,SAA4C;CACnF,MAAM,cAAuC,EAAE;AAG/C,KAAI,QAAQ,YACV,MAAK,MAAM,CAAC,SAAS,eAAe,OAAO,QAAQ,QAAQ,YAAY,CAErE,KAAI,OAAO,eAAe,WAExB,aAAY,KAAK;EACf,MAAM;EACN,aAAa;EACb,aAAa,EAAE;EACf,SAAS,EAAE;EACZ,CAAC;KAEF,aAAY,KAAK,kBAAkB,SAAS,WAAW,CAAC;AAK9D,QAAO;EACL;EACA,aAAa,QAAQ;EACrB;EACA,SAAS,eAAe,QAAQ;EACjC;;;;;AAMH,SAAgB,sBAAsB,SAAqB,aAAqC;CAC9F,MAAM,iBAAiB,kBAAkB,aAAa,QAAQ;AAE9D,QAAO;EACL,SAAS;EACT;EAEA,eAAe,eAAe;EAC/B;;;;;;;;AC7EH,SAASC,4BAA0B,SAAwC;CACzE,MAAM,cAAwB,EAAE;AAEhC,MAAK,MAAM,OAAO,SAAS;AACzB,cAAY,KAAK,KAAK,IAAI,UAAU;AACpC,MAAI,IAAI,MACN,aAAY,KAAK,IAAI,IAAI,QAAQ;;AAIrC,QAAO;;;;;AAMT,SAASC,gCAA8B,aAAgD;AACrF,QAAO,YAAY,KAAK,QAAQ,IAAI,KAAK;;;;;AAM3C,SAAS,mBACP,SACA,aACA,qBACQ;CACR,MAAM,aAAa,kBAAkB,QAAQ;CAE7C,MAAM,aAAaD,4BAA0B,WAAW,CAAC,KAAK,IAAI;CAClE,MAAM,iBAAiBC,gCAA8B,QAAQ,YAAY,CAAC,KAAK,IAAI;CAGnF,MAAM,kBAAkB,qBAAqB,QAAQ,aAAa,oBAAoB;AAEtF,QAAO,yBAAyB,YAAY;;;GAG3C,YAAY;;;;sBAIO,eAAe;yBACZ,WAAW;;;;;;;;;;;;;;;;;sBAkBd,WACG,QAAQ,MAAM,EAAE,WAAW,CAC3B,KAAK,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAE,SAAS,KAAK,CAC9C,KAAK,IAAI,IAAI,MACjB;;;;;;;;;;;;;;;;EAgBnB,gBAAgB;;;;;;;;;;;;;;;eAeH,YAAY,eAAe,YAAY;;;;;;AAOtD,SAAS,qBACP,aACA,qBACQ;AACR,KAAI,YAAY,WAAW,EACzB,QAAO;CAGT,IAAI,QAAQ;AAEZ,MAAK,MAAM,OAAO,aAAa;EAG7B,MAAM,cAAc,CAFJD,4BAA0B,IAAI,QAAQ,CAAC,KAAK,IAAI,EACtCC,gCAA8B,IAAI,YAAY,CAAC,KAAK,IAAI,CAClC,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI;AAE1E,WAAS,WAAW,IAAI,KAAK;AAC7B,WAAS,wCAAwC,YAAY;AAC7D,WAAS;AAGT,MAAI,IAAI,YAAY,SAAS,GAAG;GAC9B,MAAM,cAAc,qBAAqB,IAAI,aAAa,oBAAoB;AAC9E,OAAI,YACF,UAAS;;;AAKf,QAAO;;;;;AAMT,SAAS,kBAAkB,SAAqD;CAC9E,MAAM,UAAU,CAAC,GAAG,QAAQ,QAAQ;AAEpC,MAAK,MAAM,OAAO,QAAQ,YACxB,SAAQ,KAAK,GAAG,kBAAkB,IAAI,CAAC;CAIzC,MAAM,uBAAO,IAAI,KAAa;AAC9B,QAAO,QAAQ,QAAQ,QAAQ;AAC7B,MAAI,KAAK,IAAI,IAAI,KAAK,CACpB,QAAO;AAET,OAAK,IAAI,IAAI,KAAK;AAClB,SAAO;GACP;;;;;AAMJ,SAAgB,uBACd,SACA,SACkB;CAClB,MAAM,OAAO,sBAAsB,SAAS,QAAQ,YAAY;CAChE,MAAM,sBAAsB,QAAQ,uBAAuB;AAI3D,QAAO;EACL,QAHa,mBAAmB,KAAK,SAAS,QAAQ,aAAa,oBAAoB;EAIvF,OAAO;EACP,qBAAqB;;;UAGf,QAAQ,YAAY;;;EAG5B,QAAQ,YAAY,gEAAgE,QAAQ,YAAY;;;;EAIvG;;;;;;;;ACrLH,SAAS,cAAc,KAAqB;AAC1C,QAAO,IAAI,QAAQ,MAAM,MAAM,CAAC,QAAQ,MAAM,OAAM;;;;;AAMtD,SAAS,0BACP,SACA,aACA,WACA,qBACU;CACV,MAAM,cAAwB,EAAE;AAEhC,MAAK,MAAM,OAAO,SAAS;EACzB,IAAI,MAAM,eAAe;AAGzB,MAAI,UACF,QAAO,QAAQ,UAAU;AAI3B,SAAO,OAAO,IAAI;AAGlB,MAAI,IAAI,MACN,QAAO,OAAO,IAAI;AAIpB,MAAI,IAAI,WACN,QAAO;MAEP,QAAO;AAIT,MAAI,uBAAuB,IAAI,YAC7B,QAAO,QAAQ,cAAc,IAAI,YAAY,CAAC;AAGhD,cAAY,KAAK,IAAI;;AAGvB,QAAO;;;;;AAMT,SAAS,8BACP,aACA,aACA,WACA,qBACU;CACV,MAAM,cAAwB,EAAE;AAEhC,MAAK,MAAM,OAAO,aAAa;EAC7B,IAAI,MAAM,eAAe;AAGzB,MAAI,UACF,QAAO,QAAQ,UAAU;AAI3B,SAAO,UAAU,IAAI;AAGrB,MAAI,uBAAuB,IAAI,YAC7B,QAAO,QAAQ,cAAc,IAAI,YAAY,CAAC;AAGhD,cAAY,KAAK,IAAI;;AAGvB,QAAO;;;;;AAMT,SAAS,wBAAwB,aAA6B;AAC5D,QAAO;iCACwB,YAAY;;;;;;;;;kBAS3B,YAAY;;;;;;;;;;;;AAa9B,SAAS,2BACP,SACA,aACA,qBACA,iBAA2B,EAAE,EACnB;CACV,MAAM,cAAwB,EAAE;CAGhC,MAAM,kBACJ,eAAe,WAAW,IACtB,KACA,UAAU,YAAY,iBAAiB,eAAe,eAAe,SAAS;CAEpF,MAAM,sBACJ,eAAe,WAAW,IACtB,yBAAyB,gBACzB,UAAU,YAAY,iBAAiB,eAAe,eAAe,SAAS;AAGpF,aAAY,KACV,GAAG,0BACD,QAAQ,SACR,aACA,iBACA,oBACD,CACF;AAGD,KAAI,QAAQ,YAAY,SAAS,GAAG;AAClC,cAAY,KACV,GAAG,8BACD,QAAQ,aACR,aACA,qBACA,oBACD,CACF;AAGD,OAAK,MAAM,OAAO,QAAQ,YACxB,aAAY,KACV,GAAG,2BAA2B,KAAK,aAAa,qBAAqB,CACnE,GAAG,gBACH,IAAI,KACL,CAAC,CACH;;AAIL,QAAO;;;;;AAMT,SAAS,mBACP,SACA,aACA,qBACQ;CACR,MAAM,UAAU,wBAAwB,YAAY;CACpD,MAAM,cAAc,2BAA2B,SAAS,aAAa,oBAAoB;AAQzF,QAAO,yBAAyB,YAAY;;;EAG5C,QAAQ;;;iBAGO,YAAY;;;EAXA,CACzB,eAAe,YAAY,2CAC3B,eAAe,YAAY,2CAC5B,CAWkB,KAAK,KAAK,CAAC;;;EAG9B,YAAY,KAAK,KAAK,CAAC;;;;;;AAOzB,SAAgB,uBACd,SACA,SACkB;CAClB,MAAM,OAAO,sBAAsB,SAAS,QAAQ,YAAY;CAChE,MAAM,sBAAsB,QAAQ,uBAAuB;AAI3D,QAAO;EACL,QAHa,mBAAmB,KAAK,SAAS,QAAQ,aAAa,oBAAoB;EAIvF,OAAO;EACP,qBAAqB;;;EAGvB,QAAQ,YAAY;;;EAGpB,QAAQ,YAAY,gDAAgD,QAAQ,YAAY;;;;oCAItD,QAAQ,YAAY;EACrD;;;;;;;;AC9NH,SAAS,aAAa,KAAqB;AACzC,QAAO,IAAI,QAAQ,MAAM,KAAK,CAAC,QAAQ,OAAO,MAAM,CAAC,QAAQ,OAAO,MAAM;;;;;AAM5E,SAAS,oBAAoB,SAA8B,qBAAwC;CACjG,MAAM,QAAkB,EAAE;AAE1B,MAAK,MAAM,OAAO,SAAS;EACzB,MAAM,OAAO,uBAAuB,IAAI,cAAc,aAAa,IAAI,YAAY,GAAG;EACtF,MAAM,YAAY,IAAI,aAAa,MAAM;AAGzC,MAAI,KACF,OAAM,KAAK,MAAM,IAAI,QAAQ,GAAG,KAAK,GAAG,UAAU,GAAG;MAErD,OAAM,KAAK,MAAM,IAAI,UAAU,UAAU,GAAG;AAI9C,MAAI,IAAI,MACN,KAAI,KACF,OAAM,KAAK,KAAK,IAAI,MAAM,GAAG,KAAK,GAAG,UAAU,GAAG;MAElD,OAAM,KAAK,KAAK,IAAI,QAAQ,UAAU,GAAG;;AAK/C,QAAO;;;;;AAMT,SAAS,+BACP,aACA,qBACQ;AACR,KAAI,YAAY,WAAW,EACzB,QAAO;AAQT,QALc,YAAY,KAAK,QAAQ;EACrC,MAAM,OAAO,uBAAuB,IAAI,cAAc,aAAa,IAAI,YAAY,GAAG,IAAI;AAC1F,SAAO,IAAI,IAAI,KAAK,GAAG,KAAK;GAC5B,CAEW,KAAK,iBAAiB;;;;;AAMrC,SAAS,2BACP,SACA,aACA,qBACA,aAAuB,EAAE,EACjB;CACR,MAAM,cAAc,CAAC,GAAG,YAAY,QAAQ,KAAK;CACjD,MAAM,WACJ,WAAW,WAAW,IAClB,IAAI,gBACJ,IAAI,YAAY,GAAG,YAAY,MAAM,EAAE,CAAC,KAAK,IAAI;CAEvD,MAAM,cAAc,oBAAoB,QAAQ,SAAS,oBAAoB;CAC7E,MAAM,iBAAiB,QAAQ,YAAY,SAAS;CAEpD,IAAI,OAAO,GAAG,SAAS;AACvB,SAAQ;AAER,KAAI,gBAAgB;EAClB,MAAM,iBAAiB,+BAA+B,QAAQ,aAAa,oBAAoB;AAC/F,UAAQ;AACR,UAAQ;AACR,UAAQ,eAAe,eAAe;AACtC,UAAQ;;AAGV,SAAQ;AAER,KAAI,gBAAgB;AAClB,UAAQ;AACR,UAAQ;;AAGV,MAAK,MAAM,QAAQ,YACjB,SAAQ,WAAW,KAAK;AAG1B,SAAQ;AAER,SAAQ;AAER,KAAI,gBAAgB;AAClB,UAAQ;AACR,UAAQ;AACR,UAAQ;AACR,UAAQ;AACR,UAAQ;AACR,UAAQ;AAER,OAAK,MAAM,OAAO,QAAQ,aAAa;GACrC,MAAM,cAAc,IAAI,YAAY,GAAG,CAAC,GAAG,YAAY,MAAM,EAAE,EAAE,IAAI,KAAK,CAAC,KAAK,IAAI;AACpF,WAAQ,mBAAmB,IAAI,KAAK;AACpC,WAAQ,uBAAuB,YAAY;AAC3C,WAAQ;;AAGV,UAAQ;AACR,UAAQ;AACR,UAAQ;;AAGV,SAAQ;AAER,QAAO;;;;;AAMT,SAAS,2BACP,SACA,aACA,qBACA,aAAuB,EAAE,EACf;CACV,MAAM,YAAsB,EAAE;AAG9B,WAAU,KAAK,2BAA2B,SAAS,aAAa,qBAAqB,WAAW,CAAC;CAGjG,MAAM,cAAc,WAAW,WAAW,IAAI,CAAC,QAAQ,KAAK,GAAG,CAAC,GAAG,YAAY,QAAQ,KAAK;AAE5F,MAAK,MAAM,OAAO,QAAQ,YACxB,WAAU,KACR,GAAG,2BAA2B,KAAK,aAAa,qBAAqB,YAAY,CAClF;AAGH,QAAO;;;;;AAMT,SAAS,kBACP,SACA,aACA,qBACQ;AAGR,QAAO,YAAY,YAAY;;uBAEV,YAAY;;;EAJf,2BAA2B,SAAS,aAAa,oBAAoB,CAO7E,KAAK,KAAK,CAAC;;WAEZ,YAAY,GAAG,YAAY;;;;;;AAOtC,SAAgB,sBACd,SACA,SACkB;CAClB,MAAM,OAAO,sBAAsB,SAAS,QAAQ,YAAY;CAChE,MAAM,sBAAsB,QAAQ,uBAAuB;AAI3D,QAAO;EACL,QAHa,kBAAkB,KAAK,SAAS,QAAQ,aAAa,oBAAoB;EAItF,OAAO;EACP,qBAAqB;;;UAGf,QAAQ,YAAY;;;EAG5B,QAAQ,YAAY,wCAAwC,QAAQ,YAAY;;;;;;;;EAQ/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnKH,SAAgB,mBACd,SACA,SACkB;AAClB,SAAQ,QAAQ,OAAhB;EACE,KAAK,OACH,QAAO,uBAAuB,SAAS,QAAQ;EACjD,KAAK,MACH,QAAO,sBAAsB,SAAS,QAAQ;EAChD,KAAK,OACH,QAAO,uBAAuB,SAAS,QAAQ;EACjD,QACE,OAAM,IAAI,MAAM,sBAAsB,QAAQ,QAAQ;;;;;;AAO5D,SAAgB,qBAAkC;AAChD,QAAO;EAAC;EAAQ;EAAO;EAAO;;;;;AAMhC,SAAgB,cAAgC;CAE9C,MAAM,aADQ,QAAQ,IAAI,SAAS,IACX,MAAM,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI;AAE3D,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;AAET,KAAI,UAAU,SAAS,MAAM,CAC3B,QAAO;AAET,KAAI,UAAU,SAAS,OAAO,CAC5B,QAAO;AAGT,QAAO;;;;;AAMT,MAAM,uBAAuBC,MAAE,OAAO;CACpC,OAAOC,6BACLD,MACG,KAAK;EAAC;EAAQ;EAAO;EAAO,CAAC,CAC7B,UAAU,CACV,SAAS,8CAA8C,EAC1D;EACE,YAAY;EACZ,aAAa;EACb,aAAa;EACd,CACF;CACD,cAAcC,6BAAID,MAAE,SAAS,CAAC,QAAQ,MAAM,EAAE;EAC5C,OAAO;EACP,aAAa;EACd,CAAC;CACH,CAAC;;;;;;;;;;;;;;;;AAmBF,SAAgB,wBACd,aACA,aAE2D;AAC3D,QAAOE,8BAAc;EACnB,MAAM;EACN,aAAa;EACb,MAAM;EACN,IAAI,MAAM;GAER,MAAM,YAAY,KAAK,SAAS,aAAa;AAE7C,OAAI,CAAC,WAAW;AACd,YAAQ,MAAM,sEAAsE;AACpF,YAAQ,WAAW;AACnB;;GAGF,MAAM,SAAS,mBAAmB,aAAa;IAC7C,OAAO;IACP;IACA,qBAAqB;IACtB,CAAC;AAEF,OAAI,KAAK,aACP,SAAQ,IAAI,OAAO,oBAAoB;OAEvC,SAAQ,IAAI,OAAO,OAAO;;EAG/B,CAAC;;;;;;;;;;;;;;;;AAiBJ,SAAgB,sBACd,aACA,aAC4D;AAC5D,QAAO,EACL,YAAY,wBAAwB,aAAa,YAAY,EAC9D"}
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 = withCompletionCommand(\n * defineCommand({\n * name: \"mycli\",\n * subCommands: { ... },\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)\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 const resolvedProgramName = programName ?? rootCommand.name;\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: resolvedProgramName,\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 * Wrap a command with a completion subcommand\n *\n * This avoids circular references that occur when a command references itself\n * in its subCommands (e.g., for completion generation).\n *\n * @param command - The command to wrap\n * @param programName - Override the program name (defaults to command.name)\n * @returns A new command with the completion subcommand added\n *\n * @example\n * ```typescript\n * const mainCommand = withCompletionCommand(\n * defineCommand({\n * name: \"mycli\",\n * subCommands: { ... },\n * }),\n * );\n * ```\n */\nexport function withCompletionCommand<T extends AnyCommand>(command: T, programName?: string): T {\n const wrappedCommand = {\n ...command,\n } as T;\n\n wrappedCommand.subCommands = {\n ...command.subCommands,\n completion: createCompletionCommand(wrappedCommand, programName),\n };\n\n return wrappedCommand;\n}\n"],"mappings":"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"}
@@ -123,29 +123,33 @@ type CompletionArgs = z.infer<typeof completionArgsSchema>;
123
123
  * const mainCommand = defineCommand({
124
124
  * name: "mycli",
125
125
  * subCommands: {
126
- * completion: createCompletionCommand(mainCommand, "mycli")
126
+ * completion: createCompletionCommand(mainCommand)
127
127
  * }
128
128
  * });
129
129
  * ```
130
130
  */
131
- declare function createCompletionCommand(rootCommand: AnyCommand, programName: string): Command<typeof completionArgsSchema, CompletionArgs, any>;
131
+ declare function createCompletionCommand(rootCommand: AnyCommand, programName?: string): Command<typeof completionArgsSchema, CompletionArgs, any>;
132
132
  /**
133
- * Helper to add completion command to an existing command's subCommands
133
+ * Wrap a command with a completion subcommand
134
+ *
135
+ * This avoids circular references that occur when a command references itself
136
+ * in its subCommands (e.g., for completion generation).
137
+ *
138
+ * @param command - The command to wrap
139
+ * @param programName - Override the program name (defaults to command.name)
140
+ * @returns A new command with the completion subcommand added
134
141
  *
135
142
  * @example
136
143
  * ```typescript
137
- * const command = defineCommand({
138
- * name: "mycli",
139
- * subCommands: {
140
- * ...withCompletionCommand(command, "mycli"),
141
- * // other subcommands
142
- * }
143
- * });
144
+ * const mainCommand = withCompletionCommand(
145
+ * defineCommand({
146
+ * name: "mycli",
147
+ * subCommands: { ... },
148
+ * }),
149
+ * );
144
150
  * ```
145
151
  */
146
- declare function withCompletionCommand(rootCommand: AnyCommand, programName: string): {
147
- completion: ReturnType<typeof createCompletionCommand>;
148
- };
152
+ declare function withCompletionCommand<T extends AnyCommand>(command: T, programName?: string): T;
149
153
  //#endregion
150
154
  export { type CompletableOption, type CompletableSubcommand, type CompletionData, type CompletionGenerator, type CompletionOptions, type CompletionResult, type ShellType, createCompletionCommand, detectShell, extractCompletionData, extractPositionals, generateCompletion, getSupportedShells, withCompletionCommand };
151
155
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/completion/types.ts","../../src/completion/extractor.ts","../../src/completion/index.ts"],"mappings":";;;;AASA;;;AAAA,KAAY,SAAA;;AAKZ;;UAAiB,iBAAA;EAEC;EAAhB,KAAA,EAAO,SAAA;EAAA;EAEP,WAAA;EAEA;EAAA,kBAAA;EAEmB;EAAnB,mBAAA;AAAA;;;;UAMe,iBAAA;EAIf;EAFA,IAAA;EAMA;EAJA,OAAA;EAQA;EANA,KAAA;EAQQ;EANR,WAAA;EAYe;EAVf,UAAA;;EAEA,SAAA;EAUA;EARA,QAAA;AAAA;;;;UAMe,qBAAA;EAQW;EAN1B,IAAA;EAY6B;EAV7B,WAAA;EAgBgC;EAdhC,WAAA,EAAa,qBAAA;EAUJ;EART,OAAA,EAAS,iBAAA;AAAA;;;;UAMM,cAAA;EAYgB;EAV/B,OAAA,EAAS,qBAAA;EAcO;EAZhB,WAAA;EAYA;EAVA,aAAA,EAAe,iBAAA;AAAA;;;AAkBjB;UAZiB,gBAAA;;EAEf,MAAA;EAYS;EAVT,KAAA,EAAO,SAAA;EAWY;EATnB,mBAAA;AAAA;;;;KAMU,mBAAA,IACV,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,KACN,gBAAA;;;;;;iBChDW,kBAAA,CAAmB,OAAA,EAAS,UAAA,GAAa,iBAAA;;;;iBA4CzC,qBAAA,CAAsB,OAAA,EAAS,UAAA,EAAY,WAAA,WAAsB,cAAA;;;;;;iBClCjE,kBAAA,CACd,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,GACR,gBAAA;;;;iBAgBa,kBAAA,CAAA,GAAsB,SAAA;;;;iBAOtB,WAAA,CAAA,GAAe,SAAA;;;;cAoBzB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;KAkBrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;;;AFzCrC;;;;;;;;;;AAYA;;;iBE8CgB,uBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA,WAEC,OAAA,QAAe,oBAAA,EAAsB,cAAA;;;;;;;;;;;;;;;iBA4CxB,qBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA;EACG,UAAA,EAAY,UAAA,QAAkB,uBAAA;AAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/completion/types.ts","../../src/completion/extractor.ts","../../src/completion/index.ts"],"mappings":";;;;AASA;;;AAAA,KAAY,SAAA;;AAKZ;;UAAiB,iBAAA;EAEC;EAAhB,KAAA,EAAO,SAAA;EAAA;EAEP,WAAA;EAEA;EAAA,kBAAA;EAEmB;EAAnB,mBAAA;AAAA;;;;UAMe,iBAAA;EAIf;EAFA,IAAA;EAMA;EAJA,OAAA;EAQA;EANA,KAAA;EAQQ;EANR,WAAA;EAYe;EAVf,UAAA;;EAEA,SAAA;EAUA;EARA,QAAA;AAAA;;;;UAMe,qBAAA;EAQW;EAN1B,IAAA;EAY6B;EAV7B,WAAA;EAgBgC;EAdhC,WAAA,EAAa,qBAAA;EAUJ;EART,OAAA,EAAS,iBAAA;AAAA;;;;UAMM,cAAA;EAYgB;EAV/B,OAAA,EAAS,qBAAA;EAcO;EAZhB,WAAA;EAYA;EAVA,aAAA,EAAe,iBAAA;AAAA;;;AAkBjB;UAZiB,gBAAA;;EAEf,MAAA;EAYS;EAVT,KAAA,EAAO,SAAA;EAWY;EATnB,mBAAA;AAAA;;;;KAMU,mBAAA,IACV,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,KACN,gBAAA;;;;;;iBChDW,kBAAA,CAAmB,OAAA,EAAS,UAAA,GAAa,iBAAA;;;;iBA4CzC,qBAAA,CAAsB,OAAA,EAAS,UAAA,EAAY,WAAA,WAAsB,cAAA;;;;;;iBClCjE,kBAAA,CACd,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,GACR,gBAAA;;;;iBAgBa,kBAAA,CAAA,GAAsB,SAAA;;;;iBAOtB,WAAA,CAAA,GAAe,SAAA;;;;cAoBzB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;KAkBrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;;;AFzCrC;;;;;;;;;;AAYA;;;iBE8CgB,uBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA,YAEC,OAAA,QAAe,oBAAA,EAAsB,cAAA;;;;;;;;;;;;;;;AD/FxC;;;;;;iBCkJgB,qBAAA,WAAgC,UAAA,CAAA,CAAY,OAAA,EAAS,CAAA,EAAG,WAAA,YAAuB,CAAA"}
@@ -123,29 +123,33 @@ type CompletionArgs = z.infer<typeof completionArgsSchema>;
123
123
  * const mainCommand = defineCommand({
124
124
  * name: "mycli",
125
125
  * subCommands: {
126
- * completion: createCompletionCommand(mainCommand, "mycli")
126
+ * completion: createCompletionCommand(mainCommand)
127
127
  * }
128
128
  * });
129
129
  * ```
130
130
  */
131
- declare function createCompletionCommand(rootCommand: AnyCommand, programName: string): Command<typeof completionArgsSchema, CompletionArgs, any>;
131
+ declare function createCompletionCommand(rootCommand: AnyCommand, programName?: string): Command<typeof completionArgsSchema, CompletionArgs, any>;
132
132
  /**
133
- * Helper to add completion command to an existing command's subCommands
133
+ * Wrap a command with a completion subcommand
134
+ *
135
+ * This avoids circular references that occur when a command references itself
136
+ * in its subCommands (e.g., for completion generation).
137
+ *
138
+ * @param command - The command to wrap
139
+ * @param programName - Override the program name (defaults to command.name)
140
+ * @returns A new command with the completion subcommand added
134
141
  *
135
142
  * @example
136
143
  * ```typescript
137
- * const command = defineCommand({
138
- * name: "mycli",
139
- * subCommands: {
140
- * ...withCompletionCommand(command, "mycli"),
141
- * // other subcommands
142
- * }
143
- * });
144
+ * const mainCommand = withCompletionCommand(
145
+ * defineCommand({
146
+ * name: "mycli",
147
+ * subCommands: { ... },
148
+ * }),
149
+ * );
144
150
  * ```
145
151
  */
146
- declare function withCompletionCommand(rootCommand: AnyCommand, programName: string): {
147
- completion: ReturnType<typeof createCompletionCommand>;
148
- };
152
+ declare function withCompletionCommand<T extends AnyCommand>(command: T, programName?: string): T;
149
153
  //#endregion
150
154
  export { type CompletableOption, type CompletableSubcommand, type CompletionData, type CompletionGenerator, type CompletionOptions, type CompletionResult, type ShellType, createCompletionCommand, detectShell, extractCompletionData, extractPositionals, generateCompletion, getSupportedShells, withCompletionCommand };
151
155
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/completion/types.ts","../../src/completion/extractor.ts","../../src/completion/index.ts"],"mappings":";;;;AASA;;;AAAA,KAAY,SAAA;;AAKZ;;UAAiB,iBAAA;EAEC;EAAhB,KAAA,EAAO,SAAA;EAAA;EAEP,WAAA;EAEA;EAAA,kBAAA;EAEmB;EAAnB,mBAAA;AAAA;;;;UAMe,iBAAA;EAIf;EAFA,IAAA;EAMA;EAJA,OAAA;EAQA;EANA,KAAA;EAQQ;EANR,WAAA;EAYe;EAVf,UAAA;;EAEA,SAAA;EAUA;EARA,QAAA;AAAA;;;;UAMe,qBAAA;EAQW;EAN1B,IAAA;EAY6B;EAV7B,WAAA;EAgBgC;EAdhC,WAAA,EAAa,qBAAA;EAUJ;EART,OAAA,EAAS,iBAAA;AAAA;;;;UAMM,cAAA;EAYgB;EAV/B,OAAA,EAAS,qBAAA;EAcO;EAZhB,WAAA;EAYA;EAVA,aAAA,EAAe,iBAAA;AAAA;;;AAkBjB;UAZiB,gBAAA;;EAEf,MAAA;EAYS;EAVT,KAAA,EAAO,SAAA;EAWY;EATnB,mBAAA;AAAA;;;;KAMU,mBAAA,IACV,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,KACN,gBAAA;;;;;;iBChDW,kBAAA,CAAmB,OAAA,EAAS,UAAA,GAAa,iBAAA;;;;iBA4CzC,qBAAA,CAAsB,OAAA,EAAS,UAAA,EAAY,WAAA,WAAsB,cAAA;;;;;;iBClCjE,kBAAA,CACd,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,GACR,gBAAA;;;;iBAgBa,kBAAA,CAAA,GAAsB,SAAA;;;;iBAOtB,WAAA,CAAA,GAAe,SAAA;;;;cAoBzB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;KAkBrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;;;AFzCrC;;;;;;;;;;AAYA;;;iBE8CgB,uBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA,WAEC,OAAA,QAAe,oBAAA,EAAsB,cAAA;;;;;;;;;;;;;;;iBA4CxB,qBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA;EACG,UAAA,EAAY,UAAA,QAAkB,uBAAA;AAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/completion/types.ts","../../src/completion/extractor.ts","../../src/completion/index.ts"],"mappings":";;;;AASA;;;AAAA,KAAY,SAAA;;AAKZ;;UAAiB,iBAAA;EAEC;EAAhB,KAAA,EAAO,SAAA;EAAA;EAEP,WAAA;EAEA;EAAA,kBAAA;EAEmB;EAAnB,mBAAA;AAAA;;;;UAMe,iBAAA;EAIf;EAFA,IAAA;EAMA;EAJA,OAAA;EAQA;EANA,KAAA;EAQQ;EANR,WAAA;EAYe;EAVf,UAAA;;EAEA,SAAA;EAUA;EARA,QAAA;AAAA;;;;UAMe,qBAAA;EAQW;EAN1B,IAAA;EAY6B;EAV7B,WAAA;EAgBgC;EAdhC,WAAA,EAAa,qBAAA;EAUJ;EART,OAAA,EAAS,iBAAA;AAAA;;;;UAMM,cAAA;EAYgB;EAV/B,OAAA,EAAS,qBAAA;EAcO;EAZhB,WAAA;EAYA;EAVA,aAAA,EAAe,iBAAA;AAAA;;;AAkBjB;UAZiB,gBAAA;;EAEf,MAAA;EAYS;EAVT,KAAA,EAAO,SAAA;EAWY;EATnB,mBAAA;AAAA;;;;KAMU,mBAAA,IACV,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,KACN,gBAAA;;;;;;iBChDW,kBAAA,CAAmB,OAAA,EAAS,UAAA,GAAa,iBAAA;;;;iBA4CzC,qBAAA,CAAsB,OAAA,EAAS,UAAA,EAAY,WAAA,WAAsB,cAAA;;;;;;iBClCjE,kBAAA,CACd,OAAA,EAAS,UAAA,EACT,OAAA,EAAS,iBAAA,GACR,gBAAA;;;;iBAgBa,kBAAA,CAAA,GAAsB,SAAA;;;;iBAOtB,WAAA,CAAA,GAAe,SAAA;;;;cAoBzB,oBAAA,EAAoB,CAAA,CAAA,SAAA;;;;;;;;KAkBrB,cAAA,GAAiB,CAAA,CAAE,KAAA,QAAa,oBAAA;;;AFzCrC;;;;;;;;;;AAYA;;;iBE8CgB,uBAAA,CACd,WAAA,EAAa,UAAA,EACb,WAAA,YAEC,OAAA,QAAe,oBAAA,EAAsB,cAAA;;;;;;;;;;;;;;;AD/FxC;;;;;;iBCkJgB,qBAAA,WAAgC,UAAA,CAAA,CAAY,OAAA,EAAS,CAAA,EAAG,WAAA,YAAuB,CAAA"}
@@ -471,12 +471,12 @@ source ~/.zshrc`
471
471
  * console.log(result.script);
472
472
  *
473
473
  * // Or add a completion subcommand to your CLI
474
- * const mainCommand = defineCommand({
475
- * name: "mycli",
476
- * subCommands: {
477
- * completion: createCompletionCommand(myCommand, "mycli")
478
- * }
479
- * });
474
+ * const mainCommand = withCompletionCommand(
475
+ * defineCommand({
476
+ * name: "mycli",
477
+ * subCommands: { ... },
478
+ * }),
479
+ * );
480
480
  * ```
481
481
  */
482
482
  /**
@@ -538,12 +538,13 @@ const completionArgsSchema = z.object({
538
538
  * const mainCommand = defineCommand({
539
539
  * name: "mycli",
540
540
  * subCommands: {
541
- * completion: createCompletionCommand(mainCommand, "mycli")
541
+ * completion: createCompletionCommand(mainCommand)
542
542
  * }
543
543
  * });
544
544
  * ```
545
545
  */
546
546
  function createCompletionCommand(rootCommand, programName) {
547
+ const resolvedProgramName = programName ?? rootCommand.name;
547
548
  return defineCommand({
548
549
  name: "completion",
549
550
  description: "Generate shell completion script",
@@ -557,7 +558,7 @@ function createCompletionCommand(rootCommand, programName) {
557
558
  }
558
559
  const result = generateCompletion(rootCommand, {
559
560
  shell: shellType,
560
- programName,
561
+ programName: resolvedProgramName,
561
562
  includeDescriptions: true
562
563
  });
563
564
  if (args.instructions) console.log(result.installInstructions);
@@ -566,21 +567,32 @@ function createCompletionCommand(rootCommand, programName) {
566
567
  });
567
568
  }
568
569
  /**
569
- * Helper to add completion command to an existing command's subCommands
570
+ * Wrap a command with a completion subcommand
571
+ *
572
+ * This avoids circular references that occur when a command references itself
573
+ * in its subCommands (e.g., for completion generation).
574
+ *
575
+ * @param command - The command to wrap
576
+ * @param programName - Override the program name (defaults to command.name)
577
+ * @returns A new command with the completion subcommand added
570
578
  *
571
579
  * @example
572
580
  * ```typescript
573
- * const command = defineCommand({
574
- * name: "mycli",
575
- * subCommands: {
576
- * ...withCompletionCommand(command, "mycli"),
577
- * // other subcommands
578
- * }
579
- * });
581
+ * const mainCommand = withCompletionCommand(
582
+ * defineCommand({
583
+ * name: "mycli",
584
+ * subCommands: { ... },
585
+ * }),
586
+ * );
580
587
  * ```
581
588
  */
582
- function withCompletionCommand(rootCommand, programName) {
583
- return { completion: createCompletionCommand(rootCommand, programName) };
589
+ function withCompletionCommand(command, programName) {
590
+ const wrappedCommand = { ...command };
591
+ wrappedCommand.subCommands = {
592
+ ...command.subCommands,
593
+ completion: createCompletionCommand(wrappedCommand, programName)
594
+ };
595
+ return wrappedCommand;
584
596
  }
585
597
 
586
598
  //#endregion
@@ -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\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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"}
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 = withCompletionCommand(\n * defineCommand({\n * name: \"mycli\",\n * subCommands: { ... },\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)\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 const resolvedProgramName = programName ?? rootCommand.name;\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: resolvedProgramName,\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 * Wrap a command with a completion subcommand\n *\n * This avoids circular references that occur when a command references itself\n * in its subCommands (e.g., for completion generation).\n *\n * @param command - The command to wrap\n * @param programName - Override the program name (defaults to command.name)\n * @returns A new command with the completion subcommand added\n *\n * @example\n * ```typescript\n * const mainCommand = withCompletionCommand(\n * defineCommand({\n * name: \"mycli\",\n * subCommands: { ... },\n * }),\n * );\n * ```\n */\nexport function withCompletionCommand<T extends AnyCommand>(command: T, programName?: string): T {\n const wrappedCommand = {\n ...command,\n } as T;\n\n wrappedCommand.subCommands = {\n ...command.subCommands,\n completion: createCompletionCommand(wrappedCommand, programName),\n };\n\n return wrappedCommand;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "politty",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "A lightweight CLI framework inspired by citty with zod v4 registry integration for type-safe metadata management",
5
5
  "keywords": [
6
6
  "argument-parser",
@@ -68,16 +68,16 @@
68
68
  "devDependencies": {
69
69
  "@changesets/cli": "2.29.8",
70
70
  "@quansync/fs": "1.0.0",
71
- "@types/node": "25.2.0",
72
- "@typescript/native-preview": "7.0.0-dev.20260204.1",
71
+ "@types/node": "25.2.1",
72
+ "@typescript/native-preview": "7.0.0-dev.20260206.1",
73
73
  "@vitest/coverage-v8": "4.0.18",
74
- "knip": "5.83.0",
74
+ "knip": "5.83.1",
75
75
  "lefthook": "2.1.0",
76
76
  "organize-imports-cli": "0.10.0",
77
77
  "oxfmt": "0.28.0",
78
78
  "oxlint": "1.43.0",
79
79
  "quansync": "1.0.0",
80
- "tsdown": "0.20.2",
80
+ "tsdown": "0.20.3",
81
81
  "typescript": "5.9.3",
82
82
  "vitest": "4.0.18",
83
83
  "zod": "4.3.6"