blob: 53a7629be0586d59b590bbdb562b8daab2754d0a [file] [log] [blame]
'use strict'
var trim = require('trim-trailing-lines')
module.exports = fencedCode
var lineFeed = '\n'
var tab = '\t'
var space = ' '
var tilde = '~'
var graveAccent = '`'
var minFenceCount = 3
var tabSize = 4
function fencedCode(eat, value, silent) {
var self = this
var gfm = self.options.gfm
var length = value.length + 1
var index = 0
var subvalue = ''
var fenceCount
var marker
var character
var flag
var lang
var meta
var queue
var content
var exdentedContent
var closing
var exdentedClosing
var indent
var now
if (!gfm) {
return
}
// Eat initial spacing.
while (index < length) {
character = value.charAt(index)
if (character !== space && character !== tab) {
break
}
subvalue += character
index++
}
indent = index
// Eat the fence.
character = value.charAt(index)
if (character !== tilde && character !== graveAccent) {
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 < minFenceCount) {
return
}
// Eat spacing before flag.
while (index < length) {
character = value.charAt(index)
if (character !== space && character !== tab) {
break
}
subvalue += character
index++
}
// Eat flag.
flag = ''
queue = ''
while (index < length) {
character = value.charAt(index)
if (
character === lineFeed ||
character === tilde ||
character === graveAccent
) {
break
}
if (character === space || character === tab) {
queue += character
} else {
flag += queue + character
queue = ''
}
index++
}
character = value.charAt(index)
if (character && character !== lineFeed) {
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 !== lineFeed) {
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 !== space) {
break
}
queue += character
index++
}
closing += queue
exdentedClosing += queue.slice(indent)
if (queue.length >= tabSize) {
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 !== space && character !== tab) {
break
}
closing += character
exdentedClosing += character
index++
}
if (!character || character === lineFeed) {
break
}
}
subvalue += content + closing
// Get lang and meta from the flag.
index = -1
length = flag.length
while (++index < length) {
character = flag.charAt(index)
if (character === space || character === tab) {
if (!lang) {
lang = flag.slice(0, index)
}
} else if (lang) {
meta = flag.slice(index)
break
}
}
return eat(subvalue)({
type: 'code',
lang: lang || flag || null,
meta: meta || null,
value: trim(exdentedContent)
})
}