UNPKG

markdown-it-graph

Version:

A markdown-it plugin that parses custom graph syntax like ```graph bar and outputs structured graph data

77 lines (60 loc) 2.44 kB
/** @typedef {import('./index')} */ export default function graph_plugin (md) { const defaultType = 'bar' // Add renderer override for "graph" fences const originalFence = md.renderer.rules.fence || function (tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options) } md.renderer.rules.fence = function (tokens, idx, options, env, self) { const token = tokens[idx] const info = token.info.trim() const [typeKeyword, graphType = defaultType] = info.split(/\s+/) if (typeKeyword !== 'graph') { return originalFence(tokens, idx, options, env, self) } const lines = token.content.trim().split('\n') const data = lines .map((line) => { const [labelPart, valuePart] = line.split('|').map((s) => s.trim()) if (!labelPart || !valuePart) return null const match = valuePart.match(/^([█▉▊▋▌▍▎▏ ]*)([-+]?[\d.]+.*)$/) let valueRaw = valuePart if (match && match.length >= 3) { valueRaw = match[2] ? match[2].trim() : valuePart } const value = parseFloat(valueRaw.replace(/[^0-9.-]/g, '')) return { label: labelPart, value } }) .filter(Boolean) const payload = { type: graphType, data } return `<graph-block type="${graphType}" data-graph='${JSON.stringify(payload)}'></graph-block>` } // Add custom block rule to detect ```graph blocks md.block.ruler.before('fence', 'graph_block', function (state, startLine, endLine, silent) { const startPos = state.bMarks[startLine] + state.tShift[startLine] const maxPos = state.eMarks[startLine] const marker = state.src.slice(startPos, maxPos).trim() if (!marker.startsWith('```graph')) return false if (silent) return true let nextLine = startLine while (++nextLine < endLine) { const lineStart = state.bMarks[nextLine] + state.tShift[nextLine] const lineEnd = state.eMarks[nextLine] const lineText = state.src.slice(lineStart, lineEnd).trim() if (lineText.startsWith('```')) break } const token = state.push('fence', 'code', 0) token.info = marker.slice(3).trim() // e.g., "graph bar" token.content = state.getLines(startLine + 1, nextLine, state.tShift[startLine], true) token.map = [startLine, nextLine + 1] token.markup = '```' state.line = nextLine + 1 return true }) }