All files / src/utils wikilinks.ts

65.85% Statements 27/41
56% Branches 14/25
85.71% Functions 6/7
72.22% Lines 26/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69  2x 2x 2x       8x         9x 1x 1x   1x 1x   1x         1x 1x 1x 1x 1x                                         1x         16x 16x 16x 16x 16x 16x       8x 8x 8x 8x    
// Wikilink placeholder tokens for markdown round-trip
const WL_START = '\u2039WIKILINK:'
const WL_END = '\u203A'
const WL_RE = new RegExp(`${WL_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([^${WL_END}]+)${WL_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`, 'g')
 
/** Pre-process markdown: replace [[target]] with placeholder tokens */
export function preProcessWikilinks(md: string): string {
  return md.replace(/\[\[([^\]]+)\]\]/g, (_m, target) => `${WL_START}${target}${WL_END}`)
}
 
/** Walk blocks and replace placeholder text with wikilink inline content */
export function injectWikilinks(blocks: any[]): any[] {
  return blocks.map(block => {
    Eif (block.content && Array.isArray(block.content)) {
      block.content = expandWikilinksInContent(block.content)
    }
    Eif (block.children && Array.isArray(block.children)) {
      block.children = injectWikilinks(block.children)
    }
    return block
  })
}
 
function expandWikilinksInContent(content: any[]): any[] {
  const result: any[] = []
  for (const item of content) {
    Eif (item.type !== 'text' || typeof item.text !== 'string' || !item.text.includes(WL_START)) {
      result.push(item)
      continue
    }
    const text = item.text as string
    let lastIndex = 0
    WL_RE.lastIndex = 0
    let match
    while ((match = WL_RE.exec(text)) !== null) {
      if (match.index > lastIndex) {
        result.push({ ...item, text: text.slice(lastIndex, match.index) })
      }
      result.push({
        type: 'wikilink',
        props: { target: match[1] },
        content: undefined,
      })
      lastIndex = match.index + match[0].length
    }
    if (lastIndex < text.length) {
      result.push({ ...item, text: text.slice(lastIndex) })
    }
  }
  return result
}
 
/** Strip YAML frontmatter from markdown, returning [frontmatter, body] */
export function splitFrontmatter(content: string): [string, string] {
  Iif (!content.startsWith('---')) return ['', content]
  const end = content.indexOf('\n---', 3)
  Iif (end === -1) return ['', content]
  let to = end + 4
  Eif (content[to] === '\n') to++
  return [content.slice(0, to), content.slice(to)]
}
 
export function countWords(content: string): number {
  const [, body] = splitFrontmatter(content)
  const text = body.replace(/[#*_\[\]`>~\-|]/g, '').trim()
  Iif (!text) return 0
  return text.split(/\s+/).filter(Boolean).length
}