1import { builtInSourceControlDefinitions } from "@t3tools/source-control-definitions/registry";
2import {
3 HostCredentialSettings,
4 readSourceControlHostSettings,
5 type SourceControlAppSignIn,
6 type SourceControlDefinition,
7} from "@t3tools/source-control-core/shared/definition";
8import type { ServerSettings, SourceControlAppAccessInput } from "@t3tools/contracts";
9import { parseGitRemoteRepository } from "@t3tools/shared/git";
10
11export {
12 isMonochromeSourceControlIcon,
13 UNKNOWN_SOURCE_CONTROL_CLIENT,
14 type ChangeRequestLink,
15 type ChangeRequestTerminology,
16 type HostAccountChoice,
17 type HostCredentialSettings,
18 type ParsedChangeRequestUrl,
19 type ReferenceAutolink,
20 type SourceControlAppSignIn,
21 type SourceControlDefinition,
22 type SourceControlHostCredentials,
23 type SourceControlIcon,
24} from "@t3tools/source-control-core/shared/definition";
25
26export const sourceControlClients = builtInSourceControlDefinitions;
27
28/** The saved per-hostname accounts and tokens of a host whose definition has `credentials`. */
29export function readHostCredentialSettings(
30 settings: Pick<ServerSettings, "sourceControlHosts">,
31 kind: string,
32): HostCredentialSettings {
33 return readSourceControlHostSettings(HostCredentialSettings, settings.sourceControlHosts[kind]);
34}
35
36/** A host's change request term where it opens a sentence: "Merge request merged". */
37export function capitalizeTerm(term: string): string {
38 return term.charAt(0).toUpperCase() + term.slice(1);
39}
40
41/** The repository a remote names, when its host has an app sign-in that could reach it. */
42export function appSignInTargetForRemote(remoteUrl: string): {
43 readonly definition: SourceControlDefinition;
44 readonly appSignIn: SourceControlAppSignIn;
45 readonly input: SourceControlAppAccessInput;
46} | null {
47 const parsed = parseGitRemoteRepository(remoteUrl);
48 const provider = sourceControlClients.recognizeRemote(remoteUrl);
49 const definition = provider ? sourceControlClients.find(provider.kind) : undefined;
50 const appSignIn = definition?.credentials?.appSignIn;
51 if (parsed === null || definition === undefined || appSignIn === undefined) return null;
52 if (!appSignIn.hosts.includes(parsed.host)) return null;
53 // The parser lowercases; keep the remote's own casing for display when it names the same path.
54 const asWritten = remoteUrl
55 .trim()
56 .replace(/\.git\/?$/i, "")
57 .split(/[/:]/)
58 .slice(-2)
59 .join("/");
60 const repository = asWritten.toLowerCase() === parsed.path ? asWritten : parsed.path;
61 return {
62 definition,
63 appSignIn,
64 input: { provider: definition.kind, host: parsed.host, repository },
65 };
66}