Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

56 linesCodeBlameRaw
1/**
2 * Where `#N` in text leads on the site: the rules of
3 * `crates/contracts/src/work/refs.rs`, which every reader of references
4 * follows. A reference is `#N`, `owner/name#N` (read in that repository)
5 * or `workspace#N` (in that workspace). Read in a repository, `#N` is its
6 * pull request N, else the work item that was its issue N, else the
7 * workspace's work item N, else a pull request N of another of its
8 * repositories, numbered after work items came (an older pull request's
9 * number is only its repository's): only the work service knows which, so a link goes through
10 * `/<owner>/<repo>/ref/<n>`, which asks it (`resolveRef`) and sends the
11 * browser on. Read in a workspace alone, `#N` is its work item N, else its
12 * pull request N numbered after work items came: the work item's page sends
13 * a pull request's number on.
14 * Pure, so it is tested under Node.
15 */
16
17/** Where text is read: in a repository (and its workspace), or in a workspace alone. */
18export type RefContext = { repo: { namespace: string; name: string } } | { workspace: string };
19
20/** A reference found in text. */
21export type Ref =
22 | { scope: "here"; number: number }
23 | { scope: "repo"; namespace: string; name: string; number: number }
24 | { scope: "workspace"; workspace: string; number: number };
25
26/** A work item's page. */
27export function itemPath(workspace: string, number: number): string {
28 return `/${workspace.toLowerCase()}/-/work/${number}`;
29}
30
31/** The page that reads `#number` in a repository and sends the browser to what it names. */
32export function repoRefPath(repo: { namespace: string; name: string }, number: number): string {
33 return `/${repo.namespace.toLowerCase()}/${repo.name}/ref/${number}`;
34}
35
36/** Where a reference leads, read in `context`; null for `#N` with no context to read it in. */
37export function refHref(ref: Ref, context: RefContext | null | undefined): string | null {
38 switch (ref.scope) {
39 case "repo":
40 return repoRefPath({ namespace: ref.namespace, name: ref.name }, ref.number);
41 case "workspace":
42 return itemPath(ref.workspace, ref.number);
43 case "here":
44 if (!context) return null;
45 return "repo" in context ? repoRefPath(context.repo, ref.number) : itemPath(context.workspace, ref.number);
46 }
47}
48
49/** A reference in its written form: `owner/name#12`, `workspace#12` or `#12`. */
50export function parseRef(owner: string | undefined, name: string | undefined, number: string): Ref | null {
51 const n = Number(number);
52 if (!Number.isInteger(n) || n < 1 || number.length > 9) return null;
53 if (owner && name) return { scope: "repo", namespace: owner.toLowerCase(), name, number: n };
54 if (owner) return { scope: "workspace", workspace: owner.toLowerCase(), number: n };
55 return { scope: "here", number: n };
56}