@ryuzaki13/react-foundation-lib 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{formatters-CQppb89D.js → formatters-ByJmJx4k.js} +3 -3
- package/dist/chunks/{formatters-CQppb89D.js.map → formatters-ByJmJx4k.js.map} +1 -1
- package/dist/chunks/{odata-service-BAYf08WI.js → odata-service-DNcNP2RM.js} +2 -2
- package/dist/chunks/{odata-service-BAYf08WI.js.map → odata-service-DNcNP2RM.js.map} +1 -1
- package/dist/chunks/{validate-BChpTW6y.js → validate-ChUa-TYM.js} +2 -2
- package/dist/chunks/{validate-BChpTW6y.js.map → validate-ChUa-TYM.js.map} +1 -1
- package/dist/error-report/index.js +5 -5
- package/dist/error-report/index.js.map +1 -1
- package/dist/excel/index.js +2 -2
- package/dist/formatters/index.js +3 -3
- package/dist/hooks/index.js +10 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/odata-service/index.js +1 -1
- package/dist/pwa/index.js +2 -1
- package/dist/pwa/index.js.map +1 -1
- package/dist/query-client/index.js +7 -3
- package/dist/query-client/index.js.map +1 -1
- package/dist/three-scene/index.js +1 -1
- package/dist/three-scene/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatters-CQppb89D.js","names":[],"sources":["../../src/formatters/strings/startsWithIgnoringZeros.ts","../../src/formatters/strings/stripInnerSpaces.ts","../../src/formatters/strings/stripLeadingZeros.ts","../../src/formatters/strings/truncateText.ts","../../src/formatters/boolean/toAbapBoolean.ts","../../src/formatters/formatName.ts","../../src/formatters/formatPhone.ts","../../src/formatters/date/calendarDate.ts","../../src/formatters/date/calendarPeriod.ts","../../src/formatters/date/dateRange.ts","../../src/formatters/date/educationDate.ts","../../src/formatters/date/relativeRanges.ts","../../src/formatters/number/compact.ts","../../src/formatters/number/isZeroValue.ts","../../src/formatters/number/formatNumber.ts","../../src/formatters/normalizeLeadingZeros.ts","../../src/formatters/pipeline/clone.ts","../../src/formatters/pipeline/dependencies.ts","../../src/formatters/valueState/valueStateRegistry.ts","../../src/formatters/valueState/fixedValueStateResolver.ts","../../src/formatters/valueState/thresholdValueStateResolver.ts","../../src/formatters/pipeline/execute.ts","../../src/formatters/pipeline/normalize.ts","../../src/formatters/pipeline/definitions.ts","../../src/formatters/pipeline/registry.ts","../../src/formatters/pipeline/rekey.ts","../../src/formatters/pipeline/runtime.ts","../../src/formatters/valueState/presentation.ts","../../src/formatters/valueState/resolveValueStateClassName.ts"],"sourcesContent":["export function startsWithIgnoringZeros(value: string, searchText: string): boolean {\n\tconst cleanValue = (value || \"\").toLowerCase().replace(/^0+/, \"\");\n\tconst cleanText = (searchText || \"\").toLowerCase().replace(/^0+/, \"\");\n\treturn cleanValue.startsWith(cleanText);\n}\n","/**\n * Удаляет пробелы и NBSP/узкие NBSP внутри строки.\n * (для случая \"1 234\" или \"1\\u00A0234\").\n */\nexport function stripInnerSpaces(s: string): string {\n\tlet out = \"\";\n\tlet changed = false;\n\n\tfor (let i = 0; i < s.length; i++) {\n\t\tconst c = s.charCodeAt(i);\n\t\t// обычный пробел, NBSP, NNBSP\n\t\tif (c === 32 || c === 160 || c === 8239) {\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\t\tout += s[i];\n\t}\n\n\treturn changed ? out : s;\n}\n","/**\n * Удаляет ведущие нули из строки.\n * - \"00123\" -> \"123\"\n * - \"0000\" -> \"0\"\n * - \"-0012\" -> \"-12\"\n * - \"\" -> \"0\"\n * - \"abc\" -> \"abc\"\n */\nexport function stripLeadingZeros(input: string): string {\n\tif (input == null) return \"\";\n\n\t// обрезаем пробелы по краям\n\tconst str = input.trim();\n\tif (str === \"\") return \"0\";\n\n\t// проверяем отрицательное число\n\tconst isNegative = str.startsWith(\"-\");\n\tconst core = isNegative ? str.slice(1) : str;\n\n\t// если core не число — вернём как есть\n\tif (!/^\\d+$/.test(core)) {\n\t\treturn str;\n\t}\n\n\t// удаляем ведущие нули\n\tconst normalized = core.replace(/^0+/, \"\");\n\tconst result = normalized === \"\" ? \"0\" : normalized;\n\n\treturn isNegative ? `-${result}` : result;\n}\n","import { normalizeText } from \"./normalizeText\";\n\nexport function truncateText(value: string | null | undefined, maxLength: number) {\n\tconst normalized = normalizeText(value);\n\tif (!normalized) return undefined;\n\n\treturn normalized.length > maxLength ? `${normalized.slice(0, maxLength)}...` : normalized;\n}\n","import { AbapBoolean } from \"../../types\";\n\nexport function toAbapBoolean(value: unknown): AbapBoolean {\n\tif (typeof value === \"string\") {\n\t\tvalue = value !== \"0\";\n\t}\n\treturn value ? \"X\" : \" \";\n}\n","/**\n * Форматирует ФИО в формат \"Фамилия Имя Отчество\"\n * @param fullName Входная строка с ФИО в любом формате\n * @returns Отформатированная строка в формате \"Иванов Иван Иванович\"\n */\nexport function formatFullName(fullName: string): string {\n\tif (!fullName) return \"\";\n\n\t// Нормализация строки: удаление лишних пробелов, приведение к нижнему регистру\n\tconst normalized = fullName\n\t\t.trim()\n\t\t.replace(/\\s+/g, \" \")\n\t\t.replace(/\\s*\\./, \" \") // если после фамилии есть точка...\n\t\t.replace(/\\s*\\.\\s*/g, \". \")\n\t\t.toLowerCase();\n\n\t// Разделение на части\n\tconst parts = normalized.split(\" \");\n\n\tif (parts.length === 0) return \"\";\n\n\t// Обработка фамилии (первая часть)\n\tconst surname = capitalize(parts[0]);\n\n\tif (parts.length === 1) return surname;\n\n\t// Обработка имени (вторая часть)\n\tconst name = parts[1].includes(\".\") ? expandInitial(parts[1]) : capitalize(parts[1]);\n\n\tif (parts.length === 2) return `${surname} ${name}`;\n\n\t// Обработка отчества (третья часть)\n\tconst patronymic = parts[2].includes(\".\") ? expandInitial(parts[2]) : capitalize(parts[2]);\n\n\treturn `${surname} ${name} ${patronymic}`;\n}\n\n/**\n * Форматирует ФИО в формат \"Фамилия И.О.\"\n * @param fullName Входная строка с ФИО в любом формате\n * @returns Отформатированная строка в формате \"Иванов И.И.\"\n */\nexport function formatShortName(fullName: string): string {\n\tif (!fullName) return \"\";\n\n\t// Нормализация строки\n\tconst normalized = fullName\n\t\t.trim()\n\t\t.replace(/\\s+/g, \" \")\n\t\t.replace(/\\s*\\.\\s*/g, \".\")\n\t\t.toLowerCase();\n\n\tconst parts = normalized.split(\" \");\n\n\tif (parts.length === 0) return \"\";\n\n\t// Фамилия всегда с большой буквы\n\tconst surname = capitalize(parts[0]);\n\n\tif (parts.length === 1) return surname;\n\n\t// Инициал имени\n\tconst nameInitial = parts[1].startsWith(\".\") ? parts[1][1] : parts[1][0];\n\n\tif (parts.length === 2) {\n\t\treturn parts[1].includes(\".\") ? `${surname} ${nameInitial.toUpperCase()}.` : `${surname} ${nameInitial.toUpperCase()}.`;\n\t}\n\n\t// Инициал отчества\n\tconst patronymicInitial = parts[2].startsWith(\".\") ? parts[2][1] : parts[2][0];\n\n\treturn `${surname} ${nameInitial.toUpperCase()}.${patronymicInitial.toUpperCase()}.`;\n}\n\nfunction capitalize(str: string): string {\n\tif (!str) return \"\";\n\treturn str[0].toUpperCase() + str.slice(1);\n}\n\nfunction expandInitial(initial: string): string {\n\treturn capitalize(initial);\n\n\t// if (!initial.includes(\".\")) return capitalize(initial);\n\n\t// const letter = initial.replace(/\\./g, \"\").toLowerCase();\n\t// if (!letter) return \"\";\n\n\t// return letter.toUpperCase();\n}\n","export function formatPhone(number: string): string {\n\tconst match = clearPhone(number).match(/^(\\+7)(\\d{3})(\\d{3})(\\d{2})(\\d{2})$/);\n\tif (!match) return number;\n\treturn `+7 (${match[2]}) ${match[3]}-${match[4]}-${match[5]}`;\n}\n\nexport function clearPhone(number: string): string {\n\treturn `+7${number\n\t\t.replace(/\\D/g, \"\")\n\t\t.slice(0, 11)\n\t\t.replace(/^(7|8)/, \"\")}`;\n}\n","/**\n * Создаёт календарную дату без timezone-семантики.\n *\n * Внутри используется локальный конструктор `Date`, чтобы видимые\n * компоненты даты и времени сохранялись без дополнительных смещений.\n */\nexport function createCalendarDate(year: number, monthIndex: number, day: number, hour = 0, minute = 0, second = 0, millisecond = 0): Date {\n\treturn new Date(year, monthIndex, day, hour, minute, second, millisecond);\n}\n\n/**\n * Нормализует дату к началу суток без timezone-сдвига.\n */\nexport function getStartOfDay(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Нормализует дату к концу суток без timezone-сдвига.\n */\nexport function getEndOfDay(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 0);\n}\n\n/**\n * Возвращает первый день месяца для переданной даты.\n */\nexport function getStartOfMonth(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);\n}\n\n/**\n * Возвращает первый день года для переданной даты.\n */\nexport function getStartOfYear(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), 0, 1, 0, 0, 0, 0);\n}\n\n/**\n * Возвращает начало календарной недели без timezone-сдвига.\n *\n * По умолчанию неделя начинается в понедельник, как в русскоязычной календарной\n * сетке. При необходимости вызывающий код может передать другой день недели\n * в формате `Date.getDay()`: 0 — воскресенье, 1 — понедельник.\n */\nexport function getStartOfWeek(date: Date, weekStartsOn = 1): Date {\n\tconst normalizedWeekStart = Number.isInteger(weekStartsOn) ? ((weekStartsOn % 7) + 7) % 7 : 1;\n\tconst start = getStartOfDay(date);\n\tconst offset = (start.getDay() - normalizedWeekStart + 7) % 7;\n\n\treturn addCalendarDays(start, -offset);\n}\n\n/**\n * Сдвигает дату на указанное количество суток в календарной семантике.\n */\nexport function addCalendarDays(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate() + amount, 0, 0, 0, 0);\n}\n\n/**\n * Сдвигает дату на указанное количество месяцев в календарной семантике.\n */\nexport function addCalendarMonths(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth() + amount, date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Сдвигает дату на указанное количество лет в календарной семантике.\n */\nexport function addCalendarYears(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear() + amount, date.getMonth(), date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Проверяет, совпадают ли две даты по календарному дню.\n */\nexport function isSameCalendarDay(left: Date | null | undefined, right: Date | null | undefined): boolean {\n\tif (!(left instanceof Date) || !(right instanceof Date)) return false;\n\n\treturn left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();\n}\n","import {\n\taddCalendarDays,\n\tcreateCalendarDate,\n\tgetEndOfDay,\n\tgetStartOfDay,\n\tgetStartOfMonth,\n\tgetStartOfWeek,\n\tgetStartOfYear\n} from \"./calendarDate\";\n\nexport type CalendarPeriodSelectionMode = \"day\" | \"week\" | \"month\" | \"year\";\nexport type CalendarWeekEndDay = \"friday\" | \"saturday\" | \"sunday\";\n\nexport interface CalendarPeriodOptions {\n\t/**\n\t * Определяет размер выбираемого календарного периода.\n\t */\n\tselectionMode?: CalendarPeriodSelectionMode;\n\t/**\n\t * Последний включённый день недели для режима `week`.\n\t */\n\tweekEndDay?: CalendarWeekEndDay;\n}\n\nexport interface CalendarPeriod {\n\treadonly start: Date;\n\treadonly end: Date;\n}\n\nexport interface CalendarPeriodDateBounds {\n\treadonly minDate?: Date;\n\treadonly maxDate?: Date;\n}\n\nconst WEEK_END_DAY_OFFSETS: Record<CalendarWeekEndDay, number> = {\n\tfriday: 4,\n\tsaturday: 5,\n\tsunday: 6\n};\n\nfunction isValidCalendarDate(value: Date | null | undefined): value is Date {\n\treturn value instanceof Date && Number.isFinite(value.getTime());\n}\n\nfunction resolveCalendarWeekEndDay(weekEndDay?: CalendarWeekEndDay): CalendarWeekEndDay {\n\treturn weekEndDay ?? \"sunday\";\n}\n\nfunction resolveCalendarPeriodSelectionMode(selectionMode?: CalendarPeriodSelectionMode): CalendarPeriodSelectionMode {\n\treturn selectionMode ?? \"day\";\n}\n\n/**\n * Возвращает включительные границы календарного периода без timezone-сдвига.\n */\nexport function getCalendarPeriod(value: Date | null | undefined, options: CalendarPeriodOptions = {}): CalendarPeriod | null {\n\tif (!isValidCalendarDate(value)) return null;\n\n\tconst selectionMode = resolveCalendarPeriodSelectionMode(options.selectionMode);\n\n\tswitch (selectionMode) {\n\t\tcase \"day\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfDay(value),\n\t\t\t\tend: getEndOfDay(value)\n\t\t\t};\n\t\t}\n\n\t\tcase \"week\": {\n\t\t\tconst start = getStartOfWeek(value);\n\t\t\tconst weekEndOffset = WEEK_END_DAY_OFFSETS[resolveCalendarWeekEndDay(options.weekEndDay)];\n\n\t\t\treturn {\n\t\t\t\tstart,\n\t\t\t\tend: getEndOfDay(addCalendarDays(start, weekEndOffset))\n\t\t\t};\n\t\t}\n\n\t\tcase \"month\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfMonth(value),\n\t\t\t\tend: getEndOfDay(createCalendarDate(value.getFullYear(), value.getMonth() + 1, 0))\n\t\t\t};\n\t\t}\n\n\t\tcase \"year\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfYear(value),\n\t\t\t\tend: getEndOfDay(createCalendarDate(value.getFullYear(), 11, 31))\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst checker: never = selectionMode;\n\t\t\tvoid checker;\n\n\t\t\treturn null;\n\t\t}\n\t}\n}\n\n/**\n * Проверяет, входит ли дата в уже вычисленные включительные границы периода.\n */\nexport function isDateInsideCalendarPeriod(value: Date | null | undefined, period: CalendarPeriod | null | undefined): boolean {\n\tif (!isValidCalendarDate(value) || !period) return false;\n\n\tconst dateTime = getStartOfDay(value).getTime();\n\treturn dateTime >= period.start.getTime() && dateTime <= period.end.getTime();\n}\n\n/**\n * Проверяет, что весь период укладывается в заданные календарные границы выбора.\n */\nexport function isCalendarPeriodWithinDateBounds(\n\tperiod: CalendarPeriod | null | undefined,\n\tbounds: CalendarPeriodDateBounds = {}\n): boolean {\n\tif (!period) return false;\n\n\tif (bounds.minDate && period.start.getTime() < getStartOfDay(bounds.minDate).getTime()) return false;\n\tif (bounds.maxDate && period.end.getTime() > getEndOfDay(bounds.maxDate).getTime()) return false;\n\n\treturn true;\n}\n","import { getEndOfDay, getStartOfDay } from \"./calendarDate\";\n\nconst MS_IN_DAY = 24 * 60 * 60 * 1000;\n\nexport type NullableDateRange = readonly [Date | null, Date | null];\nexport type DateRange = readonly [Date, Date];\n\nexport type DateRangeInput = Date | null | NullableDateRange;\n\nexport type DateRangeTimeMode = \"dayBounds\" | \"preserve\";\n\nexport interface NormalizeDateRangeOptions {\n\t/**\n\t * Режим времени для двух граничных дат.\n\t *\n\t * `dayBounds` расширяет диапазон до полных календарных дней,\n\t * `preserve` оставляет время исходных дат после упорядочивания.\n\t */\n\ttimeMode?: DateRangeTimeMode;\n}\n\nexport function isValidDate(value: Date | null): value is Date {\n\treturn value instanceof Date && Number.isFinite(value.getTime());\n}\n\nexport function isDateRangeTuple(value: DateRangeInput): value is NullableDateRange {\n\treturn Array.isArray(value);\n}\n\nexport function cloneDate(date: Date): Date {\n\treturn new Date(date.getTime());\n}\n\nexport function orderDates(left: Date, right: Date): DateRange {\n\tif (left.getTime() <= right.getTime()) return [left, right];\n\n\treturn [right, left];\n}\n\nexport function resolveDateRangePair(value: DateRangeInput): DateRange | null {\n\tif (isDateRangeTuple(value)) {\n\t\tconst [left, right] = value;\n\t\tconst hasLeft = isValidDate(left);\n\t\tconst hasRight = isValidDate(right);\n\n\t\tif (hasLeft && hasRight) return orderDates(left, right);\n\t\tif (hasLeft) return [left, left];\n\t\tif (hasRight) return [right, right];\n\n\t\treturn null;\n\t}\n\n\treturn isValidDate(value) ? [value, value] : null;\n}\n\nexport function normalizeDateRange(value: DateRangeInput, options: NormalizeDateRangeOptions = {}): DateRange | null {\n\tconst range = resolveDateRangePair(value);\n\tif (!range) return null;\n\n\tconst [start, end] = range;\n\tif (options.timeMode === \"preserve\") {\n\t\treturn [cloneDate(start), cloneDate(end)];\n\t}\n\n\treturn [getStartOfDay(start), getEndOfDay(end)];\n}\n\nexport function requireDateRange(value: DateRangeInput, options?: NormalizeDateRangeOptions): DateRange {\n\tconst range = normalizeDateRange(value, options);\n\tif (!range) {\n\t\tthrow new Error(\"Диапазон дат не задан\");\n\t}\n\n\treturn range;\n}\n\nfunction getCalendarDayTime(date: Date): number {\n\treturn Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\n/**\n * Считает количество календарных дней в диапазоне включительно.\n */\nexport function countCalendarDaysInDateRange(value: DateRangeInput): number | null {\n\tconst range = normalizeDateRange(value);\n\tif (!range) return null;\n\n\tconst [startDate, endDate] = range;\n\treturn Math.floor((getCalendarDayTime(endDate) - getCalendarDayTime(startDate)) / MS_IN_DAY) + 1;\n}\n","import { addCalendarDays, createCalendarDate, getStartOfDay } from \"./calendarDate\";\n\nconst EDUCATION_DATE_KEY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst EDUCATION_TIME_KEY_RE = /^(\\d{2}):(\\d{2})(?::(\\d{2}))?$/;\nconst EDUCATION_YEAR_START_MONTH_INDEX = 8;\nconst EDUCATION_YEAR_START_DAY = 1;\nconst EDUCATION_YEAR_END_MONTH_INDEX = 7;\nconst EDUCATION_YEAR_END_DAY = 31;\nconst EDUCATION_WEEK_DAY_COUNT = 6;\n\n/**\n * Машинный ключ календарного дня в образовательной системе.\n *\n * Формат всегда `YYYY-MM-DD`: он безопасен для URL, SQL-параметров и query keys,\n * но не несёт timezone-семантики.\n */\nexport type EducationDateKey = string;\n\n/**\n * Диапазон учебного года. Учебный год начинается 1 сентября и заканчивается 31 августа.\n */\nexport type EducationYearRange = {\n\treadonly year: number;\n\treadonly start: Date;\n\treadonly end: Date;\n};\n\n/**\n * Диапазон учебной недели. В публичном расписании неделя отображается с понедельника по субботу.\n */\nexport type EducationWeekRange = {\n\treadonly start: Date;\n\treadonly end: Date;\n};\n\nfunction isValidTimePart(value: number, max: number): boolean {\n\treturn Number.isInteger(value) && value >= 0 && value <= max;\n}\n\n/**\n * Разбирает `YYYY-MM-DD` без `Date.parse`, чтобы не получить скрытый timezone-сдвиг.\n */\nexport function parseEducationDateKey(value: string | undefined): Date | null {\n\tconst match = value?.match(EDUCATION_DATE_KEY_RE);\n\tif (!match) {\n\t\treturn null;\n\t}\n\n\tconst year = Number(match[1]);\n\tconst month = Number(match[2]);\n\tconst day = Number(match[3]);\n\tconst date = createCalendarDate(year, month - 1, day);\n\n\treturn date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day ? date : null;\n}\n\n/**\n * Форматирует `Date` в стабильный ключ `YYYY-MM-DD` по локальным календарным компонентам.\n */\nexport function formatEducationDateKey(value: Date): EducationDateKey {\n\tconst year = value.getFullYear();\n\tconst month = String(value.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(value.getDate()).padStart(2, \"0\");\n\n\treturn `${year}-${month}-${day}`;\n}\n\n/**\n * Форматирует время в `HH:mm` по локальным компонентам, без UTC-преобразования.\n */\nexport function formatEducationTimeKey(value: Date): string {\n\tconst hours = String(value.getHours()).padStart(2, \"0\");\n\tconst minutes = String(value.getMinutes()).padStart(2, \"0\");\n\n\treturn `${hours}:${minutes}`;\n}\n\n/**\n * Создаёт календарную дату-время из отдельных ключей даты и времени, удобных для SQL-выдачи.\n */\nexport function createEducationDateTime(dateKey: EducationDateKey, timeKey: string): Date | null {\n\tconst date = parseEducationDateKey(dateKey);\n\tconst match = timeKey.match(EDUCATION_TIME_KEY_RE);\n\tif (!date || !match) {\n\t\treturn null;\n\t}\n\n\tconst hours = Number(match[1]);\n\tconst minutes = Number(match[2]);\n\tconst seconds = Number(match[3] ?? 0);\n\tif (!isValidTimePart(hours, 23) || !isValidTimePart(minutes, 59) || !isValidTimePart(seconds, 59)) {\n\t\treturn null;\n\t}\n\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), hours, minutes, seconds);\n}\n\n/**\n * Возвращает учебный год для календарной даты.\n */\nexport function getEducationYear(value: Date = new Date()): number {\n\treturn value.getMonth() < EDUCATION_YEAR_START_MONTH_INDEX ? value.getFullYear() - 1 : value.getFullYear();\n}\n\n/**\n * Возвращает границы учебного года для переданной даты.\n */\nexport function getEducationYearRange(value: Date = new Date()): EducationYearRange {\n\tconst year = getEducationYear(value);\n\n\treturn {\n\t\tyear,\n\t\tstart: createCalendarDate(year, EDUCATION_YEAR_START_MONTH_INDEX, EDUCATION_YEAR_START_DAY),\n\t\tend: createCalendarDate(year + 1, EDUCATION_YEAR_END_MONTH_INDEX, EDUCATION_YEAR_END_DAY)\n\t};\n}\n\n/**\n * Проверяет, входит ли дата в учебный год, вычисленный от `now`.\n */\nexport function isEducationDateInCurrentYear(value: Date, now: Date = new Date()): boolean {\n\tconst date = getStartOfDay(value);\n\tconst { start, end } = getEducationYearRange(now);\n\n\treturn date >= start && date <= end;\n}\n\n/**\n * Возвращает понедельник учебной недели. Воскресенье относится к следующей учебной неделе.\n */\nexport function getEducationWeekStartDate(value: Date): Date {\n\tconst date = getStartOfDay(value);\n\tconst dayOfWeek = (date.getDay() + 6) % 7;\n\tconst daysToMonday = dayOfWeek === 6 ? 1 : -dayOfWeek;\n\n\treturn addCalendarDays(date, daysToMonday);\n}\n\n/**\n * Возвращает диапазон учебной недели: понедельник-суббота.\n */\nexport function getEducationWeekRange(value: Date): EducationWeekRange {\n\tconst start = getEducationWeekStartDate(value);\n\n\treturn {\n\t\tstart,\n\t\tend: addCalendarDays(start, EDUCATION_WEEK_DAY_COUNT - 1)\n\t};\n}\n\n/**\n * Возвращает ключи дней учебной недели для SSR, prefetch и клиентского отображения.\n */\nexport function getEducationWeekDays(week: EducationDateKey | Date): readonly EducationDateKey[] {\n\tconst start =\n\t\ttypeof week === \"string\" ? (parseEducationDateKey(week) ?? getEducationWeekStartDate(new Date())) : getEducationWeekStartDate(week);\n\n\treturn Array.from({ length: EDUCATION_WEEK_DAY_COUNT }, (_, index) => formatEducationDateKey(addCalendarDays(start, index)));\n}\n\n/**\n * Возвращает ключ текущей учебной недели.\n */\nexport function getCurrentEducationWeekKey(now: Date = new Date()): EducationDateKey {\n\treturn formatEducationDateKey(getEducationWeekStartDate(now));\n}\n\n/**\n * Нормализует произвольный ключ недели к понедельнику текущего учебного года.\n */\nexport function normalizeEducationWeekKey(value: string | undefined, now: Date = new Date()): EducationDateKey | undefined {\n\tconst parsed = parseEducationDateKey(value);\n\tif (!parsed || !isEducationDateInCurrentYear(parsed, now)) {\n\t\treturn undefined;\n\t}\n\n\tconst weekStart = getEducationWeekStartDate(parsed);\n\n\treturn isEducationDateInCurrentYear(weekStart, now) ? formatEducationDateKey(weekStart) : undefined;\n}\n\n/**\n * Возвращает валидный ключ недели или текущую учебную неделю как fallback.\n */\nexport function resolveEducationWeekKey(value: string | undefined, now: Date = new Date()): EducationDateKey {\n\treturn normalizeEducationWeekKey(value, now) ?? getCurrentEducationWeekKey(now);\n}\n\n/**\n * Проверяет, совпадает ли неделя с текущей учебной неделей.\n */\nexport function isCurrentEducationWeek(week: EducationDateKey, now: Date = new Date()): boolean {\n\treturn resolveEducationWeekKey(week, now) === getCurrentEducationWeekKey(now);\n}\n","import { addCalendarDays, addCalendarMonths, getEndOfDay, getStartOfDay, getStartOfMonth } from \"./calendarDate\";\n\nimport type { NullableDateRange } from \"./dateRange\";\n\n/**\n * Контекст вычисления относительного диапазона дат.\n */\nexport interface DateRangeReferenceContext {\n\treferenceDate: Date;\n}\n\n/**\n * Нормализует опорную дату к началу суток без timezone-сдвига.\n */\nexport function normalizeDateRangeReferenceDate(referenceDate: Date): Date {\n\treturn getStartOfDay(referenceDate);\n}\n\n/**\n * Возвращает безопасную конечную дату для диапазона \"с начала месяца по вчера\".\n *\n * На первом дне месяца диапазон не может закончиться \"вчера\" без инверсии,\n * поэтому конец диапазона прижимается к старту месяца.\n */\nexport function resolveMonthStartToYesterdayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\tconst monthStart = getStartOfMonth(normalizedReferenceDate);\n\tconst yesterday = addCalendarDays(normalizedReferenceDate, -1);\n\tconst safeEndDate = yesterday < monthStart ? monthStart : yesterday;\n\n\treturn [monthStart, getEndOfDay(safeEndDate)];\n}\n\n/**\n * Возвращает диапазон \"с начала месяца по сегодня\".\n */\nexport function resolveMonthStartToTodayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\treturn [getStartOfMonth(normalizedReferenceDate), getEndOfDay(normalizedReferenceDate)];\n}\n\n/**\n * Возвращает диапазон \"за сегодня\".\n */\nexport function resolveTodayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\treturn [normalizedReferenceDate, getEndOfDay(normalizedReferenceDate)];\n}\n\n/**\n * Возвращает диапазон \"за вчера\".\n */\nexport function resolveYesterdayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst yesterday = addCalendarDays(normalizeDateRangeReferenceDate(referenceDate), -1);\n\treturn [yesterday, getEndOfDay(yesterday)];\n}\n\n/**\n * Возвращает диапазон \"месяц назад\" от текущего дня.\n */\nexport function resolveMonthAgoRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\tconst monthAgo = addCalendarMonths(normalizedReferenceDate, -1);\n\treturn [getStartOfDay(monthAgo), getEndOfDay(normalizedReferenceDate)];\n}\n","import type { NumberFormatCompactOptions, NumberFormatCompactRoundingMode, NumberFormatCompactUnit, NumberFormatPreset } from \"./types\";\n\ntype PlainNumberFormatter = (value: number, preset: NumberFormatPreset) => string;\n\ntype ResolvedCompactNumberOptions = {\n\troundingMode: NumberFormatCompactRoundingMode;\n\tsuffixSeparator: string;\n\tmaxDecimals?: number;\n\tunits: readonly NumberFormatCompactUnit[];\n};\n\nconst DEFAULT_COMPACT_NUMBER_UNITS: readonly NumberFormatCompactUnit[] = [\n\t{ value: 1_000_000_000_000, suffix: \"трлн\" },\n\t{ value: 1_000_000_000, suffix: \"млрд\" },\n\t{ value: 1_000_000, suffix: \"млн\" },\n\t{ value: 1_000, suffix: \"тыс\" }\n];\n\nconst DEFAULT_COMPACT_NUMBER_OPTIONS = {\n\tminCompactValue: 1_000,\n\troundingMode: \"trunc\",\n\tsuffixSeparator: \" \"\n} satisfies Required<Pick<NumberFormatCompactOptions, \"minCompactValue\" | \"roundingMode\" | \"suffixSeparator\">>;\n\nconst DEFAULT_COMPACT_DECIMAL_SEPARATOR = \",\";\n\nfunction applyCompactRounding(value: number, mode: NumberFormatCompactRoundingMode): number {\n\tswitch (mode) {\n\t\tcase \"round\":\n\t\t\treturn Math.round(value);\n\n\t\tcase \"floor\":\n\t\t\treturn Math.floor(value);\n\n\t\tcase \"ceil\":\n\t\t\treturn Math.ceil(value);\n\n\t\tcase \"trunc\":\n\t\t\treturn Math.trunc(value);\n\t}\n}\n\nfunction roundCompactValue(value: number, decimals: number, mode: NumberFormatCompactRoundingMode): number {\n\tif (decimals === 0) return applyCompactRounding(value, mode);\n\n\tconst factor = 10 ** decimals;\n\treturn applyCompactRounding(value * factor, mode) / factor;\n}\n\nfunction getAutoCompactDecimals(normalizedValue: number): number {\n\tif (normalizedValue >= 10) return 0;\n\n\treturn 1;\n}\n\nfunction getEffectiveDecimals(value: number, maxDecimals: number): number {\n\tif (maxDecimals === 0) return 0;\n\n\tconst fixed = value.toFixed(maxDecimals);\n\tconst decimalSeparatorIndex = fixed.indexOf(\".\");\n\n\tif (decimalSeparatorIndex === -1) return 0;\n\n\tconst fraction = fixed.slice(decimalSeparatorIndex + 1).replace(/0+$/, \"\");\n\n\treturn fraction.length;\n}\n\nfunction getCompactUnitIndex(value: number, units: readonly NumberFormatCompactUnit[]): number {\n\treturn units.findIndex((unit) => value >= unit.value);\n}\n\nfunction createPlainCompactPreset(preset: NumberFormatPreset, decimals: number): NumberFormatPreset {\n\treturn {\n\t\tname: preset.name,\n\t\tdecimals,\n\t\tdecimalSeparator: decimals > 0 ? preset.decimalSeparator || DEFAULT_COMPACT_DECIMAL_SEPARATOR : preset.decimalSeparator,\n\t\tgrouping: preset.grouping,\n\t\tgroupingSeparator: preset.groupingSeparator,\n\t\tgroupingSize: preset.groupingSize\n\t};\n}\n\nfunction formatCompactValueByUnit(\n\tabsValue: number,\n\tunitIndex: number,\n\toptions: ResolvedCompactNumberOptions,\n\tpreset: NumberFormatPreset,\n\tformatPlainNumber: PlainNumberFormatter\n): string {\n\tconst unit = options.units[unitIndex];\n\tif (!unit) return formatPlainNumber(absValue, preset);\n\n\tconst normalizedValue = absValue / unit.value;\n\tconst maxDecimals = options.maxDecimals ?? getAutoCompactDecimals(normalizedValue);\n\tconst roundedValue = roundCompactValue(normalizedValue, maxDecimals, options.roundingMode);\n\n\t// Защита от результата вида \"1000 тыс\": переходим на следующую единицу.\n\tif (roundedValue >= 1000 && unitIndex > 0) {\n\t\treturn formatCompactValueByUnit(absValue, unitIndex - 1, options, preset, formatPlainNumber);\n\t}\n\n\tconst decimals = getEffectiveDecimals(roundedValue, maxDecimals);\n\tconst compactPreset = createPlainCompactPreset(preset, decimals);\n\n\treturn `${formatPlainNumber(roundedValue, compactPreset)}${options.suffixSeparator}${unit.suffix}`;\n}\n\nexport function formatCompactNumberValue(args: {\n\tvalue: number;\n\tpreset: NumberFormatPreset;\n\toptions: NumberFormatCompactOptions;\n\tformatPlainNumber: PlainNumberFormatter;\n}): string {\n\tconst {\n\t\tminCompactValue = DEFAULT_COMPACT_NUMBER_OPTIONS.minCompactValue,\n\t\troundingMode = DEFAULT_COMPACT_NUMBER_OPTIONS.roundingMode,\n\t\tsuffixSeparator = DEFAULT_COMPACT_NUMBER_OPTIONS.suffixSeparator,\n\t\tmaxDecimals,\n\t\tunits = DEFAULT_COMPACT_NUMBER_UNITS\n\t} = args.options;\n\n\tconst absValue = Math.abs(args.value);\n\n\tif (absValue < minCompactValue) {\n\t\treturn args.formatPlainNumber(args.value, args.preset);\n\t}\n\n\tconst unitIndex = getCompactUnitIndex(absValue, units);\n\n\tif (unitIndex === -1) {\n\t\treturn args.formatPlainNumber(args.value, args.preset);\n\t}\n\n\tconst sign = args.value < 0 ? \"-\" : \"\";\n\n\treturn `${sign}${formatCompactValueByUnit(\n\t\tabsValue,\n\t\tunitIndex,\n\t\t{\n\t\t\troundingMode,\n\t\t\tsuffixSeparator,\n\t\t\tmaxDecimals,\n\t\t\tunits\n\t\t},\n\t\targs.preset,\n\t\targs.formatPlainNumber\n\t)}`;\n}\n","import { toFiniteNumber } from \"./parseNumber\";\n\n/**\n * Проверяет, что значение семантически эквивалентно нулю и может быть скрыто как пустое.\n */\nexport function isZeroValue(value: unknown): boolean {\n\tconst v = toFiniteNumber(value);\n\n\tif (typeof v === \"number\") {\n\t\treturn v === 0;\n\t}\n\n\tif (typeof v === \"bigint\") {\n\t\treturn v === 0n;\n\t}\n\n\treturn false;\n}\n","import { formatCompactNumberValue } from \"./compact\";\nimport { isZeroValue } from \"./isZeroValue\";\nimport { DEFAULT_NUMBER_PRESET_NAMES, NUMBER_FORMAT_DEFAULTS, resolveNumberPreset } from \"./presets\";\n\nimport type { NumberFormatPreset } from \"./types\";\n\n/** Кеш Intl.NumberFormat по ключу \"decimals:grouping\" */\nconst cache = new Map<string, Intl.NumberFormat>();\n\n/** Усечение дробной части без округления: 1234.789 → 1234.7 (при decimals=1) */\nexport function truncateNumber(num: number, decimals: number): number {\n\tif (decimals === 0) return Math.trunc(num);\n\tconst factor = 10 ** decimals;\n\treturn Math.trunc(num * factor) / factor;\n}\n\nfunction getFormatter(decimals: number, grouping: boolean): Intl.NumberFormat {\n\tconst key = `${decimals}:${grouping ? 1 : 0}`;\n\tlet fmt = cache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(\"ru-RU\", {\n\t\t\tminimumFractionDigits: decimals,\n\t\t\tmaximumFractionDigits: decimals,\n\t\t\tuseGrouping: grouping\n\t\t});\n\t\tcache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\n/** Разделители совпадают с ru-RU — можно использовать format() напрямую */\nfunction isStandard(p: NumberFormatPreset): boolean {\n\treturn (\n\t\tp.groupingSize === 3 &&\n\t\t(p.groupingSeparator === NUMBER_FORMAT_DEFAULTS.groupingSeparator || !p.grouping) &&\n\t\t(p.decimalSeparator === \",\" || p.decimals === 0)\n\t);\n}\n\n/**\n * Быстрый путь (99% вызовов): format() напрямую, без постобработки.\n * ru-RU уже даёт неразрывный пробел и запятую — именно то, что нужно.\n */\nfunction formatStandard(num: number, decimals: number, grouping: boolean): string {\n\treturn getFormatter(decimals, grouping).format(num);\n}\n\n/** Кастомные разделители: formatToParts() с подстановкой */\nfunction formatCustomSeparator(num: number, preset: NumberFormatPreset): string {\n\tconst parts = getFormatter(preset.decimals, preset.grouping).formatToParts(num);\n\tlet result = \"\";\n\tfor (const p of parts) {\n\t\tif (p.type === \"group\") result += preset.groupingSeparator;\n\t\telse if (p.type === \"decimal\") result += preset.decimalSeparator;\n\t\telse result += p.value;\n\t}\n\treturn result;\n}\n\n/** Нестандартный размер группы: Intl для округления, ручная группировка */\nfunction formatManualGroup(num: number, preset: NumberFormatPreset): string {\n\tconst raw = getFormatter(preset.decimals, false).format(num);\n\n\t// ru-RU без группировки: \"1234567,89\" — запятая как десятичный разделитель\n\tconst sep = raw.indexOf(\",\");\n\tconst intPart = sep === -1 ? raw : raw.slice(0, sep);\n\tconst fracPart = sep === -1 ? null : raw.slice(sep + 1);\n\n\tconst neg = intPart.startsWith(\"-\");\n\tconst abs = neg ? intPart.slice(1) : intPart;\n\n\tconst size = preset.groupingSize;\n\tconst groups: string[] = [];\n\tfor (let i = abs.length; i > 0; i -= size) {\n\t\tgroups.unshift(abs.slice(Math.max(0, i - size), i));\n\t}\n\n\tlet result = (neg ? \"-\" : \"\") + groups.join(preset.groupingSeparator);\n\tif (fracPart !== null) result += preset.decimalSeparator + fracPart;\n\treturn result;\n}\n\nfunction formatPlainNumber(num: number, preset: NumberFormatPreset): string {\n\t// 99% — стандартный ru-RU формат, format() без постобработки\n\tif (isStandard(preset)) return formatStandard(num, preset.decimals, preset.grouping);\n\n\t// Стандартный размер группы (3), но кастомные разделители\n\tif (preset.groupingSize === 3 || !preset.grouping) return formatCustomSeparator(num, preset);\n\n\t// Нестандартный размер группы\n\treturn formatManualGroup(num, preset);\n}\n\n/**\n * Форматирование числа по предустановке.\n * Оптимизировано для 500+ вызовов: кеш Intl.NumberFormat + быстрый путь через format().\n *\n * Не использовать напрямую! Использовать `formatNumberAs*`\n */\nexport function formatNumber(value: unknown, presetOrName: string | NumberFormatPreset): string {\n\tif (typeof value === \"string\" && value.trim() === \"\") return \"0\";\n\n\tconst num = Number(value);\n\tif (!Number.isFinite(num)) return \"0\";\n\n\tconst preset = resolveNumberPreset(presetOrName);\n\n\t// Усечение без округления — Intl занимается только группировкой и разделителями\n\t// const truncated = truncateNumber(num, preset.decimals);\n\t// NOTE: 30.04.2026 выяснилось, что всё таки должно быть именно округление, а не усечение\n\n\tif (preset.compact) {\n\t\treturn formatCompactNumberValue({\n\t\t\tvalue: num,\n\t\t\tpreset,\n\t\t\toptions: preset.compact,\n\t\t\tformatPlainNumber\n\t\t});\n\t}\n\n\treturn formatPlainNumber(num, preset);\n}\n\n/**\n * Форматирование значения пресетом `integer` (0 знаков после запятой)\n */\nexport function formatNumberAsInteger(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.integer);\n}\n\n/**\n * Форматирование значения пресетом `currency` (0 знаков после запятой)\n */\nexport function formatNumberAsCurrency(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.currency);\n}\n\n/**\n * Форматирование значения пресетом `decimal` (1 знак после запятой)\n */\nexport function formatNumberAsDecimal(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal);\n}\n\n/**\n * Форматирование значения пресетом `decimal-2` (2 знака после запятой)\n */\nexport function formatNumberAsDecimal2(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal2);\n}\n\n/**\n * Форматирование значения пресетом `decimal-3` (3 знака после запятой)\n */\nexport function formatNumberAsDecimal3(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal3);\n}\n\n/**\n * Форматирование значения пресетом `percent` (2 знака после запятой)\n */\nexport function formatNumberAsPercent(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.percent);\n}\n\n/**\n * Форматирование значения пресетом `price` (0 знаков после запятой)\n */\nexport function formatNumberAsPrice(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.price);\n}\n\n/**\n * Форматирование значения пресетом `tonnage` (1 знак после запятой)\n */\nexport function formatNumberAsTonnage(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.tonnage);\n}\n\n/**\n * Форматирование значения пресетом `integer` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsIntegerOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.integer);\n}\n\n/**\n * Форматирование значения пресетом `currency` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsCurrencyOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.currency);\n}\n\n/**\n * Форматирование значения пресетом `decimal` (1 знак после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimalOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal);\n}\n\n/**\n * Форматирование значения пресетом `decimal-2` (2 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimal2OrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal2);\n}\n\n/**\n * Форматирование значения пресетом `decimal-3` (3 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimal3OrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal3);\n}\n\n/**\n * Форматирование значения пресетом `percent` (2 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsPercentOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.percent);\n}\n\n/**\n * Форматирование значения пресетом `price` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsPriceOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.price);\n}\n\n/**\n * Форматирование значения пресетом `tonnage` (1 знак после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsTonnageOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.tonnage);\n}\n\n/** Очистить кеш Intl.NumberFormat */\nexport function clearFormatCache(): void {\n\tcache.clear();\n}\n","import { toFiniteNumber } from \"./number\";\nimport { stripInnerSpaces } from \"./strings\";\n\n/**\n * Нормализует ведущие нули у числового значения.\n *\n * Правило fixed:\n * - fixed === 0 / undefined / NaN / не finite -> ничего не делает, возвращает исходное значение\n * - fixed < 0 -> удаляет ведущие нули (только в целой части)\n * - fixed > 0 -> дополняет целую часть ведущими нулями до длины fixed\n *\n * Если value не является числом и не парсится в число — возвращается как есть.\n * Возвращаемый тип: если вход number -> number, если вход string -> string, иначе unknown.\n */\nexport function normalizeLeadingZeros(value: unknown, fixed?: number): unknown {\n\tconst n = typeof value === \"number\" ? value : Number(value);\n\tif (!Number.isFinite(n)) return value;\n\n\t// Работаем со строкой числа, но pad применяем только к целой части\n\tconst raw = String(n); // \"-12.3\" | \"12\" | \"0.5\"\n\n\tif (typeof fixed === \"number\" && fixed > 0) {\n\t\tlet i = 0;\n\t\tlet sign = \"\";\n\n\t\tconst c0 = raw.charCodeAt(0);\n\t\tif (c0 === 45 /*-*/ || c0 === 43 /*+*/) {\n\t\t\tsign = raw[0];\n\t\t\ti = 1;\n\t\t}\n\n\t\t// отделяем дробь\n\t\tconst dot = raw.indexOf(\".\", i);\n\t\tconst intEnd = dot === -1 ? raw.length : dot;\n\n\t\tlet intPart = raw.slice(i, intEnd);\n\t\tconst fracPart = dot === -1 ? \"\" : raw.slice(dot); // включая '.'\n\n\t\t// \".5\" -> \"0.5\" не бывает у String(number), но на всякий случай:\n\t\tif (!intPart) intPart = \"0\";\n\n\t\tconst len = intPart.length;\n\t\tif (len < fixed) {\n\t\t\tintPart = \"0\".repeat(fixed - len) + intPart;\n\t\t}\n\n\t\treturn sign + intPart + fracPart;\n\t}\n\n\treturn raw;\n}\n\n/**\n * Нормализует ведущие нули у числового значения.\n *\n * Использовать только если значения могут иметь нестандартное форматирование, например разделители групп и тд.\n *\n * Правило fixed:\n * - fixed === 0 / undefined / NaN / не finite -> ничего не делает, возвращает исходное значение\n * - fixed < 0 -> удаляет ведущие нули (только в целой части)\n * - fixed > 0 -> дополняет целую часть ведущими нулями до длины fixed\n *\n * Если value не является числом и не парсится в число — возвращается как есть.\n * Возвращаемый тип: если вход number -> number, если вход string -> string, иначе unknown.\n */\nexport function normalizeLeadingZerosStrict<T>(value: T, fixed?: number): T {\n\t// fixed не задан / 0 / не число / бесконечность => no-op\n\tif (!fixed || !Number.isFinite(fixed)) return value;\n\n\t// Быстрый путь для number\n\tif (typeof value === \"number\") {\n\t\tif (!Number.isFinite(value)) return value;\n\n\t\t// Для number делаем преобразование через строку.\n\t\t// Важно: у number ведущих нулей в обычном представлении нет,\n\t\t// поэтому fixed < 0 по факту ничего не меняет.\n\t\tconst out = normalizeStringNumber(String(value), fixed);\n\t\t// Пытаемся вернуть number обратно, чтобы не ломать типы/ожидания.\n\t\tconst n = Number(out);\n\t\treturn Number.isFinite(n) ? (n as unknown as T) : value;\n\t}\n\n\t// Основной путь для строк\n\tif (typeof value === \"string\") {\n\t\t// Быстрая проверка «похоже ли на число»: если вообще нет цифр — не парсим.\n\t\t// (Чуть ускоряет кейсы с произвольными строками).\n\t\tlet hasDigit = false;\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\tconst c = value.charCodeAt(i);\n\t\t\tif (c >= 48 && c <= 57) {\n\t\t\t\thasDigit = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!hasDigit) return value;\n\n\t\t// Проверка, что строка реально парсится в число.\n\t\t// Поддержка \"SAP-like\": пробелы и NBSP как группировка, ',' как десятичный.\n\t\tconst parsed = toFiniteNumber(value);\n\t\tif (parsed === undefined) return value;\n\n\t\tconst out = normalizeStringNumber(value, fixed);\n\t\treturn out as unknown as T;\n\t}\n\n\t// Для остальных типов — не трогаем\n\treturn value;\n}\n\n/**\n * Нормализация для строкового представления числа.\n * Работает только с целой частью (до '.' или ',').\n */\nfunction normalizeStringNumber(input: string, fixed: number): string {\n\tconst s = input.trim();\n\tif (!s) return input;\n\n\t// Знак\n\tlet i = 0;\n\tlet sign = \"\";\n\tconst first = s.charCodeAt(0);\n\tif (first === 45 /* - */ || first === 43 /* + */) {\n\t\tsign = s[0];\n\t\ti = 1;\n\t}\n\n\t// Найдём позицию десятичного разделителя ('.' или ',') — берём первый найденный.\n\t// Нули нормализуем только в целой части.\n\tlet dot = -1;\n\tfor (let k = i; k < s.length; k++) {\n\t\tconst ch = s.charCodeAt(k);\n\t\tif (ch === 46 /* . */ || ch === 44 /* , */) {\n\t\t\tdot = k;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst intEnd = dot === -1 ? s.length : dot;\n\tconst frac = dot === -1 ? \"\" : s.slice(dot); // включая разделитель и дробную часть\n\n\t// Выделим целую часть (без знака)\n\tlet intPart = s.slice(i, intEnd);\n\n\t// Уберём пробелы/неразрывные пробелы внутри (SAP-like grouping), чтобы не мешали.\n\t// Делается без regex, чтобы быть дешевле при массовых вызовах.\n\tintPart = stripInnerSpaces(intPart);\n\n\t// Если целая часть пустая (\".5\") — считаем как \"0\"\n\tif (intPart.length === 0) intPart = \"0\";\n\n\tconst target = fixed | 0; // быстрый int\n\tif (target <= 0) {\n\t\t// Trim leading zeros\n\t\tlet p = 0;\n\t\twhile (p < intPart.length && intPart.charCodeAt(p) === 48 /* '0' */) p++;\n\n\t\t// Если всё было нулями — оставляем один ноль\n\t\tintPart = p === intPart.length ? \"0\" : intPart.slice(p);\n\t} else {\n\t\tif (target > 0) {\n\t\t\tconst len = intPart.length;\n\t\t\tif (len < target) {\n\t\t\t\t// Быстрое дополняние без padStart (чуть меньше накладных расходов)\n\t\t\t\tintPart = \"0\".repeat(target - len) + intPart;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sign + intPart + frac;\n}\n","import type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineGraph,\n\tFormattersPipelineNode,\n\tFormattersPipelineNormalizeLeadingZerosConfig,\n\tFormattersPipelinePlan,\n\tFormattersPipelineResolveValueStateConfig,\n\tFormattersPipelineRowBasedOverrideConfig,\n\tFormattersPipelineStep,\n\tFormattersPipelineTypedValueFormatConfig\n} from \"./types\";\n\nexport function cloneTypedValueFormatConfig(\n\tconfig: FormattersPipelineTypedValueFormatConfig | undefined\n): FormattersPipelineTypedValueFormatConfig | undefined {\n\treturn config ? { ...config } : undefined;\n}\n\nexport function cloneNormalizeLeadingZerosConfig(\n\tconfig: FormattersPipelineNormalizeLeadingZerosConfig | undefined\n): FormattersPipelineNormalizeLeadingZerosConfig | undefined {\n\treturn config ? { ...config } : undefined;\n}\n\nexport function cloneRowBasedOverrideConfig(config: FormattersPipelineRowBasedOverrideConfig): FormattersPipelineRowBasedOverrideConfig {\n\treturn config.mode === \"formula\"\n\t\t? { ...config, dependencyIds: config.dependencyIds ? [...config.dependencyIds] : undefined }\n\t\t: { ...config };\n}\n\nexport function cloneResolveValueStateConfig(config: FormattersPipelineResolveValueStateConfig): FormattersPipelineResolveValueStateConfig {\n\treturn {\n\t\tresolver:\n\t\t\tconfig.resolver.kind === \"fixed\"\n\t\t\t\t? {\n\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\tentries: { ...config.resolver.entries },\n\t\t\t\t\t\tfallbackState: config.resolver.fallbackState\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\tthresholds: config.resolver.thresholds.map((item) => (typeof item === \"number\" ? item : { ...item })),\n\t\t\t\t\t\tstates: [...config.resolver.states],\n\t\t\t\t\t\tinvalidState: config.resolver.invalidState\n\t\t\t\t\t},\n\t\ticon: config.icon ? { ...config.icon } : undefined\n\t};\n}\n\nexport function cloneFormatterPipelinePlanStep(step: FormattersPipelineStep): FormattersPipelineStep {\n\tswitch (step.type) {\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneTypedValueFormatConfig(step.config)\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneNormalizeLeadingZerosConfig(step.config)\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneRowBasedOverrideConfig(step.config)\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneResolveValueStateConfig(step.config)\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst checker: never = step;\n\t\t\tvoid checker;\n\t\t}\n\t}\n\n\tthrow new Error(`Недопустимый тип '${(step as Record<string, unknown>)?.type}' для шага FormatterPipeline`);\n}\n\nexport function cloneFormatterPipelinePlanStepToNode(\n\tstep: FormattersPipelineStep,\n\tposition: { x: number; y: number }\n): FormattersPipelineNode {\n\tswitch (step.type) {\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneTypedValueFormatConfig(step.config)\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneNormalizeLeadingZerosConfig(step.config)\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneRowBasedOverrideConfig(step.config)\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneResolveValueStateConfig(step.config)\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst checker: never = step;\n\t\t\tvoid checker;\n\t\t}\n\t}\n\n\tthrow new Error(`Недопустимый тип '${(step as Record<string, unknown>)?.type}' для шага FormatterPipeline`);\n}\n\nfunction cloneNode(node: FormattersPipelineNode): FormattersPipelineNode {\n\tswitch (node.type) {\n\t\tcase \"source\":\n\t\tcase \"sink\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tposition: { ...node.position }\n\t\t\t};\n\t\tdefault:\n\t\t\treturn cloneFormatterPipelinePlanStepToNode(node, node.position);\n\t}\n}\n\nfunction cloneGraph(graph: FormattersPipelineGraph): FormattersPipelineGraph {\n\treturn {\n\t\tnodes: graph.nodes.map(cloneNode),\n\t\tedges: graph.edges.map((edge) => ({ ...edge })),\n\t\tviewport: graph.viewport ? { ...graph.viewport } : undefined\n\t};\n}\n\nfunction clonePlan(plan: FormattersPipelinePlan): FormattersPipelinePlan {\n\treturn {\n\t\tsteps: plan.steps.map(cloneFormatterPipelinePlanStep)\n\t};\n}\n\n/**\n * Возвращает полную копию конфигурации pipeline для безопасного хранения в сторе.\n */\nexport function cloneFormattersPipelineConfig(config: FormattersPipelineConfig | undefined): FormattersPipelineConfig | undefined {\n\tif (!config) return undefined;\n\n\tconst version = config.version;\n\tconst graph = config.graph ? cloneGraph(config.graph) : undefined;\n\tconst plan = config.plan ? clonePlan(config.plan) : undefined;\n\n\treturn { version, graph, plan };\n}\n","import { addUnique } from \"../../array\";\n\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nimport type { FormattersPipelineConfig } from \"./types\";\n\n/**\n * Минимальный контракт поля, достаточный для сбора runtime-зависимостей.\n *\n * Контракт не привязан к view-config, analytical-table или detail-table:\n * любая зона может передать свой объект, если он содержит эти optional-поля.\n */\nexport type RuntimeDependencyField = {\n\tformattersPipeline?: FormattersPipelineConfig;\n\tcellRenderer?: {\n\t\tbindings?: Readonly<Record<string, string | undefined>>;\n\t};\n};\n\n/**\n * План дополнительных полей, которые нужны runtime-логике отображения.\n */\nexport type RuntimeFieldDependenciesPlan = {\n\t/** Поля, которые нужно добавить в query для formatter pipeline или renderer bindings. */\n\trequiredColumnIds: string[];\n\t/** Зависимости, указанные в настройках, но отсутствующие в справочнике полей. */\n\tmissingColumnIds: string[];\n};\n\n/**\n * Собирает только зависимости, объявленные внутри formatter pipeline.\n *\n * Pipeline не проверяет наличие этих полей в конкретной таблице или графике:\n * это ответственность потребителя, который знает свой полный набор полей.\n */\nexport function collectFormattersPipelineDependencyIds(config: FormattersPipelineConfig | undefined): string[] {\n\tconst validation = validateFormattersPipelineConfig(config);\n\tif (!validation.ok || !validation.plan) return [];\n\n\tconst dependencyIds: string[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const step of validation.plan.steps) {\n\t\tif (step.type !== \"rowBasedOverride\") continue;\n\n\t\tif (step.config.mode === \"field\") {\n\t\t\taddUnique(dependencyIds, seen, step.config.fieldKey);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const dependencyId of step.config.dependencyIds ?? []) {\n\t\t\taddUnique(dependencyIds, seen, dependencyId);\n\t\t}\n\t}\n\n\treturn dependencyIds;\n}\n\n/**\n * Собирает runtime-зависимости отображения для набора полей.\n *\n * Учитывает:\n * - binding-поля renderer-а;\n * - field/dependency поля formatter-а `rowBasedOverride`.\n */\nexport function collectRuntimeFieldDependencyIds<TField extends RuntimeDependencyField>(\n\tfieldIds: readonly string[],\n\tfieldsById: Readonly<Record<string, TField | undefined>>\n): RuntimeFieldDependenciesPlan {\n\tconst requiredColumnIds: string[] = [];\n\tconst missingColumnIds: string[] = [];\n\tconst seenRequired = new Set<string>();\n\tconst seenMissing = new Set<string>();\n\n\tconst addDependency = (fieldId: string | undefined) => {\n\t\tconst normalizedId = fieldId?.trim();\n\t\tif (!normalizedId) return;\n\n\t\tif (!fieldsById[normalizedId]) {\n\t\t\taddUnique(missingColumnIds, seenMissing, normalizedId);\n\t\t\treturn;\n\t\t}\n\n\t\taddUnique(requiredColumnIds, seenRequired, normalizedId);\n\t};\n\n\tfor (const fieldId of fieldIds) {\n\t\tconst field = fieldsById[fieldId];\n\t\tif (!field) continue;\n\n\t\tfor (const bindingFieldId of Object.values(field.cellRenderer?.bindings ?? {})) {\n\t\t\taddDependency(bindingFieldId);\n\t\t}\n\n\t\tfor (const dependencyId of collectFormattersPipelineDependencyIds(field.formattersPipeline)) {\n\t\t\taddDependency(dependencyId);\n\t\t}\n\t}\n\n\treturn { requiredColumnIds, missingColumnIds };\n}\n","import { State } from \"../../types\";\n\nimport { ValueStateResolver } from \"./types\";\n\n/** Реестр: id → скомпилированная функция-резолвер */\nconst resolverRegistry = new Map<string, ValueStateResolver>();\n\n/** Обратный индекс: каноническая строка конфигурации → id (дедупликация) */\nconst configToIdIndex = new Map<string, string>();\n\n/**\n * Вычислить короткий хеш из строки (djb2 → base36).\n * Результат — строка вида `\"id_1a2b3c4\"`.\n */\nexport function computeShortHash(input: string): string {\n\tlet hash = 5381;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash = ((hash << 5) + hash + input.charCodeAt(i)) >>> 0;\n\t}\n\treturn \"id_\" + hash.toString(36);\n}\n\n/**\n * Зарегистрировать резолвер в общем реестре.\n * Если конфигурация с таким каноническим ключом уже есть — вернуть существующий id.\n * Возвращает `{ id, isNew }`.\n */\nexport function registerResolver(canonicalKey: string, compileFunction: () => ValueStateResolver): { id: string; isNew: boolean } {\n\tconst existingId = configToIdIndex.get(canonicalKey);\n\tif (existingId) return { id: existingId, isNew: false };\n\n\tconst id = computeShortHash(canonicalKey);\n\tconst resolver = compileFunction();\n\n\tresolverRegistry.set(id, resolver);\n\tconfigToIdIndex.set(canonicalKey, id);\n\n\treturn { id, isNew: true };\n}\n\n/**\n * Найти существующий резолвер по каноническому ключу.\n * Возвращает `undefined`, если не найден.\n */\nexport function findResolverByCanonicalKey(canonicalKey: string): ValueStateResolver | undefined {\n\tconst id = configToIdIndex.get(canonicalKey);\n\tif (!id) return undefined;\n\treturn resolverRegistry.get(id);\n}\n\n/**\n * Применить зарегистрированный резолвер к значению.\n * Если резолвер с указанным `id` не найден — возвращает `\"none\"`.\n *\n * @example\n * ```ts\n * resolveValueState(\"v_1a2b3c4\", 75); // → \"success\"\n * ```\n */\nexport function resolveValueState(id: string, value: unknown): State {\n\tconst resolver = resolverRegistry.get(id);\n\tif (!resolver) return \"none\";\n\treturn resolver(value);\n}\n\n/**\n * Получить функцию-резолвер по `id`.\n * Возвращает `undefined`, если резолвер не зарегистрирован.\n */\nexport function getValueStateResolver(id: string): ValueStateResolver | undefined {\n\treturn resolverRegistry.get(id);\n}\n\n/**\n * Получить список всех зарегистрированных id.\n */\nexport function getValueStateResolverIds(): string[] {\n\treturn Array.from(resolverRegistry.keys());\n}\n\n/**\n * Полная очистка реестра. Предназначена для тестов.\n */\nexport function resetValueStateResolvers(): void {\n\tresolverRegistry.clear();\n\tconfigToIdIndex.clear();\n}\n","import { compareStrings } from \"../../string-comparison\";\nimport { State } from \"../../types\";\n\nimport { FixedValueStateResolverConfig, ValueStateResolver } from \"./types\";\nimport { findResolverByCanonicalKey, registerResolver } from \"./valueStateRegistry\";\n\n/** Создать каноническую строку конфигурации (с префиксом типа для изоляции от пороговых резолверов) */\nfunction createCanonicalKey(sortedEntries: [string, State][], fallbackState: State): string {\n\tconst entriesPart = sortedEntries.map(([key, state]) => `${key}:${state}`).join(\",\");\n\treturn `fixed|${entriesPart}|${fallbackState}`;\n}\n\n/** Скомпилировать функцию-резолвер из маппинга */\nfunction compileFixedResolver(entries: Record<string, State>, fallbackState: State): ValueStateResolver {\n\tconst lookup = new Map<string, State>(Object.entries(entries));\n\n\treturn (value: unknown): State => {\n\t\tif (value === null || value === undefined) return fallbackState;\n\n\t\tconst key = String(value);\n\t\treturn lookup.get(key) ?? fallbackState;\n\t};\n}\n\n/** Нормализовать конфигурацию и вернуть подготовленные данные */\nfunction prepareConfig(config: FixedValueStateResolverConfig) {\n\tconst fallbackState: State = config.fallbackState ?? \"none\";\n\n\t// Сортировка ключей для детерминированного канонического ключа\n\tconst sortedEntries = Object.entries(config.entries).sort(([a], [b]) => compareStrings(a, b)) as [string, State][];\n\n\tconst canonicalKey = createCanonicalKey(sortedEntries, fallbackState);\n\n\treturn { entries: config.entries, fallbackState, canonicalKey };\n}\n\n/**\n * Зарегистрировать фиксированный резолвер из конфигурации.\n * Возвращает короткий уникальный `id`.\n *\n * Фиксированный резолвер определяет State по точному совпадению значения ячейки\n * со значениями из маппинга `entries`.\n *\n * @example\n * ```ts\n * const id = registerFixedResolver({\n * entries: {\n * \"01\": \"success\",\n * \"02\": \"warning\",\n * \"03\": \"error\",\n * },\n * fallbackState: \"none\",\n * });\n *\n * // В ячейке: resolveValueState(id, cellValue)\n * ```\n */\nexport function registerFixedResolver(config: FixedValueStateResolverConfig): string {\n\tconst { entries, fallbackState, canonicalKey } = prepareConfig(config);\n\n\tconst { id } = registerResolver(canonicalKey, () => compileFixedResolver(entries, fallbackState));\n\n\treturn id;\n}\n\n/**\n * Создать фиксированный резолвер напрямую.\n * Резолвер регистрируется в общем реестре.\n * Идентичные конфигурации возвращают одну и ту же функцию.\n *\n * @example\n * ```ts\n * const resolve = createFixedResolver({\n * entries: { \"01\": \"success\", \"02\": \"warning\", \"03\": \"error\" },\n * });\n *\n * resolve(\"01\"); // → \"success\"\n * resolve(\"02\"); // → \"warning\"\n * resolve(\"99\"); // → \"none\" (fallback)\n * ```\n */\nexport function createFixedResolver(config: FixedValueStateResolverConfig): ValueStateResolver {\n\tconst { entries, fallbackState, canonicalKey } = prepareConfig(config);\n\n\tconst existing = findResolverByCanonicalKey(canonicalKey);\n\tif (existing) return existing;\n\n\tregisterResolver(canonicalKey, () => compileFixedResolver(entries, fallbackState));\n\n\treturn findResolverByCanonicalKey(canonicalKey)!;\n}\n","import { State } from \"../../types\";\n\nimport { ThresholdBoundary, ThresholdDefinition, ThresholdValueStateResolverConfig, ValueStateResolver } from \"./types\";\nimport { findResolverByCanonicalKey, registerResolver } from \"./valueStateRegistry\";\n\n/**\n * Нормализованный порог (внутренний тип)\n */\ninterface NormalizedThreshold {\n\tvalue: number;\n\tboundary: ThresholdBoundary;\n}\n\n/** Нормализовать порог: число → объект с boundary по умолчанию */\nfunction normalizeThreshold(threshold: number | ThresholdDefinition): NormalizedThreshold {\n\tif (typeof threshold === \"number\") {\n\t\treturn { value: threshold, boundary: \"upper\" };\n\t}\n\treturn { value: threshold.value, boundary: threshold.boundary ?? \"upper\" };\n}\n\n/** Создать каноническую строку конфигурации (с префиксом типа для изоляции от других резолверов) */\nfunction createCanonicalKey(sortedThresholds: NormalizedThreshold[], states: State[], invalidState: State): string {\n\tconst thresholdsPart = sortedThresholds.map((t) => `${t.value}:${t.boundary}`).join(\",\");\n\treturn `threshold|${thresholdsPart}|${states.join(\",\")}|${invalidState}`;\n}\n\n/** Валидация конфигурации */\nfunction validateConfig(thresholds: NormalizedThreshold[], states: State[]): void {\n\tif (states.length !== thresholds.length + 1) {\n\t\tthrow new Error(`Количество состояний (${states.length}) должно быть равно количеству порогов + 1 (${thresholds.length + 1})`);\n\t}\n\n\tconst seen = new Set<number>();\n\tfor (const threshold of thresholds) {\n\t\tif (seen.has(threshold.value)) {\n\t\t\tconsole.warn(`Дублирующееся пороговое значение: ${threshold.value}`);\n\t\t}\n\t\tseen.add(threshold.value);\n\t}\n}\n\n/** Скомпилировать функцию-резолвер из нормализованных данных */\nfunction compileThresholdResolver(sortedThresholds: NormalizedThreshold[], configStates: State[], invalidState: State): ValueStateResolver {\n\tconst thresholdValues = sortedThresholds.map((t) => t.value);\n\tconst thresholdIsLower = sortedThresholds.map((t) => t.boundary === \"lower\");\n\tconst states = [...configStates];\n\n\treturn (value: unknown): State => {\n\t\tif (value === \"\" || value === null || value === undefined) return invalidState;\n\n\t\tconst numericValue = +(value as number);\n\n\t\tif (!Number.isFinite(numericValue)) return invalidState;\n\n\t\tfor (let i = 0; i < thresholdValues.length; i++) {\n\t\t\tconst belongsToLowerSegment = thresholdIsLower[i] ? numericValue <= thresholdValues[i] : numericValue < thresholdValues[i];\n\n\t\t\tif (belongsToLowerSegment) return states[i];\n\t\t}\n\n\t\treturn states[states.length - 1];\n\t};\n}\n\n/** Нормализовать конфигурацию и вернуть подготовленные данные */\nfunction prepareConfig(config: ThresholdValueStateResolverConfig) {\n\tconst invalidState: State = config.invalidState ?? \"none\";\n\tconst sortedThresholds = config.thresholds.map(normalizeThreshold).sort((a, b) => a.value - b.value);\n\n\tvalidateConfig(sortedThresholds, config.states);\n\n\tconst canonicalKey = createCanonicalKey(sortedThresholds, config.states, invalidState);\n\n\treturn { sortedThresholds, invalidState, canonicalKey, states: config.states };\n}\n\n/**\n * Зарегистрировать пороговый резолвер из конфигурации.\n * Возвращает короткий уникальный `id` для использования в столбцах таблицы.\n *\n * Идентичные конфигурации (даже с разным порядком порогов)\n * возвращают один и тот же `id` — функция дедуплицирует по содержимому.\n *\n * @example\n * ```ts\n * const id = registerThresholdResolver({\n * thresholds: [60, 95],\n * states: [\"warning\", \"success\", \"error\"],\n * });\n * // id → \"v_1a2b3c4\"\n *\n * // В ячейке: resolveValueState(id, cellValue)\n * ```\n */\nexport function registerThresholdResolver(config: ThresholdValueStateResolverConfig): string {\n\tconst { sortedThresholds, invalidState, canonicalKey, states } = prepareConfig(config);\n\n\tconst { id } = registerResolver(canonicalKey, () => compileThresholdResolver(sortedThresholds, states, invalidState));\n\n\treturn id;\n}\n\n/**\n * Создать функцию-резолвер напрямую.\n * Резолвер регистрируется в общем реестре.\n * Идентичные конфигурации возвращают одну и ту же функцию.\n *\n * @example\n * ```ts\n * const resolve = createThresholdResolver({\n * thresholds: [60, 95],\n * states: [\"warning\", \"success\", \"error\"],\n * });\n *\n * resolve(45); // → \"warning\"\n * resolve(75); // → \"success\"\n * resolve(100); // → \"error\"\n * resolve(\"abc\"); // → \"none\"\n * ```\n */\nexport function createThresholdResolver(config: ThresholdValueStateResolverConfig): ValueStateResolver {\n\tconst { sortedThresholds, invalidState, canonicalKey, states } = prepareConfig(config);\n\n\tconst existing = findResolverByCanonicalKey(canonicalKey);\n\tif (existing) return existing;\n\n\tregisterResolver(canonicalKey, () => compileThresholdResolver(sortedThresholds, states, invalidState));\n\n\treturn findResolverByCanonicalKey(canonicalKey)!;\n}\n","import { getBaseTypeFromODataType } from \"../../odata-service\";\nimport { isSafe } from \"../../validators\";\nimport { formatDate, getDatePreset, parseDate } from \"../date\";\nimport { normalizeLeadingZeros } from \"../normalizeLeadingZeros\";\nimport { formatNumber, getNumberPreset } from \"../number\";\nimport { createRowBasedFormatterContext, getRowBasedFormatterById } from \"../rowBased\";\nimport { toSafeString } from \"../strings\";\nimport { registerFixedResolver } from \"../valueState/fixedValueStateResolver\";\nimport { registerThresholdResolver } from \"../valueState/thresholdValueStateResolver\";\nimport { resolveValueState } from \"../valueState/valueStateRegistry\";\n\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nimport type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineExecutionContext,\n\tFormattersPipelineExecutionResult,\n\tFormattersPipelineExecutor,\n\tFormattersPipelineTypedValueContext,\n\tFormattersPipelineTypedValueFormatConfig,\n\tFormattersPipelineValueIcon\n} from \"./types\";\n\ntype CompileFormattersPipelineExecutorResult =\n\t| {\n\t\t\tok: true;\n\t\t\texecutor: FormattersPipelineExecutor;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\treason: \"pipeline_invalid\" | \"row_based_formula_not_found\";\n\t };\n\nconst DEFAULT_TYPED_VALUE_FORMAT_PRESETS = Object.freeze({\n\tnumber: \"decimal\",\n\tdate: \"date\"\n});\n\n/**\n * Выполняет типизированное форматирование по метаданным колонки.\n */\nexport function formatTypedCellValue(\n\tvalue: unknown,\n\tcolumn: FormattersPipelineTypedValueContext,\n\tconfig?: FormattersPipelineTypedValueFormatConfig\n): string {\n\tif (!isSafe(value)) return \"\";\n\n\tconst baseType = getBaseTypeFromODataType(column.type);\n\n\tif (baseType === \"number\") {\n\t\tconst normalizedPresetName = config?.numberPresetName?.trim();\n\t\tconst presetName =\n\t\t\tnormalizedPresetName && getNumberPreset(normalizedPresetName)\n\t\t\t\t? normalizedPresetName\n\t\t\t\t: DEFAULT_TYPED_VALUE_FORMAT_PRESETS.number;\n\t\treturn formatNumber(value, presetName);\n\t}\n\n\tif (baseType === \"date\") {\n\t\tconst normalizedPresetName = config?.datePresetName?.trim();\n\t\tconst presetName =\n\t\t\tnormalizedPresetName && getDatePreset(normalizedPresetName) ? normalizedPresetName : DEFAULT_TYPED_VALUE_FORMAT_PRESETS.date;\n\t\treturn formatDate(parseDate(value), presetName);\n\t}\n\n\treturn toSafeString(value);\n}\n\nfunction resolveIconState(value: string): FormattersPipelineValueIcon | undefined {\n\tif (value === \"success\" || value === \"warning\" || value === \"error\" || value === \"information\") {\n\t\treturn value;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Определяет, должен ли `rowBasedOverride` применяться для текущего типа строки.\n *\n * Семантика:\n * - `group` — historical analytical group-row;\n * - `totals` — применяется только formula-режим;\n * - `plain`/`tree` — generic row-based override.\n */\nfunction shouldApplyRowBasedOverride(ctx: FormattersPipelineExecutionContext, mode: \"field\" | \"formula\"): boolean {\n\tswitch (ctx.rowKind) {\n\t\tcase \"group\":\n\t\tcase \"plain\":\n\t\tcase \"tree\":\n\t\t\treturn true;\n\t\tcase \"totals\":\n\t\t\treturn mode === \"formula\";\n\t}\n}\n\n/**\n * Компилирует pipeline форматтеров колонки в runtime executor.\n */\nexport function compileFormattersPipelineExecutor(args: {\n\tconfig: FormattersPipelineConfig | undefined;\n\tcolumn: FormattersPipelineTypedValueContext;\n}): CompileFormattersPipelineExecutorResult {\n\tconst validation = validateFormattersPipelineConfig(args.config);\n\tif (!validation.ok || !validation.plan) {\n\t\tif (validation.errors.some((error) => error.code === \"step_row_based_override_formula_not_found\")) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"row_based_formula_not_found\"\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"pipeline_invalid\"\n\t\t};\n\t}\n\n\tconst { steps } = validation.plan;\n\tconst hasRowBasedOverride = steps.some((step) => step.type === \"rowBasedOverride\");\n\tconst hasTypedValueFormat = steps.some((step) => step.type === \"typedValueFormat\");\n\n\tconst valueStateStep = steps.find((step) => step.type === \"resolveValueState\");\n\tconst valueStateResolverId =\n\t\tvalueStateStep?.config.resolver.kind === \"fixed\"\n\t\t\t? registerFixedResolver({\n\t\t\t\t\tentries: valueStateStep.config.resolver.entries,\n\t\t\t\t\tfallbackState: valueStateStep.config.resolver.fallbackState\n\t\t\t\t})\n\t\t\t: valueStateStep?.config.resolver.kind === \"threshold\"\n\t\t\t\t? registerThresholdResolver({\n\t\t\t\t\t\tthresholds: valueStateStep.config.resolver.thresholds,\n\t\t\t\t\t\tstates: valueStateStep.config.resolver.states,\n\t\t\t\t\t\tinvalidState: valueStateStep.config.resolver.invalidState\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\n\tconst rowBasedOverrideStep = steps.find((step) => step.type === \"rowBasedOverride\");\n\tconst rowBasedFormula =\n\t\trowBasedOverrideStep?.config.mode === \"formula\" ? getRowBasedFormatterById(rowBasedOverrideStep.config.formulaId) : undefined;\n\tif (rowBasedOverrideStep?.config.mode === \"formula\" && !rowBasedFormula) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"row_based_formula_not_found\"\n\t\t};\n\t}\n\n\treturn {\n\t\tok: true,\n\t\texecutor: {\n\t\t\thasRowBasedOverride,\n\t\t\thasTypedValueFormat,\n\t\t\texecute: (ctx: FormattersPipelineExecutionContext): FormattersPipelineExecutionResult => {\n\t\t\t\tlet nextValue = ctx.value;\n\t\t\t\tlet nextState: FormattersPipelineExecutionResult[\"state\"] = \"none\";\n\t\t\t\tlet showIcon = false;\n\t\t\t\tlet showValue = true;\n\t\t\t\tlet iconPosition: FormattersPipelineExecutionResult[\"iconPosition\"] = \"left\";\n\t\t\t\tlet icon: FormattersPipelineExecutionResult[\"icon\"] = undefined;\n\n\t\t\t\tfor (const step of steps) {\n\t\t\t\t\tswitch (step.type) {\n\t\t\t\t\t\tcase \"normalizeLeadingZeros\":\n\t\t\t\t\t\t\tnextValue = normalizeLeadingZeros(nextValue, step.config?.fixed);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"rowBasedOverride\":\n\t\t\t\t\t\t\tif (!shouldApplyRowBasedOverride(ctx, step.config.mode)) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (step.config.mode === \"field\") {\n\t\t\t\t\t\t\t\tconst fieldValue = ctx.rowData[step.config.fieldKey];\n\t\t\t\t\t\t\t\tif (fieldValue == null && step.config.fallbackToRaw !== false) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tnextValue = fieldValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!rowBasedFormula) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst formulaValue = rowBasedFormula.fn(\n\t\t\t\t\t\t\t\t\tcreateRowBasedFormatterContext({\n\t\t\t\t\t\t\t\t\t\trowData: ctx.rowData,\n\t\t\t\t\t\t\t\t\t\trawValue: nextValue,\n\t\t\t\t\t\t\t\t\t\tcolumnId: ctx.columnId,\n\t\t\t\t\t\t\t\t\t\tkeys: step.config.dependencyIds\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (formulaValue == null && step.config.fallbackToRaw !== false) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnextValue = formulaValue;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tif (step.config.fallbackToRaw === false) {\n\t\t\t\t\t\t\t\t\tnextValue = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"resolveValueState\":\n\t\t\t\t\t\t\tif (!valueStateResolverId) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnextState = resolveValueState(valueStateResolverId, nextValue);\n\t\t\t\t\t\t\tshowIcon = step.config.icon?.enabled ?? false;\n\t\t\t\t\t\t\tshowValue = step.config.icon?.showValue ?? true;\n\t\t\t\t\t\t\ticonPosition = step.config.icon?.position ?? \"left\";\n\t\t\t\t\t\t\ticon = showIcon ? resolveIconState(nextState) : undefined;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"typedValueFormat\":\n\t\t\t\t\t\t\tnextValue = formatTypedCellValue(nextValue, args.column, step.config);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tvalue: nextValue,\n\t\t\t\t\tstate: nextState,\n\t\t\t\t\ticon,\n\t\t\t\t\tshowIcon,\n\t\t\t\t\tshowValue,\n\t\t\t\t\ticonPosition,\n\t\t\t\t\thasTypedValueFormat\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n}\n","import { type State } from \"../../types\";\nimport { isRecord } from \"../../validators/isRecord\";\n\nimport { cloneFormattersPipelineConfig } from \"./clone\";\nimport {\n\ttype FormattersPipelineConfig,\n\ttype FormattersPipelineEdge,\n\ttype FormattersPipelineGraph,\n\ttype FormattersPipelineNode,\n\ttype FormattersPipelinePlan,\n\ttype FormattersPipelineResolveValueStateConfig,\n\ttype FormattersPipelineRowBasedOverrideConfig,\n\ttype FormattersPipelineStep,\n\ttype FormattersPipelineTypedValueFormatConfig\n} from \"./types\";\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nconst VALUE_STATES: readonly State[] = [\"\", \"none\", \"information\", \"success\", \"warning\", \"error\"];\n\nfunction isState(value: unknown): value is State {\n\treturn typeof value === \"string\" && VALUE_STATES.some((state) => state === value);\n}\n\nfunction isOptionalBoolean(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"boolean\";\n}\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nfunction isTypedValueFormatConfig(value: unknown): value is FormattersPipelineTypedValueFormatConfig {\n\tif (value === undefined) return true;\n\tif (!isRecord(value)) return false;\n\n\treturn isOptionalString(value.numberPresetName) && isOptionalString(value.datePresetName);\n}\n\nfunction isRowBasedOverrideConfig(value: unknown): value is FormattersPipelineRowBasedOverrideConfig {\n\tif (!isRecord(value)) return false;\n\n\tif (value.mode === \"field\") {\n\t\treturn typeof value.fieldKey === \"string\" && isOptionalBoolean(value.fallbackToRaw);\n\t}\n\n\tif (value.mode === \"formula\") {\n\t\treturn (\n\t\t\ttypeof value.formulaId === \"string\" &&\n\t\t\t(value.dependencyIds === undefined ||\n\t\t\t\t(Array.isArray(value.dependencyIds) && value.dependencyIds.every((dependencyId) => typeof dependencyId === \"string\"))) &&\n\t\t\tisOptionalBoolean(value.fallbackToRaw)\n\t\t);\n\t}\n\n\treturn false;\n}\n\nfunction isThresholdDefinition(value: unknown): boolean {\n\treturn (\n\t\ttypeof value === \"number\" ||\n\t\t(isRecord(value) &&\n\t\t\ttypeof value.value === \"number\" &&\n\t\t\t(value.boundary === undefined || value.boundary === \"lower\" || value.boundary === \"upper\"))\n\t);\n}\n\nfunction isResolveValueStateConfig(value: unknown): value is FormattersPipelineResolveValueStateConfig {\n\tif (!isRecord(value) || !isRecord(value.resolver)) return false;\n\n\tconst { resolver, icon } = value;\n\tconst hasValidIcon =\n\t\ticon === undefined ||\n\t\t(isRecord(icon) &&\n\t\t\tisOptionalBoolean(icon.enabled) &&\n\t\t\tisOptionalBoolean(icon.showValue) &&\n\t\t\t(icon.position === undefined || icon.position === \"left\" || icon.position === \"right\"));\n\n\tif (!hasValidIcon) return false;\n\n\tif (resolver.kind === \"fixed\") {\n\t\treturn (\n\t\t\tisRecord(resolver.entries) &&\n\t\t\tObject.values(resolver.entries).every(isState) &&\n\t\t\t(resolver.fallbackState === undefined || isState(resolver.fallbackState))\n\t\t);\n\t}\n\n\tif (resolver.kind === \"threshold\") {\n\t\treturn (\n\t\t\tArray.isArray(resolver.thresholds) &&\n\t\t\tresolver.thresholds.every(isThresholdDefinition) &&\n\t\t\tArray.isArray(resolver.states) &&\n\t\t\tresolver.states.every(isState) &&\n\t\t\t(resolver.invalidState === undefined || isState(resolver.invalidState))\n\t\t);\n\t}\n\n\treturn false;\n}\n\nfunction isPipelineStep(value: unknown): value is FormattersPipelineStep {\n\tif (!isRecord(value) || typeof value.id !== \"string\") return false;\n\n\tif (value.type === \"normalizeLeadingZeros\") {\n\t\treturn (\n\t\t\tvalue.config === undefined ||\n\t\t\t(isRecord(value.config) && (value.config.fixed === undefined || typeof value.config.fixed === \"number\"))\n\t\t);\n\t}\n\n\tif (value.type === \"rowBasedOverride\") {\n\t\treturn isRowBasedOverrideConfig(value.config);\n\t}\n\n\tif (value.type === \"resolveValueState\") {\n\t\treturn isResolveValueStateConfig(value.config);\n\t}\n\n\tif (value.type === \"typedValueFormat\") {\n\t\treturn isTypedValueFormatConfig(value.config);\n\t}\n\n\treturn false;\n}\n\nfunction isPipelinePlan(value: unknown): value is FormattersPipelinePlan {\n\treturn isRecord(value) && Array.isArray(value.steps) && value.steps.every(isPipelineStep);\n}\n\nfunction isPipelinePosition(value: unknown): value is { x: number; y: number } {\n\treturn isRecord(value) && typeof value.x === \"number\" && typeof value.y === \"number\";\n}\n\nfunction isPipelineNode(value: unknown): value is FormattersPipelineNode {\n\tif (!isRecord(value) || typeof value.id !== \"string\" || !isPipelinePosition(value.position)) return false;\n\n\tif (value.type === \"source\" || value.type === \"sink\") {\n\t\treturn true;\n\t}\n\n\treturn isPipelineStep(value);\n}\n\nfunction isPipelineEdge(value: unknown): value is FormattersPipelineEdge {\n\treturn isRecord(value) && typeof value.id === \"string\" && typeof value.source === \"string\" && typeof value.target === \"string\";\n}\n\nfunction isPipelineGraph(value: unknown): value is FormattersPipelineGraph {\n\treturn (\n\t\tisRecord(value) &&\n\t\tArray.isArray(value.nodes) &&\n\t\tvalue.nodes.every(isPipelineNode) &&\n\t\tArray.isArray(value.edges) &&\n\t\tvalue.edges.every(isPipelineEdge)\n\t);\n}\n\nfunction isPipelineConfig(value: unknown): value is FormattersPipelineConfig {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue.version === 1 &&\n\t\t(value.plan === undefined || isPipelinePlan(value.plan)) &&\n\t\t(value.graph === undefined || isPipelineGraph(value.graph)) &&\n\t\t(isPipelinePlan(value.plan) || isPipelineGraph(value.graph))\n\t);\n}\n\nexport function normalizeFormattersPipelineConfig(value: unknown): FormattersPipelineConfig | undefined {\n\tif (!isPipelineConfig(value)) return undefined;\n\n\tconst validation = validateFormattersPipelineConfig(value);\n\tif (!validation.ok) return undefined;\n\n\treturn cloneFormattersPipelineConfig(value);\n}\n","import type { FormattersPipelineFormatterId } from \"./types\";\n\n/**\n * Описание вида форматтера для каталога.\n */\nexport type FormattersPipelineDefinition = {\n\tid: FormattersPipelineFormatterId;\n\tname: string;\n\tdescription: string;\n};\n\n/**\n * Справочник доступных видов форматтеров.\n */\nexport const formattersPipelineDefinitions: readonly FormattersPipelineDefinition[] = Object.freeze([\n\t{\n\t\tid: \"normalizeLeadingZeros\",\n\t\tname: \"Нормализация ведущих нулей\",\n\t\tdescription: \"Нормализует числовое значение по правилам fixed.\"\n\t},\n\t{\n\t\tid: \"rowBasedOverride\",\n\t\tname: \"Контекстная формула\",\n\t\tdescription: \"Подменяет значение из другого поля текущей строки или отдельной формулы.\"\n\t},\n\t{\n\t\tid: \"resolveValueState\",\n\t\tname: \"Определение состояния значения\",\n\t\tdescription: \"Вычисляет value state и опционально настраивает отображение статусной иконки.\"\n\t},\n\t{\n\t\tid: \"typedValueFormat\",\n\t\tname: \"Типизированное форматирование\",\n\t\tdescription: \"Формирует итоговый внешний вид значения по типу и роли столбца.\"\n\t}\n]);\n","import { formattersPipelineDefinitions } from \"./definitions\";\n\nimport type { FormattersPipelineDefinition } from \"./definitions\";\nimport type { FormattersPipelineFormatterId } from \"./types\";\n\nconst formatterDefinitionsById = new Map<FormattersPipelineFormatterId, FormattersPipelineDefinition>(\n\tformattersPipelineDefinitions.map((definition) => [definition.id, definition])\n);\n\n/**\n * Возвращает каталог видов форматтеров pipeline.\n */\nexport function getFormattersPipelineDefinitions(): readonly FormattersPipelineDefinition[] {\n\treturn formattersPipelineDefinitions;\n}\n\n/**\n * Возвращает описание вида форматтера по id.\n */\nexport function getFormattersPipelineDefinitionById(id: FormattersPipelineFormatterId): FormattersPipelineDefinition | undefined {\n\treturn formatterDefinitionsById.get(id);\n}\n","import { uuidv4 } from \"../../crypto\";\n\nimport { validateFormattersPipelineGraph } from \"./validate\";\n\nimport type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineEdge,\n\tFormattersPipelineGraph,\n\tFormattersPipelineNode,\n\tFormattersPipelinePlan\n} from \"./types\";\n\ntype IdFactory = () => string;\n\nfunction isSystemNode(node: FormattersPipelineNode): boolean {\n\treturn node.type === \"source\" || node.type === \"sink\";\n}\n\nfunction cloneNodeWithId(node: FormattersPipelineNode, id: string): FormattersPipelineNode {\n\tswitch (node.type) {\n\t\tcase \"source\":\n\t\tcase \"sink\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position }\n\t\t\t};\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: node.config ? { ...node.config } : undefined\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: node.config ? { ...node.config } : undefined\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig:\n\t\t\t\t\tnode.config.mode === \"formula\"\n\t\t\t\t\t\t? { ...node.config, dependencyIds: node.config.dependencyIds ? [...node.config.dependencyIds] : undefined }\n\t\t\t\t\t\t: { ...node.config }\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: {\n\t\t\t\t\tresolver:\n\t\t\t\t\t\tnode.config.resolver.kind === \"fixed\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\t\t\t\tentries: { ...node.config.resolver.entries },\n\t\t\t\t\t\t\t\t\tfallbackState: node.config.resolver.fallbackState\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\t\t\t\tthresholds: node.config.resolver.thresholds.map((item) =>\n\t\t\t\t\t\t\t\t\t\ttypeof item === \"number\" ? item : { ...item }\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tstates: [...node.config.resolver.states],\n\t\t\t\t\t\t\t\t\tinvalidState: node.config.resolver.invalidState\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\ticon: node.config.icon ? { ...node.config.icon } : undefined\n\t\t\t\t}\n\t\t\t};\n\t}\n}\n\nfunction rekeyGraph(graph: FormattersPipelineGraph, idFactory: IdFactory): FormattersPipelineGraph {\n\tconst nodeIdByPreviousId = new Map<string, string>();\n\n\tfor (const node of graph.nodes) {\n\t\tnodeIdByPreviousId.set(node.id, isSystemNode(node) ? node.id : idFactory());\n\t}\n\n\tconst edges: FormattersPipelineEdge[] = graph.edges.map((edge) => ({\n\t\tid: idFactory(),\n\t\tsource: nodeIdByPreviousId.get(edge.source) ?? edge.source,\n\t\ttarget: nodeIdByPreviousId.get(edge.target) ?? edge.target\n\t}));\n\n\treturn {\n\t\tnodes: graph.nodes.map((node) => cloneNodeWithId(node, nodeIdByPreviousId.get(node.id) ?? node.id)),\n\t\tedges,\n\t\tviewport: graph.viewport ? { ...graph.viewport } : undefined\n\t};\n}\n\nfunction rekeyPlan(plan: FormattersPipelinePlan, idFactory: IdFactory): FormattersPipelinePlan {\n\treturn {\n\t\tsteps: plan.steps.map((step) => {\n\t\t\tswitch (step.type) {\n\t\t\t\tcase \"typedValueFormat\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: step.config ? { ...step.config } : undefined\n\t\t\t\t\t};\n\t\t\t\tcase \"normalizeLeadingZeros\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: step.config ? { ...step.config } : undefined\n\t\t\t\t\t};\n\t\t\t\tcase \"rowBasedOverride\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig:\n\t\t\t\t\t\t\tstep.config.mode === \"formula\"\n\t\t\t\t\t\t\t\t? { ...step.config, dependencyIds: step.config.dependencyIds ? [...step.config.dependencyIds] : undefined }\n\t\t\t\t\t\t\t\t: { ...step.config }\n\t\t\t\t\t};\n\t\t\t\tcase \"resolveValueState\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: {\n\t\t\t\t\t\t\tresolver:\n\t\t\t\t\t\t\t\tstep.config.resolver.kind === \"fixed\"\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\t\t\t\t\t\tentries: { ...step.config.resolver.entries },\n\t\t\t\t\t\t\t\t\t\t\tfallbackState: step.config.resolver.fallbackState\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\t\t\t\t\t\tthresholds: step.config.resolver.thresholds.map((item) =>\n\t\t\t\t\t\t\t\t\t\t\t\ttypeof item === \"number\" ? item : { ...item }\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\tstates: [...step.config.resolver.states],\n\t\t\t\t\t\t\t\t\t\t\tinvalidState: step.config.resolver.invalidState\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ticon: step.config.icon ? { ...step.config.icon } : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t}\n\t\t})\n\t};\n}\n\n/**\n * Переиздаёт технические id formatter-нод и step-ов без изменения настроек pipeline.\n *\n * Source/sink сохраняют стабильные id, потому что редактор использует их как\n * служебные якоря графа; все пользовательские formatter id не имеют бизнес-смысла.\n */\nexport function rekeyFormattersPipelineConfig(\n\tconfig: FormattersPipelineConfig | undefined,\n\tidFactory: IdFactory = uuidv4\n): FormattersPipelineConfig | undefined {\n\tif (!config) return undefined;\n\n\tconst graph = config.graph ? rekeyGraph(config.graph, idFactory) : undefined;\n\tconst graphValidation = graph ? validateFormattersPipelineGraph(graph) : undefined;\n\n\treturn {\n\t\tversion: config.version,\n\t\tgraph,\n\t\tplan:\n\t\t\tgraphValidation?.ok && graphValidation.plan ? graphValidation.plan : config.plan ? rekeyPlan(config.plan, idFactory) : undefined\n\t};\n}\n","import { compileTableFormula, type TableFormulaCompiledExecutor, type TableFormulaRowData } from \"../../formulas\";\nimport { isZeroValue } from \"../number\";\nimport { toSafeString } from \"../strings\";\n\nimport { compileFormattersPipelineExecutor, formatTypedCellValue } from \"./execute\";\n\nimport type {\n\tFormatPipelineDisplayValueArgs,\n\tFormattersPipelineDisplayValue,\n\tFormattersPipelineExecutionResult,\n\tFormattersPipelineRuntimeField,\n\tFormattersPipelineRuntimeFields\n} from \"./types\";\n\ntype ResolvedPipelineSourceValue = {\n\tvalue: unknown;\n\tshouldRenderEmpty: boolean;\n};\n\nconst missingFormulaExecutor: TableFormulaCompiledExecutor = () => ({ ok: false, reason: \"formula_not_found\" });\n\nfunction createDefaultDisplayValue(value: unknown, overflowTooltip: boolean): FormattersPipelineDisplayValue {\n\treturn {\n\t\tvalue,\n\t\tstate: \"none\",\n\t\tshowIcon: false,\n\t\tshowValue: true,\n\t\ticonPosition: \"left\",\n\t\toverflowTooltip\n\t};\n}\n\nfunction formatFallbackValue(value: unknown, field: Pick<FormattersPipelineRuntimeField, \"role\" | \"type\"> | undefined): string {\n\tif (!field) {\n\t\treturn toSafeString(value);\n\t}\n\n\treturn formatTypedCellValue(value, field);\n}\n\nfunction compileFormulaExecutor(field: FormattersPipelineRuntimeField): TableFormulaCompiledExecutor | undefined {\n\tif (!field.formulaId) {\n\t\treturn undefined;\n\t}\n\n\tconst compiled = compileTableFormula({\n\t\tformulaId: field.formulaId,\n\t\tkeys: field.formulaDependencies\n\t});\n\n\treturn compiled.ok ? compiled.execute : missingFormulaExecutor;\n}\n\nfunction resolvePipelineSourceValue(\n\trawValue: unknown,\n\trowData: TableFormulaRowData,\n\tfield: Readonly<FormattersPipelineRuntimeField>\n): ResolvedPipelineSourceValue {\n\tif (!field.formulaId) {\n\t\treturn {\n\t\t\tvalue: rawValue,\n\t\t\tshouldRenderEmpty: false\n\t\t};\n\t}\n\n\tif (!field.formulaExecutor) {\n\t\treturn {\n\t\t\tvalue: field.purelyDerived ? undefined : rawValue,\n\t\t\tshouldRenderEmpty: field.purelyDerived === true\n\t\t};\n\t}\n\n\tconst execution = field.formulaExecutor(rowData);\n\tif (execution.ok) {\n\t\treturn {\n\t\t\tvalue: execution.value,\n\t\t\tshouldRenderEmpty: false\n\t\t};\n\t}\n\n\treturn {\n\t\tvalue: field.purelyDerived ? undefined : rawValue,\n\t\tshouldRenderEmpty: field.purelyDerived === true\n\t};\n}\n\nfunction executePipelineFormatting<TField extends FormattersPipelineRuntimeField>(\n\targs: FormatPipelineDisplayValueArgs<TField>,\n\tsourceValue: unknown,\n\tfield: Readonly<TField>\n): FormattersPipelineDisplayValue {\n\tconst executor = field.formattersPipelineExecutor;\n\tif (!executor) {\n\t\treturn createDefaultDisplayValue(formatFallbackValue(sourceValue, field), field.overflowTooltip === true);\n\t}\n\n\tconst execution: FormattersPipelineExecutionResult = executor.execute({\n\t\tvalue: sourceValue,\n\t\trowData: args.rowData,\n\t\trowKind: args.rowKind,\n\t\tisGroupRow: args.rowKind === \"group\",\n\t\tisTotalsRow: args.rowKind === \"totals\",\n\t\trowLevel: args.rowLevel ?? 0,\n\t\tgroupingIds: args.groupingIds ?? [],\n\t\tcolumnId: field.id\n\t});\n\tconst value = execution.hasTypedValueFormat ? execution.value : formatFallbackValue(execution.value, field);\n\n\treturn {\n\t\tvalue,\n\t\tstate: execution.state,\n\t\ticon: execution.icon,\n\t\tshowIcon: execution.showIcon,\n\t\tshowValue: execution.showValue,\n\t\ticonPosition: execution.iconPosition,\n\t\toverflowTooltip: field.overflowTooltip === true\n\t};\n}\n\nfunction applyDisplayPostProcessing(\n\tdisplayValue: FormattersPipelineDisplayValue,\n\tsourceValue: ResolvedPipelineSourceValue,\n\tfield: Readonly<FormattersPipelineRuntimeField>\n): FormattersPipelineDisplayValue {\n\tif (sourceValue.shouldRenderEmpty) {\n\t\treturn {\n\t\t\t...displayValue,\n\t\t\tvalue: \"\"\n\t\t};\n\t}\n\n\tif (field.emptyWhenZero && isZeroValue(sourceValue.value)) {\n\t\treturn {\n\t\t\t...displayValue,\n\t\t\tvalue: \"\"\n\t\t};\n\t}\n\n\treturn displayValue;\n}\n\n/**\n * Компилирует formula/pipeline runtime прямо в исходный объект поля.\n *\n * Функция предназначена только для construction-stage: до помещения полей в\n * readonly context, memoized snapshot или query-independent cache.\n */\nexport function compileFormattersPipelineRuntime<TField extends FormattersPipelineRuntimeField>(field: TField): Readonly<TField> {\n\tconst formulaExecutor = compileFormulaExecutor(field);\n\tif (formulaExecutor) {\n\t\tfield.formulaExecutor = formulaExecutor;\n\t} else {\n\t\tdelete field.formulaExecutor;\n\t}\n\n\tif (!field.formattersPipeline) {\n\t\tdelete field.formattersPipelineExecutor;\n\t\treturn field;\n\t}\n\n\tconst compiled = compileFormattersPipelineExecutor({\n\t\tconfig: field.formattersPipeline,\n\t\tcolumn: field\n\t});\n\n\tif (compiled.ok) {\n\t\tfield.formattersPipelineExecutor = compiled.executor;\n\t} else {\n\t\tdelete field.formattersPipelineExecutor;\n\t}\n\n\treturn field;\n}\n\n/**\n * Компилирует runtime-карту без пересборки самих полей.\n */\nexport function compileFormattersPipelineRuntimeFields<TField extends FormattersPipelineRuntimeField>(\n\tfieldsById: Readonly<Record<string, TField | undefined>>\n): FormattersPipelineRuntimeFields<TField> {\n\tconst runtimeFields: Record<string, Readonly<TField>> = {};\n\n\tfor (const [fieldId, field] of Object.entries(fieldsById)) {\n\t\tif (!field) continue;\n\t\truntimeFields[fieldId] = compileFormattersPipelineRuntime(field);\n\t}\n\n\treturn runtimeFields;\n}\n\n/**\n * Вычисляет display-result для одного значения без знания о таблице или графике.\n */\nexport function formatPipelineDisplayValue<TField extends FormattersPipelineRuntimeField>(\n\targs: FormatPipelineDisplayValueArgs<TField>\n): FormattersPipelineDisplayValue {\n\tif (!args.field) {\n\t\treturn createDefaultDisplayValue(toSafeString(args.rawValue), false);\n\t}\n\n\tconst sourceValue = resolvePipelineSourceValue(args.rawValue, args.rowData, args.field);\n\tconst displayValue = executePipelineFormatting(args, sourceValue.value, args.field);\n\n\treturn applyDisplayPostProcessing(displayValue, sourceValue, args.field);\n}\n","import type { State } from \"../../types\";\n\nexport const DEFAULT_VALUE_STATES: readonly State[] = [\"none\", \"information\", \"success\", \"warning\", \"error\"];\n\nexport const VALUE_STATE_COLOR_TOKENS: Record<State, string> = {\n\t\"\": \"transparent\",\n\tnone: \"var(--content-1)\",\n\tinformation: \"var(--status-info-text)\",\n\tsuccess: \"var(--status-success-text)\",\n\twarning: \"var(--status-warning-text)\",\n\terror: \"var(--status-error-text)\"\n};\n","import { State } from \"../../types\";\n\nexport function resolveValueStateClassName(state: State, fallbackClassName?: string): string | undefined {\n\tswitch (state) {\n\t\tcase \"success\":\n\t\t\treturn \"statusSuccess\";\n\t\tcase \"warning\":\n\t\t\treturn \"statusWarning\";\n\t\tcase \"error\":\n\t\t\treturn \"statusError\";\n\t\tcase \"information\":\n\t\t\treturn \"statusInfo\";\n\t\tdefault:\n\t\t\treturn fallbackClassName;\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"formatters-ByJmJx4k.js","names":[],"sources":["../../src/formatters/strings/startsWithIgnoringZeros.ts","../../src/formatters/strings/stripInnerSpaces.ts","../../src/formatters/strings/stripLeadingZeros.ts","../../src/formatters/strings/truncateText.ts","../../src/formatters/boolean/toAbapBoolean.ts","../../src/formatters/formatName.ts","../../src/formatters/formatPhone.ts","../../src/formatters/date/calendarDate.ts","../../src/formatters/date/calendarPeriod.ts","../../src/formatters/date/dateRange.ts","../../src/formatters/date/educationDate.ts","../../src/formatters/date/relativeRanges.ts","../../src/formatters/number/compact.ts","../../src/formatters/number/isZeroValue.ts","../../src/formatters/number/formatNumber.ts","../../src/formatters/normalizeLeadingZeros.ts","../../src/formatters/pipeline/clone.ts","../../src/formatters/pipeline/dependencies.ts","../../src/formatters/valueState/valueStateRegistry.ts","../../src/formatters/valueState/fixedValueStateResolver.ts","../../src/formatters/valueState/thresholdValueStateResolver.ts","../../src/formatters/pipeline/execute.ts","../../src/formatters/pipeline/normalize.ts","../../src/formatters/pipeline/definitions.ts","../../src/formatters/pipeline/registry.ts","../../src/formatters/pipeline/rekey.ts","../../src/formatters/pipeline/runtime.ts","../../src/formatters/valueState/presentation.ts","../../src/formatters/valueState/resolveValueStateClassName.ts"],"sourcesContent":["export function startsWithIgnoringZeros(value: string, searchText: string): boolean {\n\tconst cleanValue = (value || \"\").toLowerCase().replace(/^0+/, \"\");\n\tconst cleanText = (searchText || \"\").toLowerCase().replace(/^0+/, \"\");\n\treturn cleanValue.startsWith(cleanText);\n}\n","/**\n * Удаляет пробелы и NBSP/узкие NBSP внутри строки.\n * (для случая \"1 234\" или \"1\\u00A0234\").\n */\nexport function stripInnerSpaces(s: string): string {\n\tlet out = \"\";\n\tlet changed = false;\n\n\tfor (let i = 0; i < s.length; i++) {\n\t\tconst c = s.charCodeAt(i);\n\t\t// обычный пробел, NBSP, NNBSP\n\t\tif (c === 32 || c === 160 || c === 8239) {\n\t\t\tchanged = true;\n\t\t\tcontinue;\n\t\t}\n\t\tout += s[i];\n\t}\n\n\treturn changed ? out : s;\n}\n","/**\n * Удаляет ведущие нули из строки.\n * - \"00123\" -> \"123\"\n * - \"0000\" -> \"0\"\n * - \"-0012\" -> \"-12\"\n * - \"\" -> \"0\"\n * - \"abc\" -> \"abc\"\n */\nexport function stripLeadingZeros(input: string): string {\n\tif (input == null) return \"\";\n\n\t// обрезаем пробелы по краям\n\tconst str = input.trim();\n\tif (str === \"\") return \"0\";\n\n\t// проверяем отрицательное число\n\tconst isNegative = str.startsWith(\"-\");\n\tconst core = isNegative ? str.slice(1) : str;\n\n\t// если core не число — вернём как есть\n\tif (!/^\\d+$/.test(core)) {\n\t\treturn str;\n\t}\n\n\t// удаляем ведущие нули\n\tconst normalized = core.replace(/^0+/, \"\");\n\tconst result = normalized === \"\" ? \"0\" : normalized;\n\n\treturn isNegative ? `-${result}` : result;\n}\n","import { normalizeText } from \"./normalizeText\";\n\nexport function truncateText(value: string | null | undefined, maxLength: number) {\n\tconst normalized = normalizeText(value);\n\tif (!normalized) return undefined;\n\n\treturn normalized.length > maxLength ? `${normalized.slice(0, maxLength)}...` : normalized;\n}\n","import { AbapBoolean } from \"../../types\";\n\nexport function toAbapBoolean(value: unknown): AbapBoolean {\n\tif (typeof value === \"string\") {\n\t\tvalue = value !== \"0\";\n\t}\n\treturn value ? \"X\" : \" \";\n}\n","/**\n * Форматирует ФИО в формат \"Фамилия Имя Отчество\"\n * @param fullName Входная строка с ФИО в любом формате\n * @returns Отформатированная строка в формате \"Иванов Иван Иванович\"\n */\nexport function formatFullName(fullName: string): string {\n\tif (!fullName) return \"\";\n\n\t// Нормализация строки: удаление лишних пробелов, приведение к нижнему регистру\n\tconst normalized = fullName\n\t\t.trim()\n\t\t.replace(/\\s+/g, \" \")\n\t\t.replace(/\\s*\\./, \" \") // если после фамилии есть точка...\n\t\t.replace(/\\s*\\.\\s*/g, \". \")\n\t\t.toLowerCase();\n\n\t// Разделение на части\n\tconst parts = normalized.split(\" \");\n\n\tif (parts.length === 0) return \"\";\n\n\t// Обработка фамилии (первая часть)\n\tconst surname = capitalize(parts[0]);\n\n\tif (parts.length === 1) return surname;\n\n\t// Обработка имени (вторая часть)\n\tconst name = parts[1].includes(\".\") ? expandInitial(parts[1]) : capitalize(parts[1]);\n\n\tif (parts.length === 2) return `${surname} ${name}`;\n\n\t// Обработка отчества (третья часть)\n\tconst patronymic = parts[2].includes(\".\") ? expandInitial(parts[2]) : capitalize(parts[2]);\n\n\treturn `${surname} ${name} ${patronymic}`;\n}\n\n/**\n * Форматирует ФИО в формат \"Фамилия И.О.\"\n * @param fullName Входная строка с ФИО в любом формате\n * @returns Отформатированная строка в формате \"Иванов И.И.\"\n */\nexport function formatShortName(fullName: string): string {\n\tif (!fullName) return \"\";\n\n\t// Нормализация строки\n\tconst normalized = fullName\n\t\t.trim()\n\t\t.replace(/\\s+/g, \" \")\n\t\t.replace(/\\s*\\.\\s*/g, \".\")\n\t\t.toLowerCase();\n\n\tconst parts = normalized.split(\" \");\n\n\tif (parts.length === 0) return \"\";\n\n\t// Фамилия всегда с большой буквы\n\tconst surname = capitalize(parts[0]);\n\n\tif (parts.length === 1) return surname;\n\n\t// Инициал имени\n\tconst nameInitial = parts[1].startsWith(\".\") ? parts[1][1] : parts[1][0];\n\n\tif (parts.length === 2) {\n\t\treturn parts[1].includes(\".\") ? `${surname} ${nameInitial.toUpperCase()}.` : `${surname} ${nameInitial.toUpperCase()}.`;\n\t}\n\n\t// Инициал отчества\n\tconst patronymicInitial = parts[2].startsWith(\".\") ? parts[2][1] : parts[2][0];\n\n\treturn `${surname} ${nameInitial.toUpperCase()}.${patronymicInitial.toUpperCase()}.`;\n}\n\nfunction capitalize(str: string): string {\n\tif (!str) return \"\";\n\treturn str[0].toUpperCase() + str.slice(1);\n}\n\nfunction expandInitial(initial: string): string {\n\treturn capitalize(initial);\n\n\t// if (!initial.includes(\".\")) return capitalize(initial);\n\n\t// const letter = initial.replace(/\\./g, \"\").toLowerCase();\n\t// if (!letter) return \"\";\n\n\t// return letter.toUpperCase();\n}\n","export function formatPhone(number: string): string {\n\tconst match = clearPhone(number).match(/^(\\+7)(\\d{3})(\\d{3})(\\d{2})(\\d{2})$/);\n\tif (!match) return number;\n\treturn `+7 (${match[2]}) ${match[3]}-${match[4]}-${match[5]}`;\n}\n\nexport function clearPhone(number: string): string {\n\treturn `+7${number\n\t\t.replace(/\\D/g, \"\")\n\t\t.slice(0, 11)\n\t\t.replace(/^(7|8)/, \"\")}`;\n}\n","/**\n * Создаёт календарную дату без timezone-семантики.\n *\n * Внутри используется локальный конструктор `Date`, чтобы видимые\n * компоненты даты и времени сохранялись без дополнительных смещений.\n */\nexport function createCalendarDate(year: number, monthIndex: number, day: number, hour = 0, minute = 0, second = 0, millisecond = 0): Date {\n\treturn new Date(year, monthIndex, day, hour, minute, second, millisecond);\n}\n\n/**\n * Нормализует дату к началу суток без timezone-сдвига.\n */\nexport function getStartOfDay(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Нормализует дату к концу суток без timezone-сдвига.\n */\nexport function getEndOfDay(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), 23, 59, 59, 0);\n}\n\n/**\n * Возвращает первый день месяца для переданной даты.\n */\nexport function getStartOfMonth(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), 1, 0, 0, 0, 0);\n}\n\n/**\n * Возвращает первый день года для переданной даты.\n */\nexport function getStartOfYear(date: Date): Date {\n\treturn createCalendarDate(date.getFullYear(), 0, 1, 0, 0, 0, 0);\n}\n\n/**\n * Возвращает начало календарной недели без timezone-сдвига.\n *\n * По умолчанию неделя начинается в понедельник, как в русскоязычной календарной\n * сетке. При необходимости вызывающий код может передать другой день недели\n * в формате `Date.getDay()`: 0 — воскресенье, 1 — понедельник.\n */\nexport function getStartOfWeek(date: Date, weekStartsOn = 1): Date {\n\tconst normalizedWeekStart = Number.isInteger(weekStartsOn) ? ((weekStartsOn % 7) + 7) % 7 : 1;\n\tconst start = getStartOfDay(date);\n\tconst offset = (start.getDay() - normalizedWeekStart + 7) % 7;\n\n\treturn addCalendarDays(start, -offset);\n}\n\n/**\n * Сдвигает дату на указанное количество суток в календарной семантике.\n */\nexport function addCalendarDays(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate() + amount, 0, 0, 0, 0);\n}\n\n/**\n * Сдвигает дату на указанное количество месяцев в календарной семантике.\n */\nexport function addCalendarMonths(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear(), date.getMonth() + amount, date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Сдвигает дату на указанное количество лет в календарной семантике.\n */\nexport function addCalendarYears(date: Date, amount: number): Date {\n\treturn createCalendarDate(date.getFullYear() + amount, date.getMonth(), date.getDate(), 0, 0, 0, 0);\n}\n\n/**\n * Проверяет, совпадают ли две даты по календарному дню.\n */\nexport function isSameCalendarDay(left: Date | null | undefined, right: Date | null | undefined): boolean {\n\tif (!(left instanceof Date) || !(right instanceof Date)) return false;\n\n\treturn left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate();\n}\n","import {\n\taddCalendarDays,\n\tcreateCalendarDate,\n\tgetEndOfDay,\n\tgetStartOfDay,\n\tgetStartOfMonth,\n\tgetStartOfWeek,\n\tgetStartOfYear\n} from \"./calendarDate\";\n\nexport type CalendarPeriodSelectionMode = \"day\" | \"week\" | \"month\" | \"year\";\nexport type CalendarWeekEndDay = \"friday\" | \"saturday\" | \"sunday\";\n\nexport interface CalendarPeriodOptions {\n\t/**\n\t * Определяет размер выбираемого календарного периода.\n\t */\n\tselectionMode?: CalendarPeriodSelectionMode;\n\t/**\n\t * Последний включённый день недели для режима `week`.\n\t */\n\tweekEndDay?: CalendarWeekEndDay;\n}\n\nexport interface CalendarPeriod {\n\treadonly start: Date;\n\treadonly end: Date;\n}\n\nexport interface CalendarPeriodDateBounds {\n\treadonly minDate?: Date;\n\treadonly maxDate?: Date;\n}\n\nconst WEEK_END_DAY_OFFSETS: Record<CalendarWeekEndDay, number> = {\n\tfriday: 4,\n\tsaturday: 5,\n\tsunday: 6\n};\n\nfunction isValidCalendarDate(value: Date | null | undefined): value is Date {\n\treturn value instanceof Date && Number.isFinite(value.getTime());\n}\n\nfunction resolveCalendarWeekEndDay(weekEndDay?: CalendarWeekEndDay): CalendarWeekEndDay {\n\treturn weekEndDay ?? \"sunday\";\n}\n\nfunction resolveCalendarPeriodSelectionMode(selectionMode?: CalendarPeriodSelectionMode): CalendarPeriodSelectionMode {\n\treturn selectionMode ?? \"day\";\n}\n\n/**\n * Возвращает включительные границы календарного периода без timezone-сдвига.\n */\nexport function getCalendarPeriod(value: Date | null | undefined, options: CalendarPeriodOptions = {}): CalendarPeriod | null {\n\tif (!isValidCalendarDate(value)) return null;\n\n\tconst selectionMode = resolveCalendarPeriodSelectionMode(options.selectionMode);\n\n\tswitch (selectionMode) {\n\t\tcase \"day\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfDay(value),\n\t\t\t\tend: getEndOfDay(value)\n\t\t\t};\n\t\t}\n\n\t\tcase \"week\": {\n\t\t\tconst start = getStartOfWeek(value);\n\t\t\tconst weekEndOffset = WEEK_END_DAY_OFFSETS[resolveCalendarWeekEndDay(options.weekEndDay)];\n\n\t\t\treturn {\n\t\t\t\tstart,\n\t\t\t\tend: getEndOfDay(addCalendarDays(start, weekEndOffset))\n\t\t\t};\n\t\t}\n\n\t\tcase \"month\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfMonth(value),\n\t\t\t\tend: getEndOfDay(createCalendarDate(value.getFullYear(), value.getMonth() + 1, 0))\n\t\t\t};\n\t\t}\n\n\t\tcase \"year\": {\n\t\t\treturn {\n\t\t\t\tstart: getStartOfYear(value),\n\t\t\t\tend: getEndOfDay(createCalendarDate(value.getFullYear(), 11, 31))\n\t\t\t};\n\t\t}\n\n\t\tdefault: {\n\t\t\tconst checker: never = selectionMode;\n\t\t\tvoid checker;\n\n\t\t\treturn null;\n\t\t}\n\t}\n}\n\n/**\n * Проверяет, входит ли дата в уже вычисленные включительные границы периода.\n */\nexport function isDateInsideCalendarPeriod(value: Date | null | undefined, period: CalendarPeriod | null | undefined): boolean {\n\tif (!isValidCalendarDate(value) || !period) return false;\n\n\tconst dateTime = getStartOfDay(value).getTime();\n\treturn dateTime >= period.start.getTime() && dateTime <= period.end.getTime();\n}\n\n/**\n * Проверяет, что весь период укладывается в заданные календарные границы выбора.\n */\nexport function isCalendarPeriodWithinDateBounds(\n\tperiod: CalendarPeriod | null | undefined,\n\tbounds: CalendarPeriodDateBounds = {}\n): boolean {\n\tif (!period) return false;\n\n\tif (bounds.minDate && period.start.getTime() < getStartOfDay(bounds.minDate).getTime()) return false;\n\tif (bounds.maxDate && period.end.getTime() > getEndOfDay(bounds.maxDate).getTime()) return false;\n\n\treturn true;\n}\n","import { getEndOfDay, getStartOfDay } from \"./calendarDate\";\n\nconst MS_IN_DAY = 24 * 60 * 60 * 1000;\n\nexport type NullableDateRange = readonly [Date | null, Date | null];\nexport type DateRange = readonly [Date, Date];\n\nexport type DateRangeInput = Date | null | NullableDateRange;\n\nexport type DateRangeTimeMode = \"dayBounds\" | \"preserve\";\n\nexport interface NormalizeDateRangeOptions {\n\t/**\n\t * Режим времени для двух граничных дат.\n\t *\n\t * `dayBounds` расширяет диапазон до полных календарных дней,\n\t * `preserve` оставляет время исходных дат после упорядочивания.\n\t */\n\ttimeMode?: DateRangeTimeMode;\n}\n\nexport function isValidDate(value: Date | null): value is Date {\n\treturn value instanceof Date && Number.isFinite(value.getTime());\n}\n\nexport function isDateRangeTuple(value: DateRangeInput): value is NullableDateRange {\n\treturn Array.isArray(value);\n}\n\nexport function cloneDate(date: Date): Date {\n\treturn new Date(date.getTime());\n}\n\nexport function orderDates(left: Date, right: Date): DateRange {\n\tif (left.getTime() <= right.getTime()) return [left, right];\n\n\treturn [right, left];\n}\n\nexport function resolveDateRangePair(value: DateRangeInput): DateRange | null {\n\tif (isDateRangeTuple(value)) {\n\t\tconst [left, right] = value;\n\t\tconst hasLeft = isValidDate(left);\n\t\tconst hasRight = isValidDate(right);\n\n\t\tif (hasLeft && hasRight) return orderDates(left, right);\n\t\tif (hasLeft) return [left, left];\n\t\tif (hasRight) return [right, right];\n\n\t\treturn null;\n\t}\n\n\treturn isValidDate(value) ? [value, value] : null;\n}\n\nexport function normalizeDateRange(value: DateRangeInput, options: NormalizeDateRangeOptions = {}): DateRange | null {\n\tconst range = resolveDateRangePair(value);\n\tif (!range) return null;\n\n\tconst [start, end] = range;\n\tif (options.timeMode === \"preserve\") {\n\t\treturn [cloneDate(start), cloneDate(end)];\n\t}\n\n\treturn [getStartOfDay(start), getEndOfDay(end)];\n}\n\nexport function requireDateRange(value: DateRangeInput, options?: NormalizeDateRangeOptions): DateRange {\n\tconst range = normalizeDateRange(value, options);\n\tif (!range) {\n\t\tthrow new Error(\"Диапазон дат не задан\");\n\t}\n\n\treturn range;\n}\n\nfunction getCalendarDayTime(date: Date): number {\n\treturn Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());\n}\n\n/**\n * Считает количество календарных дней в диапазоне включительно.\n */\nexport function countCalendarDaysInDateRange(value: DateRangeInput): number | null {\n\tconst range = normalizeDateRange(value);\n\tif (!range) return null;\n\n\tconst [startDate, endDate] = range;\n\treturn Math.floor((getCalendarDayTime(endDate) - getCalendarDayTime(startDate)) / MS_IN_DAY) + 1;\n}\n","import { addCalendarDays, createCalendarDate, getStartOfDay } from \"./calendarDate\";\n\nconst EDUCATION_DATE_KEY_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\nconst EDUCATION_TIME_KEY_RE = /^(\\d{2}):(\\d{2})(?::(\\d{2}))?$/;\nconst EDUCATION_YEAR_START_MONTH_INDEX = 8;\nconst EDUCATION_YEAR_START_DAY = 1;\nconst EDUCATION_YEAR_END_MONTH_INDEX = 7;\nconst EDUCATION_YEAR_END_DAY = 31;\nconst EDUCATION_WEEK_DAY_COUNT = 6;\n\n/**\n * Машинный ключ календарного дня в образовательной системе.\n *\n * Формат всегда `YYYY-MM-DD`: он безопасен для URL, SQL-параметров и query keys,\n * но не несёт timezone-семантики.\n */\nexport type EducationDateKey = string;\n\n/**\n * Диапазон учебного года. Учебный год начинается 1 сентября и заканчивается 31 августа.\n */\nexport type EducationYearRange = {\n\treadonly year: number;\n\treadonly start: Date;\n\treadonly end: Date;\n};\n\n/**\n * Диапазон учебной недели. В публичном расписании неделя отображается с понедельника по субботу.\n */\nexport type EducationWeekRange = {\n\treadonly start: Date;\n\treadonly end: Date;\n};\n\nfunction isValidTimePart(value: number, max: number): boolean {\n\treturn Number.isInteger(value) && value >= 0 && value <= max;\n}\n\n/**\n * Разбирает `YYYY-MM-DD` без `Date.parse`, чтобы не получить скрытый timezone-сдвиг.\n */\nexport function parseEducationDateKey(value: string | undefined): Date | null {\n\tconst match = value?.match(EDUCATION_DATE_KEY_RE);\n\tif (!match) {\n\t\treturn null;\n\t}\n\n\tconst year = Number(match[1]);\n\tconst month = Number(match[2]);\n\tconst day = Number(match[3]);\n\tconst date = createCalendarDate(year, month - 1, day);\n\n\treturn date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day ? date : null;\n}\n\n/**\n * Форматирует `Date` в стабильный ключ `YYYY-MM-DD` по локальным календарным компонентам.\n */\nexport function formatEducationDateKey(value: Date): EducationDateKey {\n\tconst year = value.getFullYear();\n\tconst month = String(value.getMonth() + 1).padStart(2, \"0\");\n\tconst day = String(value.getDate()).padStart(2, \"0\");\n\n\treturn `${year}-${month}-${day}`;\n}\n\n/**\n * Форматирует время в `HH:mm` по локальным компонентам, без UTC-преобразования.\n */\nexport function formatEducationTimeKey(value: Date): string {\n\tconst hours = String(value.getHours()).padStart(2, \"0\");\n\tconst minutes = String(value.getMinutes()).padStart(2, \"0\");\n\n\treturn `${hours}:${minutes}`;\n}\n\n/**\n * Создаёт календарную дату-время из отдельных ключей даты и времени, удобных для SQL-выдачи.\n */\nexport function createEducationDateTime(dateKey: EducationDateKey, timeKey: string): Date | null {\n\tconst date = parseEducationDateKey(dateKey);\n\tconst match = timeKey.match(EDUCATION_TIME_KEY_RE);\n\tif (!date || !match) {\n\t\treturn null;\n\t}\n\n\tconst hours = Number(match[1]);\n\tconst minutes = Number(match[2]);\n\tconst seconds = Number(match[3] ?? 0);\n\tif (!isValidTimePart(hours, 23) || !isValidTimePart(minutes, 59) || !isValidTimePart(seconds, 59)) {\n\t\treturn null;\n\t}\n\n\treturn createCalendarDate(date.getFullYear(), date.getMonth(), date.getDate(), hours, minutes, seconds);\n}\n\n/**\n * Возвращает учебный год для календарной даты.\n */\nexport function getEducationYear(value: Date = new Date()): number {\n\treturn value.getMonth() < EDUCATION_YEAR_START_MONTH_INDEX ? value.getFullYear() - 1 : value.getFullYear();\n}\n\n/**\n * Возвращает границы учебного года для переданной даты.\n */\nexport function getEducationYearRange(value: Date = new Date()): EducationYearRange {\n\tconst year = getEducationYear(value);\n\n\treturn {\n\t\tyear,\n\t\tstart: createCalendarDate(year, EDUCATION_YEAR_START_MONTH_INDEX, EDUCATION_YEAR_START_DAY),\n\t\tend: createCalendarDate(year + 1, EDUCATION_YEAR_END_MONTH_INDEX, EDUCATION_YEAR_END_DAY)\n\t};\n}\n\n/**\n * Проверяет, входит ли дата в учебный год, вычисленный от `now`.\n */\nexport function isEducationDateInCurrentYear(value: Date, now: Date = new Date()): boolean {\n\tconst date = getStartOfDay(value);\n\tconst { start, end } = getEducationYearRange(now);\n\n\treturn date >= start && date <= end;\n}\n\n/**\n * Возвращает понедельник учебной недели. Воскресенье относится к следующей учебной неделе.\n */\nexport function getEducationWeekStartDate(value: Date): Date {\n\tconst date = getStartOfDay(value);\n\tconst dayOfWeek = (date.getDay() + 6) % 7;\n\tconst daysToMonday = dayOfWeek === 6 ? 1 : -dayOfWeek;\n\n\treturn addCalendarDays(date, daysToMonday);\n}\n\n/**\n * Возвращает диапазон учебной недели: понедельник-суббота.\n */\nexport function getEducationWeekRange(value: Date): EducationWeekRange {\n\tconst start = getEducationWeekStartDate(value);\n\n\treturn {\n\t\tstart,\n\t\tend: addCalendarDays(start, EDUCATION_WEEK_DAY_COUNT - 1)\n\t};\n}\n\n/**\n * Возвращает ключи дней учебной недели для SSR, prefetch и клиентского отображения.\n */\nexport function getEducationWeekDays(week: EducationDateKey | Date): readonly EducationDateKey[] {\n\tconst start =\n\t\ttypeof week === \"string\" ? (parseEducationDateKey(week) ?? getEducationWeekStartDate(new Date())) : getEducationWeekStartDate(week);\n\n\treturn Array.from({ length: EDUCATION_WEEK_DAY_COUNT }, (_, index) => formatEducationDateKey(addCalendarDays(start, index)));\n}\n\n/**\n * Возвращает ключ текущей учебной недели.\n */\nexport function getCurrentEducationWeekKey(now: Date = new Date()): EducationDateKey {\n\treturn formatEducationDateKey(getEducationWeekStartDate(now));\n}\n\n/**\n * Нормализует произвольный ключ недели к понедельнику текущего учебного года.\n */\nexport function normalizeEducationWeekKey(value: string | undefined, now: Date = new Date()): EducationDateKey | undefined {\n\tconst parsed = parseEducationDateKey(value);\n\tif (!parsed || !isEducationDateInCurrentYear(parsed, now)) {\n\t\treturn undefined;\n\t}\n\n\tconst weekStart = getEducationWeekStartDate(parsed);\n\n\treturn isEducationDateInCurrentYear(weekStart, now) ? formatEducationDateKey(weekStart) : undefined;\n}\n\n/**\n * Возвращает валидный ключ недели или текущую учебную неделю как fallback.\n */\nexport function resolveEducationWeekKey(value: string | undefined, now: Date = new Date()): EducationDateKey {\n\treturn normalizeEducationWeekKey(value, now) ?? getCurrentEducationWeekKey(now);\n}\n\n/**\n * Проверяет, совпадает ли неделя с текущей учебной неделей.\n */\nexport function isCurrentEducationWeek(week: EducationDateKey, now: Date = new Date()): boolean {\n\treturn resolveEducationWeekKey(week, now) === getCurrentEducationWeekKey(now);\n}\n","import { addCalendarDays, addCalendarMonths, getEndOfDay, getStartOfDay, getStartOfMonth } from \"./calendarDate\";\n\nimport type { NullableDateRange } from \"./dateRange\";\n\n/**\n * Контекст вычисления относительного диапазона дат.\n */\nexport interface DateRangeReferenceContext {\n\treferenceDate: Date;\n}\n\n/**\n * Нормализует опорную дату к началу суток без timezone-сдвига.\n */\nexport function normalizeDateRangeReferenceDate(referenceDate: Date): Date {\n\treturn getStartOfDay(referenceDate);\n}\n\n/**\n * Возвращает безопасную конечную дату для диапазона \"с начала месяца по вчера\".\n *\n * На первом дне месяца диапазон не может закончиться \"вчера\" без инверсии,\n * поэтому конец диапазона прижимается к старту месяца.\n */\nexport function resolveMonthStartToYesterdayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\tconst monthStart = getStartOfMonth(normalizedReferenceDate);\n\tconst yesterday = addCalendarDays(normalizedReferenceDate, -1);\n\tconst safeEndDate = yesterday < monthStart ? monthStart : yesterday;\n\n\treturn [monthStart, getEndOfDay(safeEndDate)];\n}\n\n/**\n * Возвращает диапазон \"с начала месяца по сегодня\".\n */\nexport function resolveMonthStartToTodayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\treturn [getStartOfMonth(normalizedReferenceDate), getEndOfDay(normalizedReferenceDate)];\n}\n\n/**\n * Возвращает диапазон \"за сегодня\".\n */\nexport function resolveTodayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\treturn [normalizedReferenceDate, getEndOfDay(normalizedReferenceDate)];\n}\n\n/**\n * Возвращает диапазон \"за вчера\".\n */\nexport function resolveYesterdayRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst yesterday = addCalendarDays(normalizeDateRangeReferenceDate(referenceDate), -1);\n\treturn [yesterday, getEndOfDay(yesterday)];\n}\n\n/**\n * Возвращает диапазон \"месяц назад\" от текущего дня.\n */\nexport function resolveMonthAgoRange({ referenceDate }: DateRangeReferenceContext): NullableDateRange {\n\tconst normalizedReferenceDate = normalizeDateRangeReferenceDate(referenceDate);\n\tconst monthAgo = addCalendarMonths(normalizedReferenceDate, -1);\n\treturn [getStartOfDay(monthAgo), getEndOfDay(normalizedReferenceDate)];\n}\n","import type { NumberFormatCompactOptions, NumberFormatCompactRoundingMode, NumberFormatCompactUnit, NumberFormatPreset } from \"./types\";\n\ntype PlainNumberFormatter = (value: number, preset: NumberFormatPreset) => string;\n\ntype ResolvedCompactNumberOptions = {\n\troundingMode: NumberFormatCompactRoundingMode;\n\tsuffixSeparator: string;\n\tmaxDecimals?: number;\n\tunits: readonly NumberFormatCompactUnit[];\n};\n\nconst DEFAULT_COMPACT_NUMBER_UNITS: readonly NumberFormatCompactUnit[] = [\n\t{ value: 1_000_000_000_000, suffix: \"трлн\" },\n\t{ value: 1_000_000_000, suffix: \"млрд\" },\n\t{ value: 1_000_000, suffix: \"млн\" },\n\t{ value: 1_000, suffix: \"тыс\" }\n];\n\nconst DEFAULT_COMPACT_NUMBER_OPTIONS = {\n\tminCompactValue: 1_000,\n\troundingMode: \"trunc\",\n\tsuffixSeparator: \" \"\n} satisfies Required<Pick<NumberFormatCompactOptions, \"minCompactValue\" | \"roundingMode\" | \"suffixSeparator\">>;\n\nconst DEFAULT_COMPACT_DECIMAL_SEPARATOR = \",\";\n\nfunction applyCompactRounding(value: number, mode: NumberFormatCompactRoundingMode): number {\n\tswitch (mode) {\n\t\tcase \"round\":\n\t\t\treturn Math.round(value);\n\n\t\tcase \"floor\":\n\t\t\treturn Math.floor(value);\n\n\t\tcase \"ceil\":\n\t\t\treturn Math.ceil(value);\n\n\t\tcase \"trunc\":\n\t\t\treturn Math.trunc(value);\n\t}\n}\n\nfunction roundCompactValue(value: number, decimals: number, mode: NumberFormatCompactRoundingMode): number {\n\tif (decimals === 0) return applyCompactRounding(value, mode);\n\n\tconst factor = 10 ** decimals;\n\treturn applyCompactRounding(value * factor, mode) / factor;\n}\n\nfunction getAutoCompactDecimals(normalizedValue: number): number {\n\tif (normalizedValue >= 10) return 0;\n\n\treturn 1;\n}\n\nfunction getEffectiveDecimals(value: number, maxDecimals: number): number {\n\tif (maxDecimals === 0) return 0;\n\n\tconst fixed = value.toFixed(maxDecimals);\n\tconst decimalSeparatorIndex = fixed.indexOf(\".\");\n\n\tif (decimalSeparatorIndex === -1) return 0;\n\n\tconst fraction = fixed.slice(decimalSeparatorIndex + 1).replace(/0+$/, \"\");\n\n\treturn fraction.length;\n}\n\nfunction getCompactUnitIndex(value: number, units: readonly NumberFormatCompactUnit[]): number {\n\treturn units.findIndex((unit) => value >= unit.value);\n}\n\nfunction createPlainCompactPreset(preset: NumberFormatPreset, decimals: number): NumberFormatPreset {\n\treturn {\n\t\tname: preset.name,\n\t\tdecimals,\n\t\tdecimalSeparator: decimals > 0 ? preset.decimalSeparator || DEFAULT_COMPACT_DECIMAL_SEPARATOR : preset.decimalSeparator,\n\t\tgrouping: preset.grouping,\n\t\tgroupingSeparator: preset.groupingSeparator,\n\t\tgroupingSize: preset.groupingSize\n\t};\n}\n\nfunction formatCompactValueByUnit(\n\tabsValue: number,\n\tunitIndex: number,\n\toptions: ResolvedCompactNumberOptions,\n\tpreset: NumberFormatPreset,\n\tformatPlainNumber: PlainNumberFormatter\n): string {\n\tconst unit = options.units[unitIndex];\n\tif (!unit) return formatPlainNumber(absValue, preset);\n\n\tconst normalizedValue = absValue / unit.value;\n\tconst maxDecimals = options.maxDecimals ?? getAutoCompactDecimals(normalizedValue);\n\tconst roundedValue = roundCompactValue(normalizedValue, maxDecimals, options.roundingMode);\n\n\t// Защита от результата вида \"1000 тыс\": переходим на следующую единицу.\n\tif (roundedValue >= 1000 && unitIndex > 0) {\n\t\treturn formatCompactValueByUnit(absValue, unitIndex - 1, options, preset, formatPlainNumber);\n\t}\n\n\tconst decimals = getEffectiveDecimals(roundedValue, maxDecimals);\n\tconst compactPreset = createPlainCompactPreset(preset, decimals);\n\n\treturn `${formatPlainNumber(roundedValue, compactPreset)}${options.suffixSeparator}${unit.suffix}`;\n}\n\nexport function formatCompactNumberValue(args: {\n\tvalue: number;\n\tpreset: NumberFormatPreset;\n\toptions: NumberFormatCompactOptions;\n\tformatPlainNumber: PlainNumberFormatter;\n}): string {\n\tconst {\n\t\tminCompactValue = DEFAULT_COMPACT_NUMBER_OPTIONS.minCompactValue,\n\t\troundingMode = DEFAULT_COMPACT_NUMBER_OPTIONS.roundingMode,\n\t\tsuffixSeparator = DEFAULT_COMPACT_NUMBER_OPTIONS.suffixSeparator,\n\t\tmaxDecimals,\n\t\tunits = DEFAULT_COMPACT_NUMBER_UNITS\n\t} = args.options;\n\n\tconst absValue = Math.abs(args.value);\n\n\tif (absValue < minCompactValue) {\n\t\treturn args.formatPlainNumber(args.value, args.preset);\n\t}\n\n\tconst unitIndex = getCompactUnitIndex(absValue, units);\n\n\tif (unitIndex === -1) {\n\t\treturn args.formatPlainNumber(args.value, args.preset);\n\t}\n\n\tconst sign = args.value < 0 ? \"-\" : \"\";\n\n\treturn `${sign}${formatCompactValueByUnit(\n\t\tabsValue,\n\t\tunitIndex,\n\t\t{\n\t\t\troundingMode,\n\t\t\tsuffixSeparator,\n\t\t\tmaxDecimals,\n\t\t\tunits\n\t\t},\n\t\targs.preset,\n\t\targs.formatPlainNumber\n\t)}`;\n}\n","import { toFiniteNumber } from \"./parseNumber\";\n\n/**\n * Проверяет, что значение семантически эквивалентно нулю и может быть скрыто как пустое.\n */\nexport function isZeroValue(value: unknown): boolean {\n\tconst v = toFiniteNumber(value);\n\n\tif (typeof v === \"number\") {\n\t\treturn v === 0;\n\t}\n\n\tif (typeof v === \"bigint\") {\n\t\treturn v === 0n;\n\t}\n\n\treturn false;\n}\n","import { formatCompactNumberValue } from \"./compact\";\nimport { isZeroValue } from \"./isZeroValue\";\nimport { DEFAULT_NUMBER_PRESET_NAMES, NUMBER_FORMAT_DEFAULTS, resolveNumberPreset } from \"./presets\";\n\nimport type { NumberFormatPreset } from \"./types\";\n\n/** Кеш Intl.NumberFormat по ключу \"decimals:grouping\" */\nconst cache = new Map<string, Intl.NumberFormat>();\n\n/** Усечение дробной части без округления: 1234.789 → 1234.7 (при decimals=1) */\nexport function truncateNumber(num: number, decimals: number): number {\n\tif (decimals === 0) return Math.trunc(num);\n\tconst factor = 10 ** decimals;\n\treturn Math.trunc(num * factor) / factor;\n}\n\nfunction getFormatter(decimals: number, grouping: boolean): Intl.NumberFormat {\n\tconst key = `${decimals}:${grouping ? 1 : 0}`;\n\tlet fmt = cache.get(key);\n\tif (!fmt) {\n\t\tfmt = new Intl.NumberFormat(\"ru-RU\", {\n\t\t\tminimumFractionDigits: decimals,\n\t\t\tmaximumFractionDigits: decimals,\n\t\t\tuseGrouping: grouping\n\t\t});\n\t\tcache.set(key, fmt);\n\t}\n\treturn fmt;\n}\n\n/** Разделители совпадают с ru-RU — можно использовать format() напрямую */\nfunction isStandard(p: NumberFormatPreset): boolean {\n\treturn (\n\t\tp.groupingSize === 3 &&\n\t\t(p.groupingSeparator === NUMBER_FORMAT_DEFAULTS.groupingSeparator || !p.grouping) &&\n\t\t(p.decimalSeparator === \",\" || p.decimals === 0)\n\t);\n}\n\n/**\n * Быстрый путь (99% вызовов): format() напрямую, без постобработки.\n * ru-RU уже даёт неразрывный пробел и запятую — именно то, что нужно.\n */\nfunction formatStandard(num: number, decimals: number, grouping: boolean): string {\n\treturn getFormatter(decimals, grouping).format(num);\n}\n\n/** Кастомные разделители: formatToParts() с подстановкой */\nfunction formatCustomSeparator(num: number, preset: NumberFormatPreset): string {\n\tconst parts = getFormatter(preset.decimals, preset.grouping).formatToParts(num);\n\tlet result = \"\";\n\tfor (const p of parts) {\n\t\tif (p.type === \"group\") result += preset.groupingSeparator;\n\t\telse if (p.type === \"decimal\") result += preset.decimalSeparator;\n\t\telse result += p.value;\n\t}\n\treturn result;\n}\n\n/** Нестандартный размер группы: Intl для округления, ручная группировка */\nfunction formatManualGroup(num: number, preset: NumberFormatPreset): string {\n\tconst raw = getFormatter(preset.decimals, false).format(num);\n\n\t// ru-RU без группировки: \"1234567,89\" — запятая как десятичный разделитель\n\tconst sep = raw.indexOf(\",\");\n\tconst intPart = sep === -1 ? raw : raw.slice(0, sep);\n\tconst fracPart = sep === -1 ? null : raw.slice(sep + 1);\n\n\tconst neg = intPart.startsWith(\"-\");\n\tconst abs = neg ? intPart.slice(1) : intPart;\n\n\tconst size = preset.groupingSize;\n\tconst groups: string[] = [];\n\tfor (let i = abs.length; i > 0; i -= size) {\n\t\tgroups.unshift(abs.slice(Math.max(0, i - size), i));\n\t}\n\n\tlet result = (neg ? \"-\" : \"\") + groups.join(preset.groupingSeparator);\n\tif (fracPart !== null) result += preset.decimalSeparator + fracPart;\n\treturn result;\n}\n\nfunction formatPlainNumber(num: number, preset: NumberFormatPreset): string {\n\t// 99% — стандартный ru-RU формат, format() без постобработки\n\tif (isStandard(preset)) return formatStandard(num, preset.decimals, preset.grouping);\n\n\t// Стандартный размер группы (3), но кастомные разделители\n\tif (preset.groupingSize === 3 || !preset.grouping) return formatCustomSeparator(num, preset);\n\n\t// Нестандартный размер группы\n\treturn formatManualGroup(num, preset);\n}\n\n/**\n * Форматирование числа по предустановке.\n * Оптимизировано для 500+ вызовов: кеш Intl.NumberFormat + быстрый путь через format().\n *\n * Не использовать напрямую! Использовать `formatNumberAs*`\n */\nexport function formatNumber(value: unknown, presetOrName: string | NumberFormatPreset): string {\n\tif (typeof value === \"string\" && value.trim() === \"\") return \"0\";\n\n\tconst num = Number(value);\n\tif (!Number.isFinite(num)) return \"0\";\n\n\tconst preset = resolveNumberPreset(presetOrName);\n\n\t// Усечение без округления — Intl занимается только группировкой и разделителями\n\t// const truncated = truncateNumber(num, preset.decimals);\n\t// NOTE: 30.04.2026 выяснилось, что всё таки должно быть именно округление, а не усечение\n\n\tif (preset.compact) {\n\t\treturn formatCompactNumberValue({\n\t\t\tvalue: num,\n\t\t\tpreset,\n\t\t\toptions: preset.compact,\n\t\t\tformatPlainNumber\n\t\t});\n\t}\n\n\treturn formatPlainNumber(num, preset);\n}\n\n/**\n * Форматирование значения пресетом `integer` (0 знаков после запятой)\n */\nexport function formatNumberAsInteger(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.integer);\n}\n\n/**\n * Форматирование значения пресетом `currency` (0 знаков после запятой)\n */\nexport function formatNumberAsCurrency(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.currency);\n}\n\n/**\n * Форматирование значения пресетом `decimal` (1 знак после запятой)\n */\nexport function formatNumberAsDecimal(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal);\n}\n\n/**\n * Форматирование значения пресетом `decimal-2` (2 знака после запятой)\n */\nexport function formatNumberAsDecimal2(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal2);\n}\n\n/**\n * Форматирование значения пресетом `decimal-3` (3 знака после запятой)\n */\nexport function formatNumberAsDecimal3(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal3);\n}\n\n/**\n * Форматирование значения пресетом `percent` (2 знака после запятой)\n */\nexport function formatNumberAsPercent(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.percent);\n}\n\n/**\n * Форматирование значения пресетом `price` (0 знаков после запятой)\n */\nexport function formatNumberAsPrice(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.price);\n}\n\n/**\n * Форматирование значения пресетом `tonnage` (1 знак после запятой)\n */\nexport function formatNumberAsTonnage(value: unknown): string {\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.tonnage);\n}\n\n/**\n * Форматирование значения пресетом `integer` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsIntegerOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.integer);\n}\n\n/**\n * Форматирование значения пресетом `currency` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsCurrencyOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.currency);\n}\n\n/**\n * Форматирование значения пресетом `decimal` (1 знак после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimalOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal);\n}\n\n/**\n * Форматирование значения пресетом `decimal-2` (2 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimal2OrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal2);\n}\n\n/**\n * Форматирование значения пресетом `decimal-3` (3 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsDecimal3OrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.decimal3);\n}\n\n/**\n * Форматирование значения пресетом `percent` (2 знака после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsPercentOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.percent);\n}\n\n/**\n * Форматирование значения пресетом `price` (0 знаков после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsPriceOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.price);\n}\n\n/**\n * Форматирование значения пресетом `tonnage` (1 знак после запятой)\n *\n * Проверяет, если значение семантически эквивалентно нулю, то возвращается пустая строка.\n */\nexport function formatNumberAsTonnageOrEmpty(value: unknown): string {\n\tif (isZeroValue(value)) return \"\";\n\treturn formatNumber(value, DEFAULT_NUMBER_PRESET_NAMES.tonnage);\n}\n\n/** Очистить кеш Intl.NumberFormat */\nexport function clearFormatCache(): void {\n\tcache.clear();\n}\n","import { toFiniteNumber } from \"./number\";\nimport { stripInnerSpaces } from \"./strings\";\n\n/**\n * Нормализует ведущие нули у числового значения.\n *\n * Правило fixed:\n * - fixed === 0 / undefined / NaN / не finite -> ничего не делает, возвращает исходное значение\n * - fixed < 0 -> удаляет ведущие нули (только в целой части)\n * - fixed > 0 -> дополняет целую часть ведущими нулями до длины fixed\n *\n * Если value не является числом и не парсится в число — возвращается как есть.\n * Возвращаемый тип: если вход number -> number, если вход string -> string, иначе unknown.\n */\nexport function normalizeLeadingZeros(value: unknown, fixed?: number): unknown {\n\tconst n = typeof value === \"number\" ? value : Number(value);\n\tif (!Number.isFinite(n)) return value;\n\n\t// Работаем со строкой числа, но pad применяем только к целой части\n\tconst raw = String(n); // \"-12.3\" | \"12\" | \"0.5\"\n\n\tif (typeof fixed === \"number\" && fixed > 0) {\n\t\tlet i = 0;\n\t\tlet sign = \"\";\n\n\t\tconst c0 = raw.charCodeAt(0);\n\t\tif (c0 === 45 /*-*/ || c0 === 43 /*+*/) {\n\t\t\tsign = raw[0];\n\t\t\ti = 1;\n\t\t}\n\n\t\t// отделяем дробь\n\t\tconst dot = raw.indexOf(\".\", i);\n\t\tconst intEnd = dot === -1 ? raw.length : dot;\n\n\t\tlet intPart = raw.slice(i, intEnd);\n\t\tconst fracPart = dot === -1 ? \"\" : raw.slice(dot); // включая '.'\n\n\t\t// \".5\" -> \"0.5\" не бывает у String(number), но на всякий случай:\n\t\tif (!intPart) intPart = \"0\";\n\n\t\tconst len = intPart.length;\n\t\tif (len < fixed) {\n\t\t\tintPart = \"0\".repeat(fixed - len) + intPart;\n\t\t}\n\n\t\treturn sign + intPart + fracPart;\n\t}\n\n\treturn raw;\n}\n\n/**\n * Нормализует ведущие нули у числового значения.\n *\n * Использовать только если значения могут иметь нестандартное форматирование, например разделители групп и тд.\n *\n * Правило fixed:\n * - fixed === 0 / undefined / NaN / не finite -> ничего не делает, возвращает исходное значение\n * - fixed < 0 -> удаляет ведущие нули (только в целой части)\n * - fixed > 0 -> дополняет целую часть ведущими нулями до длины fixed\n *\n * Если value не является числом и не парсится в число — возвращается как есть.\n * Возвращаемый тип: если вход number -> number, если вход string -> string, иначе unknown.\n */\nexport function normalizeLeadingZerosStrict<T>(value: T, fixed?: number): T {\n\t// fixed не задан / 0 / не число / бесконечность => no-op\n\tif (!fixed || !Number.isFinite(fixed)) return value;\n\n\t// Быстрый путь для number\n\tif (typeof value === \"number\") {\n\t\tif (!Number.isFinite(value)) return value;\n\n\t\t// Для number делаем преобразование через строку.\n\t\t// Важно: у number ведущих нулей в обычном представлении нет,\n\t\t// поэтому fixed < 0 по факту ничего не меняет.\n\t\tconst out = normalizeStringNumber(String(value), fixed);\n\t\t// Пытаемся вернуть number обратно, чтобы не ломать типы/ожидания.\n\t\tconst n = Number(out);\n\t\treturn Number.isFinite(n) ? (n as unknown as T) : value;\n\t}\n\n\t// Основной путь для строк\n\tif (typeof value === \"string\") {\n\t\t// Быстрая проверка «похоже ли на число»: если вообще нет цифр — не парсим.\n\t\t// (Чуть ускоряет кейсы с произвольными строками).\n\t\tlet hasDigit = false;\n\t\tfor (let i = 0; i < value.length; i++) {\n\t\t\tconst c = value.charCodeAt(i);\n\t\t\tif (c >= 48 && c <= 57) {\n\t\t\t\thasDigit = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!hasDigit) return value;\n\n\t\t// Проверка, что строка реально парсится в число.\n\t\t// Поддержка \"SAP-like\": пробелы и NBSP как группировка, ',' как десятичный.\n\t\tconst parsed = toFiniteNumber(value);\n\t\tif (parsed === undefined) return value;\n\n\t\tconst out = normalizeStringNumber(value, fixed);\n\t\treturn out as unknown as T;\n\t}\n\n\t// Для остальных типов — не трогаем\n\treturn value;\n}\n\n/**\n * Нормализация для строкового представления числа.\n * Работает только с целой частью (до '.' или ',').\n */\nfunction normalizeStringNumber(input: string, fixed: number): string {\n\tconst s = input.trim();\n\tif (!s) return input;\n\n\t// Знак\n\tlet i = 0;\n\tlet sign = \"\";\n\tconst first = s.charCodeAt(0);\n\tif (first === 45 /* - */ || first === 43 /* + */) {\n\t\tsign = s[0];\n\t\ti = 1;\n\t}\n\n\t// Найдём позицию десятичного разделителя ('.' или ',') — берём первый найденный.\n\t// Нули нормализуем только в целой части.\n\tlet dot = -1;\n\tfor (let k = i; k < s.length; k++) {\n\t\tconst ch = s.charCodeAt(k);\n\t\tif (ch === 46 /* . */ || ch === 44 /* , */) {\n\t\t\tdot = k;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tconst intEnd = dot === -1 ? s.length : dot;\n\tconst frac = dot === -1 ? \"\" : s.slice(dot); // включая разделитель и дробную часть\n\n\t// Выделим целую часть (без знака)\n\tlet intPart = s.slice(i, intEnd);\n\n\t// Уберём пробелы/неразрывные пробелы внутри (SAP-like grouping), чтобы не мешали.\n\t// Делается без regex, чтобы быть дешевле при массовых вызовах.\n\tintPart = stripInnerSpaces(intPart);\n\n\t// Если целая часть пустая (\".5\") — считаем как \"0\"\n\tif (intPart.length === 0) intPart = \"0\";\n\n\tconst target = fixed | 0; // быстрый int\n\tif (target <= 0) {\n\t\t// Trim leading zeros\n\t\tlet p = 0;\n\t\twhile (p < intPart.length && intPart.charCodeAt(p) === 48 /* '0' */) p++;\n\n\t\t// Если всё было нулями — оставляем один ноль\n\t\tintPart = p === intPart.length ? \"0\" : intPart.slice(p);\n\t} else {\n\t\tif (target > 0) {\n\t\t\tconst len = intPart.length;\n\t\t\tif (len < target) {\n\t\t\t\t// Быстрое дополняние без padStart (чуть меньше накладных расходов)\n\t\t\t\tintPart = \"0\".repeat(target - len) + intPart;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn sign + intPart + frac;\n}\n","import type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineGraph,\n\tFormattersPipelineNode,\n\tFormattersPipelineNormalizeLeadingZerosConfig,\n\tFormattersPipelinePlan,\n\tFormattersPipelineResolveValueStateConfig,\n\tFormattersPipelineRowBasedOverrideConfig,\n\tFormattersPipelineStep,\n\tFormattersPipelineTypedValueFormatConfig\n} from \"./types\";\n\nexport function cloneTypedValueFormatConfig(\n\tconfig: FormattersPipelineTypedValueFormatConfig | undefined\n): FormattersPipelineTypedValueFormatConfig | undefined {\n\treturn config ? { ...config } : undefined;\n}\n\nexport function cloneNormalizeLeadingZerosConfig(\n\tconfig: FormattersPipelineNormalizeLeadingZerosConfig | undefined\n): FormattersPipelineNormalizeLeadingZerosConfig | undefined {\n\treturn config ? { ...config } : undefined;\n}\n\nexport function cloneRowBasedOverrideConfig(config: FormattersPipelineRowBasedOverrideConfig): FormattersPipelineRowBasedOverrideConfig {\n\treturn config.mode === \"formula\"\n\t\t? { ...config, dependencyIds: config.dependencyIds ? [...config.dependencyIds] : undefined }\n\t\t: { ...config };\n}\n\nexport function cloneResolveValueStateConfig(config: FormattersPipelineResolveValueStateConfig): FormattersPipelineResolveValueStateConfig {\n\treturn {\n\t\tresolver:\n\t\t\tconfig.resolver.kind === \"fixed\"\n\t\t\t\t? {\n\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\tentries: { ...config.resolver.entries },\n\t\t\t\t\t\tfallbackState: config.resolver.fallbackState\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\tthresholds: config.resolver.thresholds.map((item) => (typeof item === \"number\" ? item : { ...item })),\n\t\t\t\t\t\tstates: [...config.resolver.states],\n\t\t\t\t\t\tinvalidState: config.resolver.invalidState\n\t\t\t\t\t},\n\t\ticon: config.icon ? { ...config.icon } : undefined\n\t};\n}\n\nexport function cloneFormatterPipelinePlanStep(step: FormattersPipelineStep): FormattersPipelineStep {\n\tswitch (step.type) {\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneTypedValueFormatConfig(step.config)\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneNormalizeLeadingZerosConfig(step.config)\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneRowBasedOverrideConfig(step.config)\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tconfig: cloneResolveValueStateConfig(step.config)\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst checker: never = step;\n\t\t\tvoid checker;\n\t\t}\n\t}\n\n\tthrow new Error(`Недопустимый тип '${(step as Record<string, unknown>)?.type}' для шага FormatterPipeline`);\n}\n\nexport function cloneFormatterPipelinePlanStepToNode(\n\tstep: FormattersPipelineStep,\n\tposition: { x: number; y: number }\n): FormattersPipelineNode {\n\tswitch (step.type) {\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneTypedValueFormatConfig(step.config)\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneNormalizeLeadingZerosConfig(step.config)\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneRowBasedOverrideConfig(step.config)\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...step,\n\t\t\t\tposition: { ...position },\n\t\t\t\tconfig: cloneResolveValueStateConfig(step.config)\n\t\t\t};\n\t\tdefault: {\n\t\t\tconst checker: never = step;\n\t\t\tvoid checker;\n\t\t}\n\t}\n\n\tthrow new Error(`Недопустимый тип '${(step as Record<string, unknown>)?.type}' для шага FormatterPipeline`);\n}\n\nfunction cloneNode(node: FormattersPipelineNode): FormattersPipelineNode {\n\tswitch (node.type) {\n\t\tcase \"source\":\n\t\tcase \"sink\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tposition: { ...node.position }\n\t\t\t};\n\t\tdefault:\n\t\t\treturn cloneFormatterPipelinePlanStepToNode(node, node.position);\n\t}\n}\n\nfunction cloneGraph(graph: FormattersPipelineGraph): FormattersPipelineGraph {\n\treturn {\n\t\tnodes: graph.nodes.map(cloneNode),\n\t\tedges: graph.edges.map((edge) => ({ ...edge })),\n\t\tviewport: graph.viewport ? { ...graph.viewport } : undefined\n\t};\n}\n\nfunction clonePlan(plan: FormattersPipelinePlan): FormattersPipelinePlan {\n\treturn {\n\t\tsteps: plan.steps.map(cloneFormatterPipelinePlanStep)\n\t};\n}\n\n/**\n * Возвращает полную копию конфигурации pipeline для безопасного хранения в сторе.\n */\nexport function cloneFormattersPipelineConfig(config: FormattersPipelineConfig | undefined): FormattersPipelineConfig | undefined {\n\tif (!config) return undefined;\n\n\tconst version = config.version;\n\tconst graph = config.graph ? cloneGraph(config.graph) : undefined;\n\tconst plan = config.plan ? clonePlan(config.plan) : undefined;\n\n\treturn { version, graph, plan };\n}\n","import { addUnique } from \"../../array\";\n\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nimport type { FormattersPipelineConfig } from \"./types\";\n\n/**\n * Минимальный контракт поля, достаточный для сбора runtime-зависимостей.\n *\n * Контракт не привязан к view-config, analytical-table или detail-table:\n * любая зона может передать свой объект, если он содержит эти optional-поля.\n */\nexport type RuntimeDependencyField = {\n\tformattersPipeline?: FormattersPipelineConfig;\n\tcellRenderer?: {\n\t\tbindings?: Readonly<Record<string, string | undefined>>;\n\t};\n};\n\n/**\n * План дополнительных полей, которые нужны runtime-логике отображения.\n */\nexport type RuntimeFieldDependenciesPlan = {\n\t/** Поля, которые нужно добавить в query для formatter pipeline или renderer bindings. */\n\trequiredColumnIds: string[];\n\t/** Зависимости, указанные в настройках, но отсутствующие в справочнике полей. */\n\tmissingColumnIds: string[];\n};\n\n/**\n * Собирает только зависимости, объявленные внутри formatter pipeline.\n *\n * Pipeline не проверяет наличие этих полей в конкретной таблице или графике:\n * это ответственность потребителя, который знает свой полный набор полей.\n */\nexport function collectFormattersPipelineDependencyIds(config: FormattersPipelineConfig | undefined): string[] {\n\tconst validation = validateFormattersPipelineConfig(config);\n\tif (!validation.ok || !validation.plan) return [];\n\n\tconst dependencyIds: string[] = [];\n\tconst seen = new Set<string>();\n\n\tfor (const step of validation.plan.steps) {\n\t\tif (step.type !== \"rowBasedOverride\") continue;\n\n\t\tif (step.config.mode === \"field\") {\n\t\t\taddUnique(dependencyIds, seen, step.config.fieldKey);\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const dependencyId of step.config.dependencyIds ?? []) {\n\t\t\taddUnique(dependencyIds, seen, dependencyId);\n\t\t}\n\t}\n\n\treturn dependencyIds;\n}\n\n/**\n * Собирает runtime-зависимости отображения для набора полей.\n *\n * Учитывает:\n * - binding-поля renderer-а;\n * - field/dependency поля formatter-а `rowBasedOverride`.\n */\nexport function collectRuntimeFieldDependencyIds<TField extends RuntimeDependencyField>(\n\tfieldIds: readonly string[],\n\tfieldsById: Readonly<Record<string, TField | undefined>>\n): RuntimeFieldDependenciesPlan {\n\tconst requiredColumnIds: string[] = [];\n\tconst missingColumnIds: string[] = [];\n\tconst seenRequired = new Set<string>();\n\tconst seenMissing = new Set<string>();\n\n\tconst addDependency = (fieldId: string | undefined) => {\n\t\tconst normalizedId = fieldId?.trim();\n\t\tif (!normalizedId) return;\n\n\t\tif (!fieldsById[normalizedId]) {\n\t\t\taddUnique(missingColumnIds, seenMissing, normalizedId);\n\t\t\treturn;\n\t\t}\n\n\t\taddUnique(requiredColumnIds, seenRequired, normalizedId);\n\t};\n\n\tfor (const fieldId of fieldIds) {\n\t\tconst field = fieldsById[fieldId];\n\t\tif (!field) continue;\n\n\t\tfor (const bindingFieldId of Object.values(field.cellRenderer?.bindings ?? {})) {\n\t\t\taddDependency(bindingFieldId);\n\t\t}\n\n\t\tfor (const dependencyId of collectFormattersPipelineDependencyIds(field.formattersPipeline)) {\n\t\t\taddDependency(dependencyId);\n\t\t}\n\t}\n\n\treturn { requiredColumnIds, missingColumnIds };\n}\n","import { State } from \"../../types\";\n\nimport { ValueStateResolver } from \"./types\";\n\n/** Реестр: id → скомпилированная функция-резолвер */\nconst resolverRegistry = new Map<string, ValueStateResolver>();\n\n/** Обратный индекс: каноническая строка конфигурации → id (дедупликация) */\nconst configToIdIndex = new Map<string, string>();\n\n/**\n * Вычислить короткий хеш из строки (djb2 → base36).\n * Результат — строка вида `\"id_1a2b3c4\"`.\n */\nexport function computeShortHash(input: string): string {\n\tlet hash = 5381;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash = ((hash << 5) + hash + input.charCodeAt(i)) >>> 0;\n\t}\n\treturn \"id_\" + hash.toString(36);\n}\n\n/**\n * Зарегистрировать резолвер в общем реестре.\n * Если конфигурация с таким каноническим ключом уже есть — вернуть существующий id.\n * Возвращает `{ id, isNew }`.\n */\nexport function registerResolver(canonicalKey: string, compileFunction: () => ValueStateResolver): { id: string; isNew: boolean } {\n\tconst existingId = configToIdIndex.get(canonicalKey);\n\tif (existingId) return { id: existingId, isNew: false };\n\n\tconst id = computeShortHash(canonicalKey);\n\tconst resolver = compileFunction();\n\n\tresolverRegistry.set(id, resolver);\n\tconfigToIdIndex.set(canonicalKey, id);\n\n\treturn { id, isNew: true };\n}\n\n/**\n * Найти существующий резолвер по каноническому ключу.\n * Возвращает `undefined`, если не найден.\n */\nexport function findResolverByCanonicalKey(canonicalKey: string): ValueStateResolver | undefined {\n\tconst id = configToIdIndex.get(canonicalKey);\n\tif (!id) return undefined;\n\treturn resolverRegistry.get(id);\n}\n\n/**\n * Применить зарегистрированный резолвер к значению.\n * Если резолвер с указанным `id` не найден — возвращает `\"none\"`.\n *\n * @example\n * ```ts\n * resolveValueState(\"v_1a2b3c4\", 75); // → \"success\"\n * ```\n */\nexport function resolveValueState(id: string, value: unknown): State {\n\tconst resolver = resolverRegistry.get(id);\n\tif (!resolver) return \"none\";\n\treturn resolver(value);\n}\n\n/**\n * Получить функцию-резолвер по `id`.\n * Возвращает `undefined`, если резолвер не зарегистрирован.\n */\nexport function getValueStateResolver(id: string): ValueStateResolver | undefined {\n\treturn resolverRegistry.get(id);\n}\n\n/**\n * Получить список всех зарегистрированных id.\n */\nexport function getValueStateResolverIds(): string[] {\n\treturn Array.from(resolverRegistry.keys());\n}\n\n/**\n * Полная очистка реестра. Предназначена для тестов.\n */\nexport function resetValueStateResolvers(): void {\n\tresolverRegistry.clear();\n\tconfigToIdIndex.clear();\n}\n","import { compareStrings } from \"../../string-comparison\";\nimport { State } from \"../../types\";\n\nimport { FixedValueStateResolverConfig, ValueStateResolver } from \"./types\";\nimport { findResolverByCanonicalKey, registerResolver } from \"./valueStateRegistry\";\n\n/** Создать каноническую строку конфигурации (с префиксом типа для изоляции от пороговых резолверов) */\nfunction createCanonicalKey(sortedEntries: [string, State][], fallbackState: State): string {\n\tconst entriesPart = sortedEntries.map(([key, state]) => `${key}:${state}`).join(\",\");\n\treturn `fixed|${entriesPart}|${fallbackState}`;\n}\n\n/** Скомпилировать функцию-резолвер из маппинга */\nfunction compileFixedResolver(entries: Record<string, State>, fallbackState: State): ValueStateResolver {\n\tconst lookup = new Map<string, State>(Object.entries(entries));\n\n\treturn (value: unknown): State => {\n\t\tif (value === null || value === undefined) return fallbackState;\n\n\t\tconst key = String(value);\n\t\treturn lookup.get(key) ?? fallbackState;\n\t};\n}\n\n/** Нормализовать конфигурацию и вернуть подготовленные данные */\nfunction prepareConfig(config: FixedValueStateResolverConfig) {\n\tconst fallbackState: State = config.fallbackState ?? \"none\";\n\n\t// Сортировка ключей для детерминированного канонического ключа\n\tconst sortedEntries = Object.entries(config.entries).sort(([a], [b]) => compareStrings(a, b)) as [string, State][];\n\n\tconst canonicalKey = createCanonicalKey(sortedEntries, fallbackState);\n\n\treturn { entries: config.entries, fallbackState, canonicalKey };\n}\n\n/**\n * Зарегистрировать фиксированный резолвер из конфигурации.\n * Возвращает короткий уникальный `id`.\n *\n * Фиксированный резолвер определяет State по точному совпадению значения ячейки\n * со значениями из маппинга `entries`.\n *\n * @example\n * ```ts\n * const id = registerFixedResolver({\n * entries: {\n * \"01\": \"success\",\n * \"02\": \"warning\",\n * \"03\": \"error\",\n * },\n * fallbackState: \"none\",\n * });\n *\n * // В ячейке: resolveValueState(id, cellValue)\n * ```\n */\nexport function registerFixedResolver(config: FixedValueStateResolverConfig): string {\n\tconst { entries, fallbackState, canonicalKey } = prepareConfig(config);\n\n\tconst { id } = registerResolver(canonicalKey, () => compileFixedResolver(entries, fallbackState));\n\n\treturn id;\n}\n\n/**\n * Создать фиксированный резолвер напрямую.\n * Резолвер регистрируется в общем реестре.\n * Идентичные конфигурации возвращают одну и ту же функцию.\n *\n * @example\n * ```ts\n * const resolve = createFixedResolver({\n * entries: { \"01\": \"success\", \"02\": \"warning\", \"03\": \"error\" },\n * });\n *\n * resolve(\"01\"); // → \"success\"\n * resolve(\"02\"); // → \"warning\"\n * resolve(\"99\"); // → \"none\" (fallback)\n * ```\n */\nexport function createFixedResolver(config: FixedValueStateResolverConfig): ValueStateResolver {\n\tconst { entries, fallbackState, canonicalKey } = prepareConfig(config);\n\n\tconst existing = findResolverByCanonicalKey(canonicalKey);\n\tif (existing) return existing;\n\n\tregisterResolver(canonicalKey, () => compileFixedResolver(entries, fallbackState));\n\n\treturn findResolverByCanonicalKey(canonicalKey)!;\n}\n","import { State } from \"../../types\";\n\nimport { ThresholdBoundary, ThresholdDefinition, ThresholdValueStateResolverConfig, ValueStateResolver } from \"./types\";\nimport { findResolverByCanonicalKey, registerResolver } from \"./valueStateRegistry\";\n\n/**\n * Нормализованный порог (внутренний тип)\n */\ninterface NormalizedThreshold {\n\tvalue: number;\n\tboundary: ThresholdBoundary;\n}\n\n/** Нормализовать порог: число → объект с boundary по умолчанию */\nfunction normalizeThreshold(threshold: number | ThresholdDefinition): NormalizedThreshold {\n\tif (typeof threshold === \"number\") {\n\t\treturn { value: threshold, boundary: \"upper\" };\n\t}\n\treturn { value: threshold.value, boundary: threshold.boundary ?? \"upper\" };\n}\n\n/** Создать каноническую строку конфигурации (с префиксом типа для изоляции от других резолверов) */\nfunction createCanonicalKey(sortedThresholds: NormalizedThreshold[], states: State[], invalidState: State): string {\n\tconst thresholdsPart = sortedThresholds.map((t) => `${t.value}:${t.boundary}`).join(\",\");\n\treturn `threshold|${thresholdsPart}|${states.join(\",\")}|${invalidState}`;\n}\n\n/** Валидация конфигурации */\nfunction validateConfig(thresholds: NormalizedThreshold[], states: State[]): void {\n\tif (states.length !== thresholds.length + 1) {\n\t\tthrow new Error(`Количество состояний (${states.length}) должно быть равно количеству порогов + 1 (${thresholds.length + 1})`);\n\t}\n\n\tconst seen = new Set<number>();\n\tfor (const threshold of thresholds) {\n\t\tif (seen.has(threshold.value)) {\n\t\t\tconsole.warn(`Дублирующееся пороговое значение: ${threshold.value}`);\n\t\t}\n\t\tseen.add(threshold.value);\n\t}\n}\n\n/** Скомпилировать функцию-резолвер из нормализованных данных */\nfunction compileThresholdResolver(sortedThresholds: NormalizedThreshold[], configStates: State[], invalidState: State): ValueStateResolver {\n\tconst thresholdValues = sortedThresholds.map((t) => t.value);\n\tconst thresholdIsLower = sortedThresholds.map((t) => t.boundary === \"lower\");\n\tconst states = [...configStates];\n\n\treturn (value: unknown): State => {\n\t\tif (value === \"\" || value === null || value === undefined) return invalidState;\n\n\t\tconst numericValue = +(value as number);\n\n\t\tif (!Number.isFinite(numericValue)) return invalidState;\n\n\t\tfor (let i = 0; i < thresholdValues.length; i++) {\n\t\t\tconst belongsToLowerSegment = thresholdIsLower[i] ? numericValue <= thresholdValues[i] : numericValue < thresholdValues[i];\n\n\t\t\tif (belongsToLowerSegment) return states[i];\n\t\t}\n\n\t\treturn states[states.length - 1];\n\t};\n}\n\n/** Нормализовать конфигурацию и вернуть подготовленные данные */\nfunction prepareConfig(config: ThresholdValueStateResolverConfig) {\n\tconst invalidState: State = config.invalidState ?? \"none\";\n\tconst sortedThresholds = config.thresholds.map(normalizeThreshold).sort((a, b) => a.value - b.value);\n\n\tvalidateConfig(sortedThresholds, config.states);\n\n\tconst canonicalKey = createCanonicalKey(sortedThresholds, config.states, invalidState);\n\n\treturn { sortedThresholds, invalidState, canonicalKey, states: config.states };\n}\n\n/**\n * Зарегистрировать пороговый резолвер из конфигурации.\n * Возвращает короткий уникальный `id` для использования в столбцах таблицы.\n *\n * Идентичные конфигурации (даже с разным порядком порогов)\n * возвращают один и тот же `id` — функция дедуплицирует по содержимому.\n *\n * @example\n * ```ts\n * const id = registerThresholdResolver({\n * thresholds: [60, 95],\n * states: [\"warning\", \"success\", \"error\"],\n * });\n * // id → \"v_1a2b3c4\"\n *\n * // В ячейке: resolveValueState(id, cellValue)\n * ```\n */\nexport function registerThresholdResolver(config: ThresholdValueStateResolverConfig): string {\n\tconst { sortedThresholds, invalidState, canonicalKey, states } = prepareConfig(config);\n\n\tconst { id } = registerResolver(canonicalKey, () => compileThresholdResolver(sortedThresholds, states, invalidState));\n\n\treturn id;\n}\n\n/**\n * Создать функцию-резолвер напрямую.\n * Резолвер регистрируется в общем реестре.\n * Идентичные конфигурации возвращают одну и ту же функцию.\n *\n * @example\n * ```ts\n * const resolve = createThresholdResolver({\n * thresholds: [60, 95],\n * states: [\"warning\", \"success\", \"error\"],\n * });\n *\n * resolve(45); // → \"warning\"\n * resolve(75); // → \"success\"\n * resolve(100); // → \"error\"\n * resolve(\"abc\"); // → \"none\"\n * ```\n */\nexport function createThresholdResolver(config: ThresholdValueStateResolverConfig): ValueStateResolver {\n\tconst { sortedThresholds, invalidState, canonicalKey, states } = prepareConfig(config);\n\n\tconst existing = findResolverByCanonicalKey(canonicalKey);\n\tif (existing) return existing;\n\n\tregisterResolver(canonicalKey, () => compileThresholdResolver(sortedThresholds, states, invalidState));\n\n\treturn findResolverByCanonicalKey(canonicalKey)!;\n}\n","import { getBaseTypeFromODataType } from \"../../odata-service\";\nimport { isSafe } from \"../../validators\";\nimport { formatDate, getDatePreset, parseDate } from \"../date\";\nimport { normalizeLeadingZeros } from \"../normalizeLeadingZeros\";\nimport { formatNumber, getNumberPreset } from \"../number\";\nimport { createRowBasedFormatterContext, getRowBasedFormatterById } from \"../rowBased\";\nimport { toSafeString } from \"../strings\";\nimport { registerFixedResolver } from \"../valueState/fixedValueStateResolver\";\nimport { registerThresholdResolver } from \"../valueState/thresholdValueStateResolver\";\nimport { resolveValueState } from \"../valueState/valueStateRegistry\";\n\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nimport type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineExecutionContext,\n\tFormattersPipelineExecutionResult,\n\tFormattersPipelineExecutor,\n\tFormattersPipelineTypedValueContext,\n\tFormattersPipelineTypedValueFormatConfig,\n\tFormattersPipelineValueIcon\n} from \"./types\";\n\ntype CompileFormattersPipelineExecutorResult =\n\t| {\n\t\t\tok: true;\n\t\t\texecutor: FormattersPipelineExecutor;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\treason: \"pipeline_invalid\" | \"row_based_formula_not_found\";\n\t };\n\nconst DEFAULT_TYPED_VALUE_FORMAT_PRESETS = Object.freeze({\n\tnumber: \"decimal\",\n\tdate: \"date\"\n});\n\n/**\n * Выполняет типизированное форматирование по метаданным колонки.\n */\nexport function formatTypedCellValue(\n\tvalue: unknown,\n\tcolumn: FormattersPipelineTypedValueContext,\n\tconfig?: FormattersPipelineTypedValueFormatConfig\n): string {\n\tif (!isSafe(value)) return \"\";\n\n\tconst baseType = getBaseTypeFromODataType(column.type);\n\n\tif (baseType === \"number\") {\n\t\tconst normalizedPresetName = config?.numberPresetName?.trim();\n\t\tconst presetName =\n\t\t\tnormalizedPresetName && getNumberPreset(normalizedPresetName)\n\t\t\t\t? normalizedPresetName\n\t\t\t\t: DEFAULT_TYPED_VALUE_FORMAT_PRESETS.number;\n\t\treturn formatNumber(value, presetName);\n\t}\n\n\tif (baseType === \"date\") {\n\t\tconst normalizedPresetName = config?.datePresetName?.trim();\n\t\tconst presetName =\n\t\t\tnormalizedPresetName && getDatePreset(normalizedPresetName) ? normalizedPresetName : DEFAULT_TYPED_VALUE_FORMAT_PRESETS.date;\n\t\treturn formatDate(parseDate(value), presetName);\n\t}\n\n\treturn toSafeString(value);\n}\n\nfunction resolveIconState(value: string): FormattersPipelineValueIcon | undefined {\n\tif (value === \"success\" || value === \"warning\" || value === \"error\" || value === \"information\") {\n\t\treturn value;\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Определяет, должен ли `rowBasedOverride` применяться для текущего типа строки.\n *\n * Семантика:\n * - `group` — historical analytical group-row;\n * - `totals` — применяется только formula-режим;\n * - `plain`/`tree` — generic row-based override.\n */\nfunction shouldApplyRowBasedOverride(ctx: FormattersPipelineExecutionContext, mode: \"field\" | \"formula\"): boolean {\n\tswitch (ctx.rowKind) {\n\t\tcase \"group\":\n\t\tcase \"plain\":\n\t\tcase \"tree\":\n\t\t\treturn true;\n\t\tcase \"totals\":\n\t\t\treturn mode === \"formula\";\n\t}\n}\n\n/**\n * Компилирует pipeline форматтеров колонки в runtime executor.\n */\nexport function compileFormattersPipelineExecutor(args: {\n\tconfig: FormattersPipelineConfig | undefined;\n\tcolumn: FormattersPipelineTypedValueContext;\n}): CompileFormattersPipelineExecutorResult {\n\tconst validation = validateFormattersPipelineConfig(args.config);\n\tif (!validation.ok || !validation.plan) {\n\t\tif (validation.errors.some((error) => error.code === \"step_row_based_override_formula_not_found\")) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"row_based_formula_not_found\"\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"pipeline_invalid\"\n\t\t};\n\t}\n\n\tconst { steps } = validation.plan;\n\tconst hasRowBasedOverride = steps.some((step) => step.type === \"rowBasedOverride\");\n\tconst hasTypedValueFormat = steps.some((step) => step.type === \"typedValueFormat\");\n\n\tconst valueStateStep = steps.find((step) => step.type === \"resolveValueState\");\n\tconst valueStateResolverId =\n\t\tvalueStateStep?.config.resolver.kind === \"fixed\"\n\t\t\t? registerFixedResolver({\n\t\t\t\t\tentries: valueStateStep.config.resolver.entries,\n\t\t\t\t\tfallbackState: valueStateStep.config.resolver.fallbackState\n\t\t\t\t})\n\t\t\t: valueStateStep?.config.resolver.kind === \"threshold\"\n\t\t\t\t? registerThresholdResolver({\n\t\t\t\t\t\tthresholds: valueStateStep.config.resolver.thresholds,\n\t\t\t\t\t\tstates: valueStateStep.config.resolver.states,\n\t\t\t\t\t\tinvalidState: valueStateStep.config.resolver.invalidState\n\t\t\t\t\t})\n\t\t\t\t: undefined;\n\n\tconst rowBasedOverrideStep = steps.find((step) => step.type === \"rowBasedOverride\");\n\tconst rowBasedFormula =\n\t\trowBasedOverrideStep?.config.mode === \"formula\" ? getRowBasedFormatterById(rowBasedOverrideStep.config.formulaId) : undefined;\n\tif (rowBasedOverrideStep?.config.mode === \"formula\" && !rowBasedFormula) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\treason: \"row_based_formula_not_found\"\n\t\t};\n\t}\n\n\treturn {\n\t\tok: true,\n\t\texecutor: {\n\t\t\thasRowBasedOverride,\n\t\t\thasTypedValueFormat,\n\t\t\texecute: (ctx: FormattersPipelineExecutionContext): FormattersPipelineExecutionResult => {\n\t\t\t\tlet nextValue = ctx.value;\n\t\t\t\tlet nextState: FormattersPipelineExecutionResult[\"state\"] = \"none\";\n\t\t\t\tlet showIcon = false;\n\t\t\t\tlet showValue = true;\n\t\t\t\tlet iconPosition: FormattersPipelineExecutionResult[\"iconPosition\"] = \"left\";\n\t\t\t\tlet icon: FormattersPipelineExecutionResult[\"icon\"] = undefined;\n\n\t\t\t\tfor (const step of steps) {\n\t\t\t\t\tswitch (step.type) {\n\t\t\t\t\t\tcase \"normalizeLeadingZeros\":\n\t\t\t\t\t\t\tnextValue = normalizeLeadingZeros(nextValue, step.config?.fixed);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"rowBasedOverride\":\n\t\t\t\t\t\t\tif (!shouldApplyRowBasedOverride(ctx, step.config.mode)) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (step.config.mode === \"field\") {\n\t\t\t\t\t\t\t\tconst fieldValue = ctx.rowData[step.config.fieldKey];\n\t\t\t\t\t\t\t\tif (fieldValue == null && step.config.fallbackToRaw !== false) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tnextValue = fieldValue;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!rowBasedFormula) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tconst formulaValue = rowBasedFormula.fn(\n\t\t\t\t\t\t\t\t\tcreateRowBasedFormatterContext({\n\t\t\t\t\t\t\t\t\t\trowData: ctx.rowData,\n\t\t\t\t\t\t\t\t\t\trawValue: nextValue,\n\t\t\t\t\t\t\t\t\t\tcolumnId: ctx.columnId,\n\t\t\t\t\t\t\t\t\t\tkeys: step.config.dependencyIds\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tif (formulaValue == null && step.config.fallbackToRaw !== false) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tnextValue = formulaValue;\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\tif (step.config.fallbackToRaw === false) {\n\t\t\t\t\t\t\t\t\tnextValue = undefined;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"resolveValueState\":\n\t\t\t\t\t\t\tif (!valueStateResolverId) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tnextState = resolveValueState(valueStateResolverId, nextValue);\n\t\t\t\t\t\t\tshowIcon = step.config.icon?.enabled ?? false;\n\t\t\t\t\t\t\tshowValue = step.config.icon?.showValue ?? true;\n\t\t\t\t\t\t\ticonPosition = step.config.icon?.position ?? \"left\";\n\t\t\t\t\t\t\ticon = showIcon ? resolveIconState(nextState) : undefined;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"typedValueFormat\":\n\t\t\t\t\t\t\tnextValue = formatTypedCellValue(nextValue, args.column, step.config);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tvalue: nextValue,\n\t\t\t\t\tstate: nextState,\n\t\t\t\t\ticon,\n\t\t\t\t\tshowIcon,\n\t\t\t\t\tshowValue,\n\t\t\t\t\ticonPosition,\n\t\t\t\t\thasTypedValueFormat\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t};\n}\n","import { type State } from \"../../types\";\nimport { isRecord } from \"../../validators/isRecord\";\n\nimport { cloneFormattersPipelineConfig } from \"./clone\";\nimport {\n\ttype FormattersPipelineConfig,\n\ttype FormattersPipelineEdge,\n\ttype FormattersPipelineGraph,\n\ttype FormattersPipelineNode,\n\ttype FormattersPipelinePlan,\n\ttype FormattersPipelineResolveValueStateConfig,\n\ttype FormattersPipelineRowBasedOverrideConfig,\n\ttype FormattersPipelineStep,\n\ttype FormattersPipelineTypedValueFormatConfig\n} from \"./types\";\nimport { validateFormattersPipelineConfig } from \"./validate\";\n\nconst VALUE_STATES: readonly State[] = [\"\", \"none\", \"information\", \"success\", \"warning\", \"error\"];\n\nfunction isState(value: unknown): value is State {\n\treturn typeof value === \"string\" && VALUE_STATES.some((state) => state === value);\n}\n\nfunction isOptionalBoolean(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"boolean\";\n}\n\nfunction isOptionalString(value: unknown): boolean {\n\treturn value === undefined || typeof value === \"string\";\n}\n\nfunction isTypedValueFormatConfig(value: unknown): value is FormattersPipelineTypedValueFormatConfig {\n\tif (value === undefined) return true;\n\tif (!isRecord(value)) return false;\n\n\treturn isOptionalString(value.numberPresetName) && isOptionalString(value.datePresetName);\n}\n\nfunction isRowBasedOverrideConfig(value: unknown): value is FormattersPipelineRowBasedOverrideConfig {\n\tif (!isRecord(value)) return false;\n\n\tif (value.mode === \"field\") {\n\t\treturn typeof value.fieldKey === \"string\" && isOptionalBoolean(value.fallbackToRaw);\n\t}\n\n\tif (value.mode === \"formula\") {\n\t\treturn (\n\t\t\ttypeof value.formulaId === \"string\" &&\n\t\t\t(value.dependencyIds === undefined ||\n\t\t\t\t(Array.isArray(value.dependencyIds) && value.dependencyIds.every((dependencyId) => typeof dependencyId === \"string\"))) &&\n\t\t\tisOptionalBoolean(value.fallbackToRaw)\n\t\t);\n\t}\n\n\treturn false;\n}\n\nfunction isThresholdDefinition(value: unknown): boolean {\n\treturn (\n\t\ttypeof value === \"number\" ||\n\t\t(isRecord(value) &&\n\t\t\ttypeof value.value === \"number\" &&\n\t\t\t(value.boundary === undefined || value.boundary === \"lower\" || value.boundary === \"upper\"))\n\t);\n}\n\nfunction isResolveValueStateConfig(value: unknown): value is FormattersPipelineResolveValueStateConfig {\n\tif (!isRecord(value) || !isRecord(value.resolver)) return false;\n\n\tconst { resolver, icon } = value;\n\tconst hasValidIcon =\n\t\ticon === undefined ||\n\t\t(isRecord(icon) &&\n\t\t\tisOptionalBoolean(icon.enabled) &&\n\t\t\tisOptionalBoolean(icon.showValue) &&\n\t\t\t(icon.position === undefined || icon.position === \"left\" || icon.position === \"right\"));\n\n\tif (!hasValidIcon) return false;\n\n\tif (resolver.kind === \"fixed\") {\n\t\treturn (\n\t\t\tisRecord(resolver.entries) &&\n\t\t\tObject.values(resolver.entries).every(isState) &&\n\t\t\t(resolver.fallbackState === undefined || isState(resolver.fallbackState))\n\t\t);\n\t}\n\n\tif (resolver.kind === \"threshold\") {\n\t\treturn (\n\t\t\tArray.isArray(resolver.thresholds) &&\n\t\t\tresolver.thresholds.every(isThresholdDefinition) &&\n\t\t\tArray.isArray(resolver.states) &&\n\t\t\tresolver.states.every(isState) &&\n\t\t\t(resolver.invalidState === undefined || isState(resolver.invalidState))\n\t\t);\n\t}\n\n\treturn false;\n}\n\nfunction isPipelineStep(value: unknown): value is FormattersPipelineStep {\n\tif (!isRecord(value) || typeof value.id !== \"string\") return false;\n\n\tif (value.type === \"normalizeLeadingZeros\") {\n\t\treturn (\n\t\t\tvalue.config === undefined ||\n\t\t\t(isRecord(value.config) && (value.config.fixed === undefined || typeof value.config.fixed === \"number\"))\n\t\t);\n\t}\n\n\tif (value.type === \"rowBasedOverride\") {\n\t\treturn isRowBasedOverrideConfig(value.config);\n\t}\n\n\tif (value.type === \"resolveValueState\") {\n\t\treturn isResolveValueStateConfig(value.config);\n\t}\n\n\tif (value.type === \"typedValueFormat\") {\n\t\treturn isTypedValueFormatConfig(value.config);\n\t}\n\n\treturn false;\n}\n\nfunction isPipelinePlan(value: unknown): value is FormattersPipelinePlan {\n\treturn isRecord(value) && Array.isArray(value.steps) && value.steps.every(isPipelineStep);\n}\n\nfunction isPipelinePosition(value: unknown): value is { x: number; y: number } {\n\treturn isRecord(value) && typeof value.x === \"number\" && typeof value.y === \"number\";\n}\n\nfunction isPipelineNode(value: unknown): value is FormattersPipelineNode {\n\tif (!isRecord(value) || typeof value.id !== \"string\" || !isPipelinePosition(value.position)) return false;\n\n\tif (value.type === \"source\" || value.type === \"sink\") {\n\t\treturn true;\n\t}\n\n\treturn isPipelineStep(value);\n}\n\nfunction isPipelineEdge(value: unknown): value is FormattersPipelineEdge {\n\treturn isRecord(value) && typeof value.id === \"string\" && typeof value.source === \"string\" && typeof value.target === \"string\";\n}\n\nfunction isPipelineGraph(value: unknown): value is FormattersPipelineGraph {\n\treturn (\n\t\tisRecord(value) &&\n\t\tArray.isArray(value.nodes) &&\n\t\tvalue.nodes.every(isPipelineNode) &&\n\t\tArray.isArray(value.edges) &&\n\t\tvalue.edges.every(isPipelineEdge)\n\t);\n}\n\nfunction isPipelineConfig(value: unknown): value is FormattersPipelineConfig {\n\treturn (\n\t\tisRecord(value) &&\n\t\tvalue.version === 1 &&\n\t\t(value.plan === undefined || isPipelinePlan(value.plan)) &&\n\t\t(value.graph === undefined || isPipelineGraph(value.graph)) &&\n\t\t(isPipelinePlan(value.plan) || isPipelineGraph(value.graph))\n\t);\n}\n\nexport function normalizeFormattersPipelineConfig(value: unknown): FormattersPipelineConfig | undefined {\n\tif (!isPipelineConfig(value)) return undefined;\n\n\tconst validation = validateFormattersPipelineConfig(value);\n\tif (!validation.ok) return undefined;\n\n\treturn cloneFormattersPipelineConfig(value);\n}\n","import type { FormattersPipelineFormatterId } from \"./types\";\n\n/**\n * Описание вида форматтера для каталога.\n */\nexport type FormattersPipelineDefinition = {\n\tid: FormattersPipelineFormatterId;\n\tname: string;\n\tdescription: string;\n};\n\n/**\n * Справочник доступных видов форматтеров.\n */\nexport const formattersPipelineDefinitions: readonly FormattersPipelineDefinition[] = Object.freeze([\n\t{\n\t\tid: \"normalizeLeadingZeros\",\n\t\tname: \"Нормализация ведущих нулей\",\n\t\tdescription: \"Нормализует числовое значение по правилам fixed.\"\n\t},\n\t{\n\t\tid: \"rowBasedOverride\",\n\t\tname: \"Контекстная формула\",\n\t\tdescription: \"Подменяет значение из другого поля текущей строки или отдельной формулы.\"\n\t},\n\t{\n\t\tid: \"resolveValueState\",\n\t\tname: \"Определение состояния значения\",\n\t\tdescription: \"Вычисляет value state и опционально настраивает отображение статусной иконки.\"\n\t},\n\t{\n\t\tid: \"typedValueFormat\",\n\t\tname: \"Типизированное форматирование\",\n\t\tdescription: \"Формирует итоговый внешний вид значения по типу и роли столбца.\"\n\t}\n]);\n","import { formattersPipelineDefinitions } from \"./definitions\";\n\nimport type { FormattersPipelineDefinition } from \"./definitions\";\nimport type { FormattersPipelineFormatterId } from \"./types\";\n\nconst formatterDefinitionsById = new Map<FormattersPipelineFormatterId, FormattersPipelineDefinition>(\n\tformattersPipelineDefinitions.map((definition) => [definition.id, definition])\n);\n\n/**\n * Возвращает каталог видов форматтеров pipeline.\n */\nexport function getFormattersPipelineDefinitions(): readonly FormattersPipelineDefinition[] {\n\treturn formattersPipelineDefinitions;\n}\n\n/**\n * Возвращает описание вида форматтера по id.\n */\nexport function getFormattersPipelineDefinitionById(id: FormattersPipelineFormatterId): FormattersPipelineDefinition | undefined {\n\treturn formatterDefinitionsById.get(id);\n}\n","import { uuidv4 } from \"../../crypto\";\n\nimport { validateFormattersPipelineGraph } from \"./validate\";\n\nimport type {\n\tFormattersPipelineConfig,\n\tFormattersPipelineEdge,\n\tFormattersPipelineGraph,\n\tFormattersPipelineNode,\n\tFormattersPipelinePlan\n} from \"./types\";\n\ntype IdFactory = () => string;\n\nfunction isSystemNode(node: FormattersPipelineNode): boolean {\n\treturn node.type === \"source\" || node.type === \"sink\";\n}\n\nfunction cloneNodeWithId(node: FormattersPipelineNode, id: string): FormattersPipelineNode {\n\tswitch (node.type) {\n\t\tcase \"source\":\n\t\tcase \"sink\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position }\n\t\t\t};\n\t\tcase \"typedValueFormat\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: node.config ? { ...node.config } : undefined\n\t\t\t};\n\t\tcase \"normalizeLeadingZeros\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: node.config ? { ...node.config } : undefined\n\t\t\t};\n\t\tcase \"rowBasedOverride\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig:\n\t\t\t\t\tnode.config.mode === \"formula\"\n\t\t\t\t\t\t? { ...node.config, dependencyIds: node.config.dependencyIds ? [...node.config.dependencyIds] : undefined }\n\t\t\t\t\t\t: { ...node.config }\n\t\t\t};\n\t\tcase \"resolveValueState\":\n\t\t\treturn {\n\t\t\t\t...node,\n\t\t\t\tid,\n\t\t\t\tposition: { ...node.position },\n\t\t\t\tconfig: {\n\t\t\t\t\tresolver:\n\t\t\t\t\t\tnode.config.resolver.kind === \"fixed\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\t\t\t\tentries: { ...node.config.resolver.entries },\n\t\t\t\t\t\t\t\t\tfallbackState: node.config.resolver.fallbackState\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\t\t\t\tthresholds: node.config.resolver.thresholds.map((item) =>\n\t\t\t\t\t\t\t\t\t\ttypeof item === \"number\" ? item : { ...item }\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\tstates: [...node.config.resolver.states],\n\t\t\t\t\t\t\t\t\tinvalidState: node.config.resolver.invalidState\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\ticon: node.config.icon ? { ...node.config.icon } : undefined\n\t\t\t\t}\n\t\t\t};\n\t}\n}\n\nfunction rekeyGraph(graph: FormattersPipelineGraph, idFactory: IdFactory): FormattersPipelineGraph {\n\tconst nodeIdByPreviousId = new Map<string, string>();\n\n\tfor (const node of graph.nodes) {\n\t\tnodeIdByPreviousId.set(node.id, isSystemNode(node) ? node.id : idFactory());\n\t}\n\n\tconst edges: FormattersPipelineEdge[] = graph.edges.map((edge) => ({\n\t\tid: idFactory(),\n\t\tsource: nodeIdByPreviousId.get(edge.source) ?? edge.source,\n\t\ttarget: nodeIdByPreviousId.get(edge.target) ?? edge.target\n\t}));\n\n\treturn {\n\t\tnodes: graph.nodes.map((node) => cloneNodeWithId(node, nodeIdByPreviousId.get(node.id) ?? node.id)),\n\t\tedges,\n\t\tviewport: graph.viewport ? { ...graph.viewport } : undefined\n\t};\n}\n\nfunction rekeyPlan(plan: FormattersPipelinePlan, idFactory: IdFactory): FormattersPipelinePlan {\n\treturn {\n\t\tsteps: plan.steps.map((step) => {\n\t\t\tswitch (step.type) {\n\t\t\t\tcase \"typedValueFormat\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: step.config ? { ...step.config } : undefined\n\t\t\t\t\t};\n\t\t\t\tcase \"normalizeLeadingZeros\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: step.config ? { ...step.config } : undefined\n\t\t\t\t\t};\n\t\t\t\tcase \"rowBasedOverride\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig:\n\t\t\t\t\t\t\tstep.config.mode === \"formula\"\n\t\t\t\t\t\t\t\t? { ...step.config, dependencyIds: step.config.dependencyIds ? [...step.config.dependencyIds] : undefined }\n\t\t\t\t\t\t\t\t: { ...step.config }\n\t\t\t\t\t};\n\t\t\t\tcase \"resolveValueState\":\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...step,\n\t\t\t\t\t\tid: idFactory(),\n\t\t\t\t\t\tconfig: {\n\t\t\t\t\t\t\tresolver:\n\t\t\t\t\t\t\t\tstep.config.resolver.kind === \"fixed\"\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tkind: \"fixed\",\n\t\t\t\t\t\t\t\t\t\t\tentries: { ...step.config.resolver.entries },\n\t\t\t\t\t\t\t\t\t\t\tfallbackState: step.config.resolver.fallbackState\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t\t\tkind: \"threshold\",\n\t\t\t\t\t\t\t\t\t\t\tthresholds: step.config.resolver.thresholds.map((item) =>\n\t\t\t\t\t\t\t\t\t\t\t\ttypeof item === \"number\" ? item : { ...item }\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\tstates: [...step.config.resolver.states],\n\t\t\t\t\t\t\t\t\t\t\tinvalidState: step.config.resolver.invalidState\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\ticon: step.config.icon ? { ...step.config.icon } : undefined\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t}\n\t\t})\n\t};\n}\n\n/**\n * Переиздаёт технические id formatter-нод и step-ов без изменения настроек pipeline.\n *\n * Source/sink сохраняют стабильные id, потому что редактор использует их как\n * служебные якоря графа; все пользовательские formatter id не имеют бизнес-смысла.\n */\nexport function rekeyFormattersPipelineConfig(\n\tconfig: FormattersPipelineConfig | undefined,\n\tidFactory: IdFactory = uuidv4\n): FormattersPipelineConfig | undefined {\n\tif (!config) return undefined;\n\n\tconst graph = config.graph ? rekeyGraph(config.graph, idFactory) : undefined;\n\tconst graphValidation = graph ? validateFormattersPipelineGraph(graph) : undefined;\n\n\treturn {\n\t\tversion: config.version,\n\t\tgraph,\n\t\tplan:\n\t\t\tgraphValidation?.ok && graphValidation.plan ? graphValidation.plan : config.plan ? rekeyPlan(config.plan, idFactory) : undefined\n\t};\n}\n","import { compileTableFormula, type TableFormulaCompiledExecutor, type TableFormulaRowData } from \"../../formulas\";\nimport { isZeroValue } from \"../number\";\nimport { toSafeString } from \"../strings\";\n\nimport { compileFormattersPipelineExecutor, formatTypedCellValue } from \"./execute\";\n\nimport type {\n\tFormatPipelineDisplayValueArgs,\n\tFormattersPipelineDisplayValue,\n\tFormattersPipelineExecutionResult,\n\tFormattersPipelineRuntimeField,\n\tFormattersPipelineRuntimeFields\n} from \"./types\";\n\ntype ResolvedPipelineSourceValue = {\n\tvalue: unknown;\n\tshouldRenderEmpty: boolean;\n};\n\nconst missingFormulaExecutor: TableFormulaCompiledExecutor = () => ({ ok: false, reason: \"formula_not_found\" });\n\nfunction createDefaultDisplayValue(value: unknown, overflowTooltip: boolean): FormattersPipelineDisplayValue {\n\treturn {\n\t\tvalue,\n\t\tstate: \"none\",\n\t\tshowIcon: false,\n\t\tshowValue: true,\n\t\ticonPosition: \"left\",\n\t\toverflowTooltip\n\t};\n}\n\nfunction formatFallbackValue(value: unknown, field: Pick<FormattersPipelineRuntimeField, \"role\" | \"type\"> | undefined): string {\n\tif (!field) {\n\t\treturn toSafeString(value);\n\t}\n\n\treturn formatTypedCellValue(value, field);\n}\n\nfunction compileFormulaExecutor(field: FormattersPipelineRuntimeField): TableFormulaCompiledExecutor | undefined {\n\tif (!field.formulaId) {\n\t\treturn undefined;\n\t}\n\n\tconst compiled = compileTableFormula({\n\t\tformulaId: field.formulaId,\n\t\tkeys: field.formulaDependencies\n\t});\n\n\treturn compiled.ok ? compiled.execute : missingFormulaExecutor;\n}\n\nfunction resolvePipelineSourceValue(\n\trawValue: unknown,\n\trowData: TableFormulaRowData,\n\tfield: Readonly<FormattersPipelineRuntimeField>\n): ResolvedPipelineSourceValue {\n\tif (!field.formulaId) {\n\t\treturn {\n\t\t\tvalue: rawValue,\n\t\t\tshouldRenderEmpty: false\n\t\t};\n\t}\n\n\tif (!field.formulaExecutor) {\n\t\treturn {\n\t\t\tvalue: field.purelyDerived ? undefined : rawValue,\n\t\t\tshouldRenderEmpty: field.purelyDerived === true\n\t\t};\n\t}\n\n\tconst execution = field.formulaExecutor(rowData);\n\tif (execution.ok) {\n\t\treturn {\n\t\t\tvalue: execution.value,\n\t\t\tshouldRenderEmpty: false\n\t\t};\n\t}\n\n\treturn {\n\t\tvalue: field.purelyDerived ? undefined : rawValue,\n\t\tshouldRenderEmpty: field.purelyDerived === true\n\t};\n}\n\nfunction executePipelineFormatting<TField extends FormattersPipelineRuntimeField>(\n\targs: FormatPipelineDisplayValueArgs<TField>,\n\tsourceValue: unknown,\n\tfield: Readonly<TField>\n): FormattersPipelineDisplayValue {\n\tconst executor = field.formattersPipelineExecutor;\n\tif (!executor) {\n\t\treturn createDefaultDisplayValue(formatFallbackValue(sourceValue, field), field.overflowTooltip === true);\n\t}\n\n\tconst execution: FormattersPipelineExecutionResult = executor.execute({\n\t\tvalue: sourceValue,\n\t\trowData: args.rowData,\n\t\trowKind: args.rowKind,\n\t\tisGroupRow: args.rowKind === \"group\",\n\t\tisTotalsRow: args.rowKind === \"totals\",\n\t\trowLevel: args.rowLevel ?? 0,\n\t\tgroupingIds: args.groupingIds ?? [],\n\t\tcolumnId: field.id\n\t});\n\tconst value = execution.hasTypedValueFormat ? execution.value : formatFallbackValue(execution.value, field);\n\n\treturn {\n\t\tvalue,\n\t\tstate: execution.state,\n\t\ticon: execution.icon,\n\t\tshowIcon: execution.showIcon,\n\t\tshowValue: execution.showValue,\n\t\ticonPosition: execution.iconPosition,\n\t\toverflowTooltip: field.overflowTooltip === true\n\t};\n}\n\nfunction applyDisplayPostProcessing(\n\tdisplayValue: FormattersPipelineDisplayValue,\n\tsourceValue: ResolvedPipelineSourceValue,\n\tfield: Readonly<FormattersPipelineRuntimeField>\n): FormattersPipelineDisplayValue {\n\tif (sourceValue.shouldRenderEmpty) {\n\t\treturn {\n\t\t\t...displayValue,\n\t\t\tvalue: \"\"\n\t\t};\n\t}\n\n\tif (field.emptyWhenZero && isZeroValue(sourceValue.value)) {\n\t\treturn {\n\t\t\t...displayValue,\n\t\t\tvalue: \"\"\n\t\t};\n\t}\n\n\treturn displayValue;\n}\n\n/**\n * Компилирует formula/pipeline runtime прямо в исходный объект поля.\n *\n * Функция предназначена только для construction-stage: до помещения полей в\n * readonly context, memoized snapshot или query-independent cache.\n */\nexport function compileFormattersPipelineRuntime<TField extends FormattersPipelineRuntimeField>(field: TField): Readonly<TField> {\n\tconst formulaExecutor = compileFormulaExecutor(field);\n\tif (formulaExecutor) {\n\t\tfield.formulaExecutor = formulaExecutor;\n\t} else {\n\t\tdelete field.formulaExecutor;\n\t}\n\n\tif (!field.formattersPipeline) {\n\t\tdelete field.formattersPipelineExecutor;\n\t\treturn field;\n\t}\n\n\tconst compiled = compileFormattersPipelineExecutor({\n\t\tconfig: field.formattersPipeline,\n\t\tcolumn: field\n\t});\n\n\tif (compiled.ok) {\n\t\tfield.formattersPipelineExecutor = compiled.executor;\n\t} else {\n\t\tdelete field.formattersPipelineExecutor;\n\t}\n\n\treturn field;\n}\n\n/**\n * Компилирует runtime-карту без пересборки самих полей.\n */\nexport function compileFormattersPipelineRuntimeFields<TField extends FormattersPipelineRuntimeField>(\n\tfieldsById: Readonly<Record<string, TField | undefined>>\n): FormattersPipelineRuntimeFields<TField> {\n\tconst runtimeFields: Record<string, Readonly<TField>> = {};\n\n\tfor (const [fieldId, field] of Object.entries(fieldsById)) {\n\t\tif (!field) continue;\n\t\truntimeFields[fieldId] = compileFormattersPipelineRuntime(field);\n\t}\n\n\treturn runtimeFields;\n}\n\n/**\n * Вычисляет display-result для одного значения без знания о таблице или графике.\n */\nexport function formatPipelineDisplayValue<TField extends FormattersPipelineRuntimeField>(\n\targs: FormatPipelineDisplayValueArgs<TField>\n): FormattersPipelineDisplayValue {\n\tif (!args.field) {\n\t\treturn createDefaultDisplayValue(toSafeString(args.rawValue), false);\n\t}\n\n\tconst sourceValue = resolvePipelineSourceValue(args.rawValue, args.rowData, args.field);\n\tconst displayValue = executePipelineFormatting(args, sourceValue.value, args.field);\n\n\treturn applyDisplayPostProcessing(displayValue, sourceValue, args.field);\n}\n","import type { State } from \"../../types\";\n\nexport const DEFAULT_VALUE_STATES: readonly State[] = [\"none\", \"information\", \"success\", \"warning\", \"error\"];\n\nexport const VALUE_STATE_COLOR_TOKENS: Record<State, string> = {\n\t\"\": \"transparent\",\n\tnone: \"var(--content-1)\",\n\tinformation: \"var(--status-info-text)\",\n\tsuccess: \"var(--status-success-text)\",\n\twarning: \"var(--status-warning-text)\",\n\terror: \"var(--status-error-text)\"\n};\n","import { State } from \"../../types\";\n\nexport function resolveValueStateClassName(state: State, fallbackClassName?: string): string | undefined {\n\tswitch (state) {\n\t\tcase \"success\":\n\t\t\treturn \"statusSuccess\";\n\t\tcase \"warning\":\n\t\t\treturn \"statusWarning\";\n\t\tcase \"error\":\n\t\t\treturn \"statusError\";\n\t\tcase \"information\":\n\t\t\treturn \"statusInfo\";\n\t\tdefault:\n\t\t\treturn fallbackClassName;\n\t}\n}\n"],"mappings":"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"}
|