---
name: 02-normalization-helpers
description: Helper functions for normalizing field definitions, columns, filters, actions, charts, and KPIs across various JSON schema formats
---

# Normalization Helpers

These helper functions normalize field definitions, columns, filters, actions, charts, and KPIs from various JSON schema conventions into a standard format used by the HTML renderer.

## Column Normalization

```javascript
// Helper: normalize a column definition regardless of field naming convention
function normalizeColumn(c) {
  return {
    field: c.code || c.name || c.id || c.field || c.fieldCode || "",
    label: c.label || c.displayName || c.code || c.name || "",
    type: c.renderAs === "badge" ? "badge" : (c.type || c.dataType || "text"),
    sortable: !!c.sortable
  };
}
```

**Handles:** `code`, `name`, `id`, `field`, `fieldCode` for field reference; `label`, `displayName` for display; `renderAs`, `type`, `dataType` for type detection; `sortable` flag.

## Form Field Normalization

```javascript
// Helper: normalize a form field
function normalizeField(f) {
  return {
    field: f.code || f.name || f.id || f.fieldCode || f.field || "",
    label: f.label || f.displayName || f.code || f.name || "",
    type: f.type || f.fieldType || f.dataType || "text",
    required: !!f.required
  };
}
```

**Handles:** Field reference via `code`, `name`, `id`, `fieldCode`, `field`; display via `label`, `displayName`; type via `type`, `fieldType`, `dataType`; required flag.

## Filter Normalization (Simple)

```javascript
// Helper: normalize a filter (for SmartTable inline filters — label only)
function normalizeFilter(f) {
  if (typeof f === 'string') return f;
  return f.label || f.displayName || f.filterLabel || f.name || f.code || f.filterCode || "";
}
```

**Handles:** String filters (direct label) or objects with `label`, `displayName`, `filterLabel`, `name`, `code`, or `filterCode`.

## SmartFilter Field Normalization

```javascript
// Helper: normalize a SmartFilter field (preserves type/options/entity for rich rendering)
function normalizeSmartFilterField(f) {
  if (typeof f === 'string') return { label: f, type: 'text', field: '' };
  return {
    field: f.field || f.code || f.name || "",
    label: f.label || f.displayName || f.field || "",
    type: f.type || "text",
    options: f.options || [],
    entity: f.entity || ""
  };
}
```

**Handles:** String filters or rich objects with field reference, label, type, options array, and entity linkage for dropdown/select filters.

## Action Normalization

```javascript
// Helper: normalize an action
function normalizeAction(a) {
  if (typeof a === 'string') return a;
  return a.code || a.id || a.label || a.actionCode || "";
}
```

**Handles:** String actions (direct code/label) or objects with `code`, `id`, `label`, or `actionCode`.

## Chart Normalization

```javascript
// Helper: normalize a chart definition
function normalizeChart(c) {
  if (typeof c === 'string') return { type: 'bar', label: c };
  return {
    type: c.type || c.chartType || 'bar',
    label: c.label || c.displayName || c.title || 'Graphique'
  };
}
```

**Handles:** String charts (default to bar type with label) or objects with `type`/`chartType` and `label`/`displayName`/`title`.

## KPI Normalization

```javascript
// Helper: normalize a KPI — replace formula values with sample display values
function normalizeKpi(k) {
  if (typeof k !== 'object') return { label: String(k), value: "0" };
  const label = k.label || k.displayName || "";
  const rawValue = k.value || k.metric || "0";
  let displayValue = rawValue;
  // Detect formula patterns (e.g., count(...), sum(...), ratio(...), avg(...))
  if (typeof rawValue === 'string' && rawValue.includes('(')) {
    const lbl = label.toLowerCase();
    if (rawValue.includes('ratio') || rawValue.includes('%') || lbl.includes('taux') || lbl.includes('rate'))
      displayValue = "87.5%";
    else if (rawValue.includes('avg') || lbl.includes('moyen') || lbl.includes('average'))
      displayValue = "12.4";
    else if (rawValue.includes('sum'))
      displayValue = (lbl.includes('jour') || lbl.includes('day') || lbl.includes('heure') || lbl.includes('hour')) ? "156" : "45,678";
    else
      displayValue = "1,234";
  }
  // Also handle format hint from the KPI definition
  if (k.format === 'percentage' && displayValue === rawValue) displayValue = "80%";
  return { label: label, value: displayValue };
}
```

**Handles:** Non-object KPIs (converted to `{label, value}`); label via `label` or `displayName`; value via `value` or `metric`; formula pattern detection (ratio/avg/sum) to generate representative display values; percentage format hints.

---

## Usage Pattern

All helpers follow this pattern:

1. **Handle multiple naming conventions** for the same field (e.g., `code`, `name`, `id`)
2. **Preserve data** when already in canonical form
3. **Generate reasonable defaults** for optional fields
4. **Convert internal formats** to HTML-renderable values (e.g., formula → sample number)

Use these helpers when building `moduleSpecs[moduleCode].screens` arrays to normalize columns, fields, filters, actions, charts, and KPIs from heterogeneous BA JSON outputs.
