# core/converters/concern.converter.ts

> 69 lines of code and 16 definitions.

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

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

## Definitions

- `parseConcernValue` (lexical_declaration, line 56, exported)
- `resolveConcernMap` (lexical_declaration, line 69, exported)
- `CONCERN_ALIAS` (lexical_declaration, line 4)
- `numericValue` (lexical_declaration, line 6)
- `found` (lexical_declaration, line 11)
- `classifyConcerns` (lexical_declaration, line 19)
- `values` (lexical_declaration, line 23)
- `enabled` (lexical_declaration, line 24)
- `id` (lexical_declaration, line 26)
- `numeric` (lexical_declaration, line 27)
- `kind` (lexical_declaration, line 28)
- `concernsToCanonicalConfig` (lexical_declaration, line 40, exported)
- `kindById` (lexical_declaration, line 44, exported)
- `{ enabled, values }` (lexical_declaration, line 45, exported)
- `out` (lexical_declaration, line 46, exported)
- `resolved` (lexical_declaration, line 70, exported)

## Contained in

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

## Linked from

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

## Source

```typescript
import type { CanonicalConfig, CanonicalData } from "#types/canon.types";
import type { ConcernConfig, ConcernValue, ResolvedConcern } from "#types/concern.types";

const CONCERN_ALIAS: Readonly<Record<string, string>> = { spacing: "indentation" };

const numericValue = function numericValue(value: ConcernValue): number | null {
    if (typeof value === "number") {
        return value;
    }
    if (Array.isArray(value)) {
        const found = value.find((entry) => typeof entry === "number");
        if (typeof found === "number") {
            return found;
        }
    }
    return null;
};

const classifyConcerns = function classifyConcerns(
    concerns: ConcernConfig,
    kindById: Map<string, string>,
): { enabled: Record<string, boolean>; values: Record<string, number> } {
    const values: Record<string, number> = {};
    const enabled: Record<string, boolean> = {};
    for (const [concept, raw] of Object.entries(concerns)) {
        const id = CONCERN_ALIAS[concept] ?? concept;
        const numeric = numericValue(raw);
        const kind = kindById.get(id);
        if (kind === "value" && numeric !== null) {
            values[id] = numeric;
            continue;
        }
        if (kind === "rule-intent" && raw === true) {
            enabled[id] = true;
        }
    }
    return { enabled, values };
};

export const concernsToCanonicalConfig = function concernsToCanonicalConfig(
    concerns: ConcernConfig,
    data: CanonicalData,
): Partial<CanonicalConfig> {
    const kindById = new Map(data.settings.map((setting) => [setting.id, setting.kind] as const));
    const { enabled, values } = classifyConcerns(concerns, kindById);
    const out: Partial<CanonicalConfig> = {};
    if (Object.keys(values).length > 0) {
        out.values = values;
    }
    if (Object.keys(enabled).length > 0) {
        out.enabled = enabled;
    }
    return out;
};

export const parseConcernValue = function parseConcernValue(value: ConcernValue): ResolvedConcern {
    if (typeof value === "boolean") {
        return { exclude: !value };
    }
    if (typeof value === "number") {
        return { exclude: false, value };
    }
    if (typeof value === "string") {
        return { exclude: false, optionValue: [value] };
    }
    return { exclude: false, optionValue: value };
};

export const resolveConcernMap = function resolveConcernMap(concerns: ConcernConfig): Map<string, ResolvedConcern> {
    const resolved = new Map<string, ResolvedConcern>();
    for (const [concept, value] of Object.entries(concerns)) {
        resolved.set(concept, parseConcernValue(value));
    }
    return resolved;
};
```
