diff options
author | altaf-creator <dev@altafcreator.com> | 2024-05-12 12:14:02 +0700 |
---|---|---|
committer | altaf-creator <dev@altafcreator.com> | 2024-05-12 12:14:02 +0700 |
commit | d607ac12097afb5cb6f398a4e7b5cf4316efedc6 (patch) | |
tree | 6f4bc5b98a6ff3a1c3189f7ef9b570c0481e100d /packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs | |
parent | 7441f212967256ac4c9a93ba0b1f026308a8bfb6 (diff) |
self host
Diffstat (limited to 'packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs')
-rw-r--r-- | packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs b/packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs new file mode 100644 index 0000000..3c2a876 --- /dev/null +++ b/packages/markdown-it-14.1.0/lib/rules_block/state_block.mjs @@ -0,0 +1,220 @@ +// Parser state class + +import Token from '../token.mjs' +import { isSpace } from '../common/utils.mjs' + +function StateBlock (src, md, env, tokens) { + this.src = src + + // link to parser instance + this.md = md + + this.env = env + + // + // Internal state vartiables + // + + this.tokens = tokens + + this.bMarks = [] // line begin offsets for fast jumps + this.eMarks = [] // line end offsets for fast jumps + this.tShift = [] // offsets of the first non-space characters (tabs not expanded) + this.sCount = [] // indents for each line (tabs expanded) + + // An amount of virtual spaces (tabs expanded) between beginning + // of each line (bMarks) and real beginning of that line. + // + // It exists only as a hack because blockquotes override bMarks + // losing information in the process. + // + // It's used only when expanding tabs, you can think about it as + // an initial tab length, e.g. bsCount=21 applied to string `\t123` + // means first tab should be expanded to 4-21%4 === 3 spaces. + // + this.bsCount = [] + + // block parser variables + + // required block content indent (for example, if we are + // inside a list, it would be positioned after list marker) + this.blkIndent = 0 + this.line = 0 // line index in src + this.lineMax = 0 // lines count + this.tight = false // loose/tight mode for lists + this.ddIndent = -1 // indent of the current dd block (-1 if there isn't any) + this.listIndent = -1 // indent of the current list block (-1 if there isn't any) + + // can be 'blockquote', 'list', 'root', 'paragraph' or 'reference' + // used in lists to determine if they interrupt a paragraph + this.parentType = 'root' + + this.level = 0 + + // Create caches + // Generate markers. + const s = this.src + + for (let start = 0, pos = 0, indent = 0, offset = 0, len = s.length, indent_found = false; pos < len; pos++) { + const ch = s.charCodeAt(pos) + + if (!indent_found) { + if (isSpace(ch)) { + indent++ + + if (ch === 0x09) { + offset += 4 - offset % 4 + } else { + offset++ + } + continue + } else { + indent_found = true + } + } + + if (ch === 0x0A || pos === len - 1) { + if (ch !== 0x0A) { pos++ } + this.bMarks.push(start) + this.eMarks.push(pos) + this.tShift.push(indent) + this.sCount.push(offset) + this.bsCount.push(0) + + indent_found = false + indent = 0 + offset = 0 + start = pos + 1 + } + } + + // Push fake entry to simplify cache bounds checks + this.bMarks.push(s.length) + this.eMarks.push(s.length) + this.tShift.push(0) + this.sCount.push(0) + this.bsCount.push(0) + + this.lineMax = this.bMarks.length - 1 // don't count last fake line +} + +// Push new token to "stream". +// +StateBlock.prototype.push = function (type, tag, nesting) { + const token = new Token(type, tag, nesting) + token.block = true + + if (nesting < 0) this.level-- // closing tag + token.level = this.level + if (nesting > 0) this.level++ // opening tag + + this.tokens.push(token) + return token +} + +StateBlock.prototype.isEmpty = function isEmpty (line) { + return this.bMarks[line] + this.tShift[line] >= this.eMarks[line] +} + +StateBlock.prototype.skipEmptyLines = function skipEmptyLines (from) { + for (let max = this.lineMax; from < max; from++) { + if (this.bMarks[from] + this.tShift[from] < this.eMarks[from]) { + break + } + } + return from +} + +// Skip spaces from given position. +StateBlock.prototype.skipSpaces = function skipSpaces (pos) { + for (let max = this.src.length; pos < max; pos++) { + const ch = this.src.charCodeAt(pos) + if (!isSpace(ch)) { break } + } + return pos +} + +// Skip spaces from given position in reverse. +StateBlock.prototype.skipSpacesBack = function skipSpacesBack (pos, min) { + if (pos <= min) { return pos } + + while (pos > min) { + if (!isSpace(this.src.charCodeAt(--pos))) { return pos + 1 } + } + return pos +} + +// Skip char codes from given position +StateBlock.prototype.skipChars = function skipChars (pos, code) { + for (let max = this.src.length; pos < max; pos++) { + if (this.src.charCodeAt(pos) !== code) { break } + } + return pos +} + +// Skip char codes reverse from given position - 1 +StateBlock.prototype.skipCharsBack = function skipCharsBack (pos, code, min) { + if (pos <= min) { return pos } + + while (pos > min) { + if (code !== this.src.charCodeAt(--pos)) { return pos + 1 } + } + return pos +} + +// cut lines range from source. +StateBlock.prototype.getLines = function getLines (begin, end, indent, keepLastLF) { + if (begin >= end) { + return '' + } + + const queue = new Array(end - begin) + + for (let i = 0, line = begin; line < end; line++, i++) { + let lineIndent = 0 + const lineStart = this.bMarks[line] + let first = lineStart + let last + + if (line + 1 < end || keepLastLF) { + // No need for bounds check because we have fake entry on tail. + last = this.eMarks[line] + 1 + } else { + last = this.eMarks[line] + } + + while (first < last && lineIndent < indent) { + const ch = this.src.charCodeAt(first) + + if (isSpace(ch)) { + if (ch === 0x09) { + lineIndent += 4 - (lineIndent + this.bsCount[line]) % 4 + } else { + lineIndent++ + } + } else if (first - lineStart < this.tShift[line]) { + // patched tShift masked characters to look like spaces (blockquotes, list markers) + lineIndent++ + } else { + break + } + + first++ + } + + if (lineIndent > indent) { + // partially expanding tabs in code blocks, e.g '\t\tfoobar' + // with indent=2 becomes ' \tfoobar' + queue[i] = new Array(lineIndent - indent + 1).join(' ') + this.src.slice(first, last) + } else { + queue[i] = this.src.slice(first, last) + } + } + + return queue.join('') +} + +// re-export Token class to use in block rules +StateBlock.prototype.Token = Token + +export default StateBlock |