{"version":3,"file":"fish.mjs","names":[],"sources":["../../../src/codegen/parsers/fish.ts"],"sourcesContent":["import type { CommandMeta, FieldMeta } from '../types.ts';\n\n/**\n * Parse fish shell completion scripts into CommandMeta.\n *\n * Fish completions use the `complete` builtin:\n *   complete -c <command> -s <short> -l <long> -d <description> -a <arguments> -r -f\n */\nexport function parseFishCompletions(text: string): CommandMeta {\n  const lines = text.split('\\n');\n  const result: CommandMeta = {\n    name: '',\n    arguments: [],\n    subcommands: [],\n  };\n\n  const subcommandMap = new Map<string, CommandMeta>();\n\n  for (const line of lines) {\n    const trimmed = line.trim();\n    if (!trimmed || trimmed.startsWith('#')) continue;\n\n    // Match: complete -c <command> [options]\n    const completeMatch = trimmed.match(/^complete\\s+/);\n    if (!completeMatch) continue;\n\n    const parts = parseCompleteLine(trimmed);\n    if (!parts) continue;\n\n    // Set root command name\n    if (!result.name && parts.command) {\n      result.name = parts.command;\n    }\n\n    // If this completion has a condition like \"__fish_seen_subcommand_from <sub>\"\n    // it belongs to a subcommand\n    const subcommandCondition = parts.condition?.match(/__fish_seen_subcommand_from\\s+(\\S+)/);\n    if (subcommandCondition) {\n      const subName = subcommandCondition[1]!;\n      let sub = subcommandMap.get(subName);\n      if (!sub) {\n        sub = { name: subName, arguments: [] };\n        subcommandMap.set(subName, sub);\n      }\n\n      if (parts.longFlag || parts.shortFlag) {\n        const field = completionToField(parts);\n        if (field) sub.arguments!.push(field);\n      }\n      continue;\n    }\n\n    // If this defines a subcommand (has -a with no flags)\n    if (parts.arguments && !parts.longFlag && !parts.shortFlag) {\n      // Arguments list could be subcommand names\n      const names = parts.arguments.split(/\\s+/);\n      for (const name of names) {\n        if (!name || name.startsWith('(')) continue;\n        if (!subcommandMap.has(name)) {\n          subcommandMap.set(name, {\n            name,\n            description: parts.description,\n            arguments: [],\n          });\n        } else if (parts.description) {\n          subcommandMap.get(name)!.description = parts.description;\n        }\n      }\n      continue;\n    }\n\n    // Global option\n    if (parts.longFlag || parts.shortFlag) {\n      const field = completionToField(parts);\n      if (field) result.arguments!.push(field);\n    }\n  }\n\n  // Add subcommands\n  for (const sub of subcommandMap.values()) {\n    if (sub.arguments!.length === 0) delete sub.arguments;\n    result.subcommands!.push(sub);\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\ninterface CompleteParts {\n  command?: string;\n  shortFlag?: string;\n  longFlag?: string;\n  description?: string;\n  arguments?: string;\n  condition?: string;\n  requiresArg?: boolean;\n  noFiles?: boolean;\n}\n\nfunction parseCompleteLine(line: string): CompleteParts | null {\n  const parts: CompleteParts = {};\n\n  // Extract -c <command>\n  const cmdMatch = line.match(/-c\\s+(\\S+)/);\n  if (cmdMatch) parts.command = cmdMatch[1];\n\n  // Extract -s <short>\n  const shortMatch = line.match(/-s\\s+(\\S+)/);\n  if (shortMatch) parts.shortFlag = shortMatch[1];\n\n  // Extract -l <long>\n  const longMatch = line.match(/-l\\s+(\\S+)/);\n  if (longMatch) parts.longFlag = longMatch[1];\n\n  // Extract -d '<description>' or -d \"<description>\"\n  const descMatch = line.match(/-d\\s+['\"]([^'\"]+)['\"]/) || line.match(/-d\\s+(\\S+)/);\n  if (descMatch) parts.description = descMatch[1];\n\n  // Extract -a '<arguments>'\n  const argsMatch = line.match(/-a\\s+['\"]([^'\"]+)['\"]/) || line.match(/-a\\s+(\\S+)/);\n  if (argsMatch) parts.arguments = argsMatch[1];\n\n  // Extract -n '<condition>'\n  const condMatch = line.match(/-n\\s+['\"]([^'\"]+)['\"]/) || line.match(/-n\\s+(\\S+)/);\n  if (condMatch) parts.condition = condMatch[1];\n\n  // -r means requires argument\n  parts.requiresArg = /-r\\b/.test(line);\n  // -f means no file completion\n  parts.noFiles = /-f\\b/.test(line);\n\n  return parts;\n}\n\nfunction completionToField(parts: CompleteParts): FieldMeta | null {\n  const name = parts.longFlag ? parts.longFlag.replace(/-([a-z])/g, (_, c: string) => c.toUpperCase()) : parts.shortFlag || '';\n\n  if (!name) return null;\n\n  let type: FieldMeta['type'] = parts.requiresArg ? 'string' : 'boolean';\n  let enumValues: string[] | undefined;\n\n  // If -a provides specific values, treat as enum\n  if (parts.arguments) {\n    const values = parts.arguments.split(/\\s+/).filter((v) => !v.startsWith('('));\n    if (values.length > 0 && values.length <= 20) {\n      enumValues = values;\n      type = 'enum';\n    }\n  }\n\n  const aliases = parts.shortFlag && parts.longFlag ? [`-${parts.shortFlag}`] : undefined;\n\n  return {\n    name,\n    type,\n    description: parts.description,\n    aliases,\n    enumValues,\n  };\n}\n"],"mappings":"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"}