This repository has no description
1import type { BobbinContext, XrpcRequestInit } from "./client";
2import { createBobbinClient } from "./client";
3import { jsonGet, rawGet } from "./_request";
4import type * as LegacyTree from "./lexicons/types/sh/tangled/git/temp/getTree";
5import type * as Tree from "./lexicons/types/sh/tangled/repo/tree";
6import { treeEntryKind, type BranchesResponse, type LogResponse, type TagsResponse } from "./repo";
7
8const TREE_NSID = "sh.tangled.git.temp.getTree";
9const BLOB_NSID = "sh.tangled.git.temp.getBlob";
10const LOG_NSID = "sh.tangled.git.temp.listCommits";
11const BRANCHES_NSID = "sh.tangled.git.temp.listBranches";
12const TAGS_NSID = "sh.tangled.git.temp.listTags";
13const LANGUAGES_NSID = "sh.tangled.git.temp.listLanguages";
14
15export interface KnotMirrorLanguagesResponse {
16 languages?: { name: string; size: number }[];
17 total?: number;
18 ref?: string;
19}
20
21export const createKnotMirrorClient = (serviceUrl: string, fetch: typeof globalThis.fetch) =>
22 createBobbinClient({ serviceUrl, fetch });
23
24const normalizeSignature = (
25 signature: LegacyTree.Signature | undefined
26): Tree.Signature | undefined =>
27 signature ? { name: signature.name, email: signature.email, when: signature.when } : undefined;
28
29const normalizeCommit = (commit: LegacyTree.LastCommit | undefined): Tree.LastCommit | undefined =>
30 commit
31 ? {
32 hash: commit.hash,
33 message: commit.message,
34 when: commit.when,
35 author: normalizeSignature(commit.author)
36 }
37 : undefined;
38
39const normalizeTree = (tree: LegacyTree.$output): Tree.$output => ({
40 ref: tree.ref,
41 parent: tree.parent,
42 dotdot: tree.dotdot,
43 lastCommit: normalizeCommit(tree.lastCommit),
44 files: tree.files.map((entry) => ({
45 name: entry.name,
46 mode: entry.mode,
47 size: entry.size,
48 last_commit: normalizeCommit(entry.last_commit)
49 }))
50});
51
52const isReadmeFile = (name: string, mode: string): boolean =>
53 /^readme(?:\.[^.]+)?$/i.test(name) && treeEntryKind(mode) === "file";
54
55const pathInTree = (path: string | undefined, name: string): string =>
56 path ? `${path}/${name}` : name;
57
58export const tree = async (
59 ctx: BobbinContext,
60 params: { repo: string; ref: string; path?: string },
61 init?: XrpcRequestInit
62): Promise<Tree.$output> => {
63 const response = await jsonGet<LegacyTree.$output>(ctx, TREE_NSID, params, init);
64 const result = normalizeTree(response);
65 const readme = response.files.find((entry) => isReadmeFile(entry.name, entry.mode));
66 if (!readme) return result;
67
68 try {
69 const blob = await rawGet(
70 ctx,
71 BLOB_NSID,
72 { repo: params.repo, ref: params.ref, path: pathInTree(params.path, readme.name) },
73 init
74 );
75 return { ...result, readme: { filename: readme.name, contents: await blob.text() } };
76 } catch {
77 return result;
78 }
79};
80
81export const log = (
82 ctx: BobbinContext,
83 params: { repo: string; ref: string; limit: number },
84 init?: XrpcRequestInit
85) => jsonGet<LogResponse>(ctx, LOG_NSID, params, init);
86
87export const branches = (
88 ctx: BobbinContext,
89 params: { repo: string; limit: number },
90 init?: XrpcRequestInit
91) => jsonGet<BranchesResponse>(ctx, BRANCHES_NSID, params, init);
92
93export const tags = (
94 ctx: BobbinContext,
95 params: { repo: string; limit: number },
96 init?: XrpcRequestInit
97) => jsonGet<TagsResponse>(ctx, TAGS_NSID, params, init);
98
99export const languages = (
100 ctx: BobbinContext,
101 params: { repo: string; ref: string },
102 init?: XrpcRequestInit
103) => jsonGet<KnotMirrorLanguagesResponse>(ctx, LANGUAGES_NSID, params, init);