feat(plugin): support plugin-provided tools (#34619)
This commit is contained in:
parent
a5c51e11d0
commit
194b0615e0
52 changed files with 1633 additions and 959 deletions
|
|
@ -244,6 +244,16 @@ export function emitEffectImported(
|
|||
}
|
||||
}
|
||||
|
||||
export function emitEffectShape(
|
||||
contract: Contract,
|
||||
options: { readonly module: string; readonly api: string },
|
||||
): Output {
|
||||
return {
|
||||
operations: operations(contract.groups),
|
||||
files: [{ path: "api.ts", content: renderEffectShape(contract.groups, options) }],
|
||||
}
|
||||
}
|
||||
|
||||
export function emitPromise(
|
||||
contract: Contract,
|
||||
options?: {
|
||||
|
|
@ -275,6 +285,75 @@ export function emitPromise(
|
|||
}
|
||||
}
|
||||
|
||||
function renderEffectShape(groups: ReadonlyArray<Group>, options: { readonly module: string; readonly api: string }) {
|
||||
const endpointTypes = groups.map((group, groupIndex) => {
|
||||
const rawGroup = group.endpoints[0]?.topLevel ? "RawClient" : `RawClient[${JSON.stringify(group.sourceIdentifier)}]`
|
||||
const endpoints = group.endpoints.map((endpoint, endpointIndex) => {
|
||||
const prefix = `Endpoint${groupIndex}_${endpointIndex}`
|
||||
const request =
|
||||
endpoint.operation.inputMode === "none"
|
||||
? ""
|
||||
: `type ${prefix}Request = Parameters<${rawGroup}[${JSON.stringify(endpoint.endpoint.name)}]>[0]`
|
||||
const input = endpoint.input
|
||||
.map(
|
||||
(field) =>
|
||||
`readonly ${JSON.stringify(field.name)}${field.optional ? "?" : ""}: ${prefix}Request[${JSON.stringify(field.source)}][${JSON.stringify(field.name)}]`,
|
||||
)
|
||||
.join("; ")
|
||||
const inputType = endpoint.operation.inputMode === "none" ? "" : `export type ${prefix}Input = { ${input} }`
|
||||
const rawOutput = `EffectValue<ReturnType<${rawGroup}[${JSON.stringify(endpoint.endpoint.name)}]>>`
|
||||
const outputType = isStreamSchema(endpoint.successes[0])
|
||||
? `export type ${prefix}Output = StreamValue<${rawOutput}>`
|
||||
: `export type ${prefix}Output = ${endpoint.unwrapData ? `(${rawOutput})["data"]` : rawOutput}`
|
||||
return [
|
||||
request,
|
||||
endpoint.operation.inputMode === "none" ? "" : inputType,
|
||||
outputType,
|
||||
`export type ${groupShapeTypeName(group, endpoint)}<E = never> = (${endpoint.operation.inputMode === "none" ? "" : `input${endpoint.operation.inputMode === "optional" ? "?" : ""}: ${prefix}Input`}) => ${endpoint.operation.success === "stream" ? `Stream.Stream<${prefix}Output, E>` : `Effect.Effect<${prefix}Output, E>`}`,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n")
|
||||
})
|
||||
const methods = group.endpoints
|
||||
.map(
|
||||
(endpoint) => `readonly ${JSON.stringify(endpoint.operation.name)}: ${groupShapeTypeName(group, endpoint)}<E>`,
|
||||
)
|
||||
.join("\n")
|
||||
return `${endpoints.join("\n\n")}\n\nexport interface ${groupShapeName(group)}<E = never> {\n${methods}\n}`
|
||||
})
|
||||
const clientFields = groups.flatMap((group) =>
|
||||
group.endpoints[0]?.topLevel
|
||||
? group.endpoints.map(
|
||||
(endpoint) =>
|
||||
`readonly ${JSON.stringify(endpoint.operation.name)}: ${groupShapeTypeName(group, endpoint)}<E>`,
|
||||
)
|
||||
: [`readonly ${JSON.stringify(group.identifier)}: ${groupShapeName(group)}<E>`],
|
||||
)
|
||||
return `// Generated by @opencode-ai/httpapi-codegen. Do not edit.
|
||||
import type { Effect, Stream } from "effect"
|
||||
import type { HttpApiClient } from "effect/unstable/httpapi"
|
||||
import type { ${options.api} } from ${JSON.stringify(options.module)}
|
||||
|
||||
type RawClient = HttpApiClient.ForApi<typeof ${options.api}>
|
||||
type EffectValue<A> = A extends Effect.Effect<infer Success, any, any> ? Success : never
|
||||
type StreamValue<A> = A extends Stream.Stream<infer Success, any, any> ? Success : never
|
||||
|
||||
${endpointTypes.join("\n\n")}
|
||||
|
||||
export interface AppApi<E = never> {
|
||||
${clientFields.join("\n")}
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
function groupShapeName(group: Group) {
|
||||
return `${identifierPart(group.identifier)}Api`
|
||||
}
|
||||
|
||||
function groupShapeTypeName(group: Group, endpoint: Endpoint) {
|
||||
return `${identifierPart(group.identifier)}${identifierPart(endpoint.operation.name)}Operation`
|
||||
}
|
||||
|
||||
function assertPromiseEndpoint(endpoint: Endpoint) {
|
||||
const name = `${endpoint.group}.${endpoint.endpoint.name}`
|
||||
const payload = endpoint.payloads[0]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue