25 lines
1.1 KiB
JavaScript
25 lines
1.1 KiB
JavaScript
export function fileUrl(path, line, fragment) {
|
|
const query = new URLSearchParams({ file: path });
|
|
if (line) query.set('line', String(line));
|
|
return '/?' + query + (fragment ? '#' + fragment : '');
|
|
}
|
|
|
|
export function resolveDocumentLink(href, documentPath) {
|
|
if (/^https?:\/\//i.test(href) || href.startsWith('#')) return href;
|
|
const hash = href.indexOf('#');
|
|
const fragment = hash < 0 ? '' : href.slice(hash + 1);
|
|
const reference = hash < 0 ? href : href.slice(0, hash);
|
|
const match = reference.match(/^(.*?)(?::([1-9]\d*))?$/);
|
|
let target;
|
|
try { target = decodeURIComponent(match[1]); } catch { return null; }
|
|
if (!target || /^[a-z][a-z\d+.-]*:/i.test(target) || /^[\\/]/.test(target) || target.includes('\\')) return null;
|
|
const parts = documentPath.split('/').slice(0, -1);
|
|
for (const part of target.split('/')) {
|
|
if (!part || part === '.') continue;
|
|
if (part === '..' && parts.length && parts.at(-1) !== '..') parts.pop();
|
|
else parts.push(part);
|
|
}
|
|
const lineFragment = fragment.match(/^L([1-9]\d*)$/);
|
|
return fileUrl(parts.join('/'), Number(lineFragment?.[1] || match[2]) || undefined, lineFragment ? undefined : fragment);
|
|
}
|