/**
* @module parseAllTemplates
* @description Returns an array of objects representing all templates used in
* the given wikitext. The object key-value pairs are the template
* `|parameter=value` pairs.
* Piped links, nested templates, nowiki tags and even HTML comments in parameter
* values are adequately accounted for.
* Derived from <https://en.wikipedia.org/wiki/User:SD0001/parseAllTemplates.js>.
* @author User:SD0001
* @version 1.0.0
* @exports {Function} parseAllTemplates
* @param {String} wikitext Wikitext in which to search for the templates
* @returns {Object[]} The 0 key holds the name of the template. The remaining
* key-value pairs are the template |parameter=value pairs.
* @todo ISSUES:
* 1. Very rare situations where, within a parameter value, there are nowiki tags
* inside a comment, or vice-versa, will cause problems.
*
* Found any other bug? Report at [[User talk:SD0001]] or via email.
*/
Window.exportScriptModule('parseAllTemplates', (function() {
var parseAllTemplates = function (wikitext) {
var strReplaceAt = function(string, index, char) {
return string.slice(0,index) + char + string.slice(index + 1);
};
var result = [];
var processTemplateText = function (startIdx, endIdx) {
var text = wikitext.slice(startIdx, endIdx);
// swap out pipe in links with \1 control character
text = text.replace(/(\[\[[^\]]*?)\|(.*?\]\])/g, '$1\1$2')
// [[File: ]] can have multiple pipes, let's do this a couple of times more
.replace(/(\[\[File:[^\]]*?)\|(.*?\]\])/g, '$1\1$2')
.replace(/(\[\[File:[^\]]*?)\|(.*?\]\])/g, '$1\1$2');
var chunks = text.split('|');
var res = {};
// name of the template as used in the wikitext is saved as 0th index of the object
res[0] = chunks[0].trim();
var unnamedIdx = 1;
for (var i=1; i < chunks.length; i++) {
var indexOfEqualTo = chunks[i].indexOf('=');
if (indexOfEqualTo === -1) {
res[unnamedIdx++] = chunks[i].replace(/\1/g,'|').trim();
} else {
var key = chunks[i].slice(0, indexOfEqualTo).trim();
if (key.indexOf('{{') !== -1) {
res[unnamedIdx++] = chunks[i].replace(/\1/g,'|').trim();
continue;
}
var val = chunks[i].slice(indexOfEqualTo + 1).replace(/\1/g,'|').trim();
// changed back '\1' in value to pipes
res[key] = val;
}
}
result.push(res);
};
var n = wikitext.length;
// number of unclosed braces
var numUnclosed = 0;
// are we inside a comment or between nowiki tags?
var inCommentOrNowiki = false;
var startIdx, endIdx;
for (var i=0; i<n; i++) {
if (! inCommentOrNowiki) {
if (wikitext[i] === '{' && wikitext[i+1] === '{') {
if (numUnclosed === 0) {
startIdx = i+2;
}
numUnclosed += 2;
i++;
} else if (wikitext[i] === '}' && wikitext[i+1] === '}') {
if (numUnclosed === 2) {
endIdx = i;
processTemplateText(startIdx, endIdx);
}
numUnclosed -= 2;
i++;
} else if (wikitext[i] === '|' && numUnclosed > 2) {
// swap out pipes in nested templates with \1 character
wikitext = strReplaceAt(wikitext, i,'\1');
} else if (/^(<!--|<nowiki ?>)/.test(wikitext.slice(i, i + 9))) {
inCommentOrNowiki = true;
i += 3;
}
} else { // we are in a comment or nowiki
if (wikitext[i] === '|') {
// swap out pipes with \1 character
wikitext = strReplaceAt(wikitext, i,'\1');
} else if (/^(-->|<\/nowiki ?>)/.test(wikitext.slice(i, i + 10))) {
inCommentOrNowiki = false;
i += 2;
}
}
}
return result;
};
return parseAllTemplates;
})());