micro-mdx-parser
Version:
A tiny parser to convert markdown or html into JSON
122 lines (109 loc) • 3.31 kB
JavaScript
const { getTextBetweenChars } = require('./utils')
// const { inlineTags } = require('./tags')
function splitHead(str, sep) {
const idx = str.indexOf(sep)
if (idx === -1) return [str]
return [str.slice(0, idx), str.slice(idx + sep.length)]
}
function unquote(str) {
const car = str.charAt(0)
const end = str.length - 1
const isQuoteStart = car === '"' || car === "'"
if (isQuoteStart && car === str.charAt(end)) {
return str.slice(1, end)
}
return str
}
function format(nodes, options = {}, str) {
const { offset, includePositions } = options
const formattedNodes = nodes.map(node => {
// console.log('node', node)
const {
type,
tagName,
props,
propsRaw,
children,
position,
isSelfClosing
} = node
let outputNode = { type, content: node.content }
/* Apply position offset (for frontmatter and such) */
if (offset) {
const { lineOffset, charOffset } = offset
node.position.start.line = position.start.line + lineOffset
node.position.start.index = position.start.index + charOffset
node.position.end.line = position.end.line + lineOffset
node.position.end.index = position.end.index + charOffset
}
if (type === 'element') {
// console.log('node.position.start.index', node.position.start.index)
// console.log('node.position.end.index', node.position.end.index)
// console.log('str', str)
outputNode = {
// TODO maybe harden with https://github.com/riot/dom-nodes
type: (/^[A-Z]/.test(tagName)) ? 'component' : type,
tagName,
tagValue: getTextBetweenChars(str, node.position.start.index, node.position.end.index),
props,
propsRaw,
// isReactComponent: /^[A-Z]/.test(node.tagName),
children: format(children, options, str),
}
if (options && options.transforms && options.transforms[tagName]) {
outputNode = options.transforms[tagName](outputNode)
}
if (isSelfClosing) {
outputNode.isSelfClosing = isSelfClosing
}
// if (inlineTags.includes(tagName)) {
// outputNode.isInlineTag = true
// }
// if (node.isVoidTag) {
// outputNode.isVoidTag = node.isVoidTag
// }
}
if (includePositions) {
outputNode.position = node.position
}
return outputNode
})
/*
const test = formattedNodes.reduce((acc, curr, i) => {
// console.log('curr', curr)
if (curr && curr.content && curr.content.endsWith('```html\n')) {
console.log('TAG Open')
}
if (curr && curr.content && curr.content.startsWith('\n```\n')) {
console.log('TAG Close')
}
}, [])
/** */
return formattedNodes
}
function getOccuranceCount(string, searchFor) {
var count = 0,
pos = string.indexOf(searchFor);
while (pos > -1) {
++count;
pos = string.indexOf(searchFor, pos+=searchFor.length)
}
return count
}
// Old
function formatAttributes (attributes) {
return attributes.map(attribute => {
const parts = splitHead(attribute.trim(), '=')
const key = parts[0]
const value = typeof parts[1] === 'string'
? unquote(parts[1])
: null
return {key, value}
})
}
module.exports = {
splitHead,
unquote,
format,
formatAttributes
}