import{n as e}from"./rolldown-runtime-C0FnF6B9.js";import{n as t}from"./iframe-DaN-XFub.js";import{i as n,r}from"./react-qN2cStNd.js";import{l as i,m as a}from"./blocks-BiaKjftm.js";function o(e){let t={code:`code`,h1:`h1`,h2:`h2`,h3:`h3`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,strong:`strong`,ul:`ul`,...n(),...e.components};return(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(i,{title:`Foundation Lib/Formatters Runtime`}),`
`,(0,c.jsx)(t.h1,{id:`runtime-форматтеров-pipeline-row-based-и-value-state`,children:`Runtime форматтеров: pipeline, row-based и value state`}),`
`,(0,c.jsxs)(t.p,{children:[`Эта страница описывает конфигурируемый runtime из
`,(0,c.jsx)(t.code,{children:`@ryuzaki13/react-foundation-lib/formatters`}),`. Он предназначен для host-кода,
который хранит сериализуемую настройку отображения, а затем компилирует её для
ячейки таблицы, дерева или другого набора данных. Конфигурация и runtime —
разные границы: в конфигурации нет функций, а скомпилированные executors нельзя
сохранять в JSON, query cache или передавать между runtime-контекстами.`]}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import {
	compileFormattersPipelineExecutor,
	formatPipelineDisplayValue,
	validateFormattersPipelineConfig
} from "@ryuzaki13/react-foundation-lib/formatters";

import type {
	FormattersPipelineConfig,
	FormattersPipelineRuntimeField,
	RowBasedFormatterDefinition,
	ThresholdValueStateResolverConfig
} from "@ryuzaki13/react-foundation-lib/formatters";
`})}),`
`,(0,c.jsx)(t.h2,{id:`модель-данных-и-жизненный-цикл`,children:`Модель данных и жизненный цикл`}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`FormattersPipelineConfig`}),` имеет фиксированную версию `,(0,c.jsx)(t.code,{children:`1`}),` и содержит хотя бы
один источник плана:`]}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type FormattersPipelineConfig = {
	version: 1;
	graph?: FormattersPipelineGraph;
	plan?: FormattersPipelinePlan;
};
`})}),`
`,(0,c.jsxs)(t.p,{children:[`| Представление                    | Для чего хранится               | Содержимое                                                                                          |
| -------------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`graph`}),`                          | Редактор настройки              | Узлы, рёбра и необязательный `,(0,c.jsx)(t.code,{children:`viewport`}),`. Граф обязан быть линейным от `,(0,c.jsx)(t.code,{children:`source`}),` к `,(0,c.jsx)(t.code,{children:`sink`}),`.            |
| `,(0,c.jsx)(t.code,{children:`plan`}),`                           | Быстрое выполнение              | Массив последовательных шагов без координат. Если он валиден, у него приоритет над `,(0,c.jsx)(t.code,{children:`graph`}),`.         |
| `,(0,c.jsx)(t.code,{children:`FormattersPipelineExecutor`}),`     | Только runtime                  | Функция `,(0,c.jsx)(t.code,{children:`execute`}),` и флаги. Появляется после компиляции, не сериализуется.                           |
| `,(0,c.jsx)(t.code,{children:`FormattersPipelineRuntimeField`}),` | Construction-stage объекта поля | Содержит пользовательский конфиг и может получить `,(0,c.jsx)(t.code,{children:`formulaExecutor`}),` / `,(0,c.jsx)(t.code,{children:`formattersPipelineExecutor`}),`. |`]}),`
`,(0,c.jsx)(t.p,{children:`Безопасный порядок работы:`}),`
`,(0,c.jsxs)(t.ol,{children:[`
`,(0,c.jsx)(t.li,{children:`Создать или восстановить конфиг как обычные JSON-данные.`}),`
`,(0,c.jsxs)(t.li,{children:[`Для `,(0,c.jsx)(t.code,{children:`rowBasedOverride`}),` с `,(0,c.jsx)(t.code,{children:`mode: "formula"`}),` один раз настроить реестр
host-формул `,(0,c.jsx)(t.strong,{children:`до`}),` validation и compilation.`]}),`
`,(0,c.jsxs)(t.li,{children:[`Проверить `,(0,c.jsx)(t.code,{children:`validateFormattersPipelineConfig`}),`; неизвестный или устаревший
конфиг не компилировать.`]}),`
`,(0,c.jsxs)(t.li,{children:[`На явной границе восстановления можно вызвать
`,(0,c.jsx)(t.code,{children:`normalizeFormattersPipelineConfig`}),` и положить полученную независимую копию
в модель.`]}),`
`,(0,c.jsx)(t.li,{children:`В construction-stage скомпилировать поле или карту полей.`}),`
`,(0,c.jsxs)(t.li,{children:[`При отрисовке вызвать `,(0,c.jsx)(t.code,{children:`formatPipelineDisplayValue`}),` либо `,(0,c.jsx)(t.code,{children:`executor.execute`}),`.`]}),`
`]}),`
`,(0,c.jsxs)(t.p,{children:[`Не нормализуйте draft при каждом вводе. `,(0,c.jsx)(t.code,{children:`clone…`}),` создаёт независимую копию, а
`,(0,c.jsx)(t.code,{children:`normalize…`}),` — проверяет внешнее `,(0,c.jsx)(t.code,{children:`unknown`}),` значение и допустим только на
явной границе восстановления/сохранения конфигурации.`]}),`
`,(0,c.jsx)(t.h2,{id:`минимальный-сериализуемый-pipeline`,children:`Минимальный сериализуемый pipeline`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import {
	compileFormattersPipelineRuntime,
	formatPipelineDisplayValue,
	validateFormattersPipelineConfig
} from "@ryuzaki13/react-foundation-lib/formatters";

import type { FormattersPipelineConfig } from "@ryuzaki13/react-foundation-lib/formatters";

const config = {
	version: 1,
	plan: {
		steps: [
			{
				id: "pad-code",
				type: "normalizeLeadingZeros",
				config: { fixed: 5 }
			},
			{
				id: "score-state",
				type: "resolveValueState",
				config: {
					resolver: {
						kind: "threshold",
						thresholds: [60, 95],
						states: ["warning", "success", "error"]
					},
					icon: { enabled: true, showValue: true, position: "left" }
				}
			},
			{
				id: "typed-value",
				type: "typedValueFormat",
				config: { numberPresetName: "decimal-2" }
			}
		]
	}
} satisfies FormattersPipelineConfig;

const validation = validateFormattersPipelineConfig(config);
if (!validation.ok) {
	throw new Error(validation.errors.map((item) => item.message).join("\\n"));
}

const field = {
	id: "score",
	role: "measure",
	type: "decimal",
	formattersPipeline: config
};

// Важно: эта функция записывает executors в сам объект field.
compileFormattersPipelineRuntime(field);

const display = formatPipelineDisplayValue({
	field,
	rawValue: "63.4",
	rowData: { score: "63.4" },
	rowKind: "plain"
});

// display.value === "63,40"
// display.state === "success"
`})}),`
`,(0,c.jsx)(t.h2,{id:`шаги-pipeline`,children:`Шаги pipeline`}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`FormattersPipelineFormatterId`}),` допускает только четыре значения.`]}),`
`,(0,c.jsxs)(t.p,{children:[`| Шаг                     | Конфигурация                                | Выполнение и fallback                                         |
| ----------------------- | ------------------------------------------- | ------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`normalizeLeadingZeros`}),` | `,(0,c.jsx)(t.code,{children:`{ fixed?: number }`}),`                        | Передаёт текущее значение в `,(0,c.jsx)(t.code,{children:`normalizeLeadingZeros`}),`.          |
| `,(0,c.jsx)(t.code,{children:`rowBasedOverride`}),`      | field- или formula-вариант ниже             | Подменяет текущее значение данными строки.                    |
| `,(0,c.jsx)(t.code,{children:`resolveValueState`}),`     | fixed/threshold resolver и настройки иконки | Вычисляет `,(0,c.jsx)(t.code,{children:`state`}),`, `,(0,c.jsx)(t.code,{children:`showIcon`}),`, `,(0,c.jsx)(t.code,{children:`showValue`}),`, `,(0,c.jsx)(t.code,{children:`iconPosition`}),`.   |
| `,(0,c.jsx)(t.code,{children:`typedValueFormat`}),`      | `,(0,c.jsx)(t.code,{children:`{ numberPresetName?, datePresetName? }`}),`    | Форматирует итог по OData-type поля: number, date или строка. |`]}),`
`,(0,c.jsx)(t.p,{children:`Ограничения валидатора:`}),`
`,(0,c.jsxs)(t.ul,{children:[`
`,(0,c.jsx)(t.li,{children:`В плане разрешён не более чем один шаг каждого вида.`}),`
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`typedValueFormat`}),` не может идти раньше `,(0,c.jsx)(t.code,{children:`resolveValueState`}),`.`]}),`
`,(0,c.jsxs)(t.li,{children:[`У каждого шага должен быть непустой уникальный `,(0,c.jsx)(t.code,{children:`id`}),`.`]}),`
`,(0,c.jsxs)(t.li,{children:[`Для threshold-resolver длина `,(0,c.jsx)(t.code,{children:`states`}),` обязана равняться
`,(0,c.jsx)(t.code,{children:`thresholds.length + 1`}),`.`]}),`
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`showValue: false`}),` при выключенной иконке — warning: ячейка не покажет
значение.`]}),`
`,(0,c.jsxs)(t.li,{children:[`В графе должны быть ровно один `,(0,c.jsx)(t.code,{children:`source`}),` и один `,(0,c.jsx)(t.code,{children:`sink`}),`; каждый путь должен
быть линейным, без циклов, разветвлений, оборванных и отключённых узлов.`]}),`
`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`FormattersPipelineExecutionContext`}),` получает исходное `,(0,c.jsx)(t.code,{children:`value`}),`, `,(0,c.jsx)(t.code,{children:`rowData`}),`,
`,(0,c.jsx)(t.code,{children:`rowKind`}),`, уровень/группировки и `,(0,c.jsx)(t.code,{children:`columnId`}),`. Новый код определяет семантику
строки через `,(0,c.jsx)(t.code,{children:`rowKind: "plain" | "tree" | "group" | "totals"`}),` — поля
`,(0,c.jsx)(t.code,{children:`isGroupRow`}),` и `,(0,c.jsx)(t.code,{children:`isTotalsRow`}),` в этом контексте оставлены только для
совместимости.`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`executor.execute(ctx)`}),` возвращает `,(0,c.jsx)(t.code,{children:`FormattersPipelineExecutionResult`}),`:
`,(0,c.jsx)(t.code,{children:`value`}),`, `,(0,c.jsx)(t.code,{children:`state`}),`, опциональную `,(0,c.jsx)(t.code,{children:`icon`}),`, `,(0,c.jsx)(t.code,{children:`showIcon`}),`, `,(0,c.jsx)(t.code,{children:`showValue`}),`,
`,(0,c.jsx)(t.code,{children:`iconPosition`}),`, `,(0,c.jsx)(t.code,{children:`hasTypedValueFormat`}),`.`]}),`
`,(0,c.jsx)(t.h3,{id:`rowbasedoverride`,children:`rowBasedOverride`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`type FormattersPipelineRowBasedOverrideConfig =
	| {
			mode: "field";
			fieldKey: string;
			fallbackToRaw?: boolean;
	  }
	| {
			mode: "formula";
			formulaId: string;
			dependencyIds?: string[];
			fallbackToRaw?: boolean;
	  };
