Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162import { jsonGet } from "$lib/api/_request";import { coAuthorsFrom, didFromSignature, FULL_HASH_RE, splitMessage, type CommitDetail, type CommitSummary} from "$lib/api/repo";import type { Did } from "@atcute/lexicons/syntax";import type { BobbinContext, XrpcRequestInit } from "$lib/api/client";import type { Revspec } from "$lib/api/pullRoute";import type * as ShTangledGitDefs from "$lib/api/lexicons/types/sh/tangled/git/defs";import type * as GetBlame from "$lib/api/lexicons/types/sh/tangled/git/temp2/getBlame";import type * as GetDiff from "$lib/api/lexicons/types/sh/tangled/git/temp2/getDiff";import type * as GetInterdiff from "$lib/api/lexicons/types/sh/tangled/git/temp2/getInterdiff";import type * as ListCommits from "$lib/api/lexicons/types/sh/tangled/git/temp2/listCommits";import type * as MergeCheck from "$lib/api/lexicons/types/sh/tangled/git/temp2/mergeCheck";
// gitmirror's own xrpc surface, proxied through bobbin — its grpc service is// internal and streaming, so the read paths the frontend needs live hereconst LIST_COMMITS_NSID = "sh.tangled.git.temp2.listCommits";const GET_DIFF_NSID = "sh.tangled.git.temp2.getDiff";const GET_INTERDIFF_NSID = "sh.tangled.git.temp2.getInterdiff";const GET_BLAME_NSID = "sh.tangled.git.temp2.getBlame";const MERGE_CHECK_NSID = "sh.tangled.git.temp2.mergeCheck";
export const getBlame = (ctx: BobbinContext, params: GetBlame.$params, init?: XrpcRequestInit) => jsonGet<GetBlame.$output>(ctx, GET_BLAME_NSID, params, init);
export type MirrorCommit = ListCommits.Commit;
export const listCommits = ( ctx: BobbinContext, params: ListCommits.$params, init?: XrpcRequestInit) => jsonGet<ListCommits.$output>(ctx, LIST_COMMITS_NSID, params, init);
export const commitAtRef = async ( ctx: BobbinContext, repo: Did, ref: string, init?: XrpcRequestInit): Promise<MirrorCommit | undefined> => { const page = await listCommits(ctx, { repo, ranges: [ref], limit: 1 }, init); const first = page.commits[0]; if (!first || !FULL_HASH_RE.test(ref) || first.oid.toLowerCase() === ref.toLowerCase()) { return first; } const exact = await listCommits(ctx, { repo, ranges: [`${ref}^..${ref}`], limit: 100 }, init); return exact.commits.find((commit) => commit.oid.toLowerCase() === ref.toLowerCase());};
const LOG_LIMIT = 100;
// every commit a pull version brought, newest firstexport const listLog = async ( ctx: BobbinContext, repo: Did, range: Revspec, init?: XrpcRequestInit): Promise<CommitSummary[]> => { const page = await listCommits( ctx, { repo, ranges: [`${range.base}..${range.head}`], limit: LOG_LIMIT }, init ); return page.commits.map(toMirrorCommitSummary);};
export type MirrorFileDiff = ShTangledGitDefs.FileDiff;
export const getDiff = (ctx: BobbinContext, params: GetDiff.$params, init?: XrpcRequestInit) => jsonGet<GetDiff.$output>(ctx, GET_DIFF_NSID, params, init);
// `base*` is the older version's span, `head*` the newer one's: gitmirror// rebases base1..base2 onto head1 and diffs the result against head2export const getInterdiff = ( ctx: BobbinContext, params: GetInterdiff.$params, init?: XrpcRequestInit) => jsonGet<GetInterdiff.$output>(ctx, GET_INTERDIFF_NSID, params, init);
export type MirrorConflict = MergeCheck.Conflict;
export const mergeCheck = ( ctx: BobbinContext, params: MergeCheck.$params, init?: XrpcRequestInit) => jsonGet<MergeCheck.$output>(ctx, MERGE_CHECK_NSID, params, init);
export type MirrorFileKind = "new" | "deleted" | "renamed" | "changed";
// an add or delete carries the same path on both sides — gix names both resources// after the change's location — so the side that doesn't exist is the one whose oid// is null, not the one whose path is emptyexport const diffSideExists = (src: ShTangledGitDefs.DiffSrc): boolean => src.path !== "" && !/^0+$/.test(src.oid);
export const diffFileName = (file: MirrorFileDiff): string => file.rhsSrc.path || file.lhsSrc.path;
export const diffFileKind = (file: MirrorFileDiff): MirrorFileKind => { if (!diffSideExists(file.lhsSrc)) return "new"; if (!diffSideExists(file.rhsSrc)) return "deleted"; return file.lhsSrc.path === file.rhsSrc.path ? "changed" : "renamed";};
// the payload has no line text, only aligned line numbers: a pair with one side// missing is a pure insertion or deletion, a pair with both is a replaced lineexport const diffFileStat = (file: MirrorFileDiff): { insertions: number; deletions: number } => { let insertions = 0; let deletions = 0; for (const hunk of file.hunks) { for (const line of hunk.lines) { if (line.rhs !== undefined) insertions++; if (line.lhs !== undefined) deletions++; } } return { insertions, deletions };};
export const mirrorChangeId = (commit: MirrorCommit): string | undefined => commit.extraHeaders.find((header) => header.key === "change-id")?.value;
export const toMirrorCommitSummary = (commit: MirrorCommit): CommitSummary => { const [subject, body] = splitMessage(commit.message); return { hash: commit.oid, shortHash: commit.oid.slice(0, 8), subject, body, authorName: commit.author.name, authorEmail: commit.author.email, when: commit.committer.when ?? commit.author.when, // the pull page links a commit row as `firstParent..commit` parent: commit.parents[0], changeId: mirrorChangeId(commit) };};
export const toMirrorCommitDetail = (commit: MirrorCommit): CommitDetail => { const [subject, body] = splitMessage(commit.message); const committerWhen = commit.committer.when ?? ""; return { hash: commit.oid, shortHash: commit.oid.slice(0, 8), subject, body, authorName: commit.author.name, authorEmail: commit.author.email, authorDid: didFromSignature(commit.author.email), authorWhen: commit.author.when ?? "", committerName: commit.committer.name, committerEmail: commit.committer.email, committerWhen, coAuthors: coAuthorsFrom(commit.message, committerWhen).map(({ Name, Email }) => ({ name: Name, email: Email })) };};