prime8dev

prime8dev
git clone https://git.prime8.dev/prime8dev.git
Log | Files | Refs | README | LICENSE

commit 85ae0487045645646fb547fb19e307320b162543
parent 62a7de8491e0e1ce32f71fe7754887e31ff36999
Author: Damian Myrda <damian@prime8.dev>
Date:   Sat, 31 Jan 2026 19:08:11 -0600

fix(projects): rewrite relative readme links to blob urls

Diffstat:
Msrc/external/git.ts | 51+++++++++++++++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 20 deletions(-)

diff --git a/src/external/git.ts b/src/external/git.ts @@ -6,6 +6,11 @@ export interface GitMetadata { dateModified: Date; } +interface RepoUrls { + web: string; + branch: string; +} + export async function fetchGitMetadataForProject( project: Project, ): Promise<GitMetadata | null> { @@ -18,10 +23,18 @@ export async function fetchGitMetadataForProject( const data = await response.json(); - const baseUrl = `${data.web_url.replace("http://", "https://")}/-/raw/${data.default_branch}`; + const urls: RepoUrls = { + web: data.web_url.replace("http://", "https://"), + branch: data.default_branch, + }; return { - readme: await fetchReadme(baseUrl, toRawUrl(data.readme_url)), + readme: await fetchReadme( + urls, + data.readme_url + .replace("http://", "https://") + .replace("/-/blob/", "/-/raw/"), + ), dateCreated: data.created_at, dateModified: data.updated_at, }; @@ -30,39 +43,37 @@ export async function fetchGitMetadataForProject( } } -function toRawUrl(blobUrl: string): string { - return blobUrl.replace("http://", "https://").replace("/-/blob/", "/-/raw/"); -} - async function fetchReadme( - baseUrl: string, - url: string, + urls: RepoUrls, + readmeUrl: string, ): Promise<string | null> { try { - const response = await fetch(url, { + const response = await fetch(readmeUrl, { headers: { "User-Agent": "prime8dev-portfolio" }, }); if (!response.ok) return null; const content = await response.text(); - return fixRelativePaths(baseUrl, content); + return fixRelativePaths(urls, content); } catch { return null; } } -function fixRelativePaths(baseUrl: string, markdown: string): string { - // Fix relative image paths: ![alt](./path) -> ![alt](baseUrl/path) - let fixed = markdown.replace( - /!\[([^\]]*)\]\(\.\/([^)]+)\)/g, - `![$1](${baseUrl}/$2)`, +function fixRelativePaths(urls: RepoUrls, markdown: string): string { + // blob = file browser URL (for links) + const blob = `${urls.web}/-/blob/${urls.branch}`; + markdown = markdown.replace( + /(?<!!)\[([^\]]+)\]\((?!https?:\/\/)([^)]+)\)/g, + `[$1](${blob}/$2)`, ); - // Fix relative link paths (not images): [text](./path) -> [text](baseUrl/path) - fixed = fixed.replace( - /(?<!!)\[([^\]]+)\]\(\.\/([^)]+)\)/g, - `[$1](${baseUrl}/$2)`, + // raw = direct file content URL (for images) + const raw = `${urls.web}/-/raw/${urls.branch}`; + markdown = markdown.replace( + /!\[([^\]]*)\]\((?!https?:\/\/)([^)]+)\)/g, + `![$1](${raw}/$2)`, ); - return fixed; + return markdown; }