@ryuzaki13/react-foundation-lib 2.20.0 → 2.21.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.
Files changed (51) hide show
  1. package/README.md +2 -0
  2. package/dist/analytical-table/aggregation.d.ts +4 -0
  3. package/dist/analytical-table/aggregation.d.ts.map +1 -0
  4. package/dist/analytical-table/buildAnalyticalTableModel.d.ts +4 -0
  5. package/dist/analytical-table/buildAnalyticalTableModel.d.ts.map +1 -0
  6. package/dist/analytical-table/calculationTypes.d.ts +11 -0
  7. package/dist/analytical-table/calculationTypes.d.ts.map +1 -0
  8. package/dist/analytical-table/calculations.d.ts +6 -0
  9. package/dist/analytical-table/calculations.d.ts.map +1 -0
  10. package/dist/analytical-table/columnTypes.d.ts +30 -0
  11. package/dist/analytical-table/columnTypes.d.ts.map +1 -0
  12. package/dist/analytical-table/dataTypes.d.ts +14 -0
  13. package/dist/analytical-table/dataTypes.d.ts.map +1 -0
  14. package/dist/analytical-table/dateColumnTypes.d.ts +31 -0
  15. package/dist/analytical-table/dateColumnTypes.d.ts.map +1 -0
  16. package/dist/analytical-table/dateColumns.d.ts +11 -0
  17. package/dist/analytical-table/dateColumns.d.ts.map +1 -0
  18. package/dist/analytical-table/expansion.d.ts +4 -0
  19. package/dist/analytical-table/expansion.d.ts.map +1 -0
  20. package/dist/analytical-table/exportProjection.d.ts +4 -0
  21. package/dist/analytical-table/exportProjection.d.ts.map +1 -0
  22. package/dist/analytical-table/exportTypes.d.ts +31 -0
  23. package/dist/analytical-table/exportTypes.d.ts.map +1 -0
  24. package/dist/analytical-table/filtering.d.ts +4 -0
  25. package/dist/analytical-table/filtering.d.ts.map +1 -0
  26. package/dist/analytical-table/index.d.ts +8 -0
  27. package/dist/analytical-table/index.d.ts.map +1 -0
  28. package/dist/analytical-table/index.js +364 -0
  29. package/dist/analytical-table/index.js.map +1 -0
  30. package/dist/analytical-table/indexAnalyticalRows.d.ts +4 -0
  31. package/dist/analytical-table/indexAnalyticalRows.d.ts.map +1 -0
  32. package/dist/analytical-table/modelTypes.d.ts +43 -0
  33. package/dist/analytical-table/modelTypes.d.ts.map +1 -0
  34. package/dist/analytical-table/types.d.ts +8 -0
  35. package/dist/analytical-table/types.d.ts.map +1 -0
  36. package/dist/analytical-table/valueComparison.d.ts +5 -0
  37. package/dist/analytical-table/valueComparison.d.ts.map +1 -0
  38. package/dist/analytical-table/viewTypes.d.ts +24 -0
  39. package/dist/analytical-table/viewTypes.d.ts.map +1 -0
  40. package/dist/chunks/{formatters-hHUJpZqD.js → formatters-CEltML3y.js} +224 -224
  41. package/dist/chunks/{formatters-hHUJpZqD.js.map → formatters-CEltML3y.js.map} +1 -1
  42. package/dist/chunks/{validate-DnkaY38p.js → validate-M2zPiLXn.js} +24 -24
  43. package/dist/chunks/{validate-DnkaY38p.js.map → validate-M2zPiLXn.js.map} +1 -1
  44. package/dist/error-report/index.js +20 -20
  45. package/dist/excel/index.js +36 -36
  46. package/dist/excel/index.js.map +1 -1
  47. package/dist/formatters/index.js +2 -2
  48. package/dist/hooks/useFloatingListbox.d.ts +1 -1
  49. package/dist/odata-service/formatters.d.ts +2 -2
  50. package/package.json +5 -1
  51. package/src/analytical-table/README.mdx +169 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/analytical-table/aggregation.ts","../../src/analytical-table/calculations.ts","../../src/analytical-table/valueComparison.ts","../../src/analytical-table/filtering.ts","../../src/analytical-table/indexAnalyticalRows.ts","../../src/analytical-table/buildAnalyticalTableModel.ts","../../src/analytical-table/dateColumns.ts","../../src/analytical-table/expansion.ts","../../src/analytical-table/exportProjection.ts"],"sourcesContent":["import { type AnalyticalAggregation } from \"./types\";\n\n/** null/пустые/нечисловые значения не превращаются в ноль; count считает непустые факты. */\nexport function aggregateAnalyticalValues(values: readonly unknown[], aggregation: AnalyticalAggregation): number | null {\n\tconst present = values.filter((value) => value !== null && value !== undefined && value !== \"\");\n\tif (aggregation === \"count\") return present.length;\n\tlet count = 0;\n\tlet sum = 0;\n\tlet minimum = Infinity;\n\tlet maximum = -Infinity;\n\tfor (const value of present) {\n\t\tif (typeof value !== \"number\" || !Number.isFinite(value)) continue;\n\t\tcount += 1;\n\t\tsum += value;\n\t\tminimum = Math.min(minimum, value);\n\t\tmaximum = Math.max(maximum, value);\n\t}\n\tif (count === 0) return null;\n\tswitch (aggregation) {\n\t\tcase \"sum\":\n\t\t\treturn sum;\n\t\tcase \"min\":\n\t\t\treturn minimum;\n\t\tcase \"max\":\n\t\t\treturn maximum;\n\t\tcase \"avg\":\n\t\t\treturn sum / count;\n\t}\n}\n","import { arrayDeduplicate } from \"../array\";\nimport { compileTableFormula } from \"../formulas\";\n\nimport { type AnalyticalCalculationPlan, type AnalyticalCalculationStep, type AnalyticalColumn, type AnalyticalValues } from \"./types\";\n\n/** Проверяет граф зависимостей до расчёта строк и компилирует каждую формулу один раз. */\nexport function createAnalyticalCalculationPlan<T>(\n\tcolumns: readonly AnalyticalColumn<T>[],\n\trequiredColumnIds: readonly string[] = columns.map((column) => column.id)\n): AnalyticalCalculationPlan {\n\tconst byId = new Map(columns.map((column) => [column.id, column]));\n\tif (byId.size !== columns.length) throw new Error(\"Идентификаторы аналитических столбцов должны быть уникальны.\");\n\tconst visited = new Set<string>();\n\tconst visiting = new Set<string>();\n\tconst required: string[] = [];\n\tconst steps: AnalyticalCalculationStep[] = [];\n\tconst visit = (id: string): void => {\n\t\tif (visited.has(id)) return;\n\t\tif (visiting.has(id)) throw new Error(`Циклическая зависимость аналитического столбца: ${id}`);\n\t\tconst column = byId.get(id);\n\t\tif (!column) throw new Error(`Неизвестная зависимость аналитического столбца: ${id}`);\n\t\tif (column.formula && column.calculate) throw new Error(`Столбец ${id} содержит два способа вычисления.`);\n\t\tvisiting.add(id);\n\t\tconst dependencies = arrayDeduplicate(column.formula?.dependencies ?? column.calculate?.dependencies ?? []);\n\t\tfor (const dependency of dependencies) visit(dependency);\n\t\tif (column.formula) {\n\t\t\t// Порядок и повторы аргументов формулы сохраняются; уникален лишь граф зависимостей.\n\t\t\tconst compiled = compileTableFormula({ formulaId: column.formula.formulaId, keys: column.formula.dependencies });\n\t\t\tif (!compiled.ok) throw new Error(`Формула столбца ${id} не зарегистрирована: ${column.formula.formulaId}`);\n\t\t\tsteps.push({\n\t\t\t\tcolumnId: id,\n\t\t\t\tdependencies,\n\t\t\t\tcompute: (values) => {\n\t\t\t\t\tconst result = compiled.execute({ ...values });\n\t\t\t\t\tif (!result.ok) throw new Error(`Ошибка формулы столбца ${id}: ${result.reason}`);\n\t\t\t\t\treturn result.value;\n\t\t\t\t}\n\t\t\t});\n\t\t} else if (column.calculate) {\n\t\t\tsteps.push({ columnId: id, dependencies, compute: column.calculate.compute });\n\t\t}\n\t\tvisiting.delete(id);\n\t\tvisited.add(id);\n\t\trequired.push(id);\n\t};\n\tfor (const id of requiredColumnIds) visit(id);\n\treturn { steps, requiredColumnIds: required };\n}\n\n/** Возвращает отдельный набор значений; исходный DTO и значения Query не мутируются. */\nexport function calculateAnalyticalValues(values: AnalyticalValues, plan: AnalyticalCalculationPlan): AnalyticalValues {\n\tconst result: Record<string, unknown> = { ...values };\n\tfor (const step of plan.steps) result[step.columnId] = step.compute(result);\n\treturn result;\n}\n","import { parseDate } from \"../formatters\";\nimport { compareStrings } from \"../string-comparison\";\nimport { stableStringify } from \"../utils\";\n\nimport { type AnalyticalColumn, type AnalyticalValues } from \"./types\";\n\n/** Тип входит в ключ: null, undefined, строка и число не склеивают разные группы. */\nexport function analyticalIdentity(values: AnalyticalValues, ids: readonly string[]): string {\n\treturn stableStringify(\n\t\tids.map((id) => {\n\t\t\tconst value = values[id];\n\t\t\treturn [id, value === null ? \"null\" : typeof value, value];\n\t\t})\n\t);\n}\n\nexport function compareAnalyticalValues<T>(left: unknown, right: unknown, column?: AnalyticalColumn<T>): number {\n\tif (Object.is(left, right)) return 0;\n\tif (left === null || left === undefined) return 1;\n\tif (right === null || right === undefined) return -1;\n\tif (column?.compare) return column.compare(left, right);\n\tif (column?.valueType === \"date\") {\n\t\tconst leftDate = parseDate(left);\n\t\tconst rightDate = parseDate(right);\n\t\tif (leftDate && rightDate) return leftDate.getTime() - rightDate.getTime();\n\t}\n\tif (typeof left === \"number\" && typeof right === \"number\") return left - right;\n\tif (typeof left === \"boolean\" && typeof right === \"boolean\") return Number(left) - Number(right);\n\treturn compareStrings(String(left), String(right));\n}\n","import { normalizeTextToLower } from \"../formatters\";\n\nimport { type AnalyticalColumn, type AnalyticalDataRow, type AnalyticalFilter } from \"./types\";\nimport { compareAnalyticalValues } from \"./valueComparison\";\n\n/** Операции фильтра относятся к данным, поэтому одинаково работают при SSR и в браузере. */\nexport function matchesAnalyticalFilter<T>(row: AnalyticalDataRow<T>, filter: AnalyticalFilter, column?: AnalyticalColumn<T>): boolean {\n\tconst value = row.values[filter.id];\n\tif (column?.filter) return column.filter(value, filter, row);\n\tconst expected = filter.value;\n\tconst compare = (other: unknown) => compareAnalyticalValues(value, other, column);\n\tconst empty = value === null || value === undefined || value === \"\";\n\tswitch (filter.operator ?? \"equals\") {\n\t\tcase \"equals\":\n\t\t\treturn compare(expected) === 0;\n\t\tcase \"notEquals\":\n\t\t\treturn compare(expected) !== 0;\n\t\tcase \"contains\":\n\t\t\treturn normalizeTextToLower(String(value ?? \"\")).includes(normalizeTextToLower(String(expected ?? \"\")));\n\t\tcase \"startsWith\":\n\t\t\treturn normalizeTextToLower(String(value ?? \"\")).startsWith(normalizeTextToLower(String(expected ?? \"\")));\n\t\tcase \"in\":\n\t\t\treturn Array.isArray(expected) && expected.some((item: unknown) => compare(item) === 0);\n\t\tcase \"between\":\n\t\t\treturn Array.isArray(expected) && expected.length === 2 && !empty && compare(expected[0]) >= 0 && compare(expected[1]) <= 0;\n\t\tcase \"gt\":\n\t\t\treturn !empty && compare(expected) > 0;\n\t\tcase \"gte\":\n\t\t\treturn !empty && compare(expected) >= 0;\n\t\tcase \"lt\":\n\t\t\treturn !empty && compare(expected) < 0;\n\t\tcase \"lte\":\n\t\t\treturn !empty && compare(expected) <= 0;\n\t\tcase \"empty\":\n\t\t\treturn empty;\n\t\tcase \"notEmpty\":\n\t\t\treturn !empty;\n\t}\n}\n","import { type AnalyticalModelRow, type AnalyticalTableModel } from \"./types\";\n\n/** Единственный обход индексов полной и видимой проекций дерева. */\nexport function indexAnalyticalRows<T>(\n\trows: readonly AnalyticalModelRow<T>[]\n): Pick<AnalyticalTableModel<T>, \"flatRows\" | \"visibleRows\" | \"rowById\"> {\n\tconst flatRows: AnalyticalModelRow<T>[] = [];\n\tconst visibleRows: AnalyticalModelRow<T>[] = [];\n\tconst rowById = new Map<string, AnalyticalModelRow<T>>();\n\tconst visit = (nodes: readonly AnalyticalModelRow<T>[], visible: boolean): void => {\n\t\tfor (const row of nodes) {\n\t\t\tflatRows.push(row);\n\t\t\trowById.set(row.id, row);\n\t\t\tif (visible) visibleRows.push(row);\n\t\t\tvisit(row.children, visible && row.isExpanded);\n\t\t}\n\t};\n\tvisit(rows, true);\n\treturn { flatRows, visibleRows, rowById };\n}\n","import { arrayDeduplicate } from \"../array\";\nimport { buildTreeTableRows } from \"../tree-table\";\nimport { type TreeTableRowNode } from \"../tree-table\";\nimport { stableStringify } from \"../utils\";\n\nimport { aggregateAnalyticalValues } from \"./aggregation\";\nimport { calculateAnalyticalValues, createAnalyticalCalculationPlan } from \"./calculations\";\nimport { matchesAnalyticalFilter } from \"./filtering\";\nimport { indexAnalyticalRows } from \"./indexAnalyticalRows\";\nimport {\n\ttype AnalyticalDataRow,\n\ttype AnalyticalModelRow,\n\ttype AnalyticalTableModel,\n\ttype AnalyticalValues,\n\ttype BuildAnalyticalTableModelOptions\n} from \"./types\";\nimport { analyticalIdentity, compareAnalyticalValues } from \"./valueComparison\";\n\ntype PreparedNode<T> = Readonly<{\n\tid: string;\n\tkind: \"data\" | \"group\";\n\tsourceRow?: AnalyticalDataRow<T>;\n\tvalues: AnalyticalValues;\n\tchildren: PreparedNode<T>[];\n\tgroupingLevelId?: string;\n}>;\n\n/** Чистая модель полного снимка: не владеет транспортом, кэшем, DOM и жизненным циклом Query. */\nexport function buildAnalyticalTableModel<T>(options: BuildAnalyticalTableModelOptions<T>): AnalyticalTableModel<T> {\n\tconst { snapshot, columns, state = {} } = options;\n\tconst plan = createAnalyticalCalculationPlan(columns);\n\tconst columnsById = new Map(columns.map((column) => [column.id, column]));\n\tconst grouping = state.grouping ?? [];\n\tconst sorting = state.sorting ?? [];\n\tconst filters = state.filters ?? [];\n\tfor (const id of [...sorting.map((sort) => sort.id), ...filters.map((filter) => filter.id)]) {\n\t\tif (!columnsById.has(id)) throw new Error(`Неизвестный аналитический столбец: ${id}`);\n\t}\n\tif (arrayDeduplicate(grouping.map((level) => level.id)).length !== grouping.length)\n\t\tthrow new Error(\"Идентификаторы уровней группировки должны быть уникальны.\");\n\tfor (const level of grouping)\n\t\tif (level.keyColumnIds.length === 0) throw new Error(`Уровень ${level.id} не содержит ключей группировки.`);\n\tconst dataRows = snapshot.rows.map((row) => ({ ...row, values: calculateAnalyticalValues(row.values, plan) }));\n\tif (dataRows.some((row) => row.id.length === 0)) throw new Error(\"Идентификатор аналитической строки не может быть пустым.\");\n\tconst tree = buildTreeTableRows(dataRows, { getRowId: (row) => row.id, getParentRowId: (row) => row.parentId });\n\tconst roots = new Set(tree.rootRowIds);\n\tconst isAggregateRow = options.isAggregateRow ?? ((row: AnalyticalDataRow<T>) => roots.has(row.id));\n\tconst prepare = (node: TreeTableRowNode<AnalyticalDataRow<T>>): PreparedNode<T> => ({\n\t\tid: node.id,\n\t\tkind: \"data\",\n\t\tsourceRow: tree.rowById.get(node.id),\n\t\tvalues: node.values,\n\t\tchildren: (node.children ?? []).map(prepare)\n\t});\n\tconst sourceRoots = tree.rows.map(prepare);\n\tconst collectRows = (nodes: readonly PreparedNode<T>[]): AnalyticalDataRow<T>[] => {\n\t\tconst rows: AnalyticalDataRow<T>[] = [];\n\t\tconst visit = (node: PreparedNode<T>): void => {\n\t\t\tif (node.sourceRow && isAggregateRow(node.sourceRow)) rows.push(node.sourceRow);\n\t\t\tfor (const child of node.children) visit(child);\n\t\t};\n\t\tfor (const node of nodes) visit(node);\n\t\treturn rows;\n\t};\n\tconst aggregate = (nodes: readonly PreparedNode<T>[], scope: \"group\" | \"grand\", path: AnalyticalValues): AnalyticalValues => {\n\t\tconst context = { scope, rows: collectRows(nodes), groupingPath: path };\n\t\tconst values: Record<string, unknown> = { ...path };\n\t\tfor (const column of columns) {\n\t\t\tif (!column.aggregate) continue;\n\t\t\tvalues[column.id] =\n\t\t\t\ttypeof column.aggregate === \"function\"\n\t\t\t\t\t? column.aggregate(context)\n\t\t\t\t\t: aggregateAnalyticalValues(\n\t\t\t\t\t\t\tcontext.rows.map((row) => row.values[column.id]),\n\t\t\t\t\t\t\tcolumn.aggregate\n\t\t\t\t\t\t);\n\t\t}\n\t\tObject.assign(values, options.aggregate?.(context));\n\t\t// Готовый итог колонки и значения пути имеют приоритет над её построчной\n\t\t// формулой. Зависимые формулы при этом читают уже выбранный итог: например,\n\t\t// сумма произведений не превращается в произведение сумм, а ratio без\n\t\t// собственного aggregate по-прежнему вычисляется из сумм числителя и знаменателя.\n\t\tconst totalsPlan = { ...plan, steps: plan.steps.filter((step) => !Object.hasOwn(values, step.columnId)) };\n\t\treturn calculateAnalyticalValues(values, totalsPlan);\n\t};\n\t// Совпадение родителя сохраняет его ветвь целиком; совпадение ребёнка сохраняет путь к нему.\n\tconst filterNodes = (nodes: readonly PreparedNode<T>[]): PreparedNode<T>[] =>\n\t\tnodes.flatMap((node) => {\n\t\t\tconst sourceRow = node.sourceRow;\n\t\t\tif (sourceRow && filters.every((filter) => matchesAnalyticalFilter(sourceRow, filter, columnsById.get(filter.id))))\n\t\t\t\treturn [node];\n\t\t\tconst children = filterNodes(node.children);\n\t\t\treturn children.length > 0 ? [{ ...node, children }] : [];\n\t\t});\n\tconst filteredRoots = filters.length > 0 ? filterNodes(sourceRoots) : sourceRoots;\n\tconst groupNodes = (\n\t\tnodes: PreparedNode<T>[],\n\t\tlevelIndex: number,\n\t\tpath: AnalyticalValues,\n\t\tidentityPath: readonly string[]\n\t): PreparedNode<T>[] => {\n\t\tconst level = grouping[levelIndex];\n\t\tif (!level) return nodes;\n\t\tconst buckets = new Map<string, PreparedNode<T>[]>();\n\t\tfor (const node of nodes) {\n\t\t\tconst key = analyticalIdentity(node.values, level.keyColumnIds);\n\t\t\tconst bucket = buckets.get(key);\n\t\t\tif (bucket) bucket.push(node);\n\t\t\telse buckets.set(key, [node]);\n\t\t}\n\t\treturn Array.from(buckets, ([key, members]) => {\n\t\t\tconst identity = [...identityPath, level.id, key];\n\t\t\tconst id = `analytical-group:${stableStringify(identity)}`;\n\t\t\tif (tree.rowById.has(id)) throw new Error(`Идентификатор исходной строки совпал с группой: ${id}`);\n\t\t\tconst nextPath: Record<string, unknown> = { ...path };\n\t\t\tfor (const columnId of [...level.keyColumnIds, ...(level.displayColumnIds ?? [])])\n\t\t\t\tnextPath[columnId] = members[0].values[columnId];\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tkind: \"group\",\n\t\t\t\tgroupingLevelId: level.id,\n\t\t\t\tvalues: aggregate(members, \"group\", nextPath),\n\t\t\t\tchildren: groupNodes(members, levelIndex + 1, nextPath, identity)\n\t\t\t};\n\t\t});\n\t};\n\tconst prepared = groupNodes(filteredRoots, 0, {}, []);\n\tconst expanded = new Set(state.expandedRowIds === \"all\" ? [] : (state.expandedRowIds ?? []));\n\tconst sortNodes = (nodes: readonly PreparedNode<T>[]): PreparedNode<T>[] =>\n\t\t[...nodes].sort((left, right) => {\n\t\t\tfor (const sort of sorting) {\n\t\t\t\tconst comparison = compareAnalyticalValues(left.values[sort.id], right.values[sort.id], columnsById.get(sort.id));\n\t\t\t\tif (comparison !== 0) return sort.desc ? -comparison : comparison;\n\t\t\t}\n\t\t\treturn 0;\n\t\t});\n\tconst materialize = (nodes: readonly PreparedNode<T>[], parentId: string | null, level: number): AnalyticalModelRow<T>[] =>\n\t\tsortNodes(nodes).map((node) => ({\n\t\t\tid: node.id,\n\t\t\tparentId,\n\t\t\tkind: node.kind,\n\t\t\tsourceRow: node.sourceRow,\n\t\t\toriginal: node.sourceRow?.original,\n\t\t\tvalues: node.values,\n\t\t\tlevel,\n\t\t\tchildren: materialize(node.children, node.id, level + 1),\n\t\t\tisExpandable: node.children.length > 0,\n\t\t\tisExpanded: node.children.length > 0 && (state.expandedRowIds === \"all\" || expanded.has(node.id)),\n\t\t\tgroupingLevelId: node.groupingLevelId\n\t\t}));\n\tconst rows = materialize(prepared, null, 0);\n\treturn {\n\t\tcolumns,\n\t\trows,\n\t\t...indexAnalyticalRows(rows),\n\t\tgrandTotals:\n\t\t\toptions.grandTotals === false ? null : aggregate(options.grandTotalsScope === \"all\" ? sourceRoots : filteredRoots, \"grand\", {}),\n\t\tdiagnostics: { orphanRowIds: tree.orphanRowIds, duplicateRowIds: tree.duplicateRowIds, cyclicRowIds: tree.cyclicRowIds }\n\t};\n}\n","import {\n\taddCalendarDays,\n\taddCalendarMonths,\n\taddCalendarYears,\n\tcreateCalendarDate,\n\tformatDate,\n\tgetStartOfDay,\n\tgetStartOfMonth,\n\tgetStartOfWeek,\n\tgetStartOfYear,\n\tparseDateByPattern,\n\tresolveDateFormatPreset\n} from \"../formatters\";\n\nimport { aggregateAnalyticalValues } from \"./aggregation\";\nimport {\n\ttype AnalyticalDataRow,\n\ttype AnalyticalDateColumn,\n\ttype AnalyticalDateColumnsOptions,\n\ttype AnalyticalDateColumnsPlan,\n\ttype AnalyticalValues,\n\ttype ProjectAnalyticalDateFactsOptions\n} from \"./types\";\nimport { analyticalIdentity } from \"./valueComparison\";\n\nconst CALENDAR_FORMAT = resolveDateFormatPreset(\"yyyy-MM-dd\");\nconst DATE_LABEL_FORMAT = resolveDateFormatPreset(\"dd.MM.yyyy\");\n\n/** Принимает только календарный контракт; преобразование timestamp принадлежит transport/domain адаптеру. */\nfunction readCalendarDate(value: unknown): Date | null {\n\tif (typeof value !== \"string\" || value.length !== 10) return null;\n\tconst parsed = parseDateByPattern(value, \"yyyy-MM-dd\");\n\treturn parsed?.kind === \"date-time\" ? parsed.date : null;\n}\n\nfunction calendarString(date: Date): string {\n\treturn formatDate(date, CALENDAR_FORMAT);\n}\n\nfunction bucketStart(date: Date, granularity: AnalyticalDateColumnsOptions[\"granularity\"]): Date {\n\tswitch (granularity) {\n\t\tcase \"day\":\n\t\t\treturn getStartOfDay(date);\n\t\tcase \"week\":\n\t\t\treturn getStartOfWeek(date, 1);\n\t\tcase \"month\":\n\t\t\treturn getStartOfMonth(date);\n\t\tcase \"quarter\":\n\t\t\treturn createCalendarDate(date.getFullYear(), Math.floor(date.getMonth() / 3) * 3, 1);\n\t\tcase \"year\":\n\t\t\treturn getStartOfYear(date);\n\t}\n}\n\nfunction nextBucket(date: Date, granularity: AnalyticalDateColumnsOptions[\"granularity\"]): Date {\n\tswitch (granularity) {\n\t\tcase \"day\":\n\t\t\treturn addCalendarDays(date, 1);\n\t\tcase \"week\":\n\t\t\treturn addCalendarDays(date, 7);\n\t\tcase \"month\":\n\t\t\treturn addCalendarMonths(date, 1);\n\t\tcase \"quarter\":\n\t\t\treturn addCalendarMonths(date, 3);\n\t\tcase \"year\":\n\t\t\treturn addCalendarYears(date, 1);\n\t}\n}\n\n/** Строит ограниченный календарный план; ISO-моменты времени сюда не передаются. */\nexport function createAnalyticalDateColumnsPlan(options: AnalyticalDateColumnsOptions): AnalyticalDateColumnsPlan {\n\tconst from = readCalendarDate(options.from);\n\tconst to = readCalendarDate(options.to);\n\tif (!from || !to || calendarString(from) !== options.from || calendarString(to) !== options.to || options.from > options.to)\n\t\tthrow new Error(\"Некорректный календарный диапазон аналитических столбцов.\");\n\tconst maxColumns = options.maxColumns ?? 366;\n\tif (!Number.isSafeInteger(maxColumns) || maxColumns < 1)\n\t\tthrow new Error(\"Лимит динамических столбцов должен быть положительным целым числом.\");\n\tif (!options.id || options.identityColumnIds.length === 0)\n\t\tthrow new Error(\"Динамическим столбцам нужны идентификатор и ключи сопоставления фактов.\");\n\tconst columns: AnalyticalDateColumn[] = [];\n\tfor (let start = bucketStart(from, options.granularity); start <= to; start = nextBucket(start, options.granularity)) {\n\t\tif (columns.length >= maxColumns) throw new Error(`Превышен лимит динамических столбцов: ${maxColumns}`);\n\t\tconst key = calendarString(start);\n\t\tconst end = calendarString(addCalendarDays(nextBucket(start, options.granularity), -1));\n\t\tcolumns.push({\n\t\t\tid: `${options.id}:${options.granularity}:${key}`,\n\t\t\tlabel: options.granularity === \"day\" ? formatDate(start, DATE_LABEL_FORMAT) : `${key} — ${end}`,\n\t\t\tfrom: key < options.from ? options.from : key,\n\t\t\tto: end > options.to ? options.to : end\n\t\t});\n\t}\n\treturn { options: { ...options, identityColumnIds: [...options.identityColumnIds] }, columns };\n}\n\nfunction factColumnId(fact: AnalyticalValues, plan: AnalyticalDateColumnsPlan): string | undefined {\n\t// Факт без полного ключа нельзя сопоставить строке; общий итог использует ту же область допустимых фактов.\n\tif (plan.options.identityColumnIds.some((id) => fact[id] === undefined || fact[id] === null)) return undefined;\n\tconst date = readCalendarDate(fact[plan.options.dateColumnId]);\n\tif (!date) return undefined;\n\tconst day = calendarString(date);\n\tif (day < plan.options.from || day > plan.options.to) return undefined;\n\treturn `${plan.options.id}:${plan.options.granularity}:${calendarString(bucketStart(date, plan.options.granularity))}`;\n}\n\n/** Сопоставляет отдельные facts составному ключу строки; порядок и количество base rows неизменны. */\nexport function projectAnalyticalDateFacts<T>(args: ProjectAnalyticalDateFactsOptions<T>): readonly AnalyticalDataRow<T>[] {\n\tconst { rows, facts, plan } = args;\n\tconst byIdentity = new Map<string, Map<string, unknown[]>>();\n\tfor (const fact of facts) {\n\t\tconst columnId = factColumnId(fact, plan);\n\t\tif (!columnId) continue;\n\t\tconst identity = analyticalIdentity(fact, plan.options.identityColumnIds);\n\t\tlet buckets = byIdentity.get(identity);\n\t\tif (!buckets) {\n\t\t\tbuckets = new Map();\n\t\t\tbyIdentity.set(identity, buckets);\n\t\t}\n\t\tconst bucket = buckets.get(columnId);\n\t\tif (bucket) bucket.push(fact[plan.options.measureColumnId]);\n\t\telse buckets.set(columnId, [fact[plan.options.measureColumnId]]);\n\t}\n\treturn rows.map((row) => {\n\t\tconst buckets = byIdentity.get(analyticalIdentity(row.values, plan.options.identityColumnIds));\n\t\tconst values: Record<string, unknown> = { ...row.values };\n\t\tfor (const column of plan.columns) {\n\t\t\tif (Object.hasOwn(values, column.id)) throw new Error(`Динамический столбец перезаписывает исходное поле: ${column.id}`);\n\t\t\tconst bucket = buckets?.get(column.id);\n\t\t\tvalues[column.id] = bucket ? aggregateAnalyticalValues(bucket, plan.options.aggregation) : null;\n\t\t}\n\t\treturn { ...row, values };\n\t});\n}\n\n/**\n * Общие итоги считаются по исходным facts с полным ключом: среднее от средних не подменяет взвешенный результат.\n * Отбор допустимых непустых identities по области доступа и фильтрам выполняет вызывающий адаптер.\n */\nexport function aggregateAnalyticalDateFacts(facts: readonly AnalyticalValues[], plan: AnalyticalDateColumnsPlan): AnalyticalValues {\n\tconst buckets = new Map<string, unknown[]>();\n\tfor (const fact of facts) {\n\t\tconst id = factColumnId(fact, plan);\n\t\tif (!id) continue;\n\t\tconst bucket = buckets.get(id);\n\t\tif (bucket) bucket.push(fact[plan.options.measureColumnId]);\n\t\telse buckets.set(id, [fact[plan.options.measureColumnId]]);\n\t}\n\treturn Object.fromEntries(\n\t\tplan.columns.map((column) => [\n\t\t\tcolumn.id,\n\t\t\tbuckets.has(column.id) ? aggregateAnalyticalValues(buckets.get(column.id) ?? [], plan.options.aggregation) : null\n\t\t])\n\t);\n}\n","import { indexAnalyticalRows } from \"./indexAnalyticalRows\";\nimport { type AnalyticalModelRow, type AnalyticalTableModel } from \"./types\";\n\n/** Раскрытие не меняет группировки, формулы и итоги; UI мемоизирует базовую модель отдельно. */\nexport function projectAnalyticalTableExpansion<T>(\n\tmodel: AnalyticalTableModel<T>,\n\texpandedRowIds: readonly string[] | \"all\"\n): AnalyticalTableModel<T> {\n\tconst expanded = new Set(expandedRowIds === \"all\" ? [] : expandedRowIds);\n\tconst project = (nodes: readonly AnalyticalModelRow<T>[]): AnalyticalModelRow<T>[] =>\n\t\tnodes.map((node) => ({\n\t\t\t...node,\n\t\t\tisExpanded: node.isExpandable && (expandedRowIds === \"all\" || expanded.has(node.id)),\n\t\t\tchildren: project(node.children)\n\t\t}));\n\tconst rows = project(model.rows);\n\treturn { ...model, rows, ...indexAnalyticalRows(rows) };\n}\n","import { type AnalyticalExportColumn, type AnalyticalExportProjection, type ProjectAnalyticalTableExportOptions } from \"./types\";\n\n/** Проекция для /excel или /table-document; сам runtime не скачивает файлы и не читает DOM. */\nexport function projectAnalyticalTableExport<T>(args: ProjectAnalyticalTableExportOptions<T>): AnalyticalExportProjection {\n\tconst { model } = args;\n\tconst columns: readonly AnalyticalExportColumn<T>[] = args.columns ?? model.columns;\n\tconst selected = new Set(args.selectedRowIds ?? []);\n\tconst source = args.scope === \"visible\" ? model.visibleRows : model.flatRows;\n\tconst rows: AnalyticalExportProjection[\"rows\"][number][] = source\n\t\t.filter((row) => (args.includeGroups !== false || row.kind !== \"group\") && (args.scope !== \"selected\" || selected.has(row.id)))\n\t\t.map((row) => ({\n\t\t\tid: row.id,\n\t\t\tlevel: row.level,\n\t\t\tkind: row.kind,\n\t\t\tvalues: columns.map((column) => (column.format ? column.format(row.values[column.id], row) : row.values[column.id]))\n\t\t}));\n\tif (args.includeGrandTotals && model.grandTotals)\n\t\trows.push({\n\t\t\tid: \"analytical-grand-total\",\n\t\t\tlevel: 0,\n\t\t\tkind: \"grand\",\n\t\t\tvalues: columns.map((column) => {\n\t\t\t\tconst value = model.grandTotals?.[column.id];\n\t\t\t\treturn column.formatTotal ? column.formatTotal(value) : value;\n\t\t\t})\n\t\t});\n\treturn { columns: columns.map((column) => ({ id: column.id, label: column.label ?? column.id })), rows };\n}\n"],"mappings":";;;;;;;;AAGA,SAAgB,EAA0B,GAA4B,GAAmD;CACxH,IAAM,IAAU,EAAO,QAAQ,MAAU,KAAU,QAA+B,MAAU,EAAE;CAC9F,IAAI,MAAgB,SAAS,OAAO,EAAQ;CAC5C,IAAI,IAAQ,GACR,IAAM,GACN,IAAU,UACV,IAAU;CACd,KAAK,IAAM,KAAS,GACf,OAAO,KAAU,YAAY,CAAC,OAAO,SAAS,CAAK,MACvD,KAAS,GACT,KAAO,GACP,IAAU,KAAK,IAAI,GAAS,CAAK,GACjC,IAAU,KAAK,IAAI,GAAS,CAAK;CAElC,IAAI,MAAU,GAAG,OAAO;CACxB,QAAQ,GAAR;EACC,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO;EACR,KAAK,OACJ,OAAO,IAAM;CACf;AACD;;;ACtBA,SAAgB,EACf,GACA,IAAuC,EAAQ,KAAK,MAAW,EAAO,EAAE,GAC5C;CAC5B,IAAM,IAAO,IAAI,IAAI,EAAQ,KAAK,MAAW,CAAC,EAAO,IAAI,CAAM,CAAC,CAAC;CACjE,IAAI,EAAK,SAAS,EAAQ,QAAQ,MAAU,MAAM,8DAA8D;CAChH,IAAM,oBAAU,IAAI,IAAY,GAC1B,oBAAW,IAAI,IAAY,GAC3B,IAAqB,CAAC,GACtB,IAAqC,CAAC,GACtC,KAAS,MAAqB;EACnC,IAAI,EAAQ,IAAI,CAAE,GAAG;EACrB,IAAI,EAAS,IAAI,CAAE,GAAG,MAAU,MAAM,mDAAmD,GAAI;EAC7F,IAAM,IAAS,EAAK,IAAI,CAAE;EAC1B,IAAI,CAAC,GAAQ,MAAU,MAAM,mDAAmD,GAAI;EACpF,IAAI,EAAO,WAAW,EAAO,WAAW,MAAU,MAAM,WAAW,EAAG,kCAAkC;EACxG,EAAS,IAAI,CAAE;EACf,IAAM,IAAe,EAAiB,EAAO,SAAS,gBAAgB,EAAO,WAAW,gBAAgB,CAAC,CAAC;EAC1G,KAAK,IAAM,KAAc,GAAc,EAAM,CAAU;EACvD,IAAI,EAAO,SAAS;GAEnB,IAAM,IAAW,EAAoB;IAAE,WAAW,EAAO,QAAQ;IAAW,MAAM,EAAO,QAAQ;GAAa,CAAC;GAC/G,IAAI,CAAC,EAAS,IAAI,MAAU,MAAM,mBAAmB,EAAG,wBAAwB,EAAO,QAAQ,WAAW;GAC1G,EAAM,KAAK;IACV,UAAU;IACV;IACA,UAAU,MAAW;KACpB,IAAM,IAAS,EAAS,QAAQ,EAAE,GAAG,EAAO,CAAC;KAC7C,IAAI,CAAC,EAAO,IAAI,MAAU,MAAM,0BAA0B,EAAG,IAAI,EAAO,QAAQ;KAChF,OAAO,EAAO;IACf;GACD,CAAC;EACF,OAAO,AAAI,EAAO,aACjB,EAAM,KAAK;GAAE,UAAU;GAAI;GAAc,SAAS,EAAO,UAAU;EAAQ,CAAC;EAI7E,AAFA,EAAS,OAAO,CAAE,GAClB,EAAQ,IAAI,CAAE,GACd,EAAS,KAAK,CAAE;CACjB;CACA,KAAK,IAAM,KAAM,GAAmB,EAAM,CAAE;CAC5C,OAAO;EAAE;EAAO,mBAAmB;CAAS;AAC7C;AAGA,SAAgB,EAA0B,GAA0B,GAAmD;CACtH,IAAM,IAAkC,EAAE,GAAG,EAAO;CACpD,KAAK,IAAM,KAAQ,EAAK,OAAO,EAAO,EAAK,YAAY,EAAK,QAAQ,CAAM;CAC1E,OAAO;AACR;;;AC/CA,SAAgB,EAAmB,GAA0B,GAAgC;CAC5F,OAAO,EACN,EAAI,KAAK,MAAO;EACf,IAAM,IAAQ,EAAO;EACrB,OAAO;GAAC;GAAI,MAAU,OAAO,SAAS,OAAO;GAAO;EAAK;CAC1D,CAAC,CACF;AACD;AAEA,SAAgB,EAA2B,GAAe,GAAgB,GAAsC;CAC/G,IAAI,OAAO,GAAG,GAAM,CAAK,GAAG,OAAO;CACnC,IAAI,KAAS,MAA4B,OAAO;CAChD,IAAI,KAAU,MAA6B,OAAO;CAClD,IAAI,GAAQ,SAAS,OAAO,EAAO,QAAQ,GAAM,CAAK;CACtD,IAAI,GAAQ,cAAc,QAAQ;EACjC,IAAM,IAAW,EAAU,CAAI,GACzB,IAAY,EAAU,CAAK;EACjC,IAAI,KAAY,GAAW,OAAO,EAAS,QAAQ,IAAI,EAAU,QAAQ;CAC1E;CAGA,OAFI,OAAO,KAAS,YAAY,OAAO,KAAU,WAAiB,IAAO,IACrE,OAAO,KAAS,aAAa,OAAO,KAAU,YAAkB,OAAO,CAAI,IAAI,OAAO,CAAK,IACxF,EAAe,OAAO,CAAI,GAAG,OAAO,CAAK,CAAC;AAClD;;;ACvBA,SAAgB,EAA2B,GAA2B,GAA0B,GAAuC;CACtI,IAAM,IAAQ,EAAI,OAAO,EAAO;CAChC,IAAI,GAAQ,QAAQ,OAAO,EAAO,OAAO,GAAO,GAAQ,CAAG;CAC3D,IAAM,IAAW,EAAO,OAClB,KAAW,MAAmB,EAAwB,GAAO,GAAO,CAAM,GAC1E,IAAQ,KAAU,QAA+B,MAAU;CACjE,QAAQ,EAAO,YAAY,UAA3B;EACC,KAAK,UACJ,OAAO,EAAQ,CAAQ,MAAM;EAC9B,KAAK,aACJ,OAAO,EAAQ,CAAQ,MAAM;EAC9B,KAAK,YACJ,OAAO,EAAqB,OAAO,KAAS,EAAE,CAAC,CAAC,CAAC,SAAS,EAAqB,OAAO,KAAY,EAAE,CAAC,CAAC;EACvG,KAAK,cACJ,OAAO,EAAqB,OAAO,KAAS,EAAE,CAAC,CAAC,CAAC,WAAW,EAAqB,OAAO,KAAY,EAAE,CAAC,CAAC;EACzG,KAAK,MACJ,OAAO,MAAM,QAAQ,CAAQ,KAAK,EAAS,MAAM,MAAkB,EAAQ,CAAI,MAAM,CAAC;EACvF,KAAK,WACJ,OAAO,MAAM,QAAQ,CAAQ,KAAK,EAAS,WAAW,KAAK,CAAC,KAAS,EAAQ,EAAS,EAAE,KAAK,KAAK,EAAQ,EAAS,EAAE,KAAK;EAC3H,KAAK,MACJ,OAAO,CAAC,KAAS,EAAQ,CAAQ,IAAI;EACtC,KAAK,OACJ,OAAO,CAAC,KAAS,EAAQ,CAAQ,KAAK;EACvC,KAAK,MACJ,OAAO,CAAC,KAAS,EAAQ,CAAQ,IAAI;EACtC,KAAK,OACJ,OAAO,CAAC,KAAS,EAAQ,CAAQ,KAAK;EACvC,KAAK,SACJ,OAAO;EACR,KAAK,YACJ,OAAO,CAAC;CACV;AACD;;;ACnCA,SAAgB,EACf,GACwE;CACxE,IAAM,IAAoC,CAAC,GACrC,IAAuC,CAAC,GACxC,oBAAU,IAAI,IAAmC,GACjD,KAAS,GAAyC,MAA2B;EAClF,KAAK,IAAM,KAAO,GAIjB,AAHA,EAAS,KAAK,CAAG,GACjB,EAAQ,IAAI,EAAI,IAAI,CAAG,GACnB,KAAS,EAAY,KAAK,CAAG,GACjC,EAAM,EAAI,UAAU,KAAW,EAAI,UAAU;CAE/C;CAEA,OADA,EAAM,GAAM,EAAI,GACT;EAAE;EAAU;EAAa;CAAQ;AACzC;;;ACSA,SAAgB,EAA6B,GAAuE;CACnH,IAAM,EAAE,aAAU,YAAS,WAAQ,CAAC,MAAM,GACpC,IAAO,EAAgC,CAAO,GAC9C,IAAc,IAAI,IAAI,EAAQ,KAAK,MAAW,CAAC,EAAO,IAAI,CAAM,CAAC,CAAC,GAClE,IAAW,EAAM,YAAY,CAAC,GAC9B,IAAU,EAAM,WAAW,CAAC,GAC5B,IAAU,EAAM,WAAW,CAAC;CAClC,KAAK,IAAM,KAAM,CAAC,GAAG,EAAQ,KAAK,MAAS,EAAK,EAAE,GAAG,GAAG,EAAQ,KAAK,MAAW,EAAO,EAAE,CAAC,GACzF,IAAI,CAAC,EAAY,IAAI,CAAE,GAAG,MAAU,MAAM,sCAAsC,GAAI;CAErF,IAAI,EAAiB,EAAS,KAAK,MAAU,EAAM,EAAE,CAAC,CAAC,CAAC,WAAW,EAAS,QAC3E,MAAU,MAAM,2DAA2D;CAC5E,KAAK,IAAM,KAAS,GACnB,IAAI,EAAM,aAAa,WAAW,GAAG,MAAU,MAAM,WAAW,EAAM,GAAG,iCAAiC;CAC3G,IAAM,IAAW,EAAS,KAAK,KAAK,OAAS;EAAE,GAAG;EAAK,QAAQ,EAA0B,EAAI,QAAQ,CAAI;CAAE,EAAE;CAC7G,IAAI,EAAS,MAAM,MAAQ,EAAI,GAAG,WAAW,CAAC,GAAG,MAAU,MAAM,0DAA0D;CAC3H,IAAM,IAAO,EAAmB,GAAU;EAAE,WAAW,MAAQ,EAAI;EAAI,iBAAiB,MAAQ,EAAI;CAAS,CAAC,GACxG,IAAQ,IAAI,IAAI,EAAK,UAAU,GAC/B,IAAiB,EAAQ,oBAAoB,MAA8B,EAAM,IAAI,EAAI,EAAE,IAC3F,KAAW,OAAmE;EACnF,IAAI,EAAK;EACT,MAAM;EACN,WAAW,EAAK,QAAQ,IAAI,EAAK,EAAE;EACnC,QAAQ,EAAK;EACb,WAAW,EAAK,YAAY,CAAC,EAAA,CAAG,IAAI,CAAO;CAC5C,IACM,IAAc,EAAK,KAAK,IAAI,CAAO,GACnC,KAAe,MAA8D;EAClF,IAAM,IAA+B,CAAC,GAChC,KAAS,MAAgC;GAC9C,AAAI,EAAK,aAAa,EAAe,EAAK,SAAS,KAAG,EAAK,KAAK,EAAK,SAAS;GAC9E,KAAK,IAAM,KAAS,EAAK,UAAU,EAAM,CAAK;EAC/C;EACA,KAAK,IAAM,KAAQ,GAAO,EAAM,CAAI;EACpC,OAAO;CACR,GACM,KAAa,GAAmC,GAA0B,MAA6C;EAC5H,IAAM,IAAU;GAAE;GAAO,MAAM,EAAY,CAAK;GAAG,cAAc;EAAK,GAChE,IAAkC,EAAE,GAAG,EAAK;EAClD,KAAK,IAAM,KAAU,GACf,EAAO,cACZ,EAAO,EAAO,MACb,OAAO,EAAO,aAAc,aACzB,EAAO,UAAU,CAAO,IACxB,EACA,EAAQ,KAAK,KAAK,MAAQ,EAAI,OAAO,EAAO,GAAG,GAC/C,EAAO,SACR;EAQJ,OANA,OAAO,OAAO,GAAQ,EAAQ,YAAY,CAAO,CAAC,GAM3C,EAA0B,GAAQ;GADpB,GAAG;GAAM,OAAO,EAAK,MAAM,QAAQ,MAAS,CAAC,OAAO,OAAO,GAAQ,EAAK,QAAQ,CAAC;EAC7D,CAAU;CACpD,GAEM,KAAe,MACpB,EAAM,SAAS,MAAS;EACvB,IAAM,IAAY,EAAK;EACvB,IAAI,KAAa,EAAQ,OAAO,MAAW,EAAwB,GAAW,GAAQ,EAAY,IAAI,EAAO,EAAE,CAAC,CAAC,GAChH,OAAO,CAAC,CAAI;EACb,IAAM,IAAW,EAAY,EAAK,QAAQ;EAC1C,OAAO,EAAS,SAAS,IAAI,CAAC;GAAE,GAAG;GAAM;EAAS,CAAC,IAAI,CAAC;CACzD,CAAC,GACI,IAAgB,EAAQ,SAAS,IAAI,EAAY,CAAW,IAAI,GAChE,KACL,GACA,GACA,GACA,MACuB;EACvB,IAAM,IAAQ,EAAS;EACvB,IAAI,CAAC,GAAO,OAAO;EACnB,IAAM,oBAAU,IAAI,IAA+B;EACnD,KAAK,IAAM,KAAQ,GAAO;GACzB,IAAM,IAAM,EAAmB,EAAK,QAAQ,EAAM,YAAY,GACxD,IAAS,EAAQ,IAAI,CAAG;GAC9B,AAAI,IAAQ,EAAO,KAAK,CAAI,IACvB,EAAQ,IAAI,GAAK,CAAC,CAAI,CAAC;EAC7B;EACA,OAAO,MAAM,KAAK,IAAU,CAAC,GAAK,OAAa;GAC9C,IAAM,IAAW;IAAC,GAAG;IAAc,EAAM;IAAI;GAAG,GAC1C,IAAK,oBAAoB,EAAgB,CAAQ;GACvD,IAAI,EAAK,QAAQ,IAAI,CAAE,GAAG,MAAU,MAAM,mDAAmD,GAAI;GACjG,IAAM,IAAoC,EAAE,GAAG,EAAK;GACpD,KAAK,IAAM,KAAY,CAAC,GAAG,EAAM,cAAc,GAAI,EAAM,oBAAoB,CAAC,CAAE,GAC/E,EAAS,KAAY,EAAQ,EAAE,CAAC,OAAO;GACxC,OAAO;IACN;IACA,MAAM;IACN,iBAAiB,EAAM;IACvB,QAAQ,EAAU,GAAS,SAAS,CAAQ;IAC5C,UAAU,EAAW,GAAS,IAAa,GAAG,GAAU,CAAQ;GACjE;EACD,CAAC;CACF,GACM,IAAW,EAAW,GAAe,GAAG,CAAC,GAAG,CAAC,CAAC,GAC9C,IAAW,IAAI,IAAI,EAAM,mBAAmB,QAAQ,CAAC,IAAK,EAAM,kBAAkB,CAAC,CAAE,GACrF,KAAa,MAClB,CAAC,GAAG,CAAK,CAAC,CAAC,MAAM,GAAM,MAAU;EAChC,KAAK,IAAM,KAAQ,GAAS;GAC3B,IAAM,IAAa,EAAwB,EAAK,OAAO,EAAK,KAAK,EAAM,OAAO,EAAK,KAAK,EAAY,IAAI,EAAK,EAAE,CAAC;GAChH,IAAI,MAAe,GAAG,OAAO,EAAK,OAAO,CAAC,IAAa;EACxD;EACA,OAAO;CACR,CAAC,GACI,KAAe,GAAmC,GAAyB,MAChF,EAAU,CAAK,CAAC,CAAC,KAAK,OAAU;EAC/B,IAAI,EAAK;EACT;EACA,MAAM,EAAK;EACX,WAAW,EAAK;EAChB,UAAU,EAAK,WAAW;EAC1B,QAAQ,EAAK;EACb;EACA,UAAU,EAAY,EAAK,UAAU,EAAK,IAAI,IAAQ,CAAC;EACvD,cAAc,EAAK,SAAS,SAAS;EACrC,YAAY,EAAK,SAAS,SAAS,MAAM,EAAM,mBAAmB,SAAS,EAAS,IAAI,EAAK,EAAE;EAC/F,iBAAiB,EAAK;CACvB,EAAE,GACG,IAAO,EAAY,GAAU,MAAM,CAAC;CAC1C,OAAO;EACN;EACA;EACA,GAAG,EAAoB,CAAI;EAC3B,aACC,EAAQ,gBAAgB,KAAQ,OAAO,EAAU,EAAQ,qBAAqB,QAAQ,IAAc,GAAe,SAAS,CAAC,CAAC;EAC/H,aAAa;GAAE,cAAc,EAAK;GAAc,iBAAiB,EAAK;GAAiB,cAAc,EAAK;EAAa;CACxH;AACD;;;ACtIA,IAAM,IAAkB,EAAwB,YAAY,GACtD,IAAoB,EAAwB,YAAY;AAG9D,SAAS,EAAiB,GAA6B;CACtD,IAAI,OAAO,KAAU,YAAY,EAAM,WAAW,IAAI,OAAO;CAC7D,IAAM,IAAS,EAAmB,GAAO,YAAY;CACrD,OAAO,GAAQ,SAAS,cAAc,EAAO,OAAO;AACrD;AAEA,SAAS,EAAe,GAAoB;CAC3C,OAAO,EAAW,GAAM,CAAe;AACxC;AAEA,SAAS,EAAY,GAAY,GAAgE;CAChG,QAAQ,GAAR;EACC,KAAK,OACJ,OAAO,EAAc,CAAI;EAC1B,KAAK,QACJ,OAAO,EAAe,GAAM,CAAC;EAC9B,KAAK,SACJ,OAAO,EAAgB,CAAI;EAC5B,KAAK,WACJ,OAAO,EAAmB,EAAK,YAAY,GAAG,KAAK,MAAM,EAAK,SAAS,IAAI,CAAC,IAAI,GAAG,CAAC;EACrF,KAAK,QACJ,OAAO,EAAe,CAAI;CAC5B;AACD;AAEA,SAAS,EAAW,GAAY,GAAgE;CAC/F,QAAQ,GAAR;EACC,KAAK,OACJ,OAAO,EAAgB,GAAM,CAAC;EAC/B,KAAK,QACJ,OAAO,EAAgB,GAAM,CAAC;EAC/B,KAAK,SACJ,OAAO,EAAkB,GAAM,CAAC;EACjC,KAAK,WACJ,OAAO,EAAkB,GAAM,CAAC;EACjC,KAAK,QACJ,OAAO,EAAiB,GAAM,CAAC;CACjC;AACD;AAGA,SAAgB,EAAgC,GAAkE;CACjH,IAAM,IAAO,EAAiB,EAAQ,IAAI,GACpC,IAAK,EAAiB,EAAQ,EAAE;CACtC,IAAI,CAAC,KAAQ,CAAC,KAAM,EAAe,CAAI,MAAM,EAAQ,QAAQ,EAAe,CAAE,MAAM,EAAQ,MAAM,EAAQ,OAAO,EAAQ,IACxH,MAAU,MAAM,2DAA2D;CAC5E,IAAM,IAAa,EAAQ,cAAc;CACzC,IAAI,CAAC,OAAO,cAAc,CAAU,KAAK,IAAa,GACrD,MAAU,MAAM,qEAAqE;CACtF,IAAI,CAAC,EAAQ,MAAM,EAAQ,kBAAkB,WAAW,GACvD,MAAU,MAAM,yEAAyE;CAC1F,IAAM,IAAkC,CAAC;CACzC,KAAK,IAAI,IAAQ,EAAY,GAAM,EAAQ,WAAW,GAAG,KAAS,GAAI,IAAQ,EAAW,GAAO,EAAQ,WAAW,GAAG;EACrH,IAAI,EAAQ,UAAU,GAAY,MAAU,MAAM,yCAAyC,GAAY;EACvG,IAAM,IAAM,EAAe,CAAK,GAC1B,IAAM,EAAe,EAAgB,EAAW,GAAO,EAAQ,WAAW,GAAG,EAAE,CAAC;EACtF,EAAQ,KAAK;GACZ,IAAI,GAAG,EAAQ,GAAG,GAAG,EAAQ,YAAY,GAAG;GAC5C,OAAO,EAAQ,gBAAgB,QAAQ,EAAW,GAAO,CAAiB,IAAI,GAAG,EAAI,KAAK;GAC1F,MAAM,IAAM,EAAQ,OAAO,EAAQ,OAAO;GAC1C,IAAI,IAAM,EAAQ,KAAK,EAAQ,KAAK;EACrC,CAAC;CACF;CACA,OAAO;EAAE,SAAS;GAAE,GAAG;GAAS,mBAAmB,CAAC,GAAG,EAAQ,iBAAiB;EAAE;EAAG;CAAQ;AAC9F;AAEA,SAAS,EAAa,GAAwB,GAAqD;CAElG,IAAI,EAAK,QAAQ,kBAAkB,MAAM,MAAO,EAAK,OAAQ,KAAA,KAAa,EAAK,OAAQ,IAAI,GAAG;CAC9F,IAAM,IAAO,EAAiB,EAAK,EAAK,QAAQ,aAAa;CAC7D,IAAI,CAAC,GAAM;CACX,IAAM,IAAM,EAAe,CAAI;CAC3B,UAAM,EAAK,QAAQ,QAAQ,IAAM,EAAK,QAAQ,KAClD,OAAO,GAAG,EAAK,QAAQ,GAAG,GAAG,EAAK,QAAQ,YAAY,GAAG,EAAe,EAAY,GAAM,EAAK,QAAQ,WAAW,CAAC;AACpH;AAGA,SAAgB,EAA8B,GAA6E;CAC1H,IAAM,EAAE,SAAM,UAAO,YAAS,GACxB,oBAAa,IAAI,IAAoC;CAC3D,KAAK,IAAM,KAAQ,GAAO;EACzB,IAAM,IAAW,EAAa,GAAM,CAAI;EACxC,IAAI,CAAC,GAAU;EACf,IAAM,IAAW,EAAmB,GAAM,EAAK,QAAQ,iBAAiB,GACpE,IAAU,EAAW,IAAI,CAAQ;EACrC,AAAK,MACJ,oBAAU,IAAI,IAAI,GAClB,EAAW,IAAI,GAAU,CAAO;EAEjC,IAAM,IAAS,EAAQ,IAAI,CAAQ;EACnC,AAAI,IAAQ,EAAO,KAAK,EAAK,EAAK,QAAQ,gBAAgB,IACrD,EAAQ,IAAI,GAAU,CAAC,EAAK,EAAK,QAAQ,gBAAgB,CAAC;CAChE;CACA,OAAO,EAAK,KAAK,MAAQ;EACxB,IAAM,IAAU,EAAW,IAAI,EAAmB,EAAI,QAAQ,EAAK,QAAQ,iBAAiB,CAAC,GACvF,IAAkC,EAAE,GAAG,EAAI,OAAO;EACxD,KAAK,IAAM,KAAU,EAAK,SAAS;GAClC,IAAI,OAAO,OAAO,GAAQ,EAAO,EAAE,GAAG,MAAU,MAAM,sDAAsD,EAAO,IAAI;GACvH,IAAM,IAAS,GAAS,IAAI,EAAO,EAAE;GACrC,EAAO,EAAO,MAAM,IAAS,EAA0B,GAAQ,EAAK,QAAQ,WAAW,IAAI;EAC5F;EACA,OAAO;GAAE,GAAG;GAAK;EAAO;CACzB,CAAC;AACF;AAMA,SAAgB,EAA6B,GAAoC,GAAmD;CACnI,IAAM,oBAAU,IAAI,IAAuB;CAC3C,KAAK,IAAM,KAAQ,GAAO;EACzB,IAAM,IAAK,EAAa,GAAM,CAAI;EAClC,IAAI,CAAC,GAAI;EACT,IAAM,IAAS,EAAQ,IAAI,CAAE;EAC7B,AAAI,IAAQ,EAAO,KAAK,EAAK,EAAK,QAAQ,gBAAgB,IACrD,EAAQ,IAAI,GAAI,CAAC,EAAK,EAAK,QAAQ,gBAAgB,CAAC;CAC1D;CACA,OAAO,OAAO,YACb,EAAK,QAAQ,KAAK,MAAW,CAC5B,EAAO,IACP,EAAQ,IAAI,EAAO,EAAE,IAAI,EAA0B,EAAQ,IAAI,EAAO,EAAE,KAAK,CAAC,GAAG,EAAK,QAAQ,WAAW,IAAI,IAC9G,CAAC,CACF;AACD;;;ACrJA,SAAgB,EACf,GACA,GAC0B;CAC1B,IAAM,IAAW,IAAI,IAAI,MAAmB,QAAQ,CAAC,IAAI,CAAc,GACjE,KAAW,MAChB,EAAM,KAAK,OAAU;EACpB,GAAG;EACH,YAAY,EAAK,iBAAiB,MAAmB,SAAS,EAAS,IAAI,EAAK,EAAE;EAClF,UAAU,EAAQ,EAAK,QAAQ;CAChC,EAAE,GACG,IAAO,EAAQ,EAAM,IAAI;CAC/B,OAAO;EAAE,GAAG;EAAO;EAAM,GAAG,EAAoB,CAAI;CAAE;AACvD;;;ACdA,SAAgB,EAAgC,GAA0E;CACzH,IAAM,EAAE,aAAU,GACZ,IAAgD,EAAK,WAAW,EAAM,SACtE,IAAW,IAAI,IAAI,EAAK,kBAAkB,CAAC,CAAC,GAE5C,KADS,EAAK,UAAU,YAAY,EAAM,cAAc,EAAM,SAAA,CAElE,QAAQ,OAAS,EAAK,kBAAkB,MAAS,EAAI,SAAS,aAAa,EAAK,UAAU,cAAc,EAAS,IAAI,EAAI,EAAE,EAAE,CAAC,CAC9H,KAAK,OAAS;EACd,IAAI,EAAI;EACR,OAAO,EAAI;EACX,MAAM,EAAI;EACV,QAAQ,EAAQ,KAAK,MAAY,EAAO,SAAS,EAAO,OAAO,EAAI,OAAO,EAAO,KAAK,CAAG,IAAI,EAAI,OAAO,EAAO,GAAI;CACpH,EAAE;CAWH,OAVI,EAAK,sBAAsB,EAAM,eACpC,EAAK,KAAK;EACT,IAAI;EACJ,OAAO;EACP,MAAM;EACN,QAAQ,EAAQ,KAAK,MAAW;GAC/B,IAAM,IAAQ,EAAM,cAAc,EAAO;GACzC,OAAO,EAAO,cAAc,EAAO,YAAY,CAAK,IAAI;EACzD,CAAC;CACF,CAAC,GACK;EAAE,SAAS,EAAQ,KAAK,OAAY;GAAE,IAAI,EAAO;GAAI,OAAO,EAAO,SAAS,EAAO;EAAG,EAAE;EAAG;CAAK;AACxG"}
