All files / src index.ts

100% Statements 73/73
69.56% Branches 16/23
100% Functions 4/4
100% Lines 73/73

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 70 71 72 73 741x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 1x 1x 2x 2x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 1x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 4x 4x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x  
import Prism from 'prismjs'
import parse from 'rehype-parse'
import unifiedTypes, { unified } from 'unified'
import * as mdast from 'mdast'
import * as hast from 'hast'
import { Node } from 'unist'
import { visit } from 'unist-util-visit'
import { select } from 'unist-util-select'
 
 
const getLang = (node: hast.Element): string => {
  const lang: string = node.properties?.className?.[0] || ''
  return lang.replace(/^language-/, '')
}
 
const visitor = (preNode: hast.Element): void => {
  const codeNode = select('[tagName=code]', preNode) as (hast.Element | null)
 
  if (!codeNode) return
  const lang = getLang(codeNode)
 
  if (!lang || !Prism.languages[lang]) return
 
  const textNode = select('text', codeNode) as (mdast.Text | null)
  if (!textNode) return
 
  const className = `language-${lang}`
  const html = Prism.highlight(textNode.value, Prism.languages[lang], lang)
  const tree = unified()
    .use(parse, { fragment: true })
    .parse(html) as hast.Element
 
  if (!preNode.properties) preNode.properties = {}
  if (!preNode.properties.className) preNode.properties.className = []
  if (typeof preNode.properties.className === 'string') preNode.properties.className = [preNode.properties.className]
  if (typeof preNode.properties.className === 'number') preNode.properties.className = [preNode.properties.className]
  if (typeof preNode.properties.className === 'boolean') preNode.properties.className = []
  preNode.properties.className = [...preNode.properties.className, className]
 
  codeNode.children = tree.children
}
 
const selector = (node: hast.Element): boolean => node.tagName === 'pre'
 
 
export interface RehypePrismOptions {
  plugins: (
    'autolinker'| 'autoloader' | 'command-line' | 'copy-to-clipboard' |
    'custom-class' | 'data-uri-highlight' | 'diff-highlight' |
    'download-button' | 'file-highlight' | 'filter-highlight-all' |
    'highlight-keywords' | 'inline-color' | 'jsonp-highlight' |
    'keep-markup' | 'line-highlight' | 'line-numbers' | 'match-braces' |
    'normalize-whitespace' | 'previewers' | 'remove-initial-line-feed' |
    'show-invisibles' | 'show-language' | 'toolbar' | 'treeview' |
    'unescaped-markup' | 'wpd'
  )[]
}
 
const rehypePrism: unifiedTypes.Plugin<[RehypePrismOptions?]> = (options?: RehypePrismOptions) => {
  if (options && options.plugins) {
    for (const plugin of options.plugins) {
      import(`prismjs/plugins/${plugin}/prism-${plugin}.js`)
    }
  }
 
 
  return (tree: Node) => {
    console.log(tree)
    visit(tree, selector as any, visitor as any)
  }
}
 
export default rehypePrism