forked from github/quartz
feat(bases): migrate from vault to upstream
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
94
quartz/util/wikilinks.ts
Normal file
94
quartz/util/wikilinks.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user