`})}),`
`,(0,c.jsxs)(t.p,{children:[`| Режим     | Источник значения                  | Семантика по типу строки                                          |
| --------- | ---------------------------------- | ----------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`field`}),`   | `,(0,c.jsx)(t.code,{children:`rowData[fieldKey]`}),`                | Работает для `,(0,c.jsx)(t.code,{children:`plain`}),`, `,(0,c.jsx)(t.code,{children:`tree`}),`, `,(0,c.jsx)(t.code,{children:`group`}),`; не применяется к `,(0,c.jsx)(t.code,{children:`totals`}),`. |
| `,(0,c.jsx)(t.code,{children:`formula`}),` | `,(0,c.jsx)(t.code,{children:`fn(context)`}),` из row-based реестра | Работает для `,(0,c.jsx)(t.code,{children:`plain`}),`, `,(0,c.jsx)(t.code,{children:`tree`}),`, `,(0,c.jsx)(t.code,{children:`group`}),` и `,(0,c.jsx)(t.code,{children:`totals`}),`.                 |`]}),`
`,(0,c.jsxs)(t.p,{children:[`Если подмена возвращает `,(0,c.jsx)(t.code,{children:`null`}),`/`,(0,c.jsx)(t.code,{children:`undefined`}),`, `,(0,c.jsx)(t.code,{children:`fallbackToRaw`}),` по умолчанию
сохраняет предыдущее значение. При `,(0,c.jsx)(t.code,{children:`fallbackToRaw: false`}),` это значение
допускается как новый результат. Ошибка formula в executor не пробрасывается:
при default fallback остаётся прежнее значение, а при `,(0,c.jsx)(t.code,{children:`false`}),` получается
`,(0,c.jsx)(t.code,{children:`undefined`}),`.`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`dependencyIds`}),` — упорядоченные ключи, которые formula читает по индексам.
Их необходимо запросить вместе с основной строкой: для этого используйте
`,(0,c.jsx)(t.code,{children:`collectFormattersPipelineDependencyIds`}),` или
`,(0,c.jsx)(t.code,{children:`collectRuntimeFieldDependencyIds`}),` до построения query.`]}),`
`,(0,c.jsx)(t.h2,{id:`реестр-row-based-формул`,children:`Реестр row-based формул`}),`
`,(0,c.jsxs)(t.p,{children:[`В конфиге хранится только `,(0,c.jsx)(t.code,{children:`formulaId`}),`; реальная функция существует только в
runtime host-приложения. Реестр глобален для экземпляра модуля, поэтому его
надо установить один раз при bootstrap, до первого вызова валидации или
компиляции pipeline с формульным шагом.`]}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { configureRowBasedFormatterRegistry, createRowBasedFormatterRegistry } from "@ryuzaki13/react-foundation-lib/formatters";

configureRowBasedFormatterRegistry(
	createRowBasedFormatterRegistry([
		{
			id: "sum-dependencies",
			name: "Сумма зависимостей",
			description: "Складывает первые два поля строки.",
			fn: ({ num }) => num(0) + num(1)
		}
	])
);
`})}),`
`,(0,c.jsxs)(t.p,{children:[`| API                                            | Контракт                                                                                 |
| ---------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`createRowBasedFormatterRegistry(definitions)`}),` | Возвращает immutable registry. Бросает `,(0,c.jsx)(t.code,{children:`Error`}),` для пустого `,(0,c.jsx)(t.code,{children:`id`}),` или дубликата.           |
| `,(0,c.jsx)(t.code,{children:`configureRowBasedFormatterRegistry(registry)`}),` | Подменяет активный module-scoped реестр. Не вызывайте повторно в обычном rendering flow. |
| `,(0,c.jsx)(t.code,{children:`getRowBasedFormatterList()`}),`                   | Список доступных host-формул.                                                            |
| `,(0,c.jsx)(t.code,{children:`getRowBasedFormatterById(id)`}),`                 | Формула или `,(0,c.jsx)(t.code,{children:`undefined`}),` для пустого/неизвестного id.                                     |
| `,(0,c.jsx)(t.code,{children:`createRowBasedFormatterContext(args)`}),`         | Создаёт контекст для прямого запуска formula или теста.                                  |`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`RowBasedFormatterDefinition`}),` содержит `,(0,c.jsx)(t.code,{children:`id`}),`, `,(0,c.jsx)(t.code,{children:`name`}),`, `,(0,c.jsx)(t.code,{children:`description`}),`,
`,(0,c.jsx)(t.code,{children:`fn`}),`. `,(0,c.jsx)(t.code,{children:`RowBasedFormatterContext`}),` содержит `,(0,c.jsx)(t.code,{children:`rowData`}),`, `,(0,c.jsx)(t.code,{children:`rawValue`}),`, `,(0,c.jsx)(t.code,{children:`columnId`}),`
и методы:`]}),`
`,(0,c.jsxs)(t.p,{children:[`| Метод          | Результат                                                                   |
| -------------- | --------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`key(index)`}),`   | ID зависимости или `,(0,c.jsx)(t.code,{children:`undefined`}),` для некорректного/вне диапазона индекса.     |
| `,(0,c.jsx)(t.code,{children:`value(index)`}),` | Значение `,(0,c.jsx)(t.code,{children:`rowData`}),` зависимости или `,(0,c.jsx)(t.code,{children:`undefined`}),`.                             |
| `,(0,c.jsx)(t.code,{children:`num(index)`}),`   | `,(0,c.jsx)(t.code,{children:`parseNumber`}),` значения зависимости; при отсутствии/невалидном значении `,(0,c.jsx)(t.code,{children:`0`}),`. |`]}),`
`,(0,c.jsxs)(t.p,{children:[`Формула должна быть синхронной и не должна полагаться на DOM, React state или
неявные внешние данные. Валидация запускает её на тестовых положительных и
отрицательных значениях, чтобы обнаружить недостающие/неиспользуемые
`,(0,c.jsx)(t.code,{children:`dependencyIds`}),` и потенциальную runtime-ошибку. Это диагностический прогон, а
не гарантия корректности для всех данных.`]}),`
`,(0,c.jsx)(t.h2,{id:`проверка-нормализация-копирование-и-новые-id`,children:`Проверка, нормализация, копирование и новые ID`}),`
`,(0,c.jsxs)(t.p,{children:[`| API                                                                                                                              | Когда вызывать                                                       | Результат                                                                                                                   |
| -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`validateFormattersPipelinePlan(plan)`}),`                                                                                           | Перед сохранением/компиляцией готового линейного плана.              | `,(0,c.jsx)(t.code,{children:`FormattersPipelineValidationResult`}),` с `,(0,c.jsx)(t.code,{children:`ok`}),`, `,(0,c.jsx)(t.code,{children:`errors`}),`, `,(0,c.jsx)(t.code,{children:`warnings`}),` и безопасным `,(0,c.jsx)(t.code,{children:`plan`}),` только при успехе.                    |
| `,(0,c.jsx)(t.code,{children:`validateFormattersPipelineGraph(graph)`}),`                                                                                         | Для editor graph.                                                    | Проверяет структуру и строит линейный `,(0,c.jsx)(t.code,{children:`plan`}),`.                                                                               |
| `,(0,c.jsx)(t.code,{children:`validateFormattersPipelineConfig(config)`}),`                                                                                       | Основная проверка конфигурации.                                      | Валидный `,(0,c.jsx)(t.code,{children:`plan`}),` имеет приоритет; если он невалиден и есть `,(0,c.jsx)(t.code,{children:`graph`}),`, выполняется попытка построения по графу с warning.       |
| `,(0,c.jsx)(t.code,{children:`normalizeFormattersPipelineConfig(unknownValue)`}),`                                                                                | На внешней restore/save boundary.                                    | Возвращает валидный независимый `,(0,c.jsx)(t.code,{children:`FormattersPipelineConfig`}),` или `,(0,c.jsx)(t.code,{children:`undefined`}),`; не исправляет невалидные данные «по умолчанию». |
| `,(0,c.jsx)(t.code,{children:`cloneFormattersPipelineConfig(config)`}),`                                                                                          | Для literal draft, setter или безопасного переноса конфигурации.     | Глубокая независимая копия или `,(0,c.jsx)(t.code,{children:`undefined`}),`; не валидирует и не нормализует.                                                 |
| `,(0,c.jsx)(t.code,{children:`cloneTypedValueFormatConfig`}),`, `,(0,c.jsx)(t.code,{children:`cloneNormalizeLeadingZerosConfig`}),`, `,(0,c.jsx)(t.code,{children:`cloneRowBasedOverrideConfig`}),`, `,(0,c.jsx)(t.code,{children:`cloneResolveValueStateConfig`}),` | Для узких UI-операций редактора.                                     | Копия соответствующего вложенного конфига.                                                                                  |
| `,(0,c.jsx)(t.code,{children:`cloneFormatterPipelinePlanStep`}),`, `,(0,c.jsx)(t.code,{children:`cloneFormatterPipelinePlanStepToNode`}),`                                                         | При преобразовании plan-шага в editor node.                          | Независимый step или node с заданной позицией.                                                                              |
| `,(0,c.jsx)(t.code,{children:`rekeyFormattersPipelineConfig(config, idFactory?)`}),`                                                                              | Только при создании независимой копии для нового редактора/сущности. | Переиздаёт технические id пользовательских step/node и рёбер; `,(0,c.jsx)(t.code,{children:`source`}),`/`,(0,c.jsx)(t.code,{children:`sink`}),` сохраняют id. По умолчанию использует UUID.   |`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`FormattersPipelineValidationMessage`}),` содержит машинный `,(0,c.jsx)(t.code,{children:`code`}),` и русское
`,(0,c.jsx)(t.code,{children:`message`}),`; не распознавайте проблему по тексту сообщения. Для UI удобно
показывать `,(0,c.jsx)(t.code,{children:`errors`}),`, а `,(0,c.jsx)(t.code,{children:`warnings`}),` отображать как необязательные рекомендации.`]}),`
`,(0,c.jsx)(t.p,{children:`Каталог узлов можно получить без дублирования строк интерфейса:`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { getFormattersPipelineDefinitionById, getFormattersPipelineDefinitions } from "@ryuzaki13/react-foundation-lib/formatters";

getFormattersPipelineDefinitions();
getFormattersPipelineDefinitionById("typedValueFormat");
`})}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`getFormattersPipelineDefinitions()`}),` и
`,(0,c.jsx)(t.code,{children:`getFormattersPipelineDefinitionById(id)`}),` — публичный способ получить
readonly-каталог и описание конкретного вида форматтера.`]}),`
`,(0,c.jsx)(t.h2,{id:`компиляция-и-отображение`,children:`Компиляция и отображение`}),`
`,(0,c.jsx)(t.h3,{id:`низкоуровневый-executor`,children:`Низкоуровневый executor`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { compileFormattersPipelineExecutor, formatTypedCellValue } from "@ryuzaki13/react-foundation-lib/formatters";

const compiled = compileFormattersPipelineExecutor({
	config,
	column: { role: "measure", type: "decimal" }
});

if (compiled.ok) {
	compiled.executor.execute({
		value: 12.5,
		rowData: {},
		rowKind: "plain",
		isGroupRow: false,
		isTotalsRow: false,
		rowLevel: 0,
		groupingIds: [],
		columnId: "amount"
	});
}

formatTypedCellValue(12.5, { role: "measure", type: "decimal" });
// "12,5" — default number preset "decimal"
`})}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`compileFormattersPipelineExecutor`}),` повторно валидирует config и возвращает
либо `,(0,c.jsx)(t.code,{children:`{ ok: true, executor }`}),`, либо `,(0,c.jsx)(t.code,{children:`{ ok: false, reason }`}),`. Причины ошибки:
`,(0,c.jsx)(t.code,{children:`"pipeline_invalid"`}),` и `,(0,c.jsx)(t.code,{children:`"row_based_formula_not_found"`}),`. В последнем случае
надо исправить порядок bootstrap и зарегистрировать formula, а не подменять
её локальной функцией в сериализуемом конфиге.`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`formatTypedCellValue(value, column, config?)`}),` работает и без pipeline:`]}),`
`,(0,c.jsxs)(t.p,{children:[`| Базовый OData-type    | Поведение                                               |
| --------------------- | ------------------------------------------------------- |
| Число                 | `,(0,c.jsx)(t.code,{children:`formatNumber`}),`; default preset `,(0,c.jsx)(t.code,{children:`decimal`}),`.               |
| Дата                  | `,(0,c.jsx)(t.code,{children:`parseDate`}),`, затем `,(0,c.jsx)(t.code,{children:`formatDate`}),`; default preset `,(0,c.jsx)(t.code,{children:`date`}),`. |
| Остальное             | `,(0,c.jsx)(t.code,{children:`toSafeString`}),`.                                         |
| Небезопасное значение | Пустая строка.                                          |`]}),`
`,(0,c.jsxs)(t.p,{children:[`Для прямого вызова неизвестное имя number/date-пресета заменяется default
пресетом. В полноценном pipeline валидатор отдельно делает неизвестный или
пустой `,(0,c.jsx)(t.code,{children:`numberPresetName`}),` ошибкой; неизвестный `,(0,c.jsx)(t.code,{children:`datePresetName`}),` в runtime
безопасно даёт preset `,(0,c.jsx)(t.code,{children:`date`}),`.`]}),`
`,(0,c.jsx)(t.h3,{id:`runtime-полей`,children:`Runtime полей`}),`
`,(0,c.jsxs)(t.p,{children:[`| API                                                  | Важное свойство                                                                                                                                                                    |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`compileFormattersPipelineRuntime(field)`}),`            | Компилирует `,(0,c.jsx)(t.code,{children:`formulaExecutor`}),` и `,(0,c.jsx)(t.code,{children:`formattersPipelineExecutor`}),` и `,(0,c.jsxs)(t.strong,{children:[`мутирует переданный `,(0,c.jsx)(t.code,{children:`field`})]}),`. Допустим только до помещения поля в readonly snapshot, memoized context или cache. |
| `,(0,c.jsx)(t.code,{children:`compileFormattersPipelineRuntimeFields(fieldsById)`}),` | Компилирует каждое существующее поле; также не пересобирает и не копирует сами поля.                                                                                               |
| `,(0,c.jsx)(t.code,{children:`formatPipelineDisplayValue(args)`}),`                   | Возвращает `,(0,c.jsx)(t.code,{children:`FormattersPipelineDisplayValue`}),`, пригодный для UI: значение, state, настройки иконки и `,(0,c.jsx)(t.code,{children:`overflowTooltip`}),`.                                                              |`]}),`
`,(0,c.jsxs)(t.p,{children:[`Перед pipeline `,(0,c.jsx)(t.code,{children:`formatPipelineDisplayValue`}),` при необходимости выполняет
`,(0,c.jsx)(t.code,{children:`field.formulaExecutor`}),`. Если формула отсутствует/ошиблась, `,(0,c.jsx)(t.code,{children:`purelyDerived`}),`
поле отображается пустым, а обычное поле возвращается к `,(0,c.jsx)(t.code,{children:`rawValue`}),`. После
pipeline fallback-форматирование по типу применяется автоматически, если в
плане не было `,(0,c.jsx)(t.code,{children:`typedValueFormat`}),`. `,(0,c.jsx)(t.code,{children:`emptyWhenZero`}),` скрывает нулевой результат
исходной формулы/значения как пустую строку.`]}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`formulaId`}),` и `,(0,c.jsx)(t.code,{children:`formulaDependencies`}),` относятся к реестру формул host-проекта:
необходимая формула должна быть уже доступна до `,(0,c.jsx)(t.code,{children:`compile…Runtime`}),`, а её
зависимости нужно включить в данные строки.`]}),`
`,(0,c.jsx)(t.h2,{id:`планирование-зависимостей-данных`,children:`Планирование зависимостей данных`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { collectFormattersPipelineDependencyIds, collectRuntimeFieldDependencyIds } from "@ryuzaki13/react-foundation-lib/formatters";

const dependencies = collectFormattersPipelineDependencyIds(config);
// Только fieldKey/dependencyIds из rowBasedOverride.

const runtimePlan = collectRuntimeFieldDependencyIds(["score"], {
	score: {
		formattersPipeline: config,
		cellRenderer: { bindings: { caption: "score-label" } }
	},
	"score-label": {}
});
// runtimePlan.requiredColumnIds / runtimePlan.missingColumnIds
`})}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`collectFormattersPipelineDependencyIds(config)`}),` возвращает только уникальные
IDs из valid `,(0,c.jsx)(t.code,{children:`rowBasedOverride`}),` в порядке первого появления.
`,(0,c.jsx)(t.code,{children:`collectRuntimeFieldDependencyIds(fieldIds, fieldsById)`}),` дополнительно
учитывает `,(0,c.jsx)(t.code,{children:`cellRenderer.bindings`}),`, отделяя известные IDs в
`,(0,c.jsx)(t.code,{children:`requiredColumnIds`}),` от отсутствующих в `,(0,c.jsx)(t.code,{children:`missingColumnIds`}),`. Функции не делают
query сами: host обязан добавить `,(0,c.jsx)(t.code,{children:`requiredColumnIds`}),` в запрос до исполнения
pipeline.`]}),`
`,(0,c.jsx)(t.h2,{id:`value-state`,children:`Value state`}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`State`}),` допускает `,(0,c.jsx)(t.code,{children:`""`}),`, `,(0,c.jsx)(t.code,{children:`"none"`}),`, `,(0,c.jsx)(t.code,{children:`"information"`}),`, `,(0,c.jsx)(t.code,{children:`"success"`}),`,
`,(0,c.jsx)(t.code,{children:`"warning"`}),`, `,(0,c.jsx)(t.code,{children:`"error"`}),`. Resolver сопоставляет значению одно из этих состояний
и хранится в global registry данного module instance.`]}),`
`,(0,c.jsx)(t.h3,{id:`fixed-resolver`,children:`Fixed resolver`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { createFixedResolver, registerFixedResolver, resolveValueState } from "@ryuzaki13/react-foundation-lib/formatters";

const resolverId = registerFixedResolver({
	entries: { A: "success", B: "warning", C: "error" },
	fallbackState: "none"
});

resolveValueState(resolverId, "B"); // "warning"

const resolve = createFixedResolver({ entries: { A: "success" } });
resolve("A"); // "success"
`})}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`FixedValueStateResolverConfig`}),` содержит `,(0,c.jsx)(t.code,{children:`entries: Record<string, State>`}),` и
необязательный `,(0,c.jsx)(t.code,{children:`fallbackState`}),` (по умолчанию `,(0,c.jsx)(t.code,{children:`"none"`}),`). Сопоставление точное
по `,(0,c.jsx)(t.code,{children:`String(value)`}),`; `,(0,c.jsx)(t.code,{children:`null`}),` и `,(0,c.jsx)(t.code,{children:`undefined`}),` сразу дают fallback. Идентичные по
содержимому конфигурации дедуплицируются, поэтому регистрация возвращает один
и тот же id.`]}),`
`,(0,c.jsx)(t.h3,{id:`threshold-resolver`,children:`Threshold resolver`}),`
`,(0,c.jsx)(t.pre,{children:(0,c.jsx)(t.code,{className:`language-ts`,children:`import { createThresholdResolver, registerThresholdResolver } from "@ryuzaki13/react-foundation-lib/formatters";

const resolve = createThresholdResolver({
	thresholds: [{ value: 60, boundary: "lower" }, 95],
	states: ["warning", "success", "error"],
	invalidState: "none"
});

resolve(60); // "warning": boundary "lower" использует <=
resolve(95); // "error": числовой threshold по умолчанию использует <
`})}),`
`,(0,c.jsxs)(t.p,{children:[(0,c.jsx)(t.code,{children:`ThresholdValueStateResolverConfig`}),`:`]}),`
`,(0,c.jsxs)(t.p,{children:[`| Поле           | Правило                                                                                                                                                                                  |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`thresholds`}),`   | Числа либо `,(0,c.jsx)(t.code,{children:`{ value, boundary? }`}),`; `,(0,c.jsx)(t.code,{children:`boundary: "upper"`}),` по умолчанию означает, что порог относится к верхнему сегменту (`,(0,c.jsx)(t.code,{children:`<`}),` для нижнего). `,(0,c.jsx)(t.code,{children:`"lower"`}),` включает его в нижний сегмент (`,(0,c.jsx)(t.code,{children:`<=`}),`). |
| `,(0,c.jsx)(t.code,{children:`states`}),`       | Ровно `,(0,c.jsx)(t.code,{children:`thresholds.length + 1`}),` состояний в порядке диапазонов от меньших значений к большим. Иначе `,(0,c.jsx)(t.code,{children:`create…`}),`/`,(0,c.jsx)(t.code,{children:`register…`}),` бросит `,(0,c.jsx)(t.code,{children:`Error`}),`.                                                  |
| `,(0,c.jsx)(t.code,{children:`invalidState`}),` | Результат для пустого, `,(0,c.jsx)(t.code,{children:`NaN`}),`, бесконечного или нечислового значения; default `,(0,c.jsx)(t.code,{children:`"none"`}),`.                                                                                                   |`]}),`
`,(0,c.jsxs)(t.p,{children:[`Пороги сортируются перед compilation, но массив `,(0,c.jsx)(t.code,{children:`states`}),` не переставляется.
Передавайте `,(0,c.jsx)(t.code,{children:`thresholds`}),` сразу по возрастанию, чтобы соответствие сегментов и
states было однозначным. Для дублирующихся порогов библиотека выводит
`,(0,c.jsx)(t.code,{children:`console.warn`}),`, но продолжает работу.`]}),`
`,(0,c.jsx)(t.h3,{id:`реестр-и-presentation-helpers`,children:`Реестр и presentation helpers`}),`
`,(0,c.jsxs)(t.p,{children:[`| API                                                                                                 | Поведение / side effect                                                                                              |
| --------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `,(0,c.jsx)(t.code,{children:`registerFixedResolver`}),`, `,(0,c.jsx)(t.code,{children:`registerThresholdResolver`}),`                                                | Регистрируют конфигурационный resolver и возвращают его детерминированный короткий id.                               |
| `,(0,c.jsx)(t.code,{children:`createFixedResolver`}),`, `,(0,c.jsx)(t.code,{children:`createThresholdResolver`}),`                                                    | Возвращают функцию resolver; также используют общий registry и дедупликацию.                                         |
| `,(0,c.jsx)(t.code,{children:`resolveValueState(id, value)`}),`                                                                      | Возвращает `,(0,c.jsx)(t.code,{children:`"none"`}),`, если id не найден.                                                                              |
| `,(0,c.jsx)(t.code,{children:`getValueStateResolver(id)`}),`, `,(0,c.jsx)(t.code,{children:`getValueStateResolverIds()`}),`                                           | Читают resolver или список ids.                                                                                      |
| `,(0,c.jsx)(t.code,{children:`registerResolver(canonicalKey, compileFunction)`}),`, `,(0,c.jsx)(t.code,{children:`findResolverByCanonicalKey`}),`, `,(0,c.jsx)(t.code,{children:`computeShortHash`}),` | Низкоуровневый API для специальных host-резолверов. `,(0,c.jsx)(t.code,{children:`compileFunction`}),` — runtime-функция, её нельзя хранить в config. |
| `,(0,c.jsx)(t.code,{children:`resetValueStateResolvers()`}),`                                                                        | Очищает global registry. Только для изолированных тестов: сбросит resolvers, созданные скомпилированными pipeline.   |
| `,(0,c.jsx)(t.code,{children:`DEFAULT_VALUE_STATES`}),`                                                                              | Readonly список presentation-состояний без пустого значения.                                                         |
| `,(0,c.jsx)(t.code,{children:`VALUE_STATE_COLOR_TOKENS`}),`                                                                          | Соответствие `,(0,c.jsx)(t.code,{children:`State`}),` CSS token. Не меняет DOM и не подключает стили.                                                 |
| `,(0,c.jsx)(t.code,{children:`resolveValueStateClassName(state, fallbackClassName?)`}),`                                             | Для `,(0,c.jsx)(t.code,{children:`success`}),` / `,(0,c.jsx)(t.code,{children:`warning`}),` / `,(0,c.jsx)(t.code,{children:`error`}),` / `,(0,c.jsx)(t.code,{children:`information`}),` возвращает `,(0,c.jsx)(t.code,{children:`status…`}),`; для остальных — fallback.                  |`]}),`
`,(0,c.jsx)(t.h2,{id:`runtime-ограничения`,children:`Runtime-ограничения`}),`
`,(0,c.jsxs)(t.ul,{children:[`
`,(0,c.jsx)(t.li,{children:`Реестры row-based formatter-ов и value-state resolver-ов — module-scoped
mutable state. Инициализируйте их один раз до compilation и не меняйте во
время рендера.`}),`
`,(0,c.jsxs)(t.li,{children:[`Config должен оставаться сериализуемым: IDs, строки, числа, массивы и
plain objects. Не сохраняйте `,(0,c.jsx)(t.code,{children:`fn`}),`, executor, `,(0,c.jsx)(t.code,{children:`Map`}),`, `,(0,c.jsx)(t.code,{children:`Date`}),`, React node или
registry в конфигурации.`]}),`
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`compileFormattersPipelineRuntime`}),` меняет входной объект. Сначала создайте
обычный mutable construction object, затем скомпилируйте его и только после
этого публикуйте readonly snapshot.`]}),`
`,(0,c.jsxs)(t.li,{children:[(0,c.jsx)(t.code,{children:`resetDatePresets`}),`, `,(0,c.jsx)(t.code,{children:`resetNumberPresets`}),`, `,(0,c.jsx)(t.code,{children:`resetValueStateResolvers`}),` и
повторная настройка row-based registry предназначены для тестов/явно
изолированных окружений, а не для обычного пользовательского сценария.`]}),`
`,(0,c.jsx)(t.li,{children:`Ошибки validation следует показывать владельцу конфигурации. Не
компилируйте невалидный config и не маскируйте missing formula пустой
локальной реализацией.`}),`
`]})]})}function s(e={}){let{wrapper:t}={...n(),...e.components};return t?(0,c.jsx)(t,{...e,children:(0,c.jsx)(o,{...e})}):o(e)}var c;function l(){return(l=e((()=>{c=t(),r(),a()})))()}l();export{s as default};