wikiparser-node
Version:
A Node.js parser for MediaWiki markup with AST
152 lines (151 loc) • 5.11 kB
JavaScript
/* NOT FOR BROWSER */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getId = exports.html = exports.getCommon = void 0;
const string_1 = require("./string");
/* NOT FOR BROWSER END */
/**
* get common prefix length
* @param prefix
* @param lastPrefix
*/
const getCommon = (prefix, lastPrefix) =>
// eslint-disable-next-line @typescript-eslint/no-misused-spread
prefix.startsWith(lastPrefix) ? lastPrefix.length : [...lastPrefix].findIndex((ch, i) => ch !== prefix[i]);
exports.getCommon = getCommon;
/**
* get next list item
* @param char list syntax
* @param state
*/
const nextItem = (char, state) => {
if (char === '*' || char === '#') {
return '</li>\n<li>';
}
const close = state.dt[0] ? '</dt>\n' : '</dd>\n';
if (char === ';') {
state.dt[0] = true;
return `${close}<dt>`;
}
state.dt[0] = false;
return `${close}<dd>`;
};
/**
* close list item
* @param chars list syntax
* @param state
*/
const closeList = (chars, state) => {
let result = '';
for (let i = chars.length - 1; i >= 0; i--) {
const char = chars[i];
switch (char) {
case '*':
case '#':
result += `</li></${char === '*' ? 'ul' : 'ol'}>`;
break;
case ':':
result += `</${state.dt.shift() ? 'dt' : 'dd'}></dl>`;
break;
default:
//
}
}
return result;
};
/**
* open list item
* @param chars list syntax
* @param state
*/
const openList = (chars, state) => {
let result = '';
for (const char of chars) {
switch (char) {
case '*':
case '#':
result += `<${char === '*' ? 'ul' : 'ol'}><li>`;
break;
case ':':
state.dt.unshift(false);
result += '<dl><dd>';
break;
default:
state.dt.unshift(true);
result += '<dl><dt>';
}
}
return result;
};
/**
* convert to HTML
* @param childNodes a Token's contents
* @param separator delimiter between nodes
* @param opt options
*/
const html = (childNodes, separator = '', opt) => {
let lastPrefix = '';
const results = [], state = { dt: [] };
for (let j = 0; j < childNodes.length; j++) {
const child = childNodes[j];
let result = child.toHtmlInternal(opt);
if (child.is('list-range')) {
const { previousSibling } = child, { innerText } = previousSibling;
if ((child.length > 0 || /\s$/u.test(innerText))
&& previousSibling.is('list')
&& !/[;#*]/u.test(innerText)
&& child.closest('ext#poem,list-range')?.is('ext')) {
lastPrefix = '';
result = `<span style="display: inline-block; margin-inline-start: ${previousSibling.indent}em;">${result}</span>`;
}
else {
result = result.trim();
const prefix = innerText.trim(), prefix2 = prefix.replaceAll(';', ':'), commonPrefixLength = (0, exports.getCommon)(prefix2, lastPrefix);
let pre = closeList(lastPrefix.slice(commonPrefixLength), state);
if (prefix.length === commonPrefixLength) {
pre += nextItem(prefix.slice(-1), state);
}
else {
if (state.dt[0] && prefix[commonPrefixLength - 1] === ':') {
pre += nextItem(':', state);
}
if (lastPrefix) {
pre += '\n';
}
pre += openList(prefix.slice(commonPrefixLength), state);
}
result = pre + result;
let { nextSibling } = child;
while (nextSibling?.is('dd')) {
const next = nextSibling.nextSibling;
result += nextItem(':', state) + next.toHtmlInternal(opt).trim();
({ nextSibling } = next);
j += 2;
}
if (nextSibling?.type === 'text'
&& nextSibling.data === '\n'
&& nextSibling.nextVisibleSibling?.is('list')) {
j += 2;
lastPrefix = prefix2;
}
else {
lastPrefix = '';
result += closeList(prefix2, state);
}
}
}
results.push(result);
}
return results.join(separator);
};
exports.html = html;
/**
* get the id of a section heading
* @param tokens inner tokens of a section heading
*/
const getId = (tokens) => {
const opt = { nocc: true }, content = Array.isArray(tokens) ? (0, exports.html)(tokens, '', opt) : tokens.toHtmlInternal(opt), id = (0, string_1.decodeHtml)((0, string_1.sanitizeAlt)(content.replaceAll('_', ' ')))
.replace(/[\s_]+/gu, '_');
return id.endsWith('_') ? id.slice(0, -1) : id;
};
exports.getId = getId;
;