1import type { VcsRef } from "@t3tools/contracts";
2
3export interface BaseRefChoice {
4 readonly id: string;
5 readonly label: string;
6 readonly local: VcsRef | null;
7 readonly remote: VcsRef | null;
8}
9
10function remoteBranchName(ref: VcsRef): string {
11 if (ref.remoteName && ref.name.startsWith(`${ref.remoteName}/`)) {
12 return ref.name.slice(ref.remoteName.length + 1);
13 }
14 return ref.name;
15}
16
17export function buildBaseRefChoices(
18 localRefs: ReadonlyArray<VcsRef>,
19 remoteRefs: ReadonlyArray<VcsRef>,
20): ReadonlyArray<BaseRefChoice> {
21 const unusedRemoteRefs = new Set(remoteRefs);
22 const pairedChoices = localRefs.map((local) => {
23 const matches = remoteRefs.filter(
24 (remote) => unusedRemoteRefs.has(remote) && remoteBranchName(remote) === local.name,
25 );
26 const remote =
27 matches.find((candidate) => candidate.remoteName === "origin") ?? matches[0] ?? null;
28 if (remote) unusedRemoteRefs.delete(remote);
29 return {
30 id: `local:${local.name}`,
31 label: local.name,
32 local,
33 remote,
34 };
35 });
36
37 const remoteOnlyChoices = remoteRefs
38 .filter((remote) => unusedRemoteRefs.has(remote))
39 .map((remote) => ({
40 id: `remote:${remote.name}`,
41 label: remote.name,
42 local: null,
43 remote,
44 }));
45
46 return [...pairedChoices, ...remoteOnlyChoices];
47}
48
49export function filterBaseRefChoices(
50 choices: ReadonlyArray<BaseRefChoice>,
51 query: string,
52): ReadonlyArray<BaseRefChoice> {
53 const normalizedQuery = query.trim().toLocaleLowerCase();
54 if (normalizedQuery.length === 0) return choices;
55 return choices.filter(
56 (choice) =>
57 choice.label.toLocaleLowerCase().includes(normalizedQuery) ||
58 choice.local?.name.toLocaleLowerCase().includes(normalizedQuery) === true ||
59 choice.remote?.name.toLocaleLowerCase().includes(normalizedQuery) === true,
60 );
61}