"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.unitBundleSpec = unitBundleSpec;
exports.unitBundleSpecById = unitBundleSpecById;
exports.bundleSpec = bundleSpec;
const evaluateDataValue_1 = require("./spec/evaluateDataValue");
const util_1 = require("./spec/util");
const object_1 = require("./util/object");
const weakMerge_1 = require("./weakMerge");
function unitBundleSpec(unit, specs, system = false) {
    const { id } = unit;
    const custom = {};
    _bundleUnit(unit, specs, custom, new Set(), system);
    return {
        unit: {
            id,
            ...unit,
        },
        specs: custom,
    };
}
function unitBundleSpecById(id, specs, system = false) {
    const spec = (0, util_1.getSpec)(specs, id);
    const { base } = spec;
    if (base) {
        return {
            unit: {
                id,
            },
        };
    }
    else {
        const custom = {
            [id]: spec,
        };
        _bundle(spec, specs, custom, new Set(), system);
        return {
            unit: {
                id,
            },
            specs: custom,
        };
    }
}
function bundleSpec(spec, specs, system = false, custom = {}) {
    const branch = new Set([]);
    _bundle(spec, specs, custom, branch, system);
    return { spec, specs: custom };
}
function _bundle(spec, specs, custom, branch, system) {
    if (!spec.id) {
        throw new Error('spec id is required');
    }
    if (spec.system && !system) {
        return;
    }
    if (branch.has(spec.id)) {
        return;
    }
    branch.add(spec.id);
    _bundleUnits(spec, specs, custom, branch, system);
}
function _bundleUnit(unit, specs, custom, branch, system) {
    const { id, input = {} } = unit;
    for (const inputId in input) {
        const _input = input[inputId] ?? {};
        const { data } = _input;
        if (data !== undefined) {
            const dataRef = (0, evaluateDataValue_1.evaluateDataValue)(data, specs, {});
            for (const path of dataRef.ref ?? []) {
                const bundle = (0, object_1.deepGet)(dataRef.data, path);
                for (const specId in bundle.specs) {
                    const spec = bundle.specs[specId];
                    if (!custom[specId] && (!(0, util_1.isSystemSpecId)(specs, specId) || system)) {
                        custom[specId] = spec;
                    }
                    _bundle(spec, (0, weakMerge_1.weakMerge)(specs, bundle.specs ?? {}), custom, branch, system);
                }
                _bundleUnit(bundle.unit, specs, custom, branch, system);
            }
        }
    }
    const _spec = (0, util_1.getSpec)((0, weakMerge_1.weakMerge)(specs, custom), id);
    if (!custom[id] && (!(0, util_1.isSystemSpecId)(specs, id) || system)) {
        custom[id] = _spec;
    }
    _bundle(_spec, specs, custom, new Set(branch), system);
}
function _bundleUnits(spec, specs, custom, branch, system) {
    const { units = {} } = spec;
    for (const unit_id in units) {
        const unit = units[unit_id];
        _bundleUnit(unit, specs, custom, branch, system);
    }
}
//# sourceMappingURL=bundle.js.map