{"version":3,"file":"parse.mjs","names":[],"sources":["../../src/core/parse.ts"],"sourcesContent":["type ParseParts = {\n  /**\n   * An alphanumeric term representing a command, subcommand, or positional argument.\n   * Note that a term can be ambiguous until fully matched within the command hierarchy.\n   * We cannot fully distinguish between a nested command or a positional argument until\n   * the command structure is known.\n   */\n  term: {\n    type: 'term';\n    value: string;\n  };\n  /**\n   * A positional argument provided to the command.\n   * Unlike `term`, this is definitively an argument. This can be determined when\n   * the argument is non-alphanumeric, like a path or a number.\n   */\n  arg: {\n    type: 'arg';\n    value: string;\n  };\n  /**\n   * An arg provided to the command, prefixed with `--`.\n   * If the arg has an `=` sign, the value after it is used as the arg's value.\n   * Otherwise, the value is obtained from the next part or set to `true` if no value is provided.\n   * The key is an array representing the path for nested args (e.g., `--user.id=123` becomes `['user', 'id']`).\n   */\n  named: {\n    type: 'named';\n    key: string[];\n    value?: string | string[];\n    negated?: boolean;\n  };\n  /**\n   * An alias arg provided to the command, prefixed with `-`.\n   * Which arg it maps to cannot be determined until the command structure is known.\n   * Aliases cannot be nested, so the key is always a single-element array.\n   */\n  alias: {\n    type: 'alias';\n    key: string[];\n    value?: string | string[];\n  };\n};\n\ntype ParsePart = ParseParts[keyof ParseParts];\n\ntype QuoteChar = '\"' | \"'\" | '`';\n\n/**\n * Split a string by a delimiter, respecting quoted segments and optional bracket nesting.\n * Handles escape sequences within quotes (\\\\\" and \\\\\\\\).\n */\nfunction splitQuoteAware(input: string, delimiter: ' ' | ',', opts?: { brackets?: boolean; trim?: boolean }): string[] {\n  const results: string[] = [];\n  let current = '';\n  let inQuote: QuoteChar | null = null;\n  let bracketDepth = 0;\n  let i = 0;\n\n  while (i < input.length) {\n    const char = input[i];\n\n    if (inQuote) {\n      if (char === '\\\\' && i + 1 < input.length) {\n        const nextChar = input[i + 1];\n        if (nextChar === inQuote || nextChar === '\\\\') {\n          current += nextChar;\n          i += 2;\n          continue;\n        }\n      }\n      if (char === inQuote) {\n        inQuote = null;\n      } else {\n        current += char;\n      }\n    } else if (opts?.brackets && char === '[') {\n      bracketDepth++;\n      current += char;\n    } else if (opts?.brackets && char === ']') {\n      bracketDepth = Math.max(0, bracketDepth - 1);\n      current += char;\n    } else if (bracketDepth > 0) {\n      current += char;\n    } else if (char === '\"' || char === \"'\" || char === '`') {\n      inQuote = char;\n    } else if (char === delimiter || (delimiter === ' ' && char === '\\t')) {\n      if (delimiter === ' ' ? current : true) {\n        results.push(opts?.trim ? current.trim() : current);\n        current = '';\n      }\n    } else {\n      current += char;\n    }\n    i++;\n  }\n\n  if (delimiter === ' ' ? current : current || results.length > 0) {\n    results.push(opts?.trim ? current.trim() : current);\n  }\n\n  return results;\n}\n\nexport function parseCliInputToParts(input: string): ParsePart[] {\n  const parts = splitQuoteAware(input.trim(), ' ', { brackets: true });\n  const result: ParsePart[] = [];\n\n  // Index into `result` of the last part that can accept a pending value (-1 = none)\n  let pendingIdx = -1;\n  // Once a non-term positional arg appears, all subsequent bare values become args\n  let allowTerm = true;\n  let afterDoubleDash = false;\n\n  for (const part of parts) {\n    if (!part) continue;\n\n    // Bare `--` separator: everything after is a literal positional arg\n    if (part === '--' && !afterDoubleDash) {\n      pendingIdx = -1;\n      afterDoubleDash = true;\n      allowTerm = false;\n      continue;\n    }\n\n    if (afterDoubleDash) {\n      result.push({ type: 'arg', value: part });\n      continue;\n    }\n\n    const hadPending = pendingIdx;\n    pendingIdx = -1;\n\n    if (part.startsWith('--no-') && part.length > 5) {\n      // Negated boolean arg (--no-verbose or --no-config.debug)\n      const key = part.slice(5).split('.');\n      result.push({ type: 'named', key, value: undefined, negated: true });\n    } else if (part.startsWith('--')) {\n      const [keyStr = '', value] = splitNamedArgValue(part.slice(2));\n      const key = keyStr.split('.');\n      result.push({ type: 'named', key, value });\n      if (typeof value === 'undefined') pendingIdx = result.length - 1;\n    } else if (part.startsWith('-') && part.length > 1 && !/^-\\d/.test(part)) {\n      // Short flag(s) (but not negative numbers like -5)\n      // Supports flag stacking: -abc → -a -b -c (last flag can take a value)\n      const [keyStr = '', value] = splitNamedArgValue(part.slice(1));\n\n      if (keyStr.length > 1 && typeof value === 'undefined') {\n        // Flag stacking: -abc → -a, -b, -c (all set to true except last which can take next arg's value)\n        for (let ci = 0; ci < keyStr.length - 1; ci++) {\n          result.push({ type: 'alias', key: [keyStr[ci]!], value: undefined });\n        }\n        result.push({ type: 'alias', key: [keyStr[keyStr.length - 1]!], value: undefined });\n        pendingIdx = result.length - 1;\n      } else if (keyStr.length > 1 && typeof value !== 'undefined') {\n        // -abc=val → -a, -b, -c=val (stacked with value on last)\n        for (let ci = 0; ci < keyStr.length - 1; ci++) {\n          result.push({ type: 'alias', key: [keyStr[ci]!], value: undefined });\n        }\n        result.push({ type: 'alias', key: [keyStr[keyStr.length - 1]!], value });\n      } else {\n        // Single char: -v or -v=value\n        result.push({ type: 'alias', key: [keyStr], value });\n        if (typeof value === 'undefined') pendingIdx = result.length - 1;\n      }\n    } else if (hadPending >= 0) {\n      result[hadPending]!.value = part;\n    } else if (/^[a-zA-Z0-9_-]+$/.test(part) && allowTerm) {\n      result.push({ type: 'term', value: part });\n    } else {\n      result.push({ type: 'arg', value: part });\n      allowTerm = false;\n    }\n  }\n  return result;\n}\n\n/**\n * Split named arg key and value, handling quoted values after =.\n */\nfunction splitNamedArgValue(str: string): [string, string | string[] | undefined] {\n  const eqIndex = str.indexOf('=');\n  if (eqIndex === -1) return [str, undefined];\n\n  const key = str.slice(0, eqIndex);\n  let value = str.slice(eqIndex + 1);\n\n  // Remove surrounding quotes from value if present\n  if (\n    (value.startsWith('\"') && value.endsWith('\"')) ||\n    (value.startsWith(\"'\") && value.endsWith(\"'\")) ||\n    (value.startsWith('`') && value.endsWith('`'))\n  ) {\n    value = value.slice(1, -1);\n    return [key, value];\n  }\n\n  // Handle array syntax: [a,b,c] -> ['a', 'b', 'c']\n  if (value.startsWith('[') && value.endsWith(']')) {\n    const inner = value.slice(1, -1);\n    if (inner === '') return [key, []];\n    return [key, splitQuoteAware(inner, ',', { trim: true })];\n  }\n\n  return [key, value];\n}\n\n/**\n * Sets a value at a nested path in an object.\n * For example: setNestedValue(obj, ['user', 'profile', 'name'], 'John')\n * Creates intermediate objects as needed.\n */\nexport function setNestedValue(obj: Record<string, unknown>, path: string[], value: unknown): void {\n  let current: Record<string, unknown> = obj;\n\n  for (let i = 0; i < path.length - 1; i++) {\n    const part = path[i]!;\n    if (!(part in current) || typeof current[part] !== 'object' || current[part] === null) {\n      current[part] = {};\n    }\n    current = current[part] as Record<string, unknown>;\n  }\n\n  const lastPart = path[path.length - 1]!;\n  current[lastPart] = value;\n}\n\n/**\n * Gets a value at a nested path in an object.\n * Returns undefined if the path doesn't exist.\n */\nexport function getNestedValue(obj: Record<string, unknown>, path: string[]): unknown {\n  let current: unknown = obj;\n\n  for (const part of path) {\n    if (current === null || current === undefined || typeof current !== 'object') {\n      return undefined;\n    }\n    current = (current as Record<string, unknown>)[part];\n  }\n\n  return current;\n}\n"],"mappings":"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"}