// Copyright 2026 The Forgejo Authors. All rights reserved. // SPDX-License-Identifier: MIT // // Pure ifc:// URL logic shared between viewer.html and tests. export function parseIfcUrl(raw) { if (!raw?.startsWith("ifc://")) return null; const body = raw.slice("ifc://".length); const slashIdx = body.indexOf("/"); const authority = slashIdx < 0 ? body : body.slice(0, slashIdx); const pathAndQuery = slashIdx < 0 ? "" : body.slice(slashIdx + 1); const atInAuth = authority.indexOf("@"); const userAt = atInAuth < 0 ? "" : authority.slice(0, atInAuth + 1); const host = atInAuth < 0 ? authority : authority.slice(atInAuth + 1); const qIdx = pathAndQuery.indexOf("?"); const pathPart = qIdx < 0 ? pathAndQuery : pathAndQuery.slice(0, qIdx); const qs = new URLSearchParams(qIdx < 0 ? "" : pathAndQuery.slice(qIdx + 1)); const atIdx = pathPart.lastIndexOf("@"); const repoSuffix = atIdx < 0 ? pathPart : pathPart.slice(0, atIdx); const ref = atIdx < 0 ? "" : pathPart.slice(atIdx + 1); return { repo: userAt + host + "/" + repoSuffix, host, userAt, repoSuffix, ref, path: qs.get("path") ?? "", selector: qs.get("selector") ?? "", camera: qs.get("camera") ?? "", fov: qs.get("fov") ?? "", scale: qs.get("scale") ?? "", }; } export function buildIfcUrl(repo, ref, path, selector) { if (!repo || !ref) return null; const qs = new URLSearchParams(); if (path) qs.set("path", path); if (selector) qs.set("selector", selector); const qsStr = qs.toString().replace(/%2C/g, ",").replace(/%2B/g, "+").replace(/%24/g, "$"); return `ifc://${repo}@${ref}${qsStr ? "?" + qsStr : ""}`; } export function toRawUrl(raw) { const body = raw.slice("ifc://".length); const slashIdx = body.indexOf("/"); const authority = slashIdx < 0 ? body : body.slice(0, slashIdx); const pathAndQuery = slashIdx < 0 ? "" : body.slice(slashIdx + 1); const atInAuth = authority.indexOf("@"); const host = atInAuth < 0 ? authority : authority.slice(atInAuth + 1); const qIdx = pathAndQuery.indexOf("?"); const pathPart = qIdx < 0 ? pathAndQuery : pathAndQuery.slice(0, qIdx); const qs = new URLSearchParams(qIdx < 0 ? "" : pathAndQuery.slice(qIdx + 1)); const filePath = qs.get("path") ?? ""; const atIdx = pathPart.lastIndexOf("@"); const repoPath = atIdx < 0 ? pathPart : pathPart.slice(0, atIdx); const ref = atIdx < 0 ? "" : pathPart.slice(atIdx + 1); const plainRef = ref.startsWith("heads/") ? ref.slice(6) : ref.startsWith("tags/") ? ref.slice(5) : ref; if (host === "github.com" || host.endsWith(".github.com")) { return `https://raw.githubusercontent.com/${repoPath}/${plainRef}/${filePath}`; } if (host === "gitlab.com" || host.startsWith("gitlab.")) { const proto = host.startsWith("localhost") ? "http" : "https"; return `${proto}://${host}/${repoPath}/-/raw/${plainRef}/${filePath}`; } const refSeg = ref.startsWith("heads/") ? "branch/" + ref.slice(6) : ref.startsWith("tags/") ? "tag/" + ref.slice(5) : "commit/" + ref; const proto = host.startsWith("localhost") ? "http" : "https"; return `${proto}://${host}/${repoPath}/raw/${refSeg}/${filePath}`; }