1import * as Context from "effect/Context";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import type { SourceControlProviderKind } from "@t3tools/contracts";
5
6import * as BuiltInDrivers from "../sourceControl/builtInDrivers.ts";
7import type { PullRequestProviderApi } from "@t3tools/source-control-core/server/PullRequestProvider";
8
9export class PullRequestProviderRegistry extends Context.Service<
10 PullRequestProviderRegistry,
11 {
12 /** Null for a host with no implementation, which the service reports as unsupported. */
13 readonly get: (kind: SourceControlProviderKind) => PullRequestProviderApi | null;
14 readonly kinds: ReadonlyArray<SourceControlProviderKind>;
15 }
16>()("t3/pullRequest/PullRequestProviderRegistry") {}
17
18/** Exported for tests, which stand a registry up from providers they supply themselves. */
19export function fromProviders(
20 providers: ReadonlyArray<PullRequestProviderApi>,
21): PullRequestProviderRegistry["Service"] {
22 const byKind = new Map(providers.map((provider) => [provider.kind, provider]));
23 return {
24 get: (kind) => byKind.get(kind) ?? null,
25 kinds: providers.map((provider) => provider.kind),
26 };
27}
28
29/**
30 * The hosts this build can read change requests from. A host with no entry here still shows up
31 * in the provider list as unimplemented, so its projects are explained rather than missing.
32 *
33 * @public Service construction is part of the canonical Effect module API.
34 */
35export const make = Effect.gen(function* () {
36 const drivers = yield* Effect.forEach(BuiltInDrivers.BUILT_IN_SOURCE_CONTROL_DRIVERS, (driver) =>
37 driver.make.pipe(Effect.map((instance) => instance.pullRequests)),
38 );
39 return fromProviders(
40 drivers.filter((provider): provider is PullRequestProviderApi => provider !== null),
41 );
42});
43
44export const layer = Layer.effect(PullRequestProviderRegistry, make).pipe(
45 Layer.provide(BuiltInDrivers.layer),
46);