milsymbol-rs 0.3.2

A Rust wrapper for the milsymbol JavaScript library to generate military symbols (MIL-STD-2525 and APP-6).
globalThis.__ms_setup = function(config) {
    if (config.hqStaffLength !== null && config.hqStaffLength !== undefined) {
        ms.setHqStaffLength(config.hqStaffLength);
    }
    if (config.standard) {
        ms.setStandard(config.standard);
    }
    if (config.dashArrays) {
        ms.setDashArrays(
            config.dashArrays.pending,
            config.dashArrays.anticipated,
            config.dashArrays.feintDummy
        );
    }
    if (config.colorModes) {
        for (const name in config.colorModes) {
            ms.setColorMode(name, config.colorModes[name]);
        }
    }
};

globalThis.__ms_renderSymbol = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return {
        svg: sym.asSVG(),
        anchor: sym.getAnchor(),
        octagonAnchor: sym.getOctagonAnchor(),
        size: sym.getSize(),
        bbox: sym.bbox,
        metadata: sym.getMetadata(),
        colors: sym.getColors(),
        style: sym.getStyle(),
        options: sym.getOptions(),
        drawInstructions: sym.drawInstructions
    };
};
globalThis.__ms_isValid = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.isValid();
};
globalThis.__ms_isValidExtended = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.isValid(true);
};
globalThis.__ms_getColors = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.getColors();
};
globalThis.__ms_getMetadata = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.getMetadata();
};
globalThis.__ms_getStyle = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.getStyle();
};
globalThis.__ms_getDrawInstructions = function(sidc, options) {
    options = Object.assign({}, options);
    let sym = new ms.Symbol(sidc, options);
    return sym.drawInstructions;
};

globalThis.__ms_getEntitiesAndModifiers = function(symbolSet) {
    const iconSIDC = {};
    const mod1SIDC = {};
    const mod2SIDC = {};
    const dummyIcn = new Proxy({}, { get: (target, name) => name });

    for (const i in ms._iconSIDC.number) {
        ms._iconSIDC.number[i].call({}, iconSIDC, mod1SIDC, mod2SIDC, {}, symbolSet, dummyIcn, true, "D");
    }
    
    function getLabel(item) {
        let label = "";
        if (typeof item === 'string') label = item;
        else if (Array.isArray(item)) label = getLabel(item[0]);
        else if (item && typeof item === 'object') {
            if (item.label) label = getLabel(item.label);
            else if (item.draw) label = getLabel(item.draw);
            else label = JSON.stringify(item);
        } else label = String(item);
        
        // Clean up prefixes like GR.M1.
        return label.replace(/^GR\.M[12]\./, "").replace(/_/g, " ");
    }

    function buildTree(map_obj) {
        const codes = Object.keys(map_obj).sort();
        const tree = [];
        const map = {};

        codes.forEach(code => {
            const item = { code, label: getLabel(map_obj[code]), children: [] };
            map[code] = item;
            
            if (code.length === 6) {
                const level1 = code.substring(0, 2) + "0000";
                const level2 = code.substring(0, 4) + "00";
                
                if (code.endsWith("0000")) {
                    tree.push(item);
                } else if (code.endsWith("00")) {
                    const parent = map[level1];
                    if (parent) parent.children.push(item);
                    else tree.push(item);
                } else {
                    const parent = map[level2] || map[level1];
                    if (parent) parent.children.push(item);
                    else tree.push(item);
                }
            } else {
                tree.push(item);
            }
        });
        return tree;
    }

    return JSON.stringify({
        entities: buildTree(iconSIDC),
        modifiers1: buildTree(mod1SIDC),
        modifiers2: buildTree(mod2SIDC)
    });
};