wikiparser-node
Version:
A Node.js parser for MediaWiki markup with AST
192 lines (191 loc) • 8.92 kB
JavaScript
/* eslint @stylistic/operator-linebreak: [2, "before", {overrides: {"=": "after"}}] */
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const constants_1 = require("../util/constants");
const debug_1 = require("../util/debug");
const string_1 = require("../util/string");
const index_1 = __importDefault(require("../index"));
const index_2 = require("../src/index");
const transclude_1 = require("../src/transclude");
const parameter_1 = require("../src/parameter");
const atom_1 = require("../src/atom");
transclude_1.TranscludeToken.prototype.newAnonArg =
/** @implements */
function (val) {
const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(val, this.getAttribute('include'), undefined, config),
// @ts-expect-error abstract class
token = debug_1.Shadow.run(() => new parameter_1.ParameterToken(undefined, undefined, config));
token.lastChild.concat(childNodes); // eslint-disable-line unicorn/prefer-spread
return this.insertAt(token);
};
transclude_1.TranscludeToken.prototype.setValue =
/** @implements */
function (key, value) {
/* istanbul ignore if */
if (!this.isTemplate()) {
throw new Error('TranscludeToken.setValue method is only for templates!');
}
const arg = this.getArg(key);
if (arg) {
arg.setValue(value);
return;
}
const include = this.getAttribute('include'), config = this.getAttribute('config'), k = index_1.default.parse(key, include, undefined, config), v = index_1.default.parse(value, include, undefined, config),
// @ts-expect-error abstract class
token = debug_1.Shadow.run(() => new parameter_1.ParameterToken(undefined, undefined, config));
token.firstChild.safeAppend(k.childNodes);
token.lastChild.concat(v.childNodes); // eslint-disable-line unicorn/prefer-spread
this.insertAt(token);
};
transclude_1.TranscludeToken.prototype.replaceTemplate =
/** @implements */
function (title) {
/* istanbul ignore if */
if (this.type === 'magic-word') {
throw new Error('TranscludeToken.replaceTemplate method is only for templates!');
}
const { childNodes } = index_1.default
.parse(title, this.getAttribute('include'), 2, this.getAttribute('config'));
this.firstChild.safeReplaceChildren(childNodes);
};
transclude_1.TranscludeToken.prototype.replaceModule =
/** @implements */
function (title) {
/* istanbul ignore if */
if (this.type !== 'magic-word' || this.name !== 'invoke') {
throw new Error('TranscludeToken.replaceModule method is only for modules!');
}
const config = this.getAttribute('config');
if (this.length === 1) {
index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-module', config, [], {
'Stage-1': ':', '!ExtToken': '',
})));
return;
}
const { childNodes } = index_1.default.parse(title, this.getAttribute('include'), 2, config);
this.childNodes[1].safeReplaceChildren(childNodes);
};
transclude_1.TranscludeToken.prototype.replaceFunction =
/** @implements */
function (func) {
/* istanbul ignore next */
if (this.type !== 'magic-word' || this.name !== 'invoke') {
throw new Error('TranscludeToken.replaceModule method is only for modules!');
}
else if (this.length < 2) {
throw new Error('No module name specified!');
}
const config = this.getAttribute('config');
if (this.length === 2) {
index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-function', config, [], {
'Stage-1': ':', '!ExtToken': '',
})));
return;
}
const { childNodes } = index_1.default.parse(func, this.getAttribute('include'), 2, config);
this.childNodes[2].safeReplaceChildren(childNodes);
};
transclude_1.TranscludeToken.prototype.fixDuplication =
/** @implements */
function (aggressive) {
if (!this.hasDuplicatedArgs()) {
return [];
}
const duplicatedKeys = [];
let anonCount = this.getAnonArgs().length;
for (const [key, args] of this.getDuplicatedArgs()) {
if (args.length <= 1) {
continue;
}
const values = new Map();
for (const arg of args) {
const val = arg.getValue().trim();
if (values.has(val)) {
values.get(val).push(arg);
}
else {
values.set(val, [arg]);
}
}
let noMoreAnon = anonCount === 0 || !key.trim() || !Number.isInteger(Number(key));
const emptyArgs = values.get('') ?? [], duplicatedArgs = [...values].filter(([val, { length }]) => val && length > 1).flatMap(([, curArgs]) => {
const anonIndex = noMoreAnon ? -1 : curArgs.findIndex(({ anon }) => anon);
if (anonIndex !== -1) {
noMoreAnon = true;
}
curArgs.splice(anonIndex, 1);
return curArgs;
}), badArgs = [...emptyArgs, ...duplicatedArgs], index = noMoreAnon ? -1 : emptyArgs.findIndex(({ anon }) => anon);
if (badArgs.length === args.length) {
badArgs.splice(index, 1);
}
else if (index !== -1) {
this.anonToNamed();
anonCount = 0;
}
for (const arg of badArgs) {
arg.remove();
}
let remaining = args.length - badArgs.length;
if (remaining === 1) {
continue;
}
else if (aggressive && (anonCount ? /\D\d+$/u : /(?:^|\D)\d+$/u).test(key)) {
let last;
const str = key.slice(0, -/(?<!\d)\d+$/u.exec(key)[0].length);
/^a\d+$/u; // eslint-disable-line @typescript-eslint/no-unused-expressions
const regex = new RegExp(String.raw `^${(0, string_1.escapeRegExp)(str)}\d+$`, 'u'), series = this.getAllArgs().filter(({ name }) => regex.test(name)), ordered = series.every(({ name }, i) => {
const j = Number(name.slice(str.length)), cmp = j <= i + 1 && (i === 0 || j >= last || name === key);
last = j;
return cmp;
});
if (ordered) {
for (let i = 0; i < series.length; i++) {
const arg = series[i], name = `${str}${i + 1}`;
if (arg.name !== name) {
if (arg.name === key) {
remaining--;
}
arg.rename(name, true);
}
}
}
}
if (remaining > 1) {
index_1.default.error(`${this.type === 'template'
? this.name
: this.normalizeTitle(this.childNodes[1].text(), 828, { temporary: true })
.title} still has ${remaining} duplicated ${key} parameters:\n${[...this.getArgs(key)].map(arg => {
const { top, left } = arg.getBoundingClientRect();
return `Line ${String(top)} Column ${String(left)}`;
}).join('\n')}`);
duplicatedKeys.push(key);
}
}
return duplicatedKeys;
};
transclude_1.TranscludeToken.prototype.escapeTables =
/** @implements */
function () {
if (!/\n[^\S\n]*(?::+[^\S\n]*)?\{\|/u.test(this.text())) {
return this;
}
const stripped = this.toString().slice(2, -2), include = this.getAttribute('include'), config = this.getAttribute('config'), parsed = index_1.default.parse(stripped, include, 4, config);
for (const table of parsed.childNodes) {
if (table.is('table')) {
table.escape();
}
}
const { firstChild, length } = index_1.default
.parse(`{{${parsed.toString()}}}`, include, undefined, config);
/* istanbul ignore if */
if (length !== 1 || !(firstChild instanceof transclude_1.TranscludeToken)) {
throw new Error('Failed to escape tables!');
}
this.safeReplaceWith(firstChild);
return firstChild;
};
constants_1.classes['ExtendedTranscludeToken'] = __filename;
;