forked from github/quartz
95 lines
2.3 KiB
TypeScript
95 lines
2.3 KiB
TypeScript
import { FilePath, FullSlug, slugifyFilePath } from "./path"
|
|
|
|
export type WikilinkWithPosition = {
|
|
wikilink: ParsedWikilink
|
|
start: number
|
|
end: number
|
|
}
|
|
|
|
export type ParsedWikilink = {
|
|
raw: string
|
|
target: string
|
|
anchor?: string
|
|
alias?: string
|
|
embed: boolean
|
|
}
|
|
|
|
export type ResolvedWikilink = {
|
|
slug: FullSlug
|
|
anchor?: string
|
|
}
|
|
|
|
const wikilinkRegex = /^!?\[\[([^\]|#]+)(?:#([^\]|]+))?(?:\|([^\]]+))?\]\]$/
|
|
|
|
export function parseWikilink(text: string): ParsedWikilink | null {
|
|
const trimmed = text.trim()
|
|
const match = wikilinkRegex.exec(trimmed)
|
|
if (!match) return null
|
|
|
|
const [, target, anchor, alias] = match
|
|
return {
|
|
raw: trimmed,
|
|
target: target?.trim() ?? "",
|
|
anchor: anchor?.trim(),
|
|
alias: alias?.trim(),
|
|
embed: trimmed.startsWith("!"),
|
|
}
|
|
}
|
|
|
|
export function resolveWikilinkTarget(
|
|
parsed: ParsedWikilink,
|
|
currentSlug: FullSlug,
|
|
): ResolvedWikilink | null {
|
|
const target = parsed.target.trim()
|
|
if (!target) return null
|
|
|
|
if (target.startsWith("/")) {
|
|
const slug = slugifyFilePath(target.slice(1).replace(/\\/g, "/") as FilePath)
|
|
return { slug, anchor: parsed.anchor }
|
|
}
|
|
|
|
const currentParts = currentSlug.split("/")
|
|
const currentDir = currentParts.slice(0, -1)
|
|
|
|
const targetParts = target.replace(/\\/g, "/").split("/")
|
|
const resolved: string[] = [...currentDir]
|
|
|
|
for (const part of targetParts) {
|
|
if (part === "..") {
|
|
resolved.pop()
|
|
} else if (part !== "." && part.length > 0) {
|
|
resolved.push(part)
|
|
}
|
|
}
|
|
|
|
const slug = slugifyFilePath(resolved.join("/") as FilePath)
|
|
return { slug, anchor: parsed.anchor }
|
|
}
|
|
|
|
const globalWikilinkRegex = /!?\[\[([^\]|#]+)(?:#([^\]|]+))?(?:\|([^\]]+))?\]\]/g
|
|
|
|
export function extractWikilinksWithPositions(text: string): WikilinkWithPosition[] {
|
|
const results: WikilinkWithPosition[] = []
|
|
let match: RegExpExecArray | null
|
|
|
|
globalWikilinkRegex.lastIndex = 0
|
|
|
|
while ((match = globalWikilinkRegex.exec(text)) !== null) {
|
|
const [fullMatch, target, anchor, alias] = match
|
|
|
|
results.push({
|
|
wikilink: {
|
|
raw: fullMatch,
|
|
target: target?.trim() ?? "",
|
|
anchor: anchor?.trim(),
|
|
alias: alias?.trim(),
|
|
embed: fullMatch.startsWith("!"),
|
|
},
|
|
start: match.index,
|
|
end: match.index + fullMatch.length,
|
|
})
|
|
}
|
|
|
|
return results
|
|
}
|