"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "default", {
    enumerable: true,
    get: ()=>collapseDuplicateDeclarations
});
function collapseDuplicateDeclarations() {
    return (root)=>{
        root.walkRules((node)=>{
            let seen = new Map();
            let droppable = new Set([]);
            let byProperty = new Map();
            node.walkDecls((decl)=>{
                // This could happen if we have nested selectors. In that case the
                // parent will loop over all its declarations but also the declarations
                // of nested rules. With this we ensure that we are shallowly checking
                // declarations.
                if (decl.parent !== node) {
                    return;
                }
                if (seen.has(decl.prop)) {
                    // Exact same value as what we have seen so far
                    if (seen.get(decl.prop).value === decl.value) {
                        // Keep the last one, drop the one we've seen so far
                        droppable.add(seen.get(decl.prop));
                        // Override the existing one with the new value. This is necessary
                        // so that if we happen to have more than one declaration with the
                        // same value, that we keep removing the previous one. Otherwise we
                        // will only remove the *first* one.
                        seen.set(decl.prop, decl);
                        return;
                    }
                    // Not the same value, so we need to check if we can merge it so
                    // let's collect it first.
                    if (!byProperty.has(decl.prop)) {
                        byProperty.set(decl.prop, new Set());
                    }
                    byProperty.get(decl.prop).add(seen.get(decl.prop));
                    byProperty.get(decl.prop).add(decl);
                }
                seen.set(decl.prop, decl);
            });
            // Drop all the duplicate declarations with the exact same value we've
            // already seen so far.
            for (let decl of droppable){
                decl.remove();
            }
            // Analyze the declarations based on its unit, drop all the declarations
            // with the same unit but the last one in the list.
            for (let declarations of byProperty.values()){
                let byUnit = new Map();
                for (let decl1 of declarations){
                    let unit = resolveUnit(decl1.value);
                    if (unit === null) {
                        continue;
                    }
                    if (!byUnit.has(unit)) {
                        byUnit.set(unit, new Set());
                    }
                    byUnit.get(unit).add(decl1);
                }
                for (let declarations1 of byUnit.values()){
                    // Get all but the last one
                    let removableDeclarations = Array.from(declarations1).slice(0, -1);
                    for (let decl2 of removableDeclarations){
                        decl2.remove();
                    }
                }
            }
        });
    };
}
let UNITLESS_NUMBER = Symbol("unitless-number");
function resolveUnit(input) {
    let result = /^-?\d*.?\d+([\w%]+)?$/g.exec(input);
    if (result) {
        var ref;
        return (ref = result[1]) !== null && ref !== void 0 ? ref : UNITLESS_NUMBER;
    }
    return null;
}
