# core/converters/emitter.xml.converter.ts

> 36 lines of code and 14 definitions.

Tree: GovLab Quality
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-converters-emitter-xml-converter-ts
Source text: https://banes-lab.com/source/quality/core/converters/emitter.xml.converter.ts.txt

Listed in [core/converters](https://banes-lab.com/api/source/quality/core/converters.md), after [core/converters/emitter.converter.ts](https://banes-lab.com/source/quality/core/converters/emitter.converter.ts.md) and before [core/converters/eslint.converter.ts](https://banes-lab.com/source/quality/core/converters/eslint.converter.ts.md).

## Definitions

- `scalarString` (lexical_declaration, line 4)
- `valueProp` (lexical_declaration, line 11)
- `ruleElement` (lexical_declaration, line 17)
- `props` (lexical_declaration, line 18)
- `name` (lexical_declaration, line 19)
- `wrap` (lexical_declaration, line 20)
- `children` (lexical_declaration, line 21)
- `ref` (lexical_declaration, line 22)
- `xmlRulesetTree` (lexical_declaration, line 26, exported)
- `rules` (lexical_declaration, line 30, exported)
- `description` (lexical_declaration, line 31, exported)
- `leading` (lexical_declaration, line 32, exported)
- `wraps` (lexical_declaration, line 34, exported)
- `nested` (lexical_declaration, line 35, exported)

## Contained in

- [core/converters](https://banes-lab.com/anatomy/quality/folder-quality-core-converters.md)

## Uses

- [core/converters/emitter.converter.ts](https://banes-lab.com/source/quality/core/converters/emitter.converter.ts.md)

## Linked from

- [core/converters](https://banes-lab.com/anatomy/quality/folder-quality-core-converters.md)

## Source

```typescript
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" };
};
```
