{"version":3,"file":"clack.mjs","names":[],"sources":["../../src/prompt-providers/clack.ts"],"sourcesContent":["import type { Readable, Writable } from 'node:stream';\nimport type { PromptOption, PromptProvider } from '../lib/prompt-types';\n\n/**\n * Options for {@link createClackPromptProvider}.\n */\nexport interface ClackPromptProviderOptions {\n  /**\n   * Custom input stream to read from instead of `process.stdin`.\n   * Useful for testing — pass a `Readable` with `isTTY = true` and\n   * a no-op `setRawMode` to emulate a terminal.\n   */\n  input?: Readable;\n  /**\n   * Custom output stream to write to instead of `process.stdout`.\n   */\n  output?: Writable;\n}\n\n/**\n * Creates a prompt provider backed by @clack/prompts.\n * Requires `@clack/prompts` as a peer dependency.\n *\n * The provider uses dynamic imports so that `@clack/prompts` is only\n * loaded when prompting actually occurs.\n */\nexport function createClackPromptProvider(\n  providerOptions?: ClackPromptProviderOptions\n): PromptProvider {\n  // Build the common stream options once; spread into every prompt call.\n  const streamOpts: { input?: Readable; output?: Writable } = {};\n  if (providerOptions?.input) streamOpts.input = providerOptions.input;\n  if (providerOptions?.output) streamOpts.output = providerOptions.output;\n\n  return {\n    async promptBatch(\n      options: PromptOption[]\n    ): Promise<Record<string, unknown>> {\n      const clack = await import('@clack/prompts');\n\n      const results: Record<string, unknown> = {};\n\n      for (const option of options) {\n        const message = getLabel(option);\n        const defaultValue = getDefault(option.config);\n\n        let value: unknown;\n\n        if (option.config.type === 'boolean') {\n          value = await clack.confirm({\n            ...streamOpts,\n            message,\n            initialValue:\n              typeof defaultValue === 'boolean' ? defaultValue : undefined,\n          });\n        } else if (hasChoices(option.config)) {\n          const choices = getChoices(option.config);\n          if (option.config.type === 'array') {\n            value = await clack.multiselect({\n              ...streamOpts,\n              message,\n              options: choices.map((c) => ({ value: c, label: String(c) })),\n            });\n          } else {\n            value = await clack.select({\n              ...streamOpts,\n              message,\n              options: choices.map((c) => ({ value: c, label: String(c) })),\n            });\n          }\n        } else if (option.config.type === 'number') {\n          const raw = await clack.text({\n            ...streamOpts,\n            message,\n            placeholder:\n              defaultValue !== undefined ? String(defaultValue) : undefined,\n            defaultValue:\n              defaultValue !== undefined ? String(defaultValue) : undefined,\n            validate: (val: string | undefined) => {\n              if (val && isNaN(Number(val))) {\n                return 'Please enter a valid number';\n              }\n              return undefined;\n            },\n          });\n\n          if (clack.isCancel(raw)) {\n            clack.cancel('Operation cancelled.');\n            throw new Error('Prompt cancelled by user');\n          }\n\n          value = raw !== undefined && raw !== '' ? Number(raw) : defaultValue;\n        } else {\n          // string, array without choices\n          value = await clack.text({\n            ...streamOpts,\n            message,\n            placeholder:\n              defaultValue !== undefined ? String(defaultValue) : undefined,\n            defaultValue:\n              defaultValue !== undefined ? String(defaultValue) : undefined,\n          });\n        }\n\n        // clack returns a Symbol when the user cancels (Ctrl+C)\n        if (clack.isCancel(value)) {\n          clack.cancel('Operation cancelled.');\n          throw new Error('Prompt cancelled by user');\n        }\n\n        results[option.name] = value;\n      }\n\n      return results;\n    },\n  };\n}\n\n/**\n * Default clack prompt provider, uses stdin/stdout\n */\nexport const ClackPromptProvider = createClackPromptProvider();\n\n/**\n * Determine the label to show for a prompt option.\n * Priority: prompt string > description > option name.\n */\nfunction getLabel(option: PromptOption): string {\n  if (typeof option.config.prompt === 'string') {\n    return option.config.prompt;\n  }\n  return option.config.description ?? option.name;\n}\n\n/**\n * Extract the default value from an option config.\n * Handles the three forms:\n * - Primitive value directly\n * - `{ value: T; description: string }` object\n * - `{ factory: () => T; description: string }` object\n */\nfunction getDefault(config: PromptOption['config']): unknown {\n  if (config.default === undefined) return undefined;\n  if (typeof config.default === 'object' && config.default !== null) {\n    if ('factory' in config.default) {\n      return (config.default as { factory: () => unknown }).factory();\n    }\n    if ('value' in config.default) {\n      return (config.default as { value: unknown }).value;\n    }\n  }\n  return config.default;\n}\n\nfunction hasChoices(config: PromptOption['config']): boolean {\n  return (\n    'choices' in config &&\n    (config as Record<string, unknown>)['choices'] !== undefined\n  );\n}\n\nfunction getChoices(config: PromptOption['config']): unknown[] {\n  const cfg = config as Record<string, unknown>;\n  const choices = cfg['choices'];\n  if (typeof choices === 'function') {\n    return choices();\n  }\n  return (choices as unknown[]) ?? [];\n}\n"],"mappings":";;;;;;;;AA0BA,SAAgB,0BACd,iBACgB;CAEhB,MAAM,aAAsD,EAAE;AAC9D,KAAI,iBAAiB,MAAO,YAAW,QAAQ,gBAAgB;AAC/D,KAAI,iBAAiB,OAAQ,YAAW,SAAS,gBAAgB;AAEjE,QAAO,EACL,MAAM,YACJ,SACkC;EAClC,MAAM,QAAQ,MAAM,OAAO;EAE3B,MAAM,UAAmC,EAAE;AAE3C,OAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,UAAU,SAAS,OAAO;GAChC,MAAM,eAAe,WAAW,OAAO,OAAO;GAE9C,IAAI;AAEJ,OAAI,OAAO,OAAO,SAAS,UACzB,SAAQ,MAAM,MAAM,QAAQ;IAC1B,GAAG;IACH;IACA,cACE,OAAO,iBAAiB,YAAY,eAAe,KAAA;IACtD,CAAC;YACO,WAAW,OAAO,OAAO,EAAE;IACpC,MAAM,UAAU,WAAW,OAAO,OAAO;AACzC,QAAI,OAAO,OAAO,SAAS,QACzB,SAAQ,MAAM,MAAM,YAAY;KAC9B,GAAG;KACH;KACA,SAAS,QAAQ,KAAK,OAAO;MAAE,OAAO;MAAG,OAAO,OAAO,EAAE;MAAE,EAAE;KAC9D,CAAC;QAEF,SAAQ,MAAM,MAAM,OAAO;KACzB,GAAG;KACH;KACA,SAAS,QAAQ,KAAK,OAAO;MAAE,OAAO;MAAG,OAAO,OAAO,EAAE;MAAE,EAAE;KAC9D,CAAC;cAEK,OAAO,OAAO,SAAS,UAAU;IAC1C,MAAM,MAAM,MAAM,MAAM,KAAK;KAC3B,GAAG;KACH;KACA,aACE,iBAAiB,KAAA,IAAY,OAAO,aAAa,GAAG,KAAA;KACtD,cACE,iBAAiB,KAAA,IAAY,OAAO,aAAa,GAAG,KAAA;KACtD,WAAW,QAA4B;AACrC,UAAI,OAAO,MAAM,OAAO,IAAI,CAAC,CAC3B,QAAO;;KAIZ,CAAC;AAEF,QAAI,MAAM,SAAS,IAAI,EAAE;AACvB,WAAM,OAAO,uBAAuB;AACpC,WAAM,IAAI,MAAM,2BAA2B;;AAG7C,YAAQ,QAAQ,KAAA,KAAa,QAAQ,KAAK,OAAO,IAAI,GAAG;SAGxD,SAAQ,MAAM,MAAM,KAAK;IACvB,GAAG;IACH;IACA,aACE,iBAAiB,KAAA,IAAY,OAAO,aAAa,GAAG,KAAA;IACtD,cACE,iBAAiB,KAAA,IAAY,OAAO,aAAa,GAAG,KAAA;IACvD,CAAC;AAIJ,OAAI,MAAM,SAAS,MAAM,EAAE;AACzB,UAAM,OAAO,uBAAuB;AACpC,UAAM,IAAI,MAAM,2BAA2B;;AAG7C,WAAQ,OAAO,QAAQ;;AAGzB,SAAO;IAEV;;;;;AAMH,MAAa,sBAAsB,2BAA2B;;;;;AAM9D,SAAS,SAAS,QAA8B;AAC9C,KAAI,OAAO,OAAO,OAAO,WAAW,SAClC,QAAO,OAAO,OAAO;AAEvB,QAAO,OAAO,OAAO,eAAe,OAAO;;;;;;;;;AAU7C,SAAS,WAAW,QAAyC;AAC3D,KAAI,OAAO,YAAY,KAAA,EAAW,QAAO,KAAA;AACzC,KAAI,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY,MAAM;AACjE,MAAI,aAAa,OAAO,QACtB,QAAQ,OAAO,QAAuC,SAAS;AAEjE,MAAI,WAAW,OAAO,QACpB,QAAQ,OAAO,QAA+B;;AAGlD,QAAO,OAAO;;AAGhB,SAAS,WAAW,QAAyC;AAC3D,QACE,aAAa,UACZ,OAAmC,eAAe,KAAA;;AAIvD,SAAS,WAAW,QAA2C;CAE7D,MAAM,UADM,OACQ;AACpB,KAAI,OAAO,YAAY,WACrB,QAAO,SAAS;AAElB,QAAQ,WAAyB,EAAE"}