@@ -0,0 +1,4 @@
1
+ import { type AnalyticalModelRow, type AnalyticalTableModel } from "./types";
2
+ /** Единственный обход индексов полной и видимой проекций дерева. */
3
+ export declare function indexAnalyticalRows<T>(rows: readonly AnalyticalModelRow<T>[]): Pick<AnalyticalTableModel<T>, "flatRows" | "visibleRows" | "rowById">;
4
+ //# sourceMappingURL=indexAnalyticalRows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"indexAnalyticalRows.d.ts","sourceRoot":"","sources":["../../src/analytical-table/indexAnalyticalRows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAE7E,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,CAAC,EACpC,IAAI,EAAE,SAAS,kBAAkB,CAAC,CAAC,CAAC,EAAE,GACpC,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC,CAcvE"}
@@ -0,0 +1,43 @@
1
+ import { type AnalyticalAggregateContext, type AnalyticalColumn } from "./columnTypes";
2
+ import { type AnalyticalDataRow, type AnalyticalSnapshot, type AnalyticalValues } from "./dataTypes";
3
+ import { type AnalyticalViewState } from "./viewTypes";
4
+ export type AnalyticalModelRow<TOriginal = unknown> = Readonly<{
5
+ id: string;
6
+ parentId: string | null;
7
+ kind: "data" | "group";
8
+ sourceRow?: AnalyticalDataRow<TOriginal>;
9
+ original?: TOriginal;
10
+ values: AnalyticalValues;
11
+ level: number;
12
+ children: readonly AnalyticalModelRow<TOriginal>[];
13
+ isExpandable: boolean;
14
+ isExpanded: boolean;
15
+ groupingLevelId?: string;
16
+ }>;
17
+ export type AnalyticalDiagnostics = Readonly<{
18
+ orphanRowIds: readonly string[];
19
+ duplicateRowIds: readonly string[];
20
+ cyclicRowIds: readonly string[];
21
+ }>;
22
+ export type AnalyticalTableModel<TOriginal = unknown> = Readonly<{
23
+ columns: readonly AnalyticalColumn<TOriginal>[];
24
+ rows: readonly AnalyticalModelRow<TOriginal>[];
25
+ /** Все строки результата в обходе дерева; раскрытие влияет только на visibleRows. */
26
+ flatRows: readonly AnalyticalModelRow<TOriginal>[];
27
+ visibleRows: readonly AnalyticalModelRow<TOriginal>[];
28
+ rowById: ReadonlyMap<string, AnalyticalModelRow<TOriginal>>;
29
+ grandTotals: AnalyticalValues | null;
30
+ diagnostics: AnalyticalDiagnostics;
31
+ }>;
32
+ export type BuildAnalyticalTableModelOptions<TOriginal = unknown> = Readonly<{
33
+ snapshot: AnalyticalSnapshot<TOriginal>;
34
+ columns: readonly AnalyticalColumn<TOriginal>[];
35
+ state?: AnalyticalViewState;
36
+ /** По умолчанию агрегируются исходные корневые строки: дети не удваивают меры. */
37
+ isAggregateRow?: (row: AnalyticalDataRow<TOriginal>) => boolean;
38
+ aggregate?: (context: AnalyticalAggregateContext<TOriginal>) => AnalyticalValues;
39
+ grandTotals?: boolean;
40
+ /** all сохраняет общие итоги при визуальной фильтрации отдельных ветвей. */
41
+ grandTotalsScope?: "all" | "filtered";
42
+ }>;
43
+ //# sourceMappingURL=modelTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelTypes.d.ts","sourceRoot":"","sources":["../../src/analytical-table/modelTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,0BAA0B,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACrG,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,MAAM,MAAM,kBAAkB,CAAC,SAAS,GAAG,OAAO,IAAI,QAAQ,CAAC;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,iBAAiB,CAAC,SAAS,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,SAAS,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;IACnD,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IAC5C,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,MAAM,oBAAoB,CAAC,SAAS,GAAG,OAAO,IAAI,QAAQ,CAAC;IAChE,OAAO,EAAE,SAAS,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;IAChD,IAAI,EAAE,SAAS,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;IAC/C,qFAAqF;IACrF,QAAQ,EAAE,SAAS,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;IACnD,WAAW,EAAE,SAAS,kBAAkB,CAAC,SAAS,CAAC,EAAE,CAAC;IACtD,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5D,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACrC,WAAW,EAAE,qBAAqB,CAAC;CACnC,CAAC,CAAC;AAEH,MAAM,MAAM,gCAAgC,CAAC,SAAS,GAAG,OAAO,IAAI,QAAQ,CAAC;IAC5E,QAAQ,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,EAAE,SAAS,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;IAChD,KAAK,CAAC,EAAE,mBAAmB,CAAC;IAC5B,kFAAkF;IAClF,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,CAAC,SAAS,CAAC,KAAK,OAAO,CAAC;IAChE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,0BAA0B,CAAC,SAAS,CAAC,KAAK,gBAAgB,CAAC;IACjF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,KAAK,GAAG,UAAU,CAAC;CACtC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export type * from "./dataTypes";
2
+ export type * from "./columnTypes";
3
+ export type * from "./viewTypes";
4
+ export type * from "./modelTypes";
5
+ export type * from "./calculationTypes";
6
+ export type * from "./dateColumnTypes";
7
+ export type * from "./exportTypes";
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/analytical-table/types.ts"],"names":[],"mappings":"AAAA,mBAAmB,aAAa,CAAC;AACjC,mBAAmB,eAAe,CAAC;AACnC,mBAAmB,aAAa,CAAC;AACjC,mBAAmB,cAAc,CAAC;AAClC,mBAAmB,oBAAoB,CAAC;AACxC,mBAAmB,mBAAmB,CAAC;AACvC,mBAAmB,eAAe,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type AnalyticalColumn, type AnalyticalValues } from "./types";
2
+ /** Тип входит в ключ: null, undefined, строка и число не склеивают разные группы. */
3
+ export declare function analyticalIdentity(values: AnalyticalValues, ids: readonly string[]): string;
4
+ export declare function compareAnalyticalValues<T>(left: unknown, right: unknown, column?: AnalyticalColumn<T>): number;
5
+ //# sourceMappingURL=valueComparison.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"valueComparison.d.ts","sourceRoot":"","sources":["../../src/analytical-table/valueComparison.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEvE,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAO3F;AAED,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,CAa9G"}
@@ -0,0 +1,24 @@
1
+ /** Составной ключ отделён от отображаемых полей и не зависит от сортировки. */
2
+ export type AnalyticalGroupingLevel = Readonly<{
3
+ id: string;
4
+ keyColumnIds: readonly string[];
5
+ displayColumnIds?: readonly string[];
6
+ label?: string;
7
+ }>;
8
+ export type AnalyticalSorting = Readonly<{
9
+ id: string;
10
+ desc?: boolean;
11
+ }>;
12
+ export type AnalyticalFilter = Readonly<{
13
+ id: string;
14
+ operator?: "equals" | "notEquals" | "contains" | "startsWith" | "in" | "between" | "gt" | "gte" | "lt" | "lte" | "empty" | "notEmpty";
15
+ value?: unknown;
16
+ }>;
17
+ /** Состояние сериализуется для SSR/URL; Map и Set появляются только в результате. */
18
+ export type AnalyticalViewState = Readonly<{
19
+ grouping?: readonly AnalyticalGroupingLevel[];
20
+ sorting?: readonly AnalyticalSorting[];
21
+ filters?: readonly AnalyticalFilter[];
22
+ expandedRowIds?: readonly string[] | "all";
23
+ }>;
24
+ //# sourceMappingURL=viewTypes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewTypes.d.ts","sourceRoot":"","sources":["../../src/analytical-table/viewTypes.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC;IAC9C,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,OAAO,CAAC;CACf,CAAC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,CAAC;IACtI,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC,CAAC;AAEH,qFAAqF;AACrF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IAC1C,QAAQ,CAAC,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC9C,OAAO,CAAC,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACtC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;CAC3C,CAAC,CAAC"}