{"version":3,"file":"results.mjs","names":[],"sources":["../../src/core/results.ts"],"sourcesContent":["import type { AnyPadroneCommand, PadroneSchema } from '../types/index.ts';\nimport type { Thenable } from '../util/type-utils.ts';\nimport { getCommandRuntime } from './commands.ts';\n\n/**\n * Brands a schema as async, signaling that its `validate()` may return a Promise.\n * When an async-branded schema is passed to `.arguments()`, `.configFile()`, or `.env()`,\n * the command's `parse()` and `cli()` will return Promises.\n */\nexport function asyncSchema<T extends PadroneSchema>(schema: T): T & { '~async': true } {\n  return Object.assign(schema, { '~async': true as const });\n}\n\nexport const noop = <TRes>() => undefined as TRes;\n\n/**\n * Maps over a value that may or may not be a Promise.\n * If the value is a Promise, chains with `.then()`. Otherwise, calls the function synchronously.\n * This preserves sync behavior for sync schemas and async behavior for async schemas.\n */\nexport function thenMaybe<T, U>(value: T | Promise<T>, fn: (v: T) => U | Promise<U>): U | Promise<U> {\n  if (value instanceof Promise) return value.then(fn);\n  return fn(value);\n}\n\n/**\n * Makes a sync result object thenable by adding `.then()`, `.catch()`, and `.finally()` methods.\n * If the value is already a Promise, returns it as-is.\n * This allows users to write `await program.cli()` or `program.cli().then(...)` regardless of sync/async.\n *\n * The `.then()` resolves with a plain copy (without thenable methods) to avoid infinite\n * recursive unwrapping by the Promise resolution algorithm.\n */\nexport function makeThenable<T>(value: T | Promise<T>): Thenable<T> {\n  if (value instanceof Promise) return value as any;\n  if (value !== null && typeof value === 'object' && !('then' in value)) {\n    const toPlain = () => {\n      const plain = { ...value } as any;\n      delete plain.then;\n      delete plain.catch;\n      delete plain.finally;\n      return plain as T;\n    };\n    // biome-ignore lint/suspicious/noThenProperty: intentional thenable shim for sync results\n    (value as any).then = (onfulfilled?: (v: T) => any, onrejected?: (reason: any) => any) => {\n      try {\n        const result = onfulfilled ? onfulfilled(toPlain()) : toPlain();\n        return Promise.resolve(result);\n      } catch (err) {\n        if (onrejected) return Promise.resolve(onrejected(err));\n        return Promise.reject(err);\n      }\n    };\n    (value as any).catch = (onrejected?: (reason: any) => any) => (value as any).then(undefined, onrejected);\n    (value as any).finally = (onfinally?: () => void) =>\n      (value as any).then(\n        (v: any) => {\n          onfinally?.();\n          return v;\n        },\n        (err: any) => {\n          onfinally?.();\n          throw err;\n        },\n      );\n  }\n  return value as any;\n}\n\n/**\n * Wraps a Promise to include a `drain()` method at the top level.\n * This allows `await promise.drain()` without first awaiting the promise.\n * Since cli/eval never reject, this just delegates to the resolved result's `drain()`.\n */\nexport function withPromiseDrain<T extends Promise<any>>(promise: T): T & { drain: () => Promise<any> } {\n  (promise as any).drain = async () => {\n    const resolved = await promise;\n    return resolved.drain();\n  };\n  return promise as any;\n}\n\nexport function isIterator(value: unknown): value is Iterator<unknown> {\n  return typeof value === 'object' && value !== null && Symbol.iterator in value && typeof (value as any)[Symbol.iterator] === 'function';\n}\n\nexport function isAsyncIterator(value: unknown): value is AsyncIterator<unknown> {\n  return (\n    typeof value === 'object' &&\n    value !== null &&\n    Symbol.asyncIterator in value &&\n    typeof (value as any)[Symbol.asyncIterator] === 'function'\n  );\n}\n\n/**\n * Writes a command's return value to output, handling promises, iterators, and async iterators.\n * Values are passed directly to the output function without stringification —\n * runtimes like Node/Bun already format objects via console.log.\n * Returns void or a Promise depending on whether async consumption is needed.\n */\nexport function outputValue(value: unknown, output: (...args: unknown[]) => void): void | Promise<void> {\n  if (value == null) return;\n\n  // Async iterator — consume and output each yielded value\n  if (isAsyncIterator(value)) {\n    return (async () => {\n      const iter = (value as any)[Symbol.asyncIterator]();\n      while (true) {\n        const { done, value: item } = await iter.next();\n        if (done) break;\n        if (item != null) output(item);\n      }\n    })();\n  }\n\n  // Sync iterator (but not a plain string/array which also have Symbol.iterator)\n  if (typeof value !== 'string' && !Array.isArray(value) && isIterator(value)) {\n    const iter = (value as any)[Symbol.iterator]();\n    while (true) {\n      const { done, value: item } = iter.next();\n      if (done) break;\n      if (item != null) output(item);\n    }\n    return;\n  }\n\n  // Promise — await then output\n  if (value instanceof Promise) {\n    return value.then((resolved) => outputValue(resolved, output));\n  }\n\n  // Pass value directly — runtime handles formatting\n  output(value);\n}\n\n/**\n * Resolves a result value by unwrapping Promises and collecting iterables into arrays.\n * This is the runtime counterpart of the `Drained<T>` type.\n */\nexport async function drainValue(value: unknown): Promise<unknown> {\n  // Unwrap promises first\n  if (value instanceof Promise) {\n    return drainValue(await value);\n  }\n\n  // Async iterator — collect into array\n  if (isAsyncIterator(value)) {\n    const items: unknown[] = [];\n    const iter = (value as any)[Symbol.asyncIterator]();\n    while (true) {\n      const { done, value: item } = await iter.next();\n      if (done) break;\n      items.push(item);\n    }\n    return items;\n  }\n\n  // Sync iterator (but not string/array)\n  if (typeof value !== 'string' && !Array.isArray(value) && isIterator(value)) {\n    const items: unknown[] = [];\n    const iter = (value as any)[Symbol.iterator]();\n    while (true) {\n      const { done, value: item } = iter.next();\n      if (done) break;\n      items.push(item);\n    }\n    return items;\n  }\n\n  return value;\n}\n\n/**\n * Attaches a `drain()` method to a command result object.\n * If the result has an `error` field, `drain()` returns `{ error }`.\n * Otherwise, resolves the result (unwrapping Promises, collecting iterables), catches errors,\n * and returns a discriminated union `{ value } | { error }` that never throws.\n */\nexport function withDrain<T extends Record<string, unknown>>(obj: T): T & { drain: () => Promise<any> } {\n  (obj as any).drain = async () => {\n    if ('error' in obj && obj.error !== undefined) {\n      return { error: obj.error };\n    }\n    try {\n      const value = await drainValue(obj.result);\n      return { value };\n    } catch (err) {\n      return { error: err };\n    }\n  };\n  return obj as any;\n}\n\n/**\n * Creates an error command result with a `drain()` that returns the error.\n */\nexport function errorResult(error: unknown, partial?: { command?: unknown; args?: unknown; argsResult?: unknown }) {\n  return withDrain({\n    error,\n    result: undefined,\n    command: partial?.command,\n    args: partial?.args,\n    argsResult: partial?.argsResult,\n  });\n}\n\nexport function isAsyncBranded(schema: unknown): boolean {\n  return !!schema && typeof schema === 'object' && '~async' in schema && (schema as any)['~async'] === true;\n}\n\nexport function hasInteractiveConfig(meta: unknown): boolean {\n  if (!meta || typeof meta !== 'object') return false;\n  const m = meta as Record<string, unknown>;\n  return m.interactive === true || Array.isArray(m.interactive) || m.optionalInteractive === true || Array.isArray(m.optionalInteractive);\n}\n\nexport function warnIfUnexpectedAsync<T>(value: T, command: AnyPadroneCommand): T {\n  const runtime = getCommandRuntime(command);\n  if (runtime.env().NODE_ENV === 'production') return value;\n  if (value instanceof Promise && !command.isAsync) {\n    runtime.error(\n      `[padrone] Command \"${command.path || command.name}\" returned a Promise from validation, ` +\n        `but was not marked as async. Use \\`.async()\\` on the builder or \\`asyncSchema()\\` to brand your schema. ` +\n        `Without this, TypeScript will infer a sync return type and the result will be a Promise at runtime.`,\n    );\n  }\n  return value;\n}\n"],"mappings":"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"}