204 lines
6.9 KiB
JavaScript
204 lines
6.9 KiB
JavaScript
/*! markdown-it-deflist 3.0.0 https://github.com/markdown-it/markdown-it-deflist.git @license MIT */
|
|
(function(global, factory) {
|
|
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
|
|
global.markdownitDeflist = factory());
|
|
})(this, (function() {
|
|
"use strict";
|
|
// Process definition lists
|
|
|
|
function deflist_plugin(md) {
|
|
const isSpace = md.utils.isSpace;
|
|
// Search `[:~][\n ]`, returns next pos after marker on success
|
|
// or -1 on fail.
|
|
function skipMarker(state, line) {
|
|
let start = state.bMarks[line] + state.tShift[line];
|
|
const max = state.eMarks[line];
|
|
if (start >= max) {
|
|
return -1;
|
|
}
|
|
// Check bullet
|
|
const marker = state.src.charCodeAt(start++);
|
|
if (marker !== 126 /* ~ */ && marker !== 58 /* : */) {
|
|
return -1;
|
|
}
|
|
const pos = state.skipSpaces(start);
|
|
// require space after ":"
|
|
if (start === pos) {
|
|
return -1;
|
|
}
|
|
// no empty definitions, e.g. " : "
|
|
if (pos >= max) {
|
|
return -1;
|
|
}
|
|
return start;
|
|
}
|
|
function markTightParagraphs(state, idx) {
|
|
const level = state.level + 2;
|
|
for (let i = idx + 2, l = state.tokens.length - 2; i < l; i++) {
|
|
if (state.tokens[i].level === level && state.tokens[i].type === "paragraph_open") {
|
|
state.tokens[i + 2].hidden = true;
|
|
state.tokens[i].hidden = true;
|
|
i += 2;
|
|
}
|
|
}
|
|
}
|
|
function deflist(state, startLine, endLine, silent) {
|
|
if (silent) {
|
|
// quirk: validation mode validates a dd block only, not a whole deflist
|
|
if (state.ddIndent < 0) {
|
|
return false;
|
|
}
|
|
return skipMarker(state, startLine) >= 0;
|
|
}
|
|
let nextLine = startLine + 1;
|
|
if (nextLine >= endLine) {
|
|
return false;
|
|
}
|
|
if (state.isEmpty(nextLine)) {
|
|
nextLine++;
|
|
if (nextLine >= endLine) {
|
|
return false;
|
|
}
|
|
}
|
|
if (state.sCount[nextLine] < state.blkIndent) {
|
|
return false;
|
|
}
|
|
let contentStart = skipMarker(state, nextLine);
|
|
if (contentStart < 0) {
|
|
return false;
|
|
}
|
|
// Start list
|
|
const listTokIdx = state.tokens.length;
|
|
let tight = true;
|
|
const token_dl_o = state.push("dl_open", "dl", 1);
|
|
const listLines = [ startLine, 0 ];
|
|
token_dl_o.map = listLines;
|
|
|
|
// Iterate list items
|
|
|
|
let dtLine = startLine;
|
|
let ddLine = nextLine;
|
|
// One definition list can contain multiple DTs,
|
|
// and one DT can be followed by multiple DDs.
|
|
|
|
// Thus, there is two loops here, and label is
|
|
// needed to break out of the second one
|
|
|
|
/* eslint no-labels:0,block-scoped-var:0 */ OUTER: for (;;) {
|
|
let prevEmptyEnd = false;
|
|
const token_dt_o = state.push("dt_open", "dt", 1);
|
|
token_dt_o.map = [ dtLine, dtLine ];
|
|
const token_i = state.push("inline", "", 0);
|
|
token_i.map = [ dtLine, dtLine ];
|
|
token_i.content = state.getLines(dtLine, dtLine + 1, state.blkIndent, false).trim();
|
|
token_i.children = [];
|
|
state.push("dt_close", "dt", -1);
|
|
for (;;) {
|
|
const token_dd_o = state.push("dd_open", "dd", 1);
|
|
const itemLines = [ nextLine, 0 ];
|
|
token_dd_o.map = itemLines;
|
|
let pos = contentStart;
|
|
const max = state.eMarks[ddLine];
|
|
let offset = state.sCount[ddLine] + contentStart - (state.bMarks[ddLine] + state.tShift[ddLine]);
|
|
while (pos < max) {
|
|
const ch = state.src.charCodeAt(pos);
|
|
if (isSpace(ch)) {
|
|
if (ch === 9) {
|
|
offset += 4 - offset % 4;
|
|
} else {
|
|
offset++;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
pos++;
|
|
}
|
|
contentStart = pos;
|
|
const oldTight = state.tight;
|
|
const oldDDIndent = state.ddIndent;
|
|
const oldIndent = state.blkIndent;
|
|
const oldTShift = state.tShift[ddLine];
|
|
const oldSCount = state.sCount[ddLine];
|
|
const oldParentType = state.parentType;
|
|
state.blkIndent = state.ddIndent = state.sCount[ddLine] + 2;
|
|
state.tShift[ddLine] = contentStart - state.bMarks[ddLine];
|
|
state.sCount[ddLine] = offset;
|
|
state.tight = true;
|
|
state.parentType = "deflist";
|
|
state.md.block.tokenize(state, ddLine, endLine, true);
|
|
// If any of list item is tight, mark list as tight
|
|
if (!state.tight || prevEmptyEnd) {
|
|
tight = false;
|
|
}
|
|
// Item become loose if finish with empty line,
|
|
// but we should filter last element, because it means list finish
|
|
prevEmptyEnd = state.line - ddLine > 1 && state.isEmpty(state.line - 1);
|
|
state.tShift[ddLine] = oldTShift;
|
|
state.sCount[ddLine] = oldSCount;
|
|
state.tight = oldTight;
|
|
state.parentType = oldParentType;
|
|
state.blkIndent = oldIndent;
|
|
state.ddIndent = oldDDIndent;
|
|
state.push("dd_close", "dd", -1);
|
|
itemLines[1] = nextLine = state.line;
|
|
if (nextLine >= endLine) {
|
|
break OUTER;
|
|
}
|
|
if (state.sCount[nextLine] < state.blkIndent) {
|
|
break OUTER;
|
|
}
|
|
contentStart = skipMarker(state, nextLine);
|
|
if (contentStart < 0) {
|
|
break;
|
|
}
|
|
ddLine = nextLine;
|
|
// go to the next loop iteration:
|
|
// insert DD tag and repeat checking
|
|
}
|
|
if (nextLine >= endLine) {
|
|
break;
|
|
}
|
|
dtLine = nextLine;
|
|
if (state.isEmpty(dtLine)) {
|
|
break;
|
|
}
|
|
if (state.sCount[dtLine] < state.blkIndent) {
|
|
break;
|
|
}
|
|
ddLine = dtLine + 1;
|
|
if (ddLine >= endLine) {
|
|
break;
|
|
}
|
|
if (state.isEmpty(ddLine)) {
|
|
ddLine++;
|
|
}
|
|
if (ddLine >= endLine) {
|
|
break;
|
|
}
|
|
if (state.sCount[ddLine] < state.blkIndent) {
|
|
break;
|
|
}
|
|
contentStart = skipMarker(state, ddLine);
|
|
if (contentStart < 0) {
|
|
break;
|
|
}
|
|
// go to the next loop iteration:
|
|
// insert DT and DD tags and repeat checking
|
|
}
|
|
// Finilize list
|
|
state.push("dl_close", "dl", -1);
|
|
listLines[1] = nextLine;
|
|
state.line = nextLine;
|
|
// mark paragraphs tight if needed
|
|
if (tight) {
|
|
markTightParagraphs(state, listTokIdx);
|
|
}
|
|
return true;
|
|
}
|
|
md.block.ruler.before("paragraph", "deflist", deflist, {
|
|
alt: [ "paragraph", "reference", "blockquote" ]
|
|
});
|
|
}
|
|
return deflist_plugin;
|
|
}));
|