core/converters/emitter.xml.converter.ts

core/converters/emitter.xml.converter.ts is a file in GovLab Quality. 36 lines of code and 14 definitions.

import type { ActiveConcept, EmitDescriptor, XmlElement } from "#types/emitter.types";
import { hasValue, ownerRuleId } from "#core/converters/emitter.converter";

const scalarString = function scalarString(value: unknown): string {
    if (typeof value === "string") {
        return value;
    }
    return typeof value === "number" || typeof value === "boolean" ? String(value) : "";
};

const valueProp = function valueProp(concept: ActiveConcept): XmlElement[] {
    return hasValue(concept)
        ? [{ attrs: { name: concept.knob, value: scalarString(concept.value) }, tag: "property" }]
        : [];
};

const ruleElement = function ruleElement(descriptor: EmitDescriptor, concept: ActiveConcept): XmlElement {
    const props = valueProp(concept);
    const name = props.length > 0 ? ownerRuleId(concept.canonicalId, concept.ruleIds) : (concept.ruleIds[0] ?? "");
    const wrap = descriptor.xmlPropsWrap;
    const children = typeof wrap === "string" && props.length > 0 ? [{ children: props, tag: wrap }] : props;
    const ref = `${descriptor.xmlRefPrefix ?? ""}${name}`;
    return { attrs: { [descriptor.xmlNameAttr ?? "name"]: ref }, children, tag: descriptor.xmlRuleTag ?? "module" };
};

export const xmlRulesetTree = function xmlRulesetTree(
    descriptor: EmitDescriptor,
    concepts: ActiveConcept[],
): XmlElement {
    const rules = concepts.map((concept) => ruleElement(descriptor, concept));
    const description = descriptor.xmlDescription;
    const leading: XmlElement[] =
        typeof description === "string" && description.length > 0 ? [{ tag: "description", text: description }] : [];
    const wraps = descriptor.xmlWrap ?? [{ tag: "ruleset" }];
    const nested = wraps.reduceRight<XmlElement[]>(
        (level, wrap) => [{ attrs: wrap.attrs, children: level, tag: wrap.tag }],
        [...leading, ...rules],
    );
    return nested[0] ?? { tag: "ruleset" };
};