User:Polygnotus/Scripts/TemplateWhitespace.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// <nowiki>
// based on [[User:IceWelder/citationstyle.js]]
// I am making each individual template internally consistent without forcing an overall "style"

// Load the TemplateScript library
$.ajax('//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js', {
    dataType: 'script',
    cache: true
}).then(function () {
    pathoschild.TemplateScript.add([
        {
            category: 'Citation Style', 
            name: 'Fix Citation Styles', 
            isMinorEdit: true, 
            script: function (editor) {
                fixCitationStyles(editor);
            }
        }
    ]);
});

function fixCitationStyles(editor) {
    var text = editor.get();
    var original = text;

    // Regular expression to match citation templates
    var citationRegex = /\s*{{[Cc]it(?:ation|e[a-zA-Z0-9\-_\s]+)\s*\|(?:{{[^}]*}}|[^}])+}}\s*/g;

    // Function to detect and fix the style of a single template
    function fixTemplateStyle(template) {
        // Detect the predominant style
        var tidyCount = (template.match(/\s\|\s[a-zA-Z0-9\-_\s]+=/) || []).length;
        var crammedCount = (template.match(/\|[a-zA-Z0-9\-_\s]+=/) || []).length;
        var roomyCount = (template.match(/\s\|\s[a-zA-Z0-9\-_\s]+\s=\s/) || []).length;
        var spacedCount = (template.match(/[a-zA-Z0-9\-_\s]+=[^ |]+\s(?=\||})/) || []).length;

        var style = 'tidy'; // Default style
        if (crammedCount > tidyCount && crammedCount > roomyCount && crammedCount > spacedCount) {
            style = 'crammed';
        } else if (roomyCount > tidyCount && roomyCount > crammedCount && roomyCount > spacedCount) {
            style = 'roomy';
        } else if (spacedCount > tidyCount && spacedCount > crammedCount && spacedCount > roomyCount) {
            style = 'spaced';
        }

        // Fix the style
        var fixedTemplate = template.replace(/\s*\|\s*([a-zA-Z0-9\-_\s]+(?: [a-zA-Z0-9\-_\s])*)\s*=\s*([^|}\s][^|}\n]*(?:\n(?!\s*\||}}).*)?)/g, function(match, param, value) {
            param = param.trim();
            value = value.trim();
            switch(style) {
                case 'tidy':
                    return ' |' + param + '=' + value;
                case 'crammed':
                    return '|' + param + '=' + value;
                case 'roomy':
                    return ' | ' + param + ' = ' + value;
                case 'spaced':
                    return ' |' + param + '=' + value + ' ';
            }
        });

        // Normalize multiple spaces to one (except for 'spaced' style)
        //if (style !== 'spaced') {
            fixedTemplate = fixedTemplate.replace(/  +/g, ' ');
        //}

        // Align end of the template
        fixedTemplate = fixedTemplate.replace(/\s*}}(\s*)$/g, '}}$1');

        return fixedTemplate;
    }

    // Replace each citation template with its fixed version
    text = text.replace(citationRegex, function(match) {
        return fixTemplateStyle(match);
    });

    // Normalize ref tag capitalization
    text = text.replace(/<ref/gi, '<ref');
    text = text.replace(/<\/ref/gi, '</ref');

    // Normalize newlines between citation templates and ref tags
    text = text.replace(/(<ref(?:(?!>|\/>).)*>)\s*{{/g, '$1{{');
    text = text.replace(/}}\s*<\/ref>/g, '}}</ref>');

    // Only insert the edit summary when something has changed
    if (text !== original) {
        editor.set(text);
        editor.appendEditSummary('Fixing template whitespace with [[User:Polygnotus/Scripts/TemplateWhitespace.js|TemplateWhitespace]]');
        editor.clickDiff();
    }
}
// </nowiki>