@ryuzaki13/react-foundation-lib 2.31.3 → 2.33.0
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/analytical-table/index.js +2 -2
- package/dist/chunks/{formatters-CO40zvVB.js → formatters-CMfD97RB.js} +3 -3
- package/dist/chunks/{formatters-CO40zvVB.js.map → formatters-CMfD97RB.js.map} +1 -1
- package/dist/chunks/{formulas-Y0HOcFhe.js → formulas-BZtCqzBj.js} +71 -39
- package/dist/chunks/formulas-BZtCqzBj.js.map +1 -0
- package/dist/chunks/{validate-8URYKKly.js → validate-rivmPJyV.js} +5 -5
- package/dist/chunks/{validate-8URYKKly.js.map → validate-rivmPJyV.js.map} +1 -1
- package/dist/error-report/index.js +1 -1
- package/dist/excel/index.js +1 -1
- package/dist/formatters/index.js +2 -2
- package/dist/formulas/execute.d.ts +23 -1
- package/dist/formulas/execute.d.ts.map +1 -1
- package/dist/formulas/index.js +2 -2
- package/dist/formulas/types.d.ts +11 -1
- package/dist/formulas/types.d.ts.map +1 -1
- package/dist/table/columnSizing.d.ts +11 -3
- package/dist/table/columnSizing.d.ts.map +1 -1
- package/dist/table/index.d.ts +1 -0
- package/dist/table/index.d.ts.map +1 -1
- package/dist/table/index.js +74 -68
- package/dist/table/index.js.map +1 -1
- package/dist/table/resolveTableColumnsWidth.d.ts +9 -0
- package/dist/table/resolveTableColumnsWidth.d.ts.map +1 -0
- package/dist/table/types.d.ts +1 -1
- package/dist/table/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/formulas/README.mdx +111 -38
- package/src/table/README.mdx +49 -23
- package/dist/chunks/formulas-Y0HOcFhe.js.map +0 -1
package/src/table/README.mdx
CHANGED
|
@@ -394,7 +394,7 @@ const orderColumns = [
|
|
|
394
394
|
] satisfies TableColumnDef<Order>[];
|
|
395
395
|
```
|
|
396
396
|
|
|
397
|
-
Число `24` в `meta.width` означает `24em`, а не `24px`.
|
|
397
|
+
Число `24` в `meta.width` означает `24em`, а не `24px`. Размеры resize хранятся отдельно в `TableColumnSizingState`; по умолчанию это px, при явном выборе единицы поддерживаются em.
|
|
398
398
|
|
|
399
399
|
### 3. Вычислите selection
|
|
400
400
|
|
|
@@ -538,7 +538,7 @@ const fullNameColumn: TableColumnDef<Person, string> = {
|
|
|
538
538
|
|
|
539
539
|
```ts
|
|
540
540
|
interface TableColumnMeta {
|
|
541
|
-
width?: number | "auto" | `${number}
|
|
541
|
+
width?: number | "auto" | `${number}%` | `${number}px` | `${number}em`;
|
|
542
542
|
align?: "left" | "center" | "right";
|
|
543
543
|
mergeDuplicates?: boolean;
|
|
544
544
|
formatting?: TableColumnFormattingMeta;
|
|
@@ -547,13 +547,15 @@ interface TableColumnMeta {
|
|
|
547
547
|
|
|
548
548
|
#### `width`
|
|
549
549
|
|
|
550
|
-
| Значение
|
|
551
|
-
|
|
|
552
|
-
| `12`
|
|
553
|
-
| `"auto"`
|
|
554
|
-
| `"25%"`
|
|
550
|
+
| Значение | Смысл |
|
|
551
|
+
| ---------- | --------------------------------------- |
|
|
552
|
+
| `12` | `12em` в декларативной metadata колонки |
|
|
553
|
+
| `"auto"` | автоматическая CSS-ширина |
|
|
554
|
+
| `"25%"` | процентная CSS-ширина |
|
|
555
|
+
| `"120px"` | фиксированная ширина в px |
|
|
556
|
+
| `"12.5em"` | явная относительная ширина |
|
|
555
557
|
|
|
556
|
-
Это не то же самое, что `TableColumnSizingState`: sizing state хранит
|
|
558
|
+
Это не то же самое, что `TableColumnSizingState`: sizing state хранит размеры resize runtime в выбранной единице (`px` по умолчанию, `em` при явном включении).
|
|
557
559
|
|
|
558
560
|
#### `align`
|
|
559
561
|
|
|
@@ -904,12 +906,33 @@ if (nextOrder) {
|
|
|
904
906
|
|
|
905
907
|
Не смешивайте:
|
|
906
908
|
|
|
907
|
-
| Представление | Пример | Единица
|
|
908
|
-
| ------------------------ | ----------------------- |
|
|
909
|
-
| `TableColumnMeta.width` | `12`, `"auto"`, `"25%"` | число означает `em`
|
|
910
|
-
| `TableColumnSizingState` | `{ amount: 160 }` |
|
|
909
|
+
| Представление | Пример | Единица |
|
|
910
|
+
| ------------------------ | ----------------------- | ------------------------------------ |
|
|
911
|
+
| `TableColumnMeta.width` | `12`, `"auto"`, `"25%"` | число означает `em` |
|
|
912
|
+
| `TableColumnSizingState` | `{ amount: 160 }` | px по умолчанию; em при явном выборе |
|
|
911
913
|
|
|
912
|
-
Helpers этого раздела работают со вторым
|
|
914
|
+
Helpers этого раздела работают со вторым представлением. Необязательный аргумент `unit: TableColumnSizingUnit` выбирает `"px"` (по умолчанию) или `"em"`. Единица должна совпадать у нормализации, UI и сохранённого профиля; изменение единицы не конвертирует существующие числа.
|
|
915
|
+
|
|
916
|
+
Для `em` минимальная ширина по умолчанию равна `DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM` (`4em`); размеры и явно переданный minimum сохраняют до четырёх знаков после запятой:
|
|
917
|
+
|
|
918
|
+
```ts
|
|
919
|
+
normalizeTableColumnWidth(12.345678, undefined, "em"); // 12.3456
|
|
920
|
+
normalizeTableColumnSizing({ name: 20.5 }, undefined, "em"); // { name: 20.5 }
|
|
921
|
+
patchTableColumnWidth({ name: 20.5 }, "amount", 10.25, undefined, "em");
|
|
922
|
+
// { name: 20.5, amount: 10.25 }
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### `resolveTableColumnsWidth`
|
|
926
|
+
|
|
927
|
+
Суммирует определённые ширины видимых колонок в `em` и `px`, сохраняя CSS-единицы для SSR и масштабирования шрифта:
|
|
928
|
+
|
|
929
|
+
```ts
|
|
930
|
+
resolveTableColumnsWidth(["20em", "10.5em"]); // "calc(20em + 10.5em)"
|
|
931
|
+
resolveTableColumnsWidth(["20em", "120px"]); // "calc(20em + 120px)"
|
|
932
|
+
resolveTableColumnsWidth(["auto", "20em"]); // undefined
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
Пустой набор, проценты и неподдерживаемые значения возвращают `undefined`: для них общей шириной управляет браузер. Результат предназначен для `width` таблицы с `table-layout: fixed`.
|
|
913
936
|
|
|
914
937
|
### `DEFAULT_TABLE_COLUMN_MIN_WIDTH`
|
|
915
938
|
|
|
@@ -927,7 +950,7 @@ normalizeTableColumnWidth(12); // 60
|
|
|
927
950
|
normalizeTableColumnWidth(Number.NaN, 80); // 80
|
|
928
951
|
```
|
|
929
952
|
|
|
930
|
-
|
|
953
|
+
Алгоритм для единицы `px`:
|
|
931
954
|
|
|
932
955
|
1. Проверяет `minWidth`.
|
|
933
956
|
2. Если minimum не finite или не больше нуля, использует `60`.
|
|
@@ -2773,14 +2796,17 @@ it("не активирует строку по клику на кнопку", (
|
|
|
2773
2796
|
|
|
2774
2797
|
### Column sizing
|
|
2775
2798
|
|
|
2776
|
-
| API
|
|
2777
|
-
|
|
|
2778
|
-
| `TableColumnSizingState`
|
|
2779
|
-
| `
|
|
2780
|
-
| `
|
|
2781
|
-
| `
|
|
2782
|
-
| `
|
|
2783
|
-
| `
|
|
2799
|
+
| API | Вид | Назначение |
|
|
2800
|
+
| ----------------------------------- | -------- | --------------------------------------------- |
|
|
2801
|
+
| `TableColumnSizingState` | type | `Record<columnId, width>` в выбранной единице |
|
|
2802
|
+
| `TableColumnSizingUnit` | type | `"px"` или `"em"` |
|
|
2803
|
+
| `DEFAULT_TABLE_COLUMN_MIN_WIDTH_EM` | constant | default minimum `4em` |
|
|
2804
|
+
| `resolveTableColumnsWidth` | function | сумма определённых ширин колонок в CSS |
|
|
2805
|
+
| `DEFAULT_TABLE_COLUMN_MIN_WIDTH` | constant | default minimum `60` px |
|
|
2806
|
+
| `normalizeTableColumnWidth` | function | размер в выбранной единице не меньше minimum |
|
|
2807
|
+
| `normalizeTableColumnSizing` | function | очищает весь sizing state |
|
|
2808
|
+
| `patchTableColumnWidth` | function | immutable add/update одной ширины |
|
|
2809
|
+
| `removeTableColumnWidth` | function | immutable delete одной ширины |
|
|
2784
2810
|
|
|
2785
2811
|
### Row selection
|
|
2786
2812
|
|
|
@@ -2935,7 +2961,7 @@ const column = {
|
|
|
2935
2961
|
};
|
|
2936
2962
|
```
|
|
2937
2963
|
|
|
2938
|
-
Здесь `120em`, а не `120px`.
|
|
2964
|
+
Здесь `120em`, а не `120px`. Размеры resize храните в `TableColumnSizingState`, сохраняя выбранную единицу.
|
|
2939
2965
|
|
|
2940
2966
|
### Считать `normalizeTableColumnOrder` полным restore
|
|
2941
2967
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"formulas-Y0HOcFhe.js","names":[],"sources":["../../src/formulas/tableFormulaConstants.ts","../../src/formulas/isTableFormulaDependency.ts","../../src/formulas/registry.ts","../../src/formulas/execute.ts","../../src/formulas/formatTableFormulaExpression.ts","../../src/formulas/validate.ts"],"sourcesContent":["/** Виды аргументов и причины отказа общие для runtime, валидации и их литеральных контрактов. */\nexport const TABLE_FORMULA_DEPENDENCY_KIND_CONSTANT = \"constant\";\nexport const TABLE_FORMULA_NOT_FOUND = \"formula_not_found\";\nexport const TABLE_FORMULA_INVALID_RESULT = \"invalid_result\";\nexport const TABLE_FORMULA_RUNTIME_ERROR = \"runtime_error\";\nexport const TABLE_FORMULA_DEPENDENCY_INDEX_OUT_OF_RANGE = \"dependency_index_out_of_range\";\nexport const TABLE_FORMULA_DEPENDENCY_NOT_AVAILABLE = \"dependency_not_available\";\nexport const TABLE_FORMULA_INVALID_CONSTANT = \"invalid_constant\";\nexport const TABLE_FORMULA_UNUSED_DEPENDENCIES = \"unused_dependencies\";\nexport const TABLE_FORMULA_DOES_NOT_USE_DEPENDENCIES = \"formula_does_not_use_dependencies\";\nexport const TABLE_FORMULA_VALIDATION_RUNTIME_ERROR = \"formula_runtime_error\";\n","import { TABLE_FORMULA_DEPENDENCY_KIND_CONSTANT } from \"./tableFormulaConstants\";\nimport { type TableFormulaDependency } from \"./types\";\n\n/** Проверяет внешний аргумент без приведения пустых строк или нечисловых значений к нулю. */\nexport function isTableFormulaDependency(value: unknown): value is TableFormulaDependency {\n\tif (typeof value === \"string\") return true;\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\n\treturn (\n\t\t\"kind\" in value &&\n\t\tvalue.kind === TABLE_FORMULA_DEPENDENCY_KIND_CONSTANT &&\n\t\t\"value\" in value &&\n\t\ttypeof value.value === \"number\" &&\n\t\tNumber.isFinite(value.value)\n\t);\n}\n","import type { TableFormulaDefinition } from \"./types\";\n\nexport type TableFormulaRegistry = Readonly<{\n\tlist: readonly TableFormulaDefinition[];\n\tbyId: ReadonlyMap<string, TableFormulaDefinition>;\n}>;\n\nexport function createTableFormulaRegistry(definitions: readonly TableFormulaDefinition[]): TableFormulaRegistry {\n\tconst byId = new Map<string, TableFormulaDefinition>();\n\tconst list: TableFormulaDefinition[] = [];\n\n\tfor (const definition of definitions) {\n\t\tconst normalizedId = definition.id.trim();\n\t\tif (!normalizedId) {\n\t\t\tthrow new Error(\"Formula id не может быть пустым\");\n\t\t}\n\n\t\tif (byId.has(normalizedId)) {\n\t\t\tthrow new Error(`Найден дублирующийся formulaId: ${normalizedId}`);\n\t\t}\n\n\t\tconst normalizedDefinition: TableFormulaDefinition = Object.freeze({\n\t\t\t...definition,\n\t\t\tid: normalizedId,\n\t\t\tname: definition.name.trim(),\n\t\t\tdescription: definition.description.trim(),\n\t\t\tkeywords: definition.keywords ? [...definition.keywords] : undefined\n\t\t});\n\n\t\tbyId.set(normalizedId, normalizedDefinition);\n\t\tlist.push(normalizedDefinition);\n\t}\n\n\treturn Object.freeze({\n\t\tlist: Object.freeze(list),\n\t\tbyId\n\t});\n}\n\nlet tableFormulaRegistry = createTableFormulaRegistry([]);\n\n/**\n * Устанавливает реестр формул host-приложения для всех formula runtime API.\n *\n * Конфигурация выполняется composition root до первого чтения, валидации или\n * компиляции формулы. Библиотека намеренно не содержит прикладной каталог.\n */\nexport function configureTableFormulaRegistry(registry: TableFormulaRegistry): void {\n\ttableFormulaRegistry = registry;\n}\n\nexport function getTableFormulaList(): readonly TableFormulaDefinition[] {\n\treturn tableFormulaRegistry.list;\n}\n\nexport function getTableFormulaById(formulaId: string | undefined): TableFormulaDefinition | undefined {\n\tconst normalizedId = formulaId?.trim();\n\tif (!normalizedId) return undefined;\n\treturn tableFormulaRegistry.byId.get(normalizedId);\n}\n","import { isTableFormulaDependency } from \"./isTableFormulaDependency\";\nimport { getTableFormulaById } from \"./registry\";\nimport {\n\tTABLE_FORMULA_DEPENDENCY_KIND_CONSTANT,\n\tTABLE_FORMULA_NOT_FOUND,\n\tTABLE_FORMULA_INVALID_RESULT,\n\tTABLE_FORMULA_RUNTIME_ERROR\n} from \"./tableFormulaConstants\";\nimport { type TableFormulaContext, type TableFormulaDependency, type TableFormulaRowData } from \"./types\";\n\ntype TableFormulaContextInstrumentation = {\n\tonReadIndex?: (index: number) => void;\n\tonOutOfRangeIndex?: (index: number) => void;\n};\n\nfunction toFiniteNumberOrZero(value: unknown): number {\n\tconst normalized = Number(value);\n\treturn Number.isFinite(normalized) ? normalized : 0;\n}\n\nfunction snapshotDependencies(dependencies: readonly TableFormulaDependency[]): TableFormulaDependency[] {\n\treturn dependencies.map((dependency) => {\n\t\tif (!isTableFormulaDependency(dependency)) {\n\t\t\tthrow new TypeError(\"Аргумент формулы должен быть ID поля или конечной числовой константой.\");\n\t\t}\n\n\t\t// Снимок не должен меняться при последующем редактировании исходной конфигурации.\n\t\treturn typeof dependency === \"string\" ? dependency : { kind: TABLE_FORMULA_DEPENDENCY_KIND_CONSTANT, value: dependency.value };\n\t});\n}\n\nexport function createTableFormulaContext(args: {\n\trowData: TableFormulaRowData;\n\tkeys?: readonly TableFormulaDependency[];\n\tinstrumentation?: TableFormulaContextInstrumentation;\n}): TableFormulaContext {\n\tconst keys = snapshotDependencies(args.keys ?? []);\n\n\tconst readDependency = (index: number): TableFormulaDependency | undefined => {\n\t\tif (!Number.isInteger(index) || index < 0) {\n\t\t\targs.instrumentation?.onOutOfRangeIndex?.(index);\n\t\t\treturn undefined;\n\t\t}\n\n\t\targs.instrumentation?.onReadIndex?.(index);\n\n\t\tif (index >= keys.length) {\n\t\t\targs.instrumentation?.onOutOfRangeIndex?.(index);\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn keys[index];\n\t};\n\n\tconst readValue = (index: number): unknown => {\n\t\tconst dependency = readDependency(index);\n\t\tif (!dependency) return undefined;\n\t\treturn typeof dependency === \"string\" ? args.rowData[dependency] : dependency.value;\n\t};\n\n\treturn {\n\t\tkey: (index) => {\n\t\t\tconst dependency = readDependency(index);\n\t\t\treturn typeof dependency === \"string\" ? dependency : undefined;\n\t\t},\n\t\tvalue: readValue,\n\t\tnum: (index) => toFiniteNumberOrZero(readValue(index))\n\t};\n}\n\nexport type TableFormulaExecutionResult =\n\t| {\n\t\t\tok: true;\n\t\t\tvalue: number;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\treason: typeof TABLE_FORMULA_NOT_FOUND | typeof TABLE_FORMULA_INVALID_RESULT | typeof TABLE_FORMULA_RUNTIME_ERROR;\n\t };\n\nexport type TableFormulaCompiledExecutor = (rowData: TableFormulaRowData) => TableFormulaExecutionResult;\n\ntype CompileTableFormulaResult =\n\t| {\n\t\t\tok: true;\n\t\t\texecute: TableFormulaCompiledExecutor;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\treason: typeof TABLE_FORMULA_NOT_FOUND;\n\t };\n\nexport function compileTableFormula(args: {\n\tformulaId: string | undefined;\n\tkeys?: readonly TableFormulaDependency[];\n}): CompileTableFormulaResult {\n\tconst formula = getTableFormulaById(args.formulaId);\n\tif (!formula) {\n\t\treturn { ok: false, reason: TABLE_FORMULA_NOT_FOUND };\n\t}\n\n\tlet keys: TableFormulaDependency[];\n\ttry {\n\t\tkeys = snapshotDependencies(args.keys ?? []);\n\t} catch {\n\t\t// Ошибка новых входов проходит через прежний execution-result, без успешного расчёта с нулём.\n\t\treturn { ok: true, execute: () => ({ ok: false, reason: TABLE_FORMULA_RUNTIME_ERROR }) };\n\t}\n\tlet rowDataRef: TableFormulaRowData = {};\n\tconst context: TableFormulaContext = {\n\t\tkey: (index) => {\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= keys.length) return undefined;\n\t\t\tconst dependency = keys[index];\n\t\t\treturn typeof dependency === \"string\" ? dependency : undefined;\n\t\t},\n\t\tvalue: (index) => {\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= keys.length) return undefined;\n\t\t\tconst dependency = keys[index];\n\t\t\tif (!dependency) return undefined;\n\t\t\treturn typeof dependency === \"string\" ? rowDataRef[dependency] : dependency.value;\n\t\t},\n\t\tnum: (index) => {\n\t\t\tif (!Number.isInteger(index) || index < 0 || index >= keys.length) return 0;\n\t\t\tconst dependency = keys[index];\n\t\t\tif (!dependency) return 0;\n\t\t\treturn typeof dependency === \"string\" ? toFiniteNumberOrZero(rowDataRef[dependency]) : dependency.value;\n\t\t}\n\t};\n\n\treturn {\n\t\tok: true,\n\t\texecute: (rowData) => {\n\t\t\trowDataRef = rowData;\n\n\t\t\ttry {\n\t\t\t\tconst value = formula.fn(context);\n\t\t\t\tif (!Number.isFinite(value)) {\n\t\t\t\t\treturn { ok: false, reason: TABLE_FORMULA_INVALID_RESULT };\n\t\t\t\t}\n\n\t\t\t\treturn { ok: true, value };\n\t\t\t} catch {\n\t\t\t\treturn { ok: false, reason: TABLE_FORMULA_RUNTIME_ERROR };\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport function executeTableFormula(args: {\n\tformulaId: string | undefined;\n\trowData: TableFormulaRowData;\n\tkeys?: readonly TableFormulaDependency[];\n}): TableFormulaExecutionResult {\n\tconst compiled = compileTableFormula({\n\t\tformulaId: args.formulaId,\n\t\tkeys: args.keys\n\t});\n\tif (!compiled.ok) {\n\t\treturn { ok: false, reason: compiled.reason };\n\t}\n\n\treturn compiled.execute(args.rowData);\n}\n","import { isTableFormulaDependency } from \"./isTableFormulaDependency\";\nimport { type TableFormulaDependency } from \"./types\";\n\n/**\n * Подставляет ID полей и числовые константы в шаблон превью формулы.\n *\n * Незаданные позиции остаются в виде $n, чтобы редактор мог показывать неполный\n * черновик. Подстановка однопроходная: ID сохраняются буквально, а полученный\n * текст предназначен только для отображения и никогда не исполняется.\n */\nexport function formatTableFormulaExpression(expressionTemplate: string, dependencies: readonly TableFormulaDependency[]): string {\n\treturn expressionTemplate.replace(/\\$([0-9]+)/g, (placeholder: string, index: string) => {\n\t\tconst dependency = dependencies[Number(index)];\n\t\tif (!isTableFormulaDependency(dependency) || dependency === \"\") return placeholder;\n\t\tif (typeof dependency === \"string\") return dependency;\n\n\t\t// Скобки сохраняют смысл при вычитании, делении и возведении отрицательного значения в степень.\n\t\treturn dependency.value < 0 || Object.is(dependency.value, -0) ? `(${dependency.value})` : String(dependency.value);\n\t});\n}\n","import { createTableFormulaContext } from \"./execute\";\nimport { formatTableFormulaExpression } from \"./formatTableFormulaExpression\";\nimport { isTableFormulaDependency } from \"./isTableFormulaDependency\";\nimport { getTableFormulaById } from \"./registry\";\nimport {\n\tTABLE_FORMULA_NOT_FOUND,\n\tTABLE_FORMULA_DEPENDENCY_INDEX_OUT_OF_RANGE,\n\tTABLE_FORMULA_DEPENDENCY_NOT_AVAILABLE,\n\tTABLE_FORMULA_INVALID_CONSTANT,\n\tTABLE_FORMULA_UNUSED_DEPENDENCIES,\n\tTABLE_FORMULA_DOES_NOT_USE_DEPENDENCIES,\n\tTABLE_FORMULA_VALIDATION_RUNTIME_ERROR\n} from \"./tableFormulaConstants\";\nimport { type TableFormulaDependency } from \"./types\";\n\n/** Положительная и отрицательная пробы выявляют обращения к зависимостям в разных ветках формулы. */\nconst FORMULA_VALIDATION_PROBE_VALUE = 100;\n\ntype ValidationCode =\n\t| typeof TABLE_FORMULA_NOT_FOUND\n\t| typeof TABLE_FORMULA_DEPENDENCY_INDEX_OUT_OF_RANGE\n\t| typeof TABLE_FORMULA_DEPENDENCY_NOT_AVAILABLE\n\t| typeof TABLE_FORMULA_INVALID_CONSTANT\n\t| typeof TABLE_FORMULA_UNUSED_DEPENDENCIES\n\t| typeof TABLE_FORMULA_DOES_NOT_USE_DEPENDENCIES\n\t| typeof TABLE_FORMULA_VALIDATION_RUNTIME_ERROR;\n\nexport interface TableFormulaValidationMessage {\n\tcode: ValidationCode;\n\tmessage: string;\n}\nexport interface TableFormulaDependenciesValidationResult {\n\tok: boolean;\n\terrors: TableFormulaValidationMessage[];\n\twarnings: TableFormulaValidationMessage[];\n\tusage: {\n\t\tusedDependencyIndexes: number[];\n\t\tusedDependencyIds: string[];\n\t\trequiredDependencyCount: number;\n\t};\n}\n\nfunction toSortedArray(items: Set<number>): number[] {\n\treturn [...items].sort((left, right) => left - right);\n}\n\nfunction createSampleRowData(dependencies: readonly TableFormulaDependency[], multiplier: number): Record<string, unknown> {\n\treturn dependencies.reduce<Record<string, unknown>>((acc, dependency, index) => {\n\t\t// Константа сохраняет своё значение в каждом проходе и не создаёт виртуального поля строки.\n\t\tif (typeof dependency === \"string\") acc[dependency] = (index + 1) * multiplier;\n\t\treturn acc;\n\t}, {});\n}\n\nexport function validateTableFormulaDependencies(args: {\n\tformulaId: string | undefined;\n\tdependencies?: readonly TableFormulaDependency[];\n\tavailableColumnIds?: readonly string[];\n}): TableFormulaDependenciesValidationResult {\n\tconst errors: TableFormulaValidationMessage[] = [];\n\tconst warnings: TableFormulaValidationMessage[] = [];\n\n\tconst formula = getTableFormulaById(args.formulaId);\n\tconst dependencies = [...(args.dependencies ?? [])];\n\tconst availableColumnIds = args.availableColumnIds ?? [];\n\n\tif (!formula) {\n\t\terrors.push({\n\t\t\tcode: TABLE_FORMULA_NOT_FOUND,\n\t\t\tmessage: \"Формула не найдена в реестре.\"\n\t\t});\n\n\t\treturn {\n\t\t\tok: false,\n\t\t\terrors,\n\t\t\twarnings,\n\t\t\tusage: {\n\t\t\t\tusedDependencyIndexes: [],\n\t\t\t\tusedDependencyIds: [],\n\t\t\t\trequiredDependencyCount: 0\n\t\t\t}\n\t\t};\n\t}\n\n\tconst availableSet = new Set(availableColumnIds);\n\tconst missingDependencies = dependencies.filter((dependency) => typeof dependency === \"string\" && !availableSet.has(dependency));\n\tif (missingDependencies.length > 0) {\n\t\terrors.push({\n\t\t\tcode: TABLE_FORMULA_DEPENDENCY_NOT_AVAILABLE,\n\t\t\tmessage: `Не найдены среди доступных полей: ${missingDependencies.join(\", \")}.`\n\t\t});\n\t}\n\n\tconst invalidConstantIndexes = dependencies.flatMap((dependency, index) => (isTableFormulaDependency(dependency) ? [] : [index]));\n\tif (invalidConstantIndexes.length > 0) {\n\t\terrors.push({\n\t\t\tcode: TABLE_FORMULA_INVALID_CONSTANT,\n\t\t\tmessage: `Ожидаются конечные числовые константы в позициях: ${invalidConstantIndexes.map((index) => `$${index}`).join(\", \")}.`\n\t\t});\n\t}\n\n\tconst usedIndexes = new Set<number>();\n\tconst outOfRangeIndexes = new Set<number>();\n\tlet runtimeErrorCount = 0;\n\n\tconst runValidationPass = (sampleRowData: Record<string, unknown>) => {\n\t\ttry {\n\t\t\tconst context = createTableFormulaContext({\n\t\t\t\trowData: sampleRowData,\n\t\t\t\tkeys: dependencies,\n\t\t\t\tinstrumentation: {\n\t\t\t\t\tonReadIndex: (index) => {\n\t\t\t\t\t\tusedIndexes.add(index);\n\t\t\t\t\t},\n\t\t\t\t\tonOutOfRangeIndex: (index) => {\n\t\t\t\t\t\toutOfRangeIndexes.add(index);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t\tformula.fn(context);\n\t\t} catch {\n\t\t\truntimeErrorCount += 1;\n\t\t}\n\t};\n\n\t// Несколько прогонов повышают шанс увидеть обращения к индексам в разных ветках формулы.\n\trunValidationPass(createSampleRowData(dependencies, FORMULA_VALIDATION_PROBE_VALUE));\n\trunValidationPass(createSampleRowData(dependencies, -FORMULA_VALIDATION_PROBE_VALUE));\n\n\tconst sortedUsedIndexes = toSortedArray(usedIndexes);\n\tconst requiredDependencyCount = sortedUsedIndexes.length > 0 ? sortedUsedIndexes[sortedUsedIndexes.length - 1] + 1 : 0;\n\n\tif (outOfRangeIndexes.size > 0) {\n\t\terrors.push({\n\t\t\tcode: TABLE_FORMULA_DEPENDENCY_INDEX_OUT_OF_RANGE,\n\t\t\tmessage: `Формула обращается к несуществующим индексам. Минимально требуется зависимостей: ${requiredDependencyCount}, выбрано: ${dependencies.length}.`\n\t\t});\n\t}\n\n\tif (sortedUsedIndexes.length === 0) {\n\t\twarnings.push({\n\t\t\tcode: TABLE_FORMULA_DOES_NOT_USE_DEPENDENCIES,\n\t\t\tmessage: \"Формула не использует dependencies.\"\n\t\t});\n\t}\n\n\tconst unusedDependencies = dependencies.filter((_, index) => !usedIndexes.has(index));\n\tif (unusedDependencies.length > 0) {\n\t\twarnings.push({\n\t\t\tcode: TABLE_FORMULA_UNUSED_DEPENDENCIES,\n\t\t\tmessage: `Выбраны, но не используются формулой: ${unusedDependencies.map((dependency) => formatTableFormulaExpression(\"$0\", [dependency])).join(\", \")}.`\n\t\t});\n\t}\n\n\tif (runtimeErrorCount > 0) {\n\t\twarnings.push({\n\t\t\tcode: TABLE_FORMULA_VALIDATION_RUNTIME_ERROR,\n\t\t\tmessage: \"На тестовых данных формула завершилась с ошибкой.\"\n\t\t});\n\t}\n\n\tconst usedDependencyIds = sortedUsedIndexes\n\t\t.map((index) => dependencies[index])\n\t\t.filter((dependency): dependency is string => typeof dependency === \"string\" && dependency !== \"\");\n\n\treturn {\n\t\tok: errors.length === 0,\n\t\terrors,\n\t\twarnings,\n\t\tusage: {\n\t\t\tusedDependencyIndexes: sortedUsedIndexes,\n\t\t\tusedDependencyIds,\n\t\t\trequiredDependencyCount\n\t\t}\n\t};\n}\n"],"mappings":"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"}
|