Skip to content
Source
Sign inSign up

codexFileCitations.ts

56 lines1.9 KB

1export interface CodexFileCitationLink {
2 readonly path: string;
3 readonly href: string;
4 readonly label: string;
5 readonly lineRangeStart?: number;
6}
7​
8export type CodexFileCitationAttributes = Readonly<Record<string, string | null | undefined>>;
9​
10function positiveInteger(value: string | null | undefined): number | undefined {
11 if (value === null || value === undefined || value.trim().length === 0) return undefined;
12 const parsed = Number(value);
13 return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
15​
16function citationLabel(path: string): string {
17 const normalized = path.replaceAll("\\", "/").replace(/\/+$/, "");
18 return normalized.slice(normalized.lastIndexOf("/") + 1) || normalized || "File";
20​
21function markdownDestinationPath(path: string): string {
22 return path.replaceAll("%", "%25").replaceAll("#", "%23").replaceAll("?", "%3F");
24​
25export function resolveCodexFileCitationLink(
26 attributes: CodexFileCitationAttributes | null | undefined,
27): CodexFileCitationLink | null {
28 const path = attributes?.path?.trim();
29 if (!path) return null;
30​
31 const lineRangeStart = positiveInteger(attributes?.line_range_start);
32 const destinationPath = markdownDestinationPath(path);
33 return {
34 path,
35 href: lineRangeStart === undefined ? destinationPath : `${destinationPath}#L${lineRangeStart}`,
36 label: citationLabel(path),
37 ...(lineRangeStart === undefined ? {} : { lineRangeStart }),
38 };
40​
41function markdownLabel(value: string): string {
42 return value.replace(/[\\[\]*_`<&]/g, "\\$&");
44​
45function markdownDestination(value: string): string {
46 return value
47 .replaceAll("\\", "%5C")
48 .replaceAll("<", "%3C")
49 .replaceAll(">", "%3E")
50 .replaceAll("\r", "%0D")
51 .replaceAll("\n", "%0A");
53​
54export function codexFileCitationMarkdown(citation: CodexFileCitationLink): string {
55 return `[${markdownLabel(citation.label)}](<${markdownDestination(citation.href)}>)`;