| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- /** Simple content hash for change detection (djb2 variant, base-36 encoded). */
- export function contentHash(content: string): string {
- let hash = 0
- for (let i = 0; i < content.length; i++) {
- const chr = content.charCodeAt(i)
- hash = (hash << 5) - hash + chr
- hash |= 0
- }
- return hash.toString(36)
- }
- /**
- * Classify a block's type from its first line content.
- * Matches the block_type CHECK constraint in the schema.
- */
- export function detectBlockType(content: string): string {
- const first = content.trimStart()
- if (/^#{1,6}\s/.test(first)) return "heading"
- if (
- /^TODO\s|^DOING\s|^DONE\s|^LATER\s|^NOW\s|^WAITING\s|^CANCELLED\s/i.test(
- first,
- )
- )
- return "task"
- if (/^>\s*\[!/.test(first)) return "callout"
- if (/^>\s/.test(first)) return "blockquote"
- if (/^```/.test(first)) return "code"
- if (/^\|.+\|/.test(first)) return "table"
- if (/^\$\$/.test(first)) return "math"
- if (/^\w+::\s/.test(first)) return "property"
- return "paragraph"
- }
- /** Extract the first `# Heading 1` from markdown content. */
- export function extractTitle(content: string): string {
- const match = content.match(/^# (.+)/m)
- return match ? match[1]?.trim() : ""
- }
- export interface ExtractedLink {
- target: string
- linkType: "page-ref" | "block-ref" | "tag"
- offset: number
- }
- /**
- * Extract [[Page Name]], ((block-id)), and #tag references from block content.
- * Returns target text, link type, and character offset within the block.
- */
- export function extractLinks(content: string): ExtractedLink[] {
- const links: ExtractedLink[] = []
- for (const m of content.matchAll(/\[\[([^\]|]+)(?:\|[^\]]+)?\]\]/g)) {
- links.push({
- target: m[1]!, // biome-ignore lint/style/noNonNullAssertion: matchAll guarantees group 1
- linkType: "page-ref",
- offset: m.index,
- })
- }
- for (const m of content.matchAll(/\(\(([a-zA-Z0-9_-]+)\)\)/g)) {
- links.push({ target: m[1]!, linkType: "block-ref", offset: m.index })
- }
- for (const m of content.matchAll(/(?:\s|^)#([a-zA-Z0-9_-]+)/g)) {
- links.push({
- target: m[1]!,
- linkType: "tag",
- offset: m.index + 1,
- })
- }
- return links
- }
|