Skip to content

Instantly share code, notes, and snippets.

@Rokt33r
Created February 18, 2017 08:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Rokt33r/1e109b8ead365c378335175b3d61b98a to your computer and use it in GitHub Desktop.
Save Rokt33r/1e109b8ead365c378335175b3d61b98a to your computer and use it in GitHub Desktop.
Unknown MDAST nodes are not compiled to DIV
{
"type": "root",
"children": [
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Inline math! ",
"position": {
"start": {
"line": 2,
"column": 1,
"offset": 1
},
"end": {
"line": 2,
"column": 14,
"offset": 14
},
"indent": []
}
},
{
"type": "inlineMath",
"value": "\\alpha",
"position": {
"start": {
"line": 2,
"column": 14,
"offset": 14
},
"end": {
"line": 2,
"column": 22,
"offset": 22
},
"indent": []
}
}
],
"position": {
"start": {
"line": 2,
"column": 1,
"offset": 1
},
"end": {
"line": 2,
"column": 22,
"offset": 22
},
"indent": []
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Math block",
"position": {
"start": {
"line": 4,
"column": 1,
"offset": 24
},
"end": {
"line": 4,
"column": 11,
"offset": 34
},
"indent": []
}
}
],
"position": {
"start": {
"line": 4,
"column": 1,
"offset": 24
},
"end": {
"line": 4,
"column": 11,
"offset": 34
},
"indent": []
}
},
{
"type": "math",
"value": "\\beta",
"data": {
"hName": "div",
"hChildren": [
{
"type": "text",
"value": "\\beta"
}
],
"hProperties": {
"class": "math"
}
},
"position": {
"start": {
"line": 6,
"column": 1,
"offset": 36
},
"end": {
"line": 8,
"column": 3,
"offset": 47
},
"indent": [
1,
1
]
}
},
{
"type": "paragraph",
"children": [
{
"type": "text",
"value": "Below code should not be parsed as Math block",
"position": {
"start": {
"line": 10,
"column": 1,
"offset": 49
},
"end": {
"line": 10,
"column": 46,
"offset": 94
},
"indent": []
}
}
],
"position": {
"start": {
"line": 10,
"column": 1,
"offset": 49
},
"end": {
"line": 10,
"column": 46,
"offset": 94
},
"indent": []
}
},
{
"type": "code",
"lang": null,
"value": "$$\n\\gamma\n$$",
"position": {
"start": {
"line": 12,
"column": 1,
"offset": 96
},
"end": {
"line": 16,
"column": 4,
"offset": 116
},
"indent": [
1,
1,
1,
1
]
}
}
],
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 17,
"column": 1,
"offset": 117
}
}
}
var trim = require('trim-trailing-lines')
/* Characters */
var C_NEWLINE = '\n'
var C_TAB = '\t'
var C_SPACE = ' '
var C_DOLLAR = '$'
/* Constants */
var MIN_FENCE_COUNT = 2
var CODE_INDENT_COUNT = 4
/**
* Tokenise fenced code.
*
* @property {Function} locator.
* @param {function(string)} eat - Eater.
* @param {string} value - Rest of content.
* @param {boolean?} [silent] - Whether this is a dry run.
* @return {Node?|boolean} - `code` node.
*/
function blockTokenizer (eat, value, silent) {
var self = this
var length = value.length + 1
var index = 0
var subvalue = ''
var fenceCount
var marker
var character
var flag
var queue
var content
var exdentedContent
var closing
var exdentedClosing
var indent
var now
/* Eat initial spacing. */
while (index < length) {
character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) {
break
}
subvalue += character
index++
}
indent = index
/* Eat the fence. */
character = value.charAt(index)
if (character !== C_DOLLAR) {
return
}
index++
marker = character
fenceCount = 1
subvalue += character
while (index < length) {
character = value.charAt(index)
if (character !== marker) {
break
}
subvalue += character
fenceCount++
index++
}
if (fenceCount < MIN_FENCE_COUNT) {
return
}
/* Eat spacing before flag. */
while (index < length) {
character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) {
break
}
subvalue += character
index++
}
/* Eat flag. */
flag = queue = ''
while (index < length) {
character = value.charAt(index)
if (
character === C_NEWLINE ||
character === C_DOLLAR
) {
break
}
if (character === C_SPACE || character === C_TAB) {
queue += character
} else {
flag += queue + character
queue = ''
}
index++
}
character = value.charAt(index)
if (character && character !== C_NEWLINE) {
return
}
if (silent) {
return true
}
now = eat.now()
now.column += subvalue.length
now.offset += subvalue.length
subvalue += flag
flag = self.decode.raw(self.unescape(flag), now)
if (queue) {
subvalue += queue
}
queue = closing = exdentedClosing = content = exdentedContent = ''
/* Eat content. */
while (index < length) {
character = value.charAt(index)
content += closing
exdentedContent += exdentedClosing
closing = exdentedClosing = ''
if (character !== C_NEWLINE) {
content += character
exdentedClosing += character
index++
continue
}
/* Add the newline to `subvalue` if its the first
* character. Otherwise, add it to the `closing`
* queue. */
if (content) {
closing += character
exdentedClosing += character
} else {
subvalue += character
}
queue = ''
index++
while (index < length) {
character = value.charAt(index)
if (character !== C_SPACE) {
break
}
queue += character
index++
}
closing += queue
exdentedClosing += queue.slice(indent)
if (queue.length >= CODE_INDENT_COUNT) {
continue
}
queue = ''
while (index < length) {
character = value.charAt(index)
if (character !== marker) {
break
}
queue += character
index++
}
closing += queue
exdentedClosing += queue
if (queue.length < fenceCount) {
continue
}
queue = ''
while (index < length) {
character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) {
break
}
closing += character
exdentedClosing += character
index++
}
if (!character || character === C_NEWLINE) {
break
}
}
subvalue += content + closing
const trimmedValue = trim(exdentedContent)
return eat(subvalue)({
type: 'math',
value: trimmedValue,
data: {
hName: 'div',
hChildren: [{
type: 'text',
value: trimmedValue
}],
hProperties: {
class: 'math'
}
}
})
}
module.exports = function plugin (p) {
const Parser = p.Parser
const blockTokenizers = Parser.prototype.blockTokenizers
const blockMethods = Parser.prototype.blockMethods
blockTokenizers.math = blockTokenizer
blockMethods.splice(blockMethods.indexOf('fencedCode') + 1, 0, 'math')
}
function locator (value, fromIndex) {
return value.indexOf('$', fromIndex)
}
const INLINE_MATH = /^\$((?:\\\$|[^$])+)\$/
function inlineTokenizer (eat, value, silent) {
const match = INLINE_MATH.exec(value)
if (match) {
if (silent) {
return true
}
return eat(match[0])({
type: 'inlineMath',
value: match[1].trim()
})
}
}
inlineTokenizer.locator = locator
inlineTokenizer.notInLink = true
module.exports = function plugin (p) {
const Parser = p.Parser
// Inline math
const inlineTokenizers = Parser.prototype.inlineTokenizers
const inlineMethods = Parser.prototype.inlineMethods
inlineTokenizers.math = inlineTokenizer
inlineMethods.splice(inlineMethods.indexOf('text'), 0, 'math')
}
<p>Inline math! \alpha</p>
<p>Math block</p>
\beta
<p>Below code should not be parsed as Math block</p>
<pre><code>$$
\gamma
$$
</code></pre>
const text = `
Inline math! $\\alpha$
Math block
$$
\\beta
$$
Below code should not be parsed as Math block
\`\`\`
$$
\\gamma
$$
\`\`\`
`
const processor = remark().use(p => {
inlineParser(p)
blockParser(p)
})
const ast = processor.parse(text)
const htmlString = processor.stringify(ast)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment