Aliexpress URL Cleaner

Removes unnecessary parameters from Aliexpress URLs

// ==UserScript==
// @name         Aliexpress URL Cleaner
// @version      0.4
// @description  Removes unnecessary parameters from Aliexpress URLs
// @match        *://*.aliexpress.com/*
// @namespace    https://greasyfork.org/users/168
// @run-at       document-start
// @noframes
// ==/UserScript==


function whenReady() {
    return new Promise((resolve) => {
        function completed() {
            document.removeEventListener('DOMContentLoaded', completed);
            window.removeEventListener('load', completed);
            resolve();
        }

        if (document.readyState === 'complete'
            || document.readyState === 'interactive') {
            resolve();
        } else {
            document.addEventListener('DOMContentLoaded', completed);
            window.addEventListener('load', completed);
        }
    });
}


whenReady().then(() => {

    let reg = /((?:https?:)?\/\/(?:\w+\.)?aliexpress\.com\/(?:store\/product\/[^\/]+\/[0-9_]+|item\/(?:[^\/]+\/)?[0-9_]+)\.html)(\?[^#\r\n]+)?(#.+)?/i;

    function toCanonical(original) {
        let match = original.match(reg);
        if (match) {
            return match[1] + (match[3] || '');
        }
        return null;
    }


    // For current tab URL.
    let canonical = toCanonical(window.location.href);
    if (!canonical) {
        let link = document.querySelector('head > link[rel=canonical]');
        if (link) {
            canonical = toCanonical(link.href + window.location.hash);
        }
    }
    if (canonical) {
        window.history.replaceState(history.state, document.title, canonical);
    }


    // For static html links.
    document.querySelectorAll('a').forEach((e) => {
        let canonical = toCanonical(e.href);
        if (canonical) {
            e.href = canonical;
        }
    });


    // For lazy-loaded links.
    let observer = new MutationObserver(function (mutationsList) {
        for (let i = 0; i < mutationsList.length; i++) {
            const mutation = mutationsList[i];
            const addedNodes = mutation.addedNodes;
            for (let j = 0; j < addedNodes.length; j++) {
                cleanAndTraverse(addedNodes[j]);
            }
            if (mutation.type === 'attributes') {
                cleanNodeHref(mutation.target)
            }
        }
    });

    function cleanAndTraverse(root) {
        cleanNodeHref(root);
        let children = root.children;
        if (children) {
            for (let k = 0; k < children.length; k++) {
                cleanAndTraverse(children[k]);
            }
        }
    }

    function cleanNodeHref(elem) {
        if (elem.tagName === 'A') {
            const original = elem.href;
            const canonical = toCanonical(elem.href);
            if (canonical && original !== canonical) {
                elem.href = canonical;
            }
        }
    }

    observer.observe(document.documentElement, {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ['href']
    });
});