{"version":3,"file":"bash.mjs","names":[],"sources":["../../../src/codegen/parsers/bash.ts"],"sourcesContent":["import type { CommandMeta, FieldMeta } from '../types.ts';\n\n/**\n * Parse bash completion scripts into CommandMeta.\n *\n * Bash completions typically use `complete -F <func> <command>` and define\n * a function that sets COMPREPLY. Common patterns:\n *\n *   local commands=\"init build deploy\"\n *   local args=\"--verbose --output --format\"\n *   case \"$prev\" in --format) COMPREPLY=($(compgen -W \"json yaml toml\" ...)) ;;\n *   COMPREPLY=($(compgen -W \"$commands\" ...))\n *   COMPREPLY=($(compgen -W \"$args\" ...))\n */\nexport function parseBashCompletions(text: string): CommandMeta {\n  const result: CommandMeta = {\n    name: '',\n    arguments: [],\n    subcommands: [],\n  };\n\n  // Detect command name from `complete -F _func <command>` or `complete -o ... -F _func <command>`\n  const completeMatch = text.match(/complete\\s+(?:[^-]|-[^F])*-F\\s+\\S+\\s+(\\S+)/);\n  if (completeMatch) {\n    result.name = completeMatch[1]!;\n  }\n\n  // Fallback: detect from marker comments like ###-begin-<name>-completion-###\n  if (!result.name) {\n    const markerMatch = text.match(/###-begin-(\\S+)-completion-###/);\n    if (markerMatch) {\n      result.name = markerMatch[1]!;\n    }\n  }\n\n  // Join continuation lines for easier parsing\n  const joined = text.replace(/\\\\\\n\\s*/g, ' ');\n\n  // Collect variable values: local commands=\"...\" or local args=\"...\"\n  const variables = extractVariables(joined);\n\n  // Extract subcommand names from commands variable or compgen -W \"cmd1 cmd2\"\n  const commandWords = variables.get('commands') ?? variables.get('cmds') ?? variables.get('subcommands');\n  if (commandWords) {\n    for (const name of splitWords(commandWords)) {\n      result.subcommands!.push({ name });\n    }\n  }\n\n  // Extract option names from args/opts/options variable\n  const argWords = variables.get('args') ?? variables.get('opts') ?? variables.get('options') ?? variables.get('flags');\n  const optionNames = new Set<string>();\n\n  if (argWords) {\n    for (const word of splitWords(argWords)) {\n      if (word.startsWith('-')) {\n        optionNames.add(word);\n      }\n    }\n  }\n\n  // Also scan for compgen -W patterns not tied to a case statement\n  const compgenRegex = /compgen\\s+-W\\s+[\"']([^\"']+)[\"']/g;\n  let compgenMatch: RegExpExecArray | null;\n  while ((compgenMatch = compgenRegex.exec(joined)) !== null) {\n    // Skip variable references like $args, $commands\n    if (compgenMatch[1]!.startsWith('$')) continue;\n    for (const word of splitWords(compgenMatch[1]!)) {\n      if (word.startsWith('-')) {\n        optionNames.add(word);\n      }\n    }\n  }\n\n  // Parse case statement for option value completions (enum detection)\n  const enumMap = parseCaseStatement(joined);\n\n  // Build argument fields\n  const seenArgs = new Set<string>();\n\n  for (const rawName of optionNames) {\n    // Skip builtins\n    if (rawName === '--help' || rawName === '-h' || rawName === '--version' || rawName === '-V') continue;\n\n    const name = rawName.replace(/^-+/, '').replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n    if (!name || seenArgs.has(name)) continue;\n    seenArgs.add(name);\n\n    // Check if this option has enum values from case statement\n    const enumValues = enumMap.get(rawName);\n\n    const isShort = rawName.startsWith('-') && !rawName.startsWith('--') && rawName.length === 2;\n    const field: FieldMeta = {\n      name,\n      type: enumValues ? 'enum' : 'string',\n      enumValues,\n      ambiguous: !enumValues,\n    };\n\n    // If there's a corresponding long-form, record alias\n    if (isShort) {\n      field.aliases = [rawName];\n    }\n\n    result.arguments!.push(field);\n  }\n\n  if (result.arguments!.length === 0) delete result.arguments;\n  if (result.subcommands!.length === 0) delete result.subcommands;\n\n  return result;\n}\n\n/**\n * Extract variable assignments: `local VAR=\"value\"`, `VAR=\"value\"`, `local VAR='value'`\n */\nfunction extractVariables(text: string): Map<string, string> {\n  const vars = new Map<string, string>();\n  const regex = /(?:local\\s+)?(\\w+)=[\"']([^\"']+)[\"']/g;\n  let match: RegExpExecArray | null;\n\n  while ((match = regex.exec(text)) !== null) {\n    vars.set(match[1]!, match[2]!);\n  }\n\n  return vars;\n}\n\n/**\n * Parse case statements to find option → enum value mappings.\n *\n * Matches patterns like:\n *   case \"$prev\" in\n *     --format) COMPREPLY=($(compgen -W \"json yaml toml\" ...)) ;;\n *     --env|--environment) COMPREPLY=($(compgen -W \"dev staging prod\" ...)) ;;\n */\nfunction parseCaseStatement(text: string): Map<string, string[]> {\n  const result = new Map<string, string[]>();\n\n  // Find case blocks on $prev or similar variables\n  const caseRegex = /case\\s+[^i]*\\bin\\b\\s*([\\s\\S]*?)esac/g;\n  let caseMatch: RegExpExecArray | null;\n\n  while ((caseMatch = caseRegex.exec(text)) !== null) {\n    const body = caseMatch[1]!;\n\n    // Split into branches by ;; delimiter\n    const branches = body.split(';;');\n    for (const branch of branches) {\n      // Match pattern: --opt1|--opt2) ... compgen -W \"values\" ...\n      const patternMatch = branch.match(/^\\s*([-\\w|]+)\\)/);\n      if (!patternMatch) continue;\n\n      // Find compgen -W \"values\" within this branch\n      const compgenMatch = branch.match(/compgen\\s+-W\\s+[\"']([^\"']+)[\"']/);\n      if (!compgenMatch) continue;\n\n      const values = compgenMatch[1]!;\n      const words = splitWords(values).filter((w) => !w.startsWith('$'));\n      if (words.length === 0) continue;\n\n      for (const pattern of patternMatch[1]!.split('|')) {\n        const trimmed = pattern.trim();\n        if (trimmed.startsWith('-')) {\n          result.set(trimmed, words);\n        }\n      }\n    }\n  }\n\n  return result;\n}\n\n/**\n * Split a space-separated word list, filtering empty strings.\n */\nfunction splitWords(text: string): string[] {\n  return text.split(/\\s+/).filter(Boolean);\n}\n"],"mappings":"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"}