(
groups: ReadonlyArray<Group>,
options:
| { readonly module: string; readonly api: string }
| { readonly module: string; readonly group: string }
| { readonly module: string; readonly endpoints: Readonly<Record<string, string>> },
)
| 322 | } |
| 323 | |
| 324 | function renderImportedEffectFiles( |
| 325 | groups: ReadonlyArray<Group>, |
| 326 | options: |
| 327 | | { readonly module: string; readonly api: string } |
| 328 | | { readonly module: string; readonly group: string } |
| 329 | | { readonly module: string; readonly endpoints: Readonly<Record<string, string>> }, |
| 330 | ): Output["files"] { |
| 331 | const adapters = groups.map((group, groupIndex) => { |
| 332 | const rawGroup = group.endpoints[0]?.topLevel ? "RawClient" : `RawClient[${JSON.stringify(group.sourceIdentifier)}]` |
| 333 | const methods = group.endpoints.map((item, endpointIndex) => { |
| 334 | const prefix = `Endpoint${groupIndex}_${endpointIndex}` |
| 335 | const request = (["params", "query", "headers", "payload"] as const) |
| 336 | .flatMap((source) => { |
| 337 | const fields = item.input.filter((field) => field.source === source) |
| 338 | if (fields.length === 0) return [] |
| 339 | return [ |
| 340 | `${source}: { ${fields.map((field) => `${JSON.stringify(field.name)}: input${item.operation.inputMode === "optional" ? "?." : ""}[${JSON.stringify(field.name)}]`).join(", ")} }`, |
| 341 | ] |
| 342 | }) |
| 343 | .join(", ") |
| 344 | const input = item.input |
| 345 | .map( |
| 346 | (field) => |
| 347 | `readonly ${JSON.stringify(field.name)}${field.optional ? "?" : ""}: ${prefix}Request[${JSON.stringify(field.source)}][${JSON.stringify(field.name)}]`, |
| 348 | ) |
| 349 | .join("; ") |
| 350 | const argument = |
| 351 | item.operation.inputMode === "none" |
| 352 | ? "" |
| 353 | : `input${item.operation.inputMode === "optional" ? "?" : ""}: ${prefix}Input` |
| 354 | const rawCall = `raw[${JSON.stringify(item.endpoint.name)}]({ ${request} })` |
| 355 | const mapped = `${rawCall}.pipe(Effect.mapError(mapClientError)${item.unwrapData ? ", Effect.map((value) => value.data)" : ""})` |
| 356 | return `${item.operation.inputMode === "none" ? "" : `type ${prefix}Request = Parameters<${rawGroup}[${JSON.stringify(item.endpoint.name)}]>[0]\ntype ${prefix}Input = { ${input} }\n`}const ${prefix} = (raw: ${rawGroup}) => (${argument}) => ${item.operation.success === "stream" ? `Stream.unwrap(${rawCall}.pipe(Effect.mapError(mapClientError), Effect.map((stream) => stream.pipe(Stream.mapError(mapClientError)))))` : mapped}` |
| 357 | }) |
| 358 | return `${methods.join("\n\n")}\n\nconst adaptGroup${groupIndex} = (raw: ${rawGroup}) => ({ ${group.endpoints.map((item, endpointIndex) => `${JSON.stringify(item.operation.name)}: Endpoint${groupIndex}_${endpointIndex}(raw)`).join(", ")} })` |
| 359 | }) |
| 360 | const fields = groups.flatMap((group, index) => |
| 361 | group.endpoints[0]?.topLevel |
| 362 | ? [`...adaptGroup${index}(raw)`] |
| 363 | : [`${JSON.stringify(group.identifier)}: adaptGroup${index}(raw[${JSON.stringify(group.sourceIdentifier)}])`], |
| 364 | ) |
| 365 | const usesStream = groups.some((group) => group.endpoints.some((item) => item.operation.success === "stream")) |
| 366 | const imported = "api" in options |
| 367 | const projection = imported |
| 368 | ? undefined |
| 369 | : "group" in options |
| 370 | ? renderImportedGroup(options.group) |
| 371 | : renderImportedProjection(groups, options.endpoints) |
| 372 | const api = imported ? options.api : "Api" |
| 373 | const imports = |
| 374 | projection === undefined |
| 375 | ? `import { ${api} } from ${JSON.stringify(options.module)}` |
| 376 | : `import { HttpApi, HttpApiClient${"endpoints" in options ? ", HttpApiGroup" : ""} } from "effect/unstable/httpapi"\nimport { ${projection.imports.join(", ")} } from ${JSON.stringify(options.module)}` |
| 377 | const httpApiImport = projection === undefined ? 'import { HttpApiClient } from "effect/unstable/httpapi"\n' : "" |
| 378 | const client = `// Generated by @opencode-ai/httpapi-codegen. Do not edit.\nimport { Effect${usesStream ? ", Stream" : ""}, Schema } from "effect"\nimport { Sse } from "effect/unstable/encoding"\nimport { HttpClientError } from "effect/unstable/http"\n${httpApiImport}${imports}\nimport { ClientError } from "./client-error"\n\n${projection?.source ?? ""}type RawClient = HttpApiClient.ForApi<typeof ${api}>\n\nconst mapClientError = <E>(error: E) => HttpClientError.isHttpClientError(error) || Schema.isSchemaError(error) || Sse.Retry.is(error) ? new ClientError({ cause: error }) : error\n\n${adapters.join("\n\n")}\n\nconst adaptClient = (raw: RawClient) => ({ ${fields.join(", ")} })\n\nexport const make = (options?: { readonly baseUrl?: URL | string }) => HttpApiClient.make(${api}, options).pipe(Effect.map(adaptClient))\n` |
| 379 | return [ |
| 380 | { |
| 381 | path: "client-error.ts", |
no test coverage detected