"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function calculateSizes(budget, compilation) {
    const calculatorMap = {
        all: AllCalculator,
        allScript: AllScriptCalculator,
        any: AnyCalculator,
        anyScript: AnyScriptCalculator,
        anyComponentStyle: AnyComponentStyleCalculator,
        bundle: BundleCalculator,
        initial: InitialCalculator,
    };
    const ctor = calculatorMap[budget.type];
    const calculator = new ctor(budget, compilation);
    return calculator.calculate();
}
exports.calculateSizes = calculateSizes;
class Calculator {
    constructor(budget, compilation) {
        this.budget = budget;
        this.compilation = compilation;
    }
}
exports.Calculator = Calculator;
/**
 * A named bundle.
 */
class BundleCalculator extends Calculator {
    calculate() {
        const size = this.compilation.chunks
            .filter(chunk => chunk.name === this.budget.name)
            .reduce((files, chunk) => [...files, ...chunk.files], [])
            .filter((file) => !file.endsWith('.map'))
            .map((file) => this.compilation.assets[file].size())
            .reduce((total, size) => total + size, 0);
        return [{ size, label: this.budget.name }];
    }
}
/**
 * The sum of all initial chunks (marked as initial by webpack).
 */
class InitialCalculator extends Calculator {
    calculate() {
        const initialChunks = this.compilation.chunks.filter(chunk => chunk.isOnlyInitial());
        const size = initialChunks
            .reduce((files, chunk) => [...files, ...chunk.files], [])
            .filter((file) => !file.endsWith('.map'))
            .map((file) => this.compilation.assets[file].size())
            .reduce((total, size) => total + size, 0);
        return [{ size, label: 'initial' }];
    }
}
/**
 * The sum of all the scripts portions.
 */
class AllScriptCalculator extends Calculator {
    calculate() {
        const size = Object.keys(this.compilation.assets)
            .filter(key => key.endsWith('.js'))
            .map(key => this.compilation.assets[key])
            .map(asset => asset.size())
            .reduce((total, size) => total + size, 0);
        return [{ size, label: 'total scripts' }];
    }
}
/**
 * All scripts and assets added together.
 */
class AllCalculator extends Calculator {
    calculate() {
        const size = Object.keys(this.compilation.assets)
            .filter(key => !key.endsWith('.map'))
            .map(key => this.compilation.assets[key].size())
            .reduce((total, size) => total + size, 0);
        return [{ size, label: 'total' }];
    }
}
/**
 * Any components styles
 */
class AnyComponentStyleCalculator extends Calculator {
    calculate() {
        return Object.keys(this.compilation.assets)
            .filter(key => key.endsWith('.css'))
            .map(key => ({
            size: this.compilation.assets[key].size(),
            label: key,
        }));
    }
}
/**
 * Any script, individually.
 */
class AnyScriptCalculator extends Calculator {
    calculate() {
        return Object.keys(this.compilation.assets)
            .filter(key => key.endsWith('.js'))
            .map(key => {
            const asset = this.compilation.assets[key];
            return {
                size: asset.size(),
                label: key,
            };
        });
    }
}
/**
 * Any script or asset (images, css, etc).
 */
class AnyCalculator extends Calculator {
    calculate() {
        return Object.keys(this.compilation.assets)
            .filter(key => !key.endsWith('.map'))
            .map(key => {
            const asset = this.compilation.assets[key];
            return {
                size: asset.size(),
                label: key,
            };
        });
    }
}
/**
 * Calculate the bytes given a string value.
 */
function calculateBytes(input, baseline, factor = 1) {
    const matches = input.match(/^\s*(\d+(?:\.\d+)?)\s*(%|(?:[mM]|[kK]|[gG])?[bB])?\s*$/);
    if (!matches) {
        return NaN;
    }
    const baselineBytes = baseline && calculateBytes(baseline) || 0;
    let value = Number(matches[1]);
    switch (matches[2] && matches[2].toLowerCase()) {
        case '%':
            value = baselineBytes * value / 100;
            break;
        case 'kb':
            value *= 1024;
            break;
        case 'mb':
            value *= 1024 * 1024;
            break;
        case 'gb':
            value *= 1024 * 1024 * 1024;
            break;
    }
    if (baselineBytes === 0) {
        return value;
    }
    return baselineBytes + value * factor;
}
exports.calculateBytes = calculateBytes;
