UNPKG

astro-loader-obsidian

Version:
205 lines (171 loc) 5.3 kB
import type { AstroIntegrationLogger } from "astro"; import { dirname, extname, relative } from "node:path"; import { ALLOWED_AUDIO_EXTENSIONS, ALLOWED_VIDEO_EXTENSIONS, ALLOWED_FILE_EXTENSIONS, ALLOWED_IMAGE_EXTENSIONS } from "./constants"; import type { ObsidianContext } from "../types"; import type { ObsidianLink } from "../schemas"; import { getAssetFromLink, getDocumentFromLink, toUrl } from "./obsidianId"; import { slugify } from "./utils/slugify"; import { getAssetPublicUrl } from "./assets"; export type Wikilink = { /** @deprecated use Link.type instead */ isImage: boolean; extension?: string|undefined; text: string; file?: string|undefined; link: ObsidianLink; }; const imageDisplayClassNames: Record<string, string> = { 'float-left': 'float-left', 'float-right': 'float-right', 'left': 'float-left', 'right': 'float-right', }; const imageSizing = (text: string): { width: number; height?: number; } | null => { if (!Number.isNaN(+text)) { return { width: Number.parseInt(text) }; } const [w, h] = text.split('x') as [string, string]; if (!w || !h) { return null; } if (!Number.isNaN(+w) && !Number.isNaN(+h)) { return { width: Number.parseInt(w as string), height: Number.parseInt(h as string) }; } return null; } const getLinkType = (text: string): ObsidianLink['type'] => { if (ALLOWED_IMAGE_EXTENSIONS.some(i => text.includes(i))) { return 'image'; } if (ALLOWED_AUDIO_EXTENSIONS.some(i => text.includes(i))) { return 'audio'; } if (ALLOWED_VIDEO_EXTENSIONS.some(i => text.includes(i))) { return 'video'; } if (ALLOWED_FILE_EXTENSIONS.some(i => text.includes(i))) { return 'file'; } return 'document'; }; export const parseWikilinks = ( content: string, source: string, context: ObsidianContext, logger: AstroIntegrationLogger ): Wikilink[] => { const links: Wikilink[] = []; const regex = /(!)?\[\[([^\]]+?)\]\]/g; // /\[\[(!)?([\w/]+)\]\]/g; const matches = content.matchAll(regex); for (const match of matches) { const [text, isEmbedded, linkText] = match; if (!linkText) { links.push({ text, link: { isEmbedded: !!isEmbedded, type: getLinkType(text), title: text, href: null, }, isImage: false, }); continue; } const [hrefFragment, ...fragments] = linkText.split('|'); const idHref = hrefFragment ?? linkText; let title = idHref.split("/").slice(-1)[0] as string; const type = getLinkType(idHref); let className = ''; const caption = fragments.length > 0 ? fragments.join('|') : title; for (const fragment of fragments) { if (type === 'image') { const size = imageSizing(fragment); if (size) { if (size.width) { className += ` w-[${size.width}px]`; } if (size.height) { className += ` h-[${size.height}px]`; } continue; } const layoutClassName = imageDisplayClassNames[fragment]; if (layoutClassName) { className += ` ${layoutClassName}`; continue; } } title = fragment; } let href: string | null = null; let id: string | undefined; let file: string | undefined; let extension: string | undefined; if (type === 'document') { const [idWithoutAnchor, anchorTag] = idHref.split('#'); file = getDocumentFromLink(idWithoutAnchor ?? idHref, context.files); if (file) { extension = extname(file); href = toUrl( file, context.baseUrl, context.i18n, context.defaultLocale ); if (anchorTag) { href = `${href}#${slugify(anchorTag)}` } } else { const fallbackStrategy = context.options.brokenLinksStrategy; const errorMessage = `Could not find document from Obsidian link "${idHref}" at "${context.entry}"`; if (fallbackStrategy === "warn") { logger.warn(errorMessage); href = idHref; } else if (fallbackStrategy === "404") { href = `/404?entry=${slugify(idHref)}&collection=${context.baseUrl}`; } else { logger.debug(errorMessage); href = null; } } id = slugify(file ?? idHref); } if ( ['image', 'audio', 'video', 'file'].includes(type) ) { file = getAssetFromLink(idHref, context.assets); if (file) { extension = extname(file); const relativePath = relative(dirname(`/${context.entry}`), `/${file}`); href = type === 'image' ? relativePath.startsWith('.') ? relativePath : `./${relativePath}` : getAssetPublicUrl(file, context.publicUrl); id = slugify(file); } else { logger.warn(`Could not find ${type} from Obsidian ${type} "${idHref}"`); } } const link: ObsidianLink = { caption, className: className.trim().length > 0 ? className.trim() : undefined, id, isEmbedded: !!isEmbedded, type, source, title, href } links.push({ text, file, extension, link, isImage: link.type === 'image', }); } return links; };