import { Context, Effect } from "effect"; import type { ChangeRequest, ChangeRequestState, SourceControlProviderError, SourceControlProviderInfo, SourceControlProviderKind, SourceControlRepositoryCloneUrls, SourceControlRepositoryVisibility, } from "@t3tools/contracts"; export interface SourceControlProviderContext { readonly provider: SourceControlProviderInfo; readonly remoteName: string; readonly remoteUrl: string; } export interface SourceControlRefSelector { readonly refName: string; readonly owner?: string; readonly repository?: string; } export function parseSourceControlOwnerRef( headSelector: string, ): SourceControlRefSelector | undefined { const match = /^([^:/\s]+):(.+)$/u.exec(headSelector.trim()); const owner = match?.[1]?.trim(); const refName = match?.[2]?.trim(); return owner && refName ? { owner, refName } : undefined; } export function normalizeSourceBranch(headSelector: string): string { return parseSourceControlOwnerRef(headSelector)?.refName ?? headSelector.trim(); } export function sourceBranch(input: { readonly headSelector: string; readonly source?: SourceControlRefSelector; }): string { return input.source?.refName ?? normalizeSourceBranch(input.headSelector); } export function sourceControlRefFromInput(input: { readonly headSelector: string; readonly source?: SourceControlRefSelector; }): SourceControlRefSelector | undefined { return input.source ?? parseSourceControlOwnerRef(input.headSelector); } export interface SourceControlProviderShape { readonly kind: SourceControlProviderKind; readonly listChangeRequests: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; readonly source?: SourceControlRefSelector; readonly headSelector: string; readonly state: ChangeRequestState | "all"; readonly limit?: number; }) => Effect.Effect, SourceControlProviderError>; readonly getChangeRequest: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; readonly reference: string; }) => Effect.Effect; readonly createChangeRequest: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; readonly source?: SourceControlRefSelector; readonly target?: SourceControlRefSelector; readonly baseRefName: string; readonly headSelector: string; readonly title: string; readonly bodyFile: string; }) => Effect.Effect; readonly getRepositoryCloneUrls: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; readonly repository: string; }) => Effect.Effect; readonly createRepository: (input: { readonly cwd: string; readonly repository: string; readonly visibility: SourceControlRepositoryVisibility; }) => Effect.Effect; readonly getDefaultBranch: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; }) => Effect.Effect; readonly checkoutChangeRequest: (input: { readonly cwd: string; readonly context?: SourceControlProviderContext; readonly reference: string; readonly force?: boolean; }) => Effect.Effect; } export class SourceControlProvider extends Context.Service< SourceControlProvider, SourceControlProviderShape >()("t3/source-control/SourceControlProvider") {}