{"version":3,"file":"resolve-completions.mjs","names":[],"sources":["../../src/lib/resolve-completions.ts"],"sourcesContent":["import type { InternalOptionConfig } from '@cli-forge/parser';\nimport type { AnyInternalCLI } from './internal-cli';\nimport type { CompletionContext, OptionCompletionCallback } from './completion-types';\n\nexport interface ResolveCompletionsOptions {\n  /** The root CLI instance */\n  rootCLI: AnyInternalCLI;\n  /** The raw argv (without --get-completions) */\n  argv: string[];\n}\n\n/**\n * Compute default completions from a command's registered subcommands and options.\n */\nfunction getDefaultCompletions(\n  cmd: AnyInternalCLI\n): string[] {\n  const completions: string[] = [];\n\n  // Subcommand names (deduplicated, excluding hidden)\n  const seenCommands = new Set<AnyInternalCLI>();\n  for (const [key, subcmd] of Object.entries(cmd.registeredCommands)) {\n    if (seenCommands.has(subcmd)) continue;\n    seenCommands.add(subcmd);\n    if (subcmd.configuration?.hidden) continue;\n    completions.push(key);\n  }\n\n  // Flag names (excluding hidden and positionals).\n  // Show only one name per option: prefer the primary key, fall back\n  // to the first alias if the key is somehow unavailable.\n  const configuredOptions: Record<string, InternalOptionConfig> =\n    cmd.parser.configuredOptions as any;\n  const seenOptionKeys = new Set<string>();\n  for (const [key, config] of Object.entries(configuredOptions)) {\n    if (config.hidden) continue;\n    if (config.positional) continue;\n    // Deduplicate — the parser may register the same option under\n    // both its camelCase key and dashed alias.\n    const canonicalKey = config.key;\n    if (seenOptionKeys.has(canonicalKey)) continue;\n    seenOptionKeys.add(canonicalKey);\n    completions.push(key.length === 1 ? `-${key}` : `--${key}`);\n    if (config.alias) {\n      for (const alias of config.alias) {\n        // Include long-form aliases but skip single-char shortflags\n        if (alias.length > 1) {\n          completions.push(`--${alias}`);\n        }\n      }\n    }\n  }\n\n  return completions;\n}\n\n/**\n * Determine if we're completing an option's value (the token after a flag like --foo).\n * Returns the option config key if so, null otherwise.\n */\nfunction getOptionExpectingValue(\n  argv: string[],\n  configuredOptions: Record<string, InternalOptionConfig>\n): string | null {\n  if (argv.length < 1) return null;\n\n  // The last token is what we're completing. If the second-to-last token\n  // is a flag that expects a value, we're completing that flag's value.\n  const penultimate = argv.length >= 2 ? argv[argv.length - 2] : null;\n  if (!penultimate || !penultimate.startsWith('-')) return null;\n\n  const key = penultimate.replace(/^-+/, '');\n\n  // Direct key match\n  if (configuredOptions[key] && configuredOptions[key].type !== 'boolean') {\n    return configuredOptions[key].key;\n  }\n\n  // Alias match\n  for (const [, config] of Object.entries(configuredOptions)) {\n    if (config.alias?.includes(key) && config.type !== 'boolean') {\n      return config.key;\n    }\n  }\n\n  return null;\n}\n\n/**\n * Search for an option completion callback in the command chain (deepest first).\n */\nfunction findOptionCompletionCallback(\n  cmd: AnyInternalCLI,\n  rootCLI: AnyInternalCLI,\n  optionKey: string\n): OptionCompletionCallback | undefined {\n  // Walk from the deepest command upward\n  let current: AnyInternalCLI | undefined = cmd;\n  while (current) {\n    const cb = current.completionConfigs.get(optionKey);\n    if (cb) return cb;\n    current = current.getParent() as\n      | AnyInternalCLI\n      | undefined;\n  }\n  // Also check root explicitly (may not be reachable via getParent chain)\n  return rootCLI.completionConfigs.get(optionKey);\n}\n\n/**\n * Resolve completions for the current argv state.\n */\nexport async function resolveCompletions(\n  options: ResolveCompletionsOptions\n): Promise<string[]> {\n  const { rootCLI, argv } = options;\n\n  // Walk argv to find the deepest resolved subcommand.\n  // Track built commands to avoid re-running builders on live objects.\n  let currentCmd: AnyInternalCLI = rootCLI;\n  const builtCommands = new Set<AnyInternalCLI>();\n\n  for (const token of argv) {\n    if (token.startsWith('-')) continue;\n\n    const subcmd = currentCmd.registeredCommands[token];\n    if (subcmd && subcmd.configuration) {\n      if (!builtCommands.has(subcmd)) {\n        builtCommands.add(subcmd);\n        subcmd.parser = rootCLI.parser;\n        subcmd.configuration.builder?.(subcmd as any);\n      }\n      currentCmd = subcmd;\n    }\n  }\n\n  // Partially parse what we have so far (non-strict, no validation)\n  let currentArgs: Record<string, any> = {};\n  try {\n    currentArgs = rootCLI.parser\n      .clone({\n        ...rootCLI.parser.options,\n        strict: false,\n        validate: false,\n        unmatchedParser: () => false,\n      })\n      .parse(argv, {}) as any;\n  } catch {\n    // Ignore parse errors during completion\n  }\n\n  const defaultCompletions = getDefaultCompletions(currentCmd);\n\n  const context: CompletionContext = {\n    current: currentArgs,\n    argv,\n    defaultCompletions,\n  };\n\n  // Check if we're completing an option's value\n  const configuredOptions = rootCLI.parser.configuredOptions as Record<\n    string,\n    InternalOptionConfig\n  >;\n  const optionKey = getOptionExpectingValue(argv, configuredOptions);\n  if (optionKey) {\n    // Per-option completion callback\n    const optionCb = findOptionCompletionCallback(\n      currentCmd,\n      rootCLI,\n      optionKey\n    );\n    if (optionCb) {\n      return optionCb(context);\n    }\n    // If the option has choices, return those\n    // Cast to any because InternalOptionConfig is a union where `choices`\n    // isn't directly accessible without narrowing by type discriminator\n    const optionConfig = configuredOptions[optionKey] as any;\n    if (optionConfig?.choices) {\n      const choices =\n        typeof optionConfig.choices === 'function'\n          ? optionConfig.choices()\n          : optionConfig.choices;\n      return (choices as unknown[]).map(String);\n    }\n    return [];\n  }\n\n  // Command-level completion callback (walk up to find one)\n  let cmdForCallback: AnyInternalCLI | undefined = currentCmd;\n  while (cmdForCallback) {\n    if (cmdForCallback.completionCallback) {\n      return cmdForCallback.completionCallback(context);\n    }\n    cmdForCallback = cmdForCallback.getParent() as\n      | AnyInternalCLI\n      | undefined;\n  }\n\n  // Return defaults\n  return defaultCompletions;\n}\n"],"mappings":"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"}