{"version":3,"file":"zsh.mjs","names":[],"sources":["../../../src/codegen/parsers/zsh.ts"],"sourcesContent":["import type { CommandMeta, FieldMeta } from '../types.ts';\n\n/**\n * Parse zsh completion function definitions into CommandMeta.\n *\n * Zsh completions typically use _arguments or compadd:\n *   _arguments \\\n *     '-v[verbose mode]' \\\n *     '--output=[output file]:filename:_files' \\\n *     '1:command:(start stop restart)'\n */\nexport function parseZshCompletions(text: string): CommandMeta {\n  const result: CommandMeta = {\n    name: '',\n    arguments: [],\n    positionals: [],\n    subcommands: [],\n  };\n\n  // Try to detect command name from function name: _command() or #compdef command\n  const compdefMatch = text.match(/#compdef\\s+(\\S+)/);\n  if (compdefMatch) {\n    result.name = compdefMatch[1]!;\n  } else {\n    const funcMatch = text.match(/^_(\\w+)\\s*\\(\\)/m);\n    if (funcMatch) {\n      result.name = funcMatch[1]!;\n    }\n  }\n\n  // Find _arguments blocks\n  const argumentsBlocks = findArgumentsBlocks(text);\n\n  for (const block of argumentsBlocks) {\n    const specs = parseArgumentSpecs(block);\n    for (const spec of specs) {\n      if (spec.positional) {\n        result.positionals!.push(spec);\n      } else {\n        result.arguments!.push(spec);\n      }\n    }\n  }\n\n  // Find subcommand definitions from case statements or _describe\n  const subcommands = findSubcommands(text);\n  result.subcommands!.push(...subcommands);\n\n  if (result.arguments!.length === 0) delete result.arguments;\n  if (result.positionals!.length === 0) delete result.positionals;\n  if (result.subcommands!.length === 0) delete result.subcommands;\n\n  return result;\n}\n\n/**\n * Extract _arguments blocks from zsh completion text.\n * Handles backslash continuation lines.\n */\nfunction findArgumentsBlocks(text: string): string[] {\n  const blocks: string[] = [];\n\n  // Join continuation lines\n  const joined = text.replace(/\\\\\\n\\s*/g, ' ');\n  const lines = joined.split('\\n');\n\n  for (const line of lines) {\n    const match = line.match(/_arguments\\s+(.+)/);\n    if (match) {\n      blocks.push(match[1]!);\n    }\n  }\n\n  return blocks;\n}\n\n/**\n * Parse individual argument specs from an _arguments line.\n */\nfunction parseArgumentSpecs(block: string): FieldMeta[] {\n  const results: FieldMeta[] = [];\n\n  // Split into individual specs (quoted strings)\n  const specs = extractQuotedStrings(block);\n\n  for (const spec of specs) {\n    const field = parseZshSpec(spec);\n    if (field) results.push(field);\n  }\n\n  return results;\n}\n\n/**\n * Extract single-quoted strings from an _arguments block.\n */\nfunction extractQuotedStrings(text: string): string[] {\n  const strings: string[] = [];\n  const regex = /'([^']+)'/g;\n  let match: RegExpExecArray | null;\n\n  while ((match = regex.exec(text)) !== null) {\n    strings.push(match[1]!);\n  }\n\n  return strings;\n}\n\n/**\n * Parse a single zsh argument spec.\n *\n * Formats:\n *   '-v[verbose mode]'                              → boolean flag\n *   '--output=[output file]:filename:_files'         → string with value\n *   '(-v --verbose)'{-v,--verbose}'[verbose mode]'   → flag with aliases\n *   '*--flag[repeatable]'                            → array\n *   '1:command:(start stop restart)'                 → positional enum\n *   ':filename:_files'                               → positional\n */\nfunction parseZshSpec(spec: string): FieldMeta | null {\n  // Positional argument: 'N:description:action' or ':description:action'\n  const positionalMatch = spec.match(/^(\\d+)?:([^:]*):(.*)$/);\n  if (positionalMatch) {\n    const description = positionalMatch[2] || undefined;\n\n    // Check for enum values in (val1 val2 val3)\n    const enumMatch = positionalMatch[3]?.match(/^\\(([^)]+)\\)$/);\n    if (enumMatch) {\n      const values = enumMatch[1]!.split(/\\s+/);\n      return {\n        name: description?.toLowerCase().replace(/\\s+/g, '_') || `arg${positionalMatch[1] || '0'}`,\n        type: 'enum',\n        enumValues: values,\n        description,\n        positional: true,\n      };\n    }\n\n    return {\n      name: description?.toLowerCase().replace(/\\s+/g, '_') || `arg${positionalMatch[1] || '0'}`,\n      type: 'string',\n      description,\n      positional: true,\n      ambiguous: true,\n    };\n  }\n\n  // Flag argument\n  const repeatable = spec.startsWith('*');\n  const flagSpec = repeatable ? spec.slice(1) : spec;\n\n  // Extract flag name and description\n  // Pattern: --flag=[description]:value_description:action\n  // Pattern: -f[description]\n  const flagMatch = flagSpec.match(/^(-{1,2}[\\w-]+)(?:=?)(?:\\[([^\\]]*)\\])?(?::([^:]*):?(.*))?$/);\n  if (!flagMatch) return null;\n\n  const rawName = flagMatch[1]!;\n  const description = flagMatch[2] || undefined;\n  const valueName = flagMatch[3] || undefined;\n\n  const name = rawName.replace(/^-+/, '').replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());\n  const hasValue = rawName.includes('=') || !!valueName;\n  let type: FieldMeta['type'] = hasValue ? 'string' : 'boolean';\n\n  if (repeatable) type = 'array';\n\n  // Check for enum values\n  let enumValues: string[] | undefined;\n  if (flagMatch[4]) {\n    const enumMatch = flagMatch[4].match(/^\\(([^)]+)\\)$/);\n    if (enumMatch) {\n      enumValues = enumMatch[1]!.split(/\\s+/);\n      type = 'enum';\n    }\n  }\n\n  return {\n    name,\n    type,\n    description,\n    enumValues,\n  };\n}\n\n/**\n * Find subcommand definitions from _describe calls or case statements.\n */\nfunction findSubcommands(text: string): CommandMeta[] {\n  const subcommands: CommandMeta[] = [];\n  const seen = new Set<string>();\n\n  // Look for _describe patterns: _describe 'command' commands\n  // where commands is an array like: ('start:start the service' 'stop:stop the service')\n  const describeRegex = /\\(([^)]+)\\)/g;\n  const joined = text.replace(/\\\\\\n\\s*/g, ' ');\n\n  // Look for arrays of 'name:description' patterns near _describe\n  let match: RegExpExecArray | null;\n  while ((match = describeRegex.exec(joined)) !== null) {\n    const content = match[1]!;\n    const entries = content.match(/'([^']+)'/g) || content.match(/\"([^\"]+)\"/g);\n    if (!entries) continue;\n\n    for (const entry of entries) {\n      const clean = entry.replace(/^['\"]|['\"]$/g, '');\n      const parts = clean.split(':');\n      if (parts.length >= 2 && /^[\\w-]+$/.test(parts[0]!)) {\n        const name = parts[0]!;\n        if (seen.has(name)) continue;\n        seen.add(name);\n        subcommands.push({\n          name,\n          description: parts.slice(1).join(':'),\n        });\n      }\n    }\n  }\n\n  return subcommands;\n}\n"],"mappings":"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"}