{"version":3,"file":"progress.mjs","names":[],"sources":["../../src/extension/progress.ts"],"sourcesContent":["import { defineInterceptor } from '../core/interceptors.ts';\nimport type { PadroneBarConfig, PadroneProgress, PadroneProgressOptions, PadroneSpinnerConfig } from '../core/runtime.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase } from '../types/index.ts';\nimport type { WithInterceptor } from '../util/type-utils.ts';\nimport type { PadroneProgressRenderer } from './progress-renderer.ts';\nimport { createTerminalProgress } from './progress-renderer.ts';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** A progress message value: a plain string, `null` to suppress, or an object with a message and custom indicator icon. */\nexport type PadroneProgressMessage = string | null | { message?: string | null; indicator?: string };\n\n/** Per-phase message configuration for progress indicators. */\nexport type PadroneProgressMessages<TRes = unknown> = {\n  /** Message shown during async validation. Defaults to `''` (spinner only). */\n  validation?: string;\n  /** Message shown while the command's action is running. */\n  progress?: string;\n  /** Message shown when the command succeeds. `null` to suppress. Defaults to the `progress` message. */\n  success?: PadroneProgressMessage | ((result: TRes) => PadroneProgressMessage);\n  /** Message shown when the command fails. `null` to suppress. Defaults to the error message. */\n  error?: PadroneProgressMessage | ((error: unknown) => PadroneProgressMessage);\n};\n\n/**\n * Progress indicator configuration with messages, visual options, and renderer.\n */\nexport type PadroneProgressConfig<TRes = unknown> = {\n  /** Per-phase messages. A string sets the `progress` message; an object configures individual phases. */\n  message?: string | PadroneProgressMessages<TRes>;\n  /** Spinner configuration. Default `show` is `'auto'` (visible when bar is not shown). `true` forces spinner to always show (even alongside a bar). */\n  spinner?: PadroneSpinnerConfig;\n  /** Enable a progress bar. `true` for defaults (`show: 'always'`), or a `PadroneBarConfig` object. `false` to disable entirely. When omitted, bar defaults to `show: 'auto'`. */\n  bar?: boolean | PadroneBarConfig;\n  /** Show elapsed time since the indicator started. Can also be started on demand via `update({ time: true })`. */\n  time?: boolean;\n  /** Show estimated time remaining based on progress rate. Requires numeric `update()` calls. */\n  eta?: boolean;\n  /**\n   * Custom renderer factory. Called to create the progress indicator.\n   * Defaults to the built-in terminal renderer (`createTerminalProgress`).\n   */\n  renderer?: PadroneProgressRenderer;\n  /** Suppress all progress output. The `progress` interface is still provided on the context as a no-op. */\n  silent?: boolean;\n};\n\n/**\n * Shared progress defaults that can be provided via context instead of repeating\n * at each call site. Per-instance message fields are excluded — those always come\n * from the constructor argument.\n *\n * Provide via context as `{ progressConfig: PadroneProgressDefaults }`.\n */\nexport type PadroneProgressDefaults = Pick<PadroneProgressConfig, 'message' | 'spinner' | 'bar' | 'time' | 'eta' | 'renderer' | 'silent'>;\n\n/** Builder/program type after applying `padroneProgress()`. Adds `{ progress: PadroneProgress }` to the command context. */\nexport type WithProgress<T> = WithInterceptor<T, { progress: PadroneProgress }>;\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst noopEta = { start() {}, stop() {}, reset() {} };\nconst noopIndicator: PadroneProgress = {\n  update() {},\n  eta: noopEta,\n  succeed() {},\n  fail() {},\n  stop() {},\n  pause() {},\n  resume() {},\n};\n\nfunction resolveMessage(field: unknown, value: unknown, fallback?: string): { message: string | null | undefined; indicator?: string } {\n  const raw = typeof field === 'function' ? (field as (v: unknown) => unknown)(value) : field;\n  if (raw === undefined) return { message: fallback };\n  if (raw === null || typeof raw === 'string') return { message: raw };\n  if (typeof raw === 'object' && raw !== null) {\n    const obj = raw as { message?: string | null; indicator?: string };\n    return { message: obj.message, indicator: obj.indicator };\n  }\n  return { message: fallback };\n}\n\nfunction cleanup(\n  indicator: PadroneProgress,\n  successConfig: unknown,\n  errorConfig: unknown,\n  error: unknown,\n  result: unknown,\n  isError: boolean,\n) {\n  if (isError) {\n    const fallback = error instanceof Error ? error.message : String(error);\n    const { message: errorMsg, indicator: errorIcon } = resolveMessage(errorConfig, error, fallback);\n    indicator.fail(errorMsg, errorIcon !== undefined ? { indicator: errorIcon } : undefined);\n  } else {\n    const { message: successMsg, indicator: successIcon } = resolveMessage(successConfig, result);\n    indicator.succeed(successMsg, successIcon !== undefined ? { indicator: successIcon } : undefined);\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Interceptor\n// ---------------------------------------------------------------------------\n\nfunction resolveMessages(raw: string | PadroneProgressMessages | undefined): {\n  progress: string;\n  validation: string;\n  success: unknown;\n  error: unknown;\n} {\n  if (!raw || typeof raw === 'string') {\n    return { progress: raw || 'Working...', validation: '', success: undefined, error: undefined };\n  }\n  return {\n    progress: raw.progress ?? 'Working...',\n    validation: raw.validation ?? '',\n    success: raw.success,\n    error: raw.error,\n  };\n}\n\nfunction mergeMessages(\n  cmd: ReturnType<typeof resolveMessages>,\n  ctx: ReturnType<typeof resolveMessages>,\n  cmdRaw: string | PadroneProgressMessages | undefined,\n): ReturnType<typeof resolveMessages> {\n  // String shorthand: all fields come from the string, no context fallback for individual fields\n  if (typeof cmdRaw === 'string') return cmd;\n  // Object: per-field fallback to context\n  const obj = (typeof cmdRaw === 'object' ? cmdRaw : undefined) as PadroneProgressMessages | undefined;\n  return {\n    progress: obj?.progress !== undefined ? cmd.progress : (ctx.progress ?? cmd.progress),\n    validation: obj?.validation !== undefined ? cmd.validation : ctx.validation || cmd.validation,\n    success: obj?.success !== undefined ? cmd.success : (ctx.success ?? cmd.success),\n    error: obj?.error !== undefined ? cmd.error : (ctx.error ?? cmd.error),\n  };\n}\n\nfunction progressInterceptor(config: string | PadroneProgressConfig) {\n  const isObj = typeof config === 'object';\n  const rawMessage = typeof config === 'string' ? config : isObj ? config.message : undefined;\n  // Raw constructor values — undefined means \"not set by caller\"\n  const rawSpinner = isObj ? config.spinner : undefined;\n  const rawBar = isObj ? config.bar : undefined;\n  const rawRenderer = isObj ? config.renderer : undefined;\n  const rawTime = isObj ? config.time : undefined;\n  const rawEta = isObj ? config.eta : undefined;\n  const rawSilent = isObj ? config.silent : undefined;\n\n  return defineInterceptor({ id: 'padrone:progress', name: 'padrone:progress' })\n    .requires<{ progressConfig?: PadroneProgressDefaults }>()\n    .factory(() => {\n      let indicator: PadroneProgress | undefined;\n      let restoreOutput: (() => void) | undefined;\n      // Lazily resolved from context + constructor args\n      let resolvedRenderer: PadroneProgressRenderer | undefined;\n      let resolvedOptions: PadroneProgressOptions | undefined;\n      let resolvedSilent = false;\n      let msgs: ReturnType<typeof resolveMessages> | undefined;\n\n      function resolve(ctx: { context?: { progressConfig?: PadroneProgressDefaults } }) {\n        if (resolvedRenderer) return;\n        const ctxCfg = (ctx.context as Record<string, unknown> | undefined)?.progressConfig as PadroneProgressDefaults | undefined;\n        resolvedSilent = rawSilent ?? ctxCfg?.silent ?? false;\n        const spinner = rawSpinner ?? ctxCfg?.spinner;\n        const bar = rawBar ?? ctxCfg?.bar;\n        const time = rawTime ?? ctxCfg?.time;\n        const eta = rawEta ?? ctxCfg?.eta;\n        resolvedRenderer = rawRenderer ?? ctxCfg?.renderer ?? createTerminalProgress;\n        resolvedOptions =\n          spinner !== undefined || bar !== undefined || time !== undefined || eta !== undefined ? { spinner, bar, time, eta } : undefined;\n        msgs = mergeMessages(resolveMessages(rawMessage), resolveMessages(ctxCfg?.message), rawMessage);\n      }\n\n      const teardown = () => {\n        restoreOutput?.();\n        indicator = undefined;\n        restoreOutput = undefined;\n      };\n\n      return {\n        validate(ctx, next) {\n          resolve(ctx);\n          if (resolvedSilent) return next();\n          indicator = resolvedRenderer!(msgs!.validation || msgs!.progress, resolvedOptions);\n\n          const originalOutput = ctx.runtime.output;\n          const originalError = ctx.runtime.error;\n          ctx.runtime.output = (...args: unknown[]) => {\n            indicator!.pause();\n            originalOutput(...args);\n            indicator!.resume();\n          };\n          ctx.runtime.error = (text: string) => {\n            indicator!.pause();\n            originalError(text);\n            indicator!.resume();\n          };\n          restoreOutput = () => {\n            ctx.runtime.output = originalOutput;\n            ctx.runtime.error = originalError;\n          };\n\n          const onValidationFailure = (error: unknown) => {\n            if (indicator) {\n              cleanup(indicator, msgs!.success, msgs!.error, error, undefined, true);\n              teardown();\n            }\n          };\n\n          const checkResult = (result: any) => {\n            if (result.argsResult?.issues) onValidationFailure(new Error('Validation failed'));\n            return result;\n          };\n\n          let result: any;\n          try {\n            result = next();\n          } catch (err) {\n            onValidationFailure(err);\n            throw err;\n          }\n          if (result instanceof Promise) {\n            return result.then(checkResult, (err: unknown) => {\n              onValidationFailure(err);\n              throw err;\n            });\n          }\n          return checkResult(result);\n        },\n\n        execute(_ctx, next) {\n          if (resolvedSilent) return next({ context: { progress: noopIndicator } });\n\n          // Transition from validation message to progress message\n          if (indicator && msgs!.validation) indicator.update(msgs!.progress);\n\n          const effectiveIndicator = indicator ?? noopIndicator;\n\n          const onSuccess = (value: unknown) => {\n            cleanup(effectiveIndicator, msgs!.success, msgs!.error, undefined, value, false);\n            teardown();\n          };\n          const onError = (err: unknown) => {\n            if (indicator) {\n              cleanup(indicator, msgs!.success, msgs!.error, err, undefined, true);\n              teardown();\n            }\n            throw err;\n          };\n\n          let result: any;\n          try {\n            result = next({ context: { progress: effectiveIndicator } });\n          } catch (err) {\n            onError(err);\n          }\n          if (result instanceof Promise) {\n            return result.then(\n              (r) => {\n                if (r.result instanceof Promise) {\n                  return {\n                    result: r.result.then(\n                      (value: unknown) => {\n                        onSuccess(value);\n                        return value;\n                      },\n                      (err: unknown) => onError(err),\n                    ),\n                  };\n                }\n                onSuccess(r.result);\n                return r;\n              },\n              (err: unknown) => onError(err),\n            );\n          }\n          if (result!.result instanceof Promise) {\n            return {\n              result: result!.result.then(\n                (value: unknown) => {\n                  onSuccess(value);\n                  return value;\n                },\n                (err: unknown) => onError(err),\n              ),\n            };\n          }\n          onSuccess(result!.result);\n          return result;\n        },\n\n        shutdown(ctx) {\n          // Safety net: if validate/execute cleanup paths were bypassed (e.g., outer interceptor\n          // threw during execute before reaching this interceptor's execute handler), stop the indicator.\n          if (indicator) {\n            cleanup(indicator, msgs!.success, msgs!.error, ctx.error, ctx.result, !!ctx.error);\n            teardown();\n          }\n        },\n      };\n    })\n    .provides<{ progress: PadroneProgress }>();\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\n/**\n * Extension that adds an auto-managed progress indicator to the command pipeline.\n *\n * - `string` — a single message used for all states.\n * - `PadroneProgressConfig` — separate messages for validation, progress, success, and error.\n *\n * The indicator is automatically started before validation, updated at each phase transition,\n * and stopped on success (`.succeed()`) or failure (`.fail()`).\n *\n * Provides `{ progress: PadroneProgress }` on the command context.\n * Access it in action handlers as `ctx.context.progress`.\n *\n * Uses the built-in terminal renderer by default. Pass a custom `renderer` for non-terminal\n * environments (web UIs, testing, etc).\n *\n * Usage:\n * ```ts\n * createPadrone('my-cli')\n *   .command('sync', (c) =>\n *     c.extend(padroneProgress('Syncing...'))\n *       .action((_args, ctx) => {\n *         ctx.context.progress.update('halfway');\n *       })\n *   )\n * ```\n */\nexport function padroneProgress<T extends CommandTypesBase>(config?: string | PadroneProgressConfig): (builder: T) => WithProgress<T> {\n  return ((builder: AnyPadroneBuilder) => builder.intercept(progressInterceptor(config ?? 'Working...'))) as any;\n}\n"],"mappings":"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"}