import {Meta} from '@storybook/addon-docs/blocks'

<Meta title='@dxtmisha/ru/functional-basic/Classes/Formatters - Утилита для Форматирования Данных'/>

# Класс Formatters

Специализированный класс для форматирования списков данных на основе предоставленной конфигурации. Он служит мостом между необработанными данными и локализованными, удобочитаемыми строками, используя синглтон `GeoIntl` для согласованного форматирования в разных локалях.

## Ключевые особенности

- **Декларативная конфигурация** — Определите правила форматирования один раз и примените их ко всему набору данных.
- **Поддержка нескольких типов** — Встроенная поддержка валют, дат, имен, чисел, множественного числа и единиц измерения.
- **Пользовательские трансформации** — Возможность предоставления собственных функций для уникальных нужд форматирования.
- **Типизация** — Полная поддержка TypeScript для элементов, параметров и результирующих отформатированных списков.
- **Автоматическая генерация ключей** — Автоматически добавляет отформатированные значения к элементам с суффиксом `Format` (например, `price` становится `priceFormat`).

## Инициализация

Для инициализации объекта вызовите конструктор `Formatters(options, list)`.

### Ограничения дженериков (Generic Constraints)

- `Options extends FormattersOptionsList` — тип параметров форматирования.
- `List extends FormattersListProp` — тип входных данных (массив или один элемент).
- `Item extends FormattersItemProp<List>` — тип одного элемента в списке.

**Параметры:**
- `options: Options` — параметры форматирования для каждого столбца/свойства.
- `list?: List` — начальный список данных для форматирования.

```typescript
import { Formatters } from '@dxtmisha/functional-basic'

// 1. Определение параметров форматирования
const options = {
  price: { 
    type: 'currency', 
    options: { currencyPropName: 'currency' } 
  },
  created: { 
    type: 'date', 
    options: { type: 'datetime' } 
  },
  user: {
    type: 'name',
    options: { lastPropName: 'surname', firstPropName: 'name' }
  }
}

// 2. Исходные данные
const data = [
  {
    price: 100,
    currency: 'RUB',
    created: '2024-03-07T12:00:00',
    name: 'Иван',
    surname: 'Иванов'
  }
]

// 3. Инициализация
const formatter = new Formatters(options, data)
```

## Методы

### Обработка
- `to(): FormattersReturn<List, Options>` — Обрабатывает данные и возвращает результат. Если на вход был массив, возвращает новый массив обогащенных элементов. Если был один элемент — один объект. Добавляет свойства с суффиксом `Format`.

### Настройка
- `setList(list?: List): this` — Обновляет данные для форматирования. Поддерживает чейнинг.

### Информация
- `is(): boolean` — Проверяет, установлены ли данные для обработки.
- `isArray(): boolean` — Являются ли текущие данные массивом.
- `length(): number` — Возвращает количество записей в списке.
- `getList(): FormattersList<Item>` — Возвращает текущий список в виде массива.
- `getOptions(): Options` — Возвращает текущую конфигурацию форматирования.

## Типы и параметры форматирования

Конфигурация `FormattersOptionsList` — это словарь, где ключи соответствуют именам свойств в данных (поддерживается точечная нотация `path.to.prop`), а значения — объекту `FormattersOptionsItem`.

### Общая структура `FormattersOptionsItem`
- `type?: FormattersType` — Тип форматировщика.
- `transformation?: (value, item, options) => string` — Кастомная функция преобразования.
- `options?: Options` — Объект параметров, структура которого зависит от выбранного `type`.

### Подробное описание типов

#### 1. Валюта (`currency`)
Используется для локализованного отображения денежных значений.
- `currencyPropName?: string` — Имя свойства в элементе, из которого берется код валюты (по умолчанию `currency`).
- `options?: string | Intl.NumberFormatOptions` — Можно передать фиксированный код (например, `'USD'`) или объект настроек `Intl.NumberFormat`.
- `numberOnly?: boolean` — Если `true`, возвращает только отформатированное число без символа валюты.

#### 2. Дата (`date`)
Форматирование дат и времени через `GeoIntl`.
- `type?: GeoDate` — Предустановленный формат:
    - `full` — Полная дата и время.
    - `datetime` — Дата и время (без секунд).
    - `date` — Только дата.
    - `time` — Только время.
    - `year-month`, `year`, `month`, `day`, `day-month`, `hour-minute`.
- `options?: Intl.DateTimeFormatOptions` — Стандартные параметры `Intl` (например, `month: 'long'`).
- `hour24?: boolean` — Если `true`, принудительно включает 24-часовой режим.

#### 3. Имя (`name`)
Склеивает ФИО в правильном порядке.
- `lastPropName?: string` — Поле для фамилии (по умолчанию `lastName`).
- `firstPropName?: string` — Поле для имени (по умолчанию `firstName`).
- `surname?: string` — Поле для отчества (по умолчанию `surname`).
- `short?: boolean` — Если `true`, выводит фамилию и инициалы (например, «Иванов И. И.»).

#### 4. Число (`number`)
Обычное форматирование чисел с разделением разрядов.
- `options?: Intl.NumberFormatOptions` — Параметры `Intl` (количество знаков после запятой, стиль и т.д.).

#### 5. Множественное число (`plural`)
Выбор правильной формы слова в зависимости от числа.
- `words: string` — Формы слова через разделитель `|`.
    - Для русского: `"яблоко|яблока|яблок"`.
    - Для английского: `"apple|apples"`.
- `options?: Intl.PluralRulesOptions` — Настройки правил плюрализации.
- `optionsNumber?: Intl.NumberFormatOptions` — Настройки форматирования самого числа, которое выводится перед словом.

#### 6. Единица измерения (`unit`)
Добавление единиц измерения (км, кг, л).
- `unit: string` — Код единицы измерения (например, `'kilometer'`, `'kilogram'`, `'liter'`).
- `options?: Intl.NumberFormatOptions` — Параметры форматирования числовой части.

## Примеры

### Использование точечной нотации (Dot Notation)
```typescript
const options = {
  'user.profile.age': { type: 'number' }
}
const data = { user: { profile: { age: 25 } } }
const formatter = new Formatters(options, data)

const result = formatter.to()
// result.userProfileAgeFormat === "25"
```

### Кастомная трансформация
```typescript
const options = {
  status: {
    // Пользовательская функция имеет приоритет над type
    transformation: (value, item) => {
       return value === 'active' ? `✅ ${item.name} в сети` : '❌ Оффлайн'
    }
  }
}
```
