@dou-ui/pivot 0.0.0-stage → 0.1.0-alpha.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 (99) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/assets/default-PXde2wzm.js.map +1 -0
  4. package/dist/core/format.js +116 -0
  5. package/dist/core/format.js.map +1 -0
  6. package/dist/core/labels.js +28 -0
  7. package/dist/core/labels.js.map +1 -0
  8. package/dist/core/layout.js +190 -0
  9. package/dist/core/layout.js.map +1 -0
  10. package/dist/core/source.js +46 -0
  11. package/dist/core/source.js.map +1 -0
  12. package/dist/core/table.js +154 -0
  13. package/dist/core/table.js.map +1 -0
  14. package/dist/engine/aggregate.js +51 -0
  15. package/dist/engine/aggregate.js.map +1 -0
  16. package/dist/engine/compute.js +735 -0
  17. package/dist/engine/compute.js.map +1 -0
  18. package/dist/engine/engine.js +46 -0
  19. package/dist/engine/engine.js.map +1 -0
  20. package/dist/engine/formula.js +225 -0
  21. package/dist/engine/formula.js.map +1 -0
  22. package/dist/engine/group.js +107 -0
  23. package/dist/engine/group.js.map +1 -0
  24. package/dist/engine/hash.js +108 -0
  25. package/dist/engine/hash.js.map +1 -0
  26. package/dist/engine/index.js +8 -0
  27. package/dist/engine/show.js +132 -0
  28. package/dist/engine/show.js.map +1 -0
  29. package/dist/engine/source.js +339 -0
  30. package/dist/engine/source.js.map +1 -0
  31. package/dist/engine/tree.js +226 -0
  32. package/dist/engine/tree.js.map +1 -0
  33. package/dist/fields/fields.js +6 -0
  34. package/dist/fields/fields.js.map +1 -0
  35. package/dist/fields/fields.vue_vue_type_script_setup_true_lang.js +881 -0
  36. package/dist/fields/fields.vue_vue_type_script_setup_true_lang.js.map +1 -0
  37. package/dist/fields/filter-list.js +6 -0
  38. package/dist/fields/filter-list.js.map +1 -0
  39. package/dist/fields/filter-list.vue_vue_type_script_setup_true_lang.js +184 -0
  40. package/dist/fields/filter-list.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/fields/formula-dialog.js +6 -0
  42. package/dist/fields/formula-dialog.js.map +1 -0
  43. package/dist/fields/formula-dialog.vue_vue_type_script_setup_true_lang.js +165 -0
  44. package/dist/fields/formula-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/fields/model.js +200 -0
  46. package/dist/fields/model.js.map +1 -0
  47. package/dist/fields/top-dialog.js +6 -0
  48. package/dist/fields/top-dialog.js.map +1 -0
  49. package/dist/fields/top-dialog.vue_vue_type_script_setup_true_lang.js +174 -0
  50. package/dist/fields/top-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/index.js +16 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/locale.js +508 -0
  54. package/dist/locale.js.map +1 -0
  55. package/dist/pivot.js +6 -0
  56. package/dist/pivot.js.map +1 -0
  57. package/dist/pivot.vue_vue_type_script_setup_true_lang.js +1711 -0
  58. package/dist/pivot.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/style.css +1 -0
  60. package/dist/style.d.ts +1 -0
  61. package/dist/style.js +13 -0
  62. package/dist/types/core/format.d.ts +26 -0
  63. package/dist/types/core/labels.d.ts +14 -0
  64. package/dist/types/core/layout.d.ts +72 -0
  65. package/dist/types/core/source.d.ts +7 -0
  66. package/dist/types/core/table.d.ts +73 -0
  67. package/dist/types/engine/aggregate.d.ts +35 -0
  68. package/dist/types/engine/compute.d.ts +173 -0
  69. package/dist/types/engine/engine.d.ts +29 -0
  70. package/dist/types/engine/formula.d.ts +44 -0
  71. package/dist/types/engine/group.d.ts +34 -0
  72. package/dist/types/engine/hash.d.ts +36 -0
  73. package/dist/types/engine/index.d.ts +15 -0
  74. package/dist/types/engine/show.d.ts +27 -0
  75. package/dist/types/engine/source.d.ts +108 -0
  76. package/dist/types/engine/tree.d.ts +87 -0
  77. package/dist/types/engine/types.d.ts +148 -0
  78. package/dist/types/fields/fields.vue.d.ts +26 -0
  79. package/dist/types/fields/filter-list.vue.d.ts +20 -0
  80. package/dist/types/fields/formula-dialog.vue.d.ts +30 -0
  81. package/dist/types/fields/model.d.ts +52 -0
  82. package/dist/types/fields/top-dialog.vue.d.ts +25 -0
  83. package/dist/types/index.d.ts +458 -0
  84. package/dist/types/locale.d.ts +184 -0
  85. package/dist/types/pivot.vue.d.ts +29 -0
  86. package/dist/types/types.d.ts +199 -0
  87. package/dist/types/worker/client.d.ts +19 -0
  88. package/dist/types/worker/default.d.ts +1 -0
  89. package/dist/types/worker/index.d.ts +5 -0
  90. package/dist/types/worker/protocol.d.ts +60 -0
  91. package/dist/types/worker/serve.d.ts +22 -0
  92. package/dist/worker/client.js +191 -0
  93. package/dist/worker/client.js.map +1 -0
  94. package/dist/worker/default.js +20 -0
  95. package/dist/worker/default.js.map +1 -0
  96. package/dist/worker/index.js +3 -0
  97. package/dist/worker/serve.js +101 -0
  98. package/dist/worker/serve.js.map +1 -0
  99. package/package.json +64 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.js","names":[],"sources":["../../src/engine/compute.ts"],"sourcesContent":["import {\n BUILTIN_AGGREGATORS,\n distinctAggregator,\n FAST_AGGREGATES,\n type PivotAggregator,\n} from './aggregate'\nimport { parsePivotFormula, PivotFormulaError, type PivotFormula } from './formula'\nimport { IntIndex, typed, type PivotIndexPacket } from './hash'\nimport { PivotShown, resolveShow, type PivotResolvedShow } from './show'\n\nexport type { PivotResolvedShow }\nimport type { PivotResolvedField, PivotSource } from './source'\nimport { PivotTree, PivotTreeBuilder, type PivotLevel, type PivotTreePacket } from './tree'\nimport type {\n PivotConfig,\n PivotDimension,\n PivotFilter,\n PivotFormat,\n PivotMark,\n PivotShow,\n PivotShowAs,\n PivotValueSort,\n} from './types'\n\n/** A value of the config with everything filled in. */\nexport interface PivotResolvedValue {\n field: PivotResolvedField<unknown> | null\n aggregate: string\n /** The custom aggregator, for names that are not built in. */\n aggregator?: PivotAggregator\n /** As given; the component works out a header when there is none. */\n label?: string\n format?: PivotFormat\n /** Whether the value is a count, written without decimals. */\n integer: boolean\n /** Whether it stands in for an empty `values` (a count of records). */\n implicit?: boolean\n /** A calculated value's formula, as written (`aggregate` is then `'formula'`). */\n formula?: string\n /** How it is shown, as given (the axis is worked out by the result). */\n show?: PivotShow\n mark?: Required<PivotMark>\n}\n\n/** The ways of showing a value that write it as a percentage. */\nexport const PERCENT_SHOWS: ReadonlySet<PivotShowAs> = new Set([\n 'percentOfTotal',\n 'percentOfRow',\n 'percentOfColumn',\n 'percentOfParent',\n 'percentDifference',\n])\n\n/** A `show` as an object. */\nexport const showOf = (show: PivotShowAs | PivotShow | undefined): PivotShow | undefined =>\n show === undefined ? undefined : typeof show === 'string' ? { as: show } : show\n\n/** A `mark` with its tone filled in. */\nexport const markOf = (\n mark: 'bar' | 'scale' | PivotMark | undefined,\n): Required<PivotMark> | undefined =>\n mark === undefined\n ? undefined\n : typeof mark === 'string'\n ? { type: mark, tone: 'neutral' as const }\n : { type: mark.type, tone: mark.tone ?? 'neutral' }\n\n/**\n * Reads a calculated value's formula and finds its fields by name (or by\n * label). Throws a `PivotFormulaError` when it is not well formed, names a\n * field that is not there, or sums up one that is not a number.\n */\nexport function checkPivotFormula<Row>(source: PivotSource<Row>, text: string): PivotFormula {\n const formula = parsePivotFormula(text)\n const byLabel = new Map<string, string>()\n for (const f of source.fields.values()) if (!byLabel.has(f.label)) byLabel.set(f.label, f.name)\n for (const term of formula.terms) {\n if (term.field === null) continue\n const name = source.fields.has(term.field) ? term.field : byLabel.get(term.field)\n if (name === undefined) {\n const at = text.indexOf(term.field)\n throw new PivotFormulaError('unknownField', Math.max(0, at), term.field)\n }\n if (term.aggregate !== 'count' && source.field(name).type !== 'number') {\n throw new PivotFormulaError('notNumber', Math.max(0, text.indexOf(term.field)), term.field)\n }\n term.field = name\n }\n return formula\n}\n\nexport interface PivotComputeOptions {\n /** Aggregators by name, beside the built-in ones. */\n aggregators?: Readonly<Record<string, PivotAggregator>>\n}\n\n/** The fields of the config resolved against a source, without reading any records. */\nexport function resolveConfig(\n source: PivotSource<unknown>,\n config: PivotConfig,\n options: PivotComputeOptions = {},\n) {\n const level = (item: PivotDimension) => {\n const spec = typeof item === 'string' ? { field: item } : item\n return {\n field: source.field(spec.field),\n sort: spec.sort ?? 'asc',\n subtotal: spec.subtotal ?? true,\n by: spec.by,\n }\n }\n const formulas: (PivotFormula | null)[] = []\n const values: PivotResolvedValue[] = (config.values ?? []).map((item) => {\n const spec = typeof item === 'string' ? { field: item } : item\n const show = showOf(spec.show)\n const mark = markOf(spec.mark)\n // a share or a rank is not in the field's units\n const ownFormat = show && (PERCENT_SHOWS.has(show.as) || show.as === 'rank')\n if (spec.formula !== undefined) {\n formulas.push(checkPivotFormula(source, spec.formula))\n return {\n field: null,\n aggregate: 'formula',\n label: spec.label,\n format: spec.format,\n integer: false,\n formula: spec.formula,\n ...(show ? { show } : {}),\n ...(mark ? { mark } : {}),\n }\n }\n formulas.push(null)\n const field = spec.field === undefined ? null : source.field(spec.field)\n let name = spec.aggregate ?? (field?.type === 'number' ? 'sum' : 'count')\n if (!field && name !== 'count') name = 'count'\n const aggregator = FAST_AGGREGATES.has(name)\n ? undefined\n : (options.aggregators?.[name] ?? BUILTIN_AGGREGATORS[name])\n if (!FAST_AGGREGATES.has(name) && !aggregator) {\n throw new Error(`[@dou-ui/pivot] there is no aggregate named \"${name}\"`)\n }\n return {\n field,\n aggregate: name,\n aggregator,\n label: spec.label,\n format: spec.format ?? (ownFormat ? undefined : field?.format),\n integer: name === 'count' || !!aggregator?.integer,\n ...(show ? { show } : {}),\n ...(mark ? { mark } : {}),\n }\n })\n if (values.length === 0) {\n values.push({ field: null, aggregate: 'count', integer: true, implicit: true })\n formulas.push(null)\n }\n return {\n rows: (config.rows ?? []).map(level),\n columns: (config.columns ?? []).map(level),\n values,\n formulas,\n }\n}\n\n/**\n * Groups the records by the config's row and column fields and sums up\n * its values for every group, subtotal and total.\n *\n * Each record is placed once, in its innermost row group and innermost\n * column group; the values are summed per such pair, and every subtotal\n * is then merged from those pairs, never from the records again.\n */\nexport function computePivot<Row>(\n source: PivotSource<Row>,\n config: PivotConfig,\n options: PivotComputeOptions = {},\n): PivotResult {\n const src = source as PivotSource<unknown>\n if (Object.values(config.filters ?? {}).some((f) => f.top || f.between)) {\n return computePivot(\n source,\n { ...config, filters: rankedFilters(src, config, options) },\n options,\n )\n }\n const resolved = resolveConfig(src, config, options)\n const rowLevels: PivotLevel[] = resolved.rows.map((l) => ({\n ...l,\n column: src.dimension(l.field.name, l.by),\n }))\n const colLevels: PivotLevel[] = resolved.columns.map((l) => ({\n ...l,\n column: src.dimension(l.field.name, l.by),\n }))\n const n = source.length\n const rowTree = new PivotTreeBuilder(stride(rowLevels))\n const colTree = new PivotTreeBuilder(stride(colLevels))\n const rowCodes = rowLevels.map((l) => l.column.codes)\n const colCodes = colLevels.map((l) => l.column.codes)\n // more than any column node can be, so (row, column) makes a unique key\n const width = n * Math.max(1, colLevels.length) + 2\n\n const filters = Object.entries(config.filters ?? {}).flatMap(([name, filter]) => {\n if (!filter.include && !filter.exclude) return []\n // without its own grouping, a filter takes the one the field has on an axis\n const by =\n filter.by ?? [...resolved.rows, ...resolved.columns].find((l) => l.field.name === name)?.by\n const column = src.dimension(name, by)\n const allow = new Uint8Array(column.labels.length).fill(filter.include ? 0 : 1)\n for (const value of filter.include ?? []) {\n const code = column.find(value)\n if (code >= 0) allow[code] = 1\n }\n for (const value of filter.exclude ?? []) {\n const code = column.find(value)\n if (code >= 0) allow[code] = 0\n }\n return [{ codes: column.codes, allow }]\n })\n\n const slotOf = new Int32Array(n)\n const cells = new IntIndex(1024)\n let matched = 0\n const rowCards = rowLevels.map((l) => l.column.labels.length)\n const colCards = colLevels.map((l) => l.column.labels.length)\n const rowSpace = rowCards.reduce((a, b) => a * b, 1)\n const colSpace = colCards.reduce((a, b) => a * b, 1)\n const skip = (i: number) => {\n for (let f = 0; f < filters.length; f++) {\n const filter = filters[f]!\n if (filter.allow[filter.codes[i]!] === 0) return true\n }\n return false\n }\n\n if (rowSpace * colSpace <= Number.MAX_SAFE_INTEGER) {\n // Each record's innermost groups, written as one number per axis (the group\n // numbers as digits). A pair of them is looked up once per record, in a\n // plain array when every pair fits in one; the trees are grown once per pair.\n const space = rowSpace * colSpace\n const dense = space <= DENSE_PAIRS ? new Int32Array(space).fill(-1) : null\n const index = dense ? null : new IntIndex(1024)\n let pairRow = new Float64Array(1024)\n let pairCol = new Float64Array(1024)\n let pairs = 0\n for (let i = 0; i < n; i++) {\n if (filters.length && skip(i)) {\n slotOf[i] = -1\n continue\n }\n let rk = 0\n for (let d = 0; d < rowCodes.length; d++) rk = rk * rowCards[d]! + rowCodes[d]![i]!\n let ck = 0\n for (let d = 0; d < colCodes.length; d++) ck = ck * colCards[d]! + colCodes[d]![i]!\n const key = rk * colSpace + ck\n let slot: number\n if (dense) {\n slot = dense[key]!\n if (slot < 0) slot = dense[key] = pairs\n } else slot = index!.add(key)\n if (slot === pairs) {\n if (pairs === pairRow.length) {\n const grownRow = new Float64Array(pairs * 2)\n grownRow.set(pairRow)\n pairRow = grownRow\n const grownCol = new Float64Array(pairs * 2)\n grownCol.set(pairCol)\n pairCol = grownCol\n }\n pairRow[pairs] = rk\n pairCol[pairs] = ck\n pairs++\n }\n slotOf[i] = slot\n matched++\n }\n const rowLeaf = new Map<number, number>()\n const colLeaf = new Map<number, number>()\n const rowDigits = new Int32Array(rowCards.length)\n const colDigits = new Int32Array(colCards.length)\n for (let p = 0; p < pairs; p++) {\n const row = leaf(pairRow[p]!, rowLeaf, rowTree, rowCards, rowDigits)\n const col = leaf(pairCol[p]!, colLeaf, colTree, colCards, colDigits)\n // pairs are distinct, so the cell made here is cell number p\n cells.add(row * width + col)\n }\n } else {\n // too many combinations to number: walk down the trees record by record\n for (let i = 0; i < n; i++) {\n if (filters.length && skip(i)) {\n slotOf[i] = -1\n continue\n }\n let row = 0\n for (let d = 0; d < rowCodes.length; d++) row = rowTree.child(row, rowCodes[d]![i]!)\n let col = 0\n for (let d = 0; d < colCodes.length; d++) col = colTree.child(col, colCodes[d]![i]!)\n slotOf[i] = cells.add(row * width + col)\n matched++\n }\n }\n\n // every (ancestor row, ancestor column) pair that each innermost pair adds into\n const leaves = cells.size\n const rowDepth = rowLevels.length\n const colDepth = colLevels.length\n const fan = (rowDepth + 1) * (colDepth + 1) - 1\n const targets = new Int32Array(leaves * fan)\n const rowUp = new Int32Array(rowDepth + 1)\n const colUp = new Int32Array(colDepth + 1)\n const leafRow = new Int32Array(leaves)\n const leafCol = new Int32Array(leaves)\n for (let s = 0; s < leaves; s++) {\n const key = cells.keys[s]!\n const row = Math.floor(key / width)\n const col = key - row * width\n leafRow[s] = row\n leafCol[s] = col\n for (let d = 0, at = row; d <= rowDepth; d++, at = rowTree.parent[at]!) rowUp[d] = at\n for (let d = 0, at = col; d <= colDepth; d++, at = colTree.parent[at]!) colUp[d] = at\n let k = s * fan\n for (let a = 0; a <= rowDepth; a++) {\n for (let b = 0; b <= colDepth; b++) {\n if (a === 0 && b === 0) continue\n targets[k++] = cells.add(rowUp[a]! * width + colUp[b]!)\n }\n }\n }\n\n const size = cells.size\n const sum = (value: PivotResolvedValue) =>\n aggregate(src, value, slotOf, leaves, size, targets, fan)\n const data = resolved.values.map((value, i) => {\n const formula = resolved.formulas[i]\n return formula ? calculate(src, formula, sum, size) : sum(value)\n })\n return new PivotResult({\n rows: new PivotTree(rowTree, rowLevels),\n columns: new PivotTree(colTree, colLevels),\n values: resolved.values,\n matched,\n cells,\n width,\n data,\n slotOf,\n leafRow,\n leafCol,\n })\n}\n\n/**\n * The filters with `top` and `between` turned into lists of the groups they\n * keep: each field's groups are summed up once on their own, over the\n * records that the `include` and `exclude` lists keep.\n */\nfunction rankedFilters(\n source: PivotSource<unknown>,\n config: PivotConfig,\n options: PivotComputeOptions,\n): Record<string, PivotFilter> {\n const given = config.filters ?? {}\n const plain: Record<string, PivotFilter> = {}\n for (const [name, f] of Object.entries(given)) {\n if (f.include || f.exclude) plain[name] = { include: f.include, exclude: f.exclude, by: f.by }\n }\n const out: Record<string, PivotFilter> = { ...plain }\n const axes = [...(config.rows ?? []), ...(config.columns ?? [])]\n for (const [name, f] of Object.entries(given)) {\n if (!f.top && !f.between) continue\n const onAxis = axes.find((d) => typeof d === 'object' && d.field === name)\n const by = f.by ?? (typeof onAxis === 'object' ? onAxis.by : undefined)\n const index = f.top?.valueIndex ?? f.between?.valueIndex ?? 0\n const value = config.values?.[index]\n const plainValue =\n value === undefined ? [] : [typeof value === 'string' ? value : { ...value, show: undefined }]\n const totals = computePivot(\n source,\n { rows: [{ field: name, by, subtotal: false }], values: plainValue, filters: plain },\n options,\n )\n const tree = totals.rows\n let groups: { label: unknown; total: number }[] = []\n for (let k = tree.childStart[0]!; k < tree.childStart[1]!; k++) {\n const node = tree.children[k]!\n groups.push({ label: tree.label(node), total: totals.get(node, 0) })\n }\n if (f.between) {\n const { min = -Infinity, max = Infinity } = f.between\n groups = groups.filter((g) => g.total >= min && g.total <= max)\n }\n if (f.top) {\n const sign = f.top.order === 'asc' ? 1 : -1\n const ranked = groups.filter((g) => g.total === g.total)\n // oxlint-disable-next-line unicorn/no-array-sort -- sorts a fresh array\n ranked.sort((a, b) => sign * (a.total - b.total))\n groups = ranked.slice(0, Math.max(0, f.top.count))\n }\n out[name] = { include: groups.map((g) => g.label), by }\n }\n return out\n}\n\n/** A calculated value: each term summed up as usual, then the formula per cell. */\nfunction calculate(\n source: PivotSource<unknown>,\n formula: PivotFormula,\n sum: (value: PivotResolvedValue) => Float64Array,\n size: number,\n) {\n const columns = formula.terms.map((term) =>\n sum({\n field: term.field === null ? null : source.field(term.field),\n aggregate: term.aggregate,\n integer: term.aggregate === 'count',\n }),\n )\n const out = new Float64Array(size)\n const values = new Float64Array(columns.length)\n for (let s = 0; s < size; s++) {\n for (let t = 0; t < columns.length; t++) values[t] = columns[t]![s]!\n out[s] = formula.evaluate(values)\n }\n return out\n}\n\n/** More than any group number of the axis, so (parent, group) makes a unique key. */\nconst stride = (levels: PivotLevel[]) =>\n Math.max(1, ...levels.map((l) => l.column.labels.length)) + 1\n\n/** The innermost group whose group numbers are the digits of `key`, made when new. */\nfunction leaf(\n key: number,\n memo: Map<number, number>,\n tree: PivotTreeBuilder,\n cards: number[],\n digits: Int32Array,\n) {\n let node = memo.get(key)\n if (node !== undefined) return node\n for (let d = cards.length - 1, rest = key; d >= 0; d--) {\n const card = cards[d]!\n const digit = rest % card\n digits[d] = digit\n rest = (rest - digit) / card\n }\n node = 0\n for (let d = 0; d < cards.length; d++) node = tree.child(node, digits[d]!)\n memo.set(key, node)\n return node\n}\n\n/** Pairs of innermost groups up to this many are found in a plain array instead of a hash. */\nconst DENSE_PAIRS = 1 << 22\n\n/** One value for every cell: summed per innermost pair, then merged up into the totals. */\nfunction aggregate(\n source: PivotSource<unknown>,\n value: PivotResolvedValue,\n slotOf: Int32Array,\n leaves: number,\n size: number,\n targets: Int32Array,\n fan: number,\n) {\n const n = slotOf.length\n const out = new Float64Array(size)\n const kind = value.aggregate\n const roll = (fn: (into: number, from: number) => void) => {\n for (let s = 0; s < leaves; s++) {\n const base = s * fan\n for (let k = 0; k < fan; k++) fn(targets[base + k]!, s)\n }\n }\n\n if (kind === 'count') {\n if (value.field) {\n const { codes, empty } = source.dimension(value.field.name)\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n if (s >= 0 && codes[i] !== empty) out[s]!++\n }\n } else {\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n if (s >= 0) out[s]!++\n }\n }\n roll((t, s) => (out[t]! += out[s]!))\n return out\n }\n\n if (FAST_AGGREGATES.has(kind)) {\n const values = source.measure(value.field!.name)\n if (kind === 'min' || kind === 'max') {\n out.fill(Number.NaN)\n const max = kind === 'max'\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n const v = values[i]!\n if (s < 0 || v !== v) continue\n const at = out[s]!\n // NaN compares false, so an empty cell takes the first value\n if (max ? !(at >= v) : !(at <= v)) out[s] = v\n }\n roll((t, s) => {\n const v = out[s]!\n if (v !== v) return\n const at = out[t]!\n if (max ? !(at >= v) : !(at <= v)) out[t] = v\n })\n return out\n }\n // sum and avg: a total and how many records went into it\n const count = new Float64Array(size)\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n const v = values[i]!\n if (s < 0 || v !== v) continue\n out[s]! += v\n count[s]!++\n }\n roll((t, s) => {\n out[t]! += out[s]!\n count[t]! += count[s]!\n })\n for (let s = 0; s < size; s++) {\n const c = count[s]!\n out[s] = c === 0 ? Number.NaN : kind === 'avg' ? out[s]! / c : out[s]!\n }\n return out\n }\n\n const aggregator = value.aggregator!\n const field = value.field!\n const states: unknown[] = Array.from({ length: size })\n const { init, merge } = aggregator\n const add = aggregator.add as (state: unknown, value: unknown) => unknown\n if (aggregator.input === 'number') {\n const values = source.measure(field.name)\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n const v = values[i]!\n if (s < 0 || v !== v) continue\n states[s] = add(states[s] ?? init(), v)\n }\n } else {\n const { codes, labels, empty } = source.dimension(field.name)\n const byCode = aggregator === distinctAggregator\n for (let i = 0; i < n; i++) {\n const s = slotOf[i]!\n const code = codes[i]!\n if (s < 0 || code === empty) continue\n states[s] = add(states[s] ?? init(), byCode ? code : labels[code])\n }\n }\n roll((t, s) => {\n const from = states[s]\n if (from !== undefined) states[t] = merge(states[t] ?? init(), from)\n })\n const { result } = aggregator\n for (let s = 0; s < size; s++) {\n const state = states[s]\n out[s] = state === undefined ? Number.NaN : (result(state) ?? Number.NaN)\n }\n return out\n}\n\ninterface PivotResultInit {\n rows: PivotTree\n columns: PivotTree\n values: PivotResolvedValue[]\n matched: number\n cells: IntIndex\n width: number\n data: Float64Array[]\n slotOf: Int32Array\n leafRow: Int32Array\n leafCol: Int32Array\n}\n\n/**\n * A `PivotResult` as data: typed arrays a worker moves to the page without\n * copying, or plain arrays from JSON (a result summed up on a server).\n */\nexport interface PivotPacket {\n rows: PivotTreePacket\n columns: PivotTreePacket\n values: {\n field: string | null\n aggregate: string\n integer: boolean\n implicit?: boolean\n label?: string\n formula?: string\n show?: PivotShow\n mark?: Required<PivotMark>\n }[]\n matched: number\n cells: PivotIndexPacket\n width: number\n data: ArrayLike<number>[]\n slotOf: ArrayLike<number>\n leafRow: ArrayLike<number>\n leafCol: ArrayLike<number>\n}\n\nconst plainArray = (a: ArrayLike<number>) => Array.from(a)\n\n/** A packet with plain arrays in place of typed ones, ready for JSON. */\nfunction toPlain(packet: PivotPacket): PivotPacket {\n const tree = (t: PivotTreePacket): PivotTreePacket => ({\n ...t,\n parent: plainArray(t.parent),\n depth: plainArray(t.depth),\n code: plainArray(t.code),\n childStart: plainArray(t.childStart),\n children: plainArray(t.children),\n enter: plainArray(t.enter),\n exit: plainArray(t.exit),\n index: index(t.index),\n levels: t.levels.map((l) => ({ ...l, rank: plainArray(l.rank) })),\n })\n const index = (i: PivotIndexPacket): PivotIndexPacket => ({\n size: i.size,\n table: plainArray(i.table),\n ids: plainArray(i.ids),\n keys: plainArray(i.keys).slice(0, i.size),\n })\n return {\n ...packet,\n rows: tree(packet.rows),\n columns: tree(packet.columns),\n cells: index(packet.cells),\n data: packet.data.map((d) => Array.from(d, (v) => (v === v ? v : (null as never)))),\n slotOf: plainArray(packet.slotOf),\n leafRow: plainArray(packet.leafRow),\n leafCol: plainArray(packet.leafCol),\n }\n}\n\n/** The groups on both axes and every cell's values. */\nexport class PivotResult {\n readonly rows: PivotTree\n readonly columns: PivotTree\n readonly values: readonly PivotResolvedValue[]\n /** How many records passed the filters. */\n readonly matched: number\n private cells: IntIndex\n private width: number\n private data: Float64Array[]\n /** Each record's innermost cell, -1 when filtered out; and each such cell's groups. */\n private slotOf: Int32Array\n private leafRow: Int32Array\n private leafCol: Int32Array\n\n constructor(init: PivotResultInit) {\n this.rows = init.rows\n this.columns = init.columns\n this.values = init.values\n this.matched = init.matched\n this.cells = init.cells\n this.width = init.width\n this.data = init.data\n this.slotOf = init.slotOf\n this.leafRow = init.leafRow\n this.leafCol = init.leafCol\n }\n\n /**\n * The result as data, to send from a worker or a server. With `plain`,\n * plain arrays for `JSON.stringify` (typed arrays do not survive it);\n * empty cells go as `null`.\n */\n pack({ plain = false }: { plain?: boolean } = {}): PivotPacket {\n const packet = this.packTyped()\n return plain ? toPlain(packet) : packet\n }\n\n private packTyped(): PivotPacket {\n return {\n rows: this.rows.pack(),\n columns: this.columns.pack(),\n values: this.values.map((v) => ({\n field: v.field?.name ?? null,\n aggregate: v.aggregate,\n integer: v.integer,\n ...(v.implicit ? { implicit: true } : {}),\n ...(v.label === undefined ? {} : { label: v.label }),\n ...(v.formula === undefined ? {} : { formula: v.formula }),\n ...(v.show ? { show: v.show } : {}),\n ...(v.mark ? { mark: v.mark } : {}),\n })),\n matched: this.matched,\n cells: this.cells.pack(),\n width: this.width,\n data: this.data,\n slotOf: this.slotOf,\n leafRow: this.leafRow,\n leafCol: this.leafCol,\n }\n }\n\n /** The typed arrays in a packet, to move them instead of copying (`postMessage`'s transfer list). */\n static transferables(packet: PivotPacket): ArrayBuffer[] {\n const out = new Set<ArrayBuffer>()\n const add = (a: ArrayLike<number>) => {\n if (ArrayBuffer.isView(a) && a.buffer instanceof ArrayBuffer) out.add(a.buffer)\n }\n for (const tree of [packet.rows, packet.columns]) {\n for (const a of [tree.parent, tree.depth, tree.code, tree.childStart, tree.children]) add(a)\n for (const a of [tree.enter, tree.exit, tree.index.table, tree.index.ids, tree.index.keys])\n add(a)\n // a level's order belongs to the source, which keeps it for the next result\n }\n for (const a of [packet.cells.table, packet.cells.ids, packet.cells.keys]) add(a)\n for (const a of [...packet.data, packet.slotOf, packet.leafRow, packet.leafCol]) add(a)\n return [...out]\n }\n\n /**\n * A result made from `pack()`'s output. Fields are described by\n * `source` (no record is read), formats come from `config`.\n */\n static unpack<Row>(packet: PivotPacket, source: PivotSource<Row>, config?: PivotConfig) {\n const field = (name: string) => source.field(name) as PivotResolvedField<unknown>\n const given = config?.values ?? []\n return new PivotResult({\n rows: PivotTree.unpack(packet.rows, field),\n columns: PivotTree.unpack(packet.columns, field),\n values: packet.values.map((v, i) => {\n const f = v.field === null ? null : field(v.field)\n const spec = v.implicit ? undefined : given[i]\n const format = typeof spec === 'object' ? spec.format : undefined\n const own =\n v.formula !== undefined ||\n (v.show && (PERCENT_SHOWS.has(v.show.as) || v.show.as === 'rank'))\n return { ...v, field: f, format: format ?? (own ? undefined : f?.format) }\n }),\n matched: packet.matched,\n cells: IntIndex.unpack(packet.cells),\n width: packet.width,\n // JSON wrote NaN (an empty cell) as null\n data: packet.data.map((d) =>\n d instanceof Float64Array ? d : Float64Array.from(d, (v) => v ?? Number.NaN),\n ),\n slotOf: typed(Int32Array, packet.slotOf),\n leafRow: typed(Int32Array, packet.leafRow),\n leafCol: typed(Int32Array, packet.leafCol),\n })\n }\n\n private showing = new Map<string, PivotShown | null>()\n private ranges = new Map<string, { min: number; max: number }>()\n\n private shownBy(valueIndex: number, show: PivotShow | null | undefined) {\n const spec = show === undefined ? this.values[valueIndex]?.show : show\n const key = `${valueIndex}|${spec ? `${spec.as}|${spec.axis ?? ''}` : ''}`\n let shown = this.showing.get(key)\n if (shown === undefined) {\n shown = spec\n ? new PivotShown(\n resolveShow(spec, this.rows, this.columns),\n this.rows,\n this.columns,\n (r, c) => this.get(r, c, valueIndex),\n )\n : null\n this.showing.set(key, shown)\n }\n return shown\n }\n\n /**\n * How a value is shown, its `show` with the axis worked out; null when as\n * it is. `show` stands in for the value's own (`null` for none).\n */\n show(valueIndex = 0, show?: PivotShow | null): PivotResolvedShow | null {\n return this.shownBy(valueIndex, show)?.show ?? null\n }\n\n /**\n * The value as it is shown: a share, a difference, a running total or a\n * rank when the value has a `show` (or one is given), the summed-up value\n * otherwise. Nothing is summed up again.\n */\n shown(row: number, column: number, valueIndex = 0, show?: PivotShow | null): number {\n const shown = this.shownBy(valueIndex, show)\n return shown ? shown.value(row, column) : this.get(row, column, valueIndex)\n }\n\n /**\n * The smallest and largest shown values of the innermost cells (those\n * under no subtotal or total), which marks are drawn against.\n */\n range(valueIndex = 0, show?: PivotShow | null): { min: number; max: number } {\n const spec = show === undefined ? this.values[valueIndex]?.show : show\n const key = `${valueIndex}|${spec ? `${spec.as}|${spec.axis ?? ''}` : ''}`\n let range = this.ranges.get(key)\n if (!range) {\n const { rows, columns, cells, width } = this\n const rowDepth = rows.levels.length\n const colDepth = columns.levels.length\n let min = Infinity\n let max = -Infinity\n for (let s = 0; s < cells.size; s++) {\n const cell = cells.keys[s]!\n const row = Math.floor(cell / width)\n const col = cell - row * width\n if (rows.depth[row] !== rowDepth || columns.depth[col] !== colDepth) continue\n const v = this.shown(row, col, valueIndex, spec ?? null)\n if (v !== v) continue\n if (v < min) min = v\n if (v > max) max = v\n }\n range = min > max ? { min: Number.NaN, max: Number.NaN } : { min, max }\n this.ranges.set(key, range)\n }\n return range\n }\n\n /**\n * The value at `valueIndex` (its place in `values`) of a row group and a\n * column group; `NaN` when no record falls in both. The trees' `total`\n * is the grand total.\n */\n get(row: number, column: number, valueIndex = 0): number {\n const slot = this.cells.get(row * this.width + column)\n return slot < 0 ? Number.NaN : this.data[valueIndex]![slot]!\n }\n\n /** The indexes of the records in a row group and a column group, for showing the details. */\n indices(row: number, column: number): number[] {\n const { slotOf, leafRow, leafCol, rows, columns } = this\n // which innermost cells fall in the cell, then which records fall in those\n const inside = new Uint8Array(leafRow.length)\n for (let s = 0; s < leafRow.length; s++)\n inside[s] = rows.within(leafRow[s]!, row) && columns.within(leafCol[s]!, column) ? 1 : 0\n const out: number[] = []\n for (let i = 0; i < slotOf.length; i++) {\n const s = slotOf[i]!\n if (s >= 0 && inside[s]) out.push(i)\n }\n return out\n }\n\n /**\n * The children of every row group, reordered by a column's values (or as\n * they are when `sort` is empty). Nothing is summed up again.\n */\n rowOrder(sort: PivotValueSort | null | undefined): Int32Array {\n const { rows } = this\n if (!sort || !this.data[sort.valueIndex]) return rows.children\n const column = this.columns.find(sort.column ?? [])\n if (column < 0) return rows.children\n const children = rows.children.slice()\n const keys = new Float64Array(rows.size)\n for (let node = 0; node < rows.size; node++)\n keys[node] = this.get(node, column, sort.valueIndex)\n const sign = sort.order === 'desc' ? -1 : 1\n const place = new Int32Array(rows.size)\n rows.children.forEach((node, at) => (place[node] = at))\n for (let node = 0; node < rows.size; node++) {\n const from = rows.childStart[node]!\n const to = rows.childStart[node + 1]!\n if (to - from < 2) continue\n children.subarray(from, to).sort((a, b) => {\n const ka = keys[a]!\n const kb = keys[b]!\n // empty cells last, ties in label order\n if (ka !== ka || kb !== kb) return ka !== ka ? (kb !== kb ? place[a]! - place[b]! : 1) : -1\n return ka === kb ? place[a]! - place[b]! : sign * (ka - kb)\n })\n }\n return children\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { BUILTIN_AGGREGATORS } from "./aggregate.js";
2
+ import { checkPivotFormula } from "./compute.js";
3
+ // src/engine/engine.ts
4
+ /**
5
+ * The fields a config reads, and how: grouped (`dimensions`: on an axis,
6
+ * filtered, counted) or as numbers (`measures`: summed and the like).
7
+ * No record is read.
8
+ */
9
+ function neededColumns(source, config, aggregators = {}) {
10
+ const src = source;
11
+ const dimensions = /* @__PURE__ */ new Set();
12
+ const measures = /* @__PURE__ */ new Set();
13
+ for (const d of [...config.rows ?? [], ...config.columns ?? []]) dimensions.add(typeof d === "string" ? d : d.field);
14
+ for (const name of Object.keys(config.filters ?? {})) {
15
+ const f = config.filters[name];
16
+ if (f.include || f.exclude || f.top || f.between) dimensions.add(name);
17
+ }
18
+ for (const v of config.values ?? []) {
19
+ const spec = typeof v === "string" ? { field: v } : v;
20
+ if (spec.formula !== void 0) {
21
+ let formula;
22
+ try {
23
+ formula = checkPivotFormula(src, spec.formula);
24
+ } catch {
25
+ continue;
26
+ }
27
+ for (const term of formula.terms) {
28
+ if (term.field === null) continue;
29
+ if (term.aggregate === "count") dimensions.add(term.field);
30
+ else measures.add(term.field);
31
+ }
32
+ continue;
33
+ }
34
+ if (spec.field === void 0) continue;
35
+ const name = spec.aggregate ?? (src.field(spec.field).type === "number" ? "sum" : "count");
36
+ if ((name === "count" ? "value" : aggregators[name]?.input ?? BUILTIN_AGGREGATORS[name]?.input ?? "number") === "value") dimensions.add(spec.field);
37
+ else measures.add(spec.field);
38
+ }
39
+ return {
40
+ dimensions: [...dimensions],
41
+ measures: [...measures]
42
+ };
43
+ }
44
+ export { neededColumns };
45
+
46
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","names":[],"sources":["../../src/engine/engine.ts"],"sourcesContent":["import { BUILTIN_AGGREGATORS, type PivotAggregator } from './aggregate'\nimport { checkPivotFormula, type PivotResult } from './compute'\nimport type { PivotConfig } from './types'\nimport type { PivotSource } from './source'\n\nexport interface PivotComputeRequest {\n /** Aggregators by name, beside the built-in ones. */\n aggregators?: Readonly<Record<string, PivotAggregator>>\n /** Aborted when a newer config makes this one stale. */\n signal?: AbortSignal\n}\n\n/**\n * Sums up the records somewhere else than in the page: in a worker\n * (`createPivotWorker`), or on a server. `DouPivot` asks it for a result\n * whenever the fields to sum up change, and shows only the newest one.\n */\nexport interface PivotEngine {\n compute<Row>(\n source: PivotSource<Row>,\n config: PivotConfig,\n request?: PivotComputeRequest,\n ): Promise<PivotResult>\n /** Lets go of what it holds (a worker, a connection) when the table goes away. */\n dispose?(): void\n}\n\n/**\n * The fields a config reads, and how: grouped (`dimensions`: on an axis,\n * filtered, counted) or as numbers (`measures`: summed and the like).\n * No record is read.\n */\nexport function neededColumns<Row>(\n source: PivotSource<Row>,\n config: PivotConfig,\n aggregators: Readonly<Record<string, PivotAggregator>> = {},\n) {\n const src = source as PivotSource<unknown>\n const dimensions = new Set<string>()\n const measures = new Set<string>()\n for (const d of [...(config.rows ?? []), ...(config.columns ?? [])])\n dimensions.add(typeof d === 'string' ? d : d.field)\n for (const name of Object.keys(config.filters ?? {})) {\n const f = config.filters![name]!\n if (f.include || f.exclude || f.top || f.between) dimensions.add(name)\n }\n for (const v of config.values ?? []) {\n const spec = typeof v === 'string' ? { field: v } : v\n if (spec.formula !== undefined) {\n let formula\n try {\n formula = checkPivotFormula(src, spec.formula)\n } catch {\n // computing it says what is wrong\n continue\n }\n for (const term of formula.terms) {\n if (term.field === null) continue\n if (term.aggregate === 'count') dimensions.add(term.field)\n else measures.add(term.field)\n }\n continue\n }\n if (spec.field === undefined) continue\n const name = spec.aggregate ?? (src.field(spec.field).type === 'number' ? 'sum' : 'count')\n const input =\n name === 'count'\n ? 'value'\n : (aggregators[name]?.input ?? BUILTIN_AGGREGATORS[name]?.input ?? 'number')\n if (input === 'value') dimensions.add(spec.field)\n else measures.add(spec.field)\n }\n return { dimensions: [...dimensions], measures: [...measures] }\n}\n"],"mappings":";;;;;;;;AAgCA,SAAgB,cACd,QACA,QACA,cAAyD,CAAC,GAC1D;CACA,MAAM,MAAM;CACZ,MAAM,6BAAa,IAAI,IAAY;CACnC,MAAM,2BAAW,IAAI,IAAY;CACjC,KAAK,MAAM,KAAK,CAAC,GAAI,OAAO,QAAQ,CAAC,GAAI,GAAI,OAAO,WAAW,CAAC,CAAE,GAChE,WAAW,IAAI,OAAO,MAAM,WAAW,IAAI,EAAE,KAAK;CACpD,KAAK,MAAM,QAAQ,OAAO,KAAK,OAAO,WAAW,CAAC,CAAC,GAAG;EACpD,MAAM,IAAI,OAAO,QAAS;EAC1B,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,WAAW,IAAI,IAAI;CACvE;CACA,KAAK,MAAM,KAAK,OAAO,UAAU,CAAC,GAAG;EACnC,MAAM,OAAO,OAAO,MAAM,WAAW,EAAE,OAAO,EAAE,IAAI;EACpD,IAAI,KAAK,YAAY,KAAA,GAAW;GAC9B,IAAI;GACJ,IAAI;IACF,UAAU,kBAAkB,KAAK,KAAK,OAAO;GAC/C,QAAQ;IAEN;GACF;GACA,KAAK,MAAM,QAAQ,QAAQ,OAAO;IAChC,IAAI,KAAK,UAAU,MAAM;IACzB,IAAI,KAAK,cAAc,SAAS,WAAW,IAAI,KAAK,KAAK;SACpD,SAAS,IAAI,KAAK,KAAK;GAC9B;GACA;EACF;EACA,IAAI,KAAK,UAAU,KAAA,GAAW;EAC9B,MAAM,OAAO,KAAK,cAAc,IAAI,MAAM,KAAK,KAAK,CAAC,CAAC,SAAS,WAAW,QAAQ;EAKlF,KAHE,SAAS,UACL,UACC,YAAY,KAAK,EAAE,SAAS,oBAAoB,KAAK,EAAE,SAAS,cACzD,SAAS,WAAW,IAAI,KAAK,KAAK;OAC3C,SAAS,IAAI,KAAK,KAAK;CAC9B;CACA,OAAO;EAAE,YAAY,CAAC,GAAG,UAAU;EAAG,UAAU,CAAC,GAAG,QAAQ;CAAE;AAChE"}
@@ -0,0 +1,225 @@
1
+ // src/engine/formula.ts
2
+ var MESSAGES = {
3
+ empty: "公式是空的",
4
+ incomplete: "公式不完整",
5
+ unknownChar: "无法识别“{detail}”",
6
+ unexpected: "这里不应出现“{detail}”",
7
+ expected: "这里应当是“{detail}”",
8
+ unclosedBracket: "缺少“]”",
9
+ emptyName: "方括号里没有字段名",
10
+ unknownFunction: "没有名为“{detail}”的函数",
11
+ needsField: "{detail}() 需要一个字段",
12
+ needsName: "这里应当是字段名",
13
+ unknownField: "没有名为“{detail}”的字段",
14
+ notNumber: "“{detail}”不是数字字段"
15
+ };
16
+ /**
17
+ * Why a formula could not be read, and where: `at` is a character offset,
18
+ * `detail` the text the message is about. `code` lets a page word it its own way.
19
+ */
20
+ var PivotFormulaError = class extends Error {
21
+ code;
22
+ at;
23
+ detail;
24
+ constructor(code, at, detail = "") {
25
+ super(`[@dou-ui/pivot] 计算值:${MESSAGES[code].replace("{detail}", detail)}`);
26
+ this.code = code;
27
+ this.at = at;
28
+ this.detail = detail;
29
+ this.name = "PivotFormulaError";
30
+ }
31
+ };
32
+ var FUNCTIONS = /* @__PURE__ */ new Set([
33
+ "sum",
34
+ "avg",
35
+ "min",
36
+ "max",
37
+ "count"
38
+ ]);
39
+ var NAME_START = /[\p{L}_$]/u;
40
+ var NAME_PART = /[\p{L}\p{N}_$.]/u;
41
+ function tokenize(text) {
42
+ const out = [];
43
+ let i = 0;
44
+ while (i < text.length) {
45
+ const ch = text[i];
46
+ if (/\s/.test(ch)) {
47
+ i++;
48
+ continue;
49
+ }
50
+ const at = i;
51
+ if (/[0-9.]/.test(ch)) {
52
+ const match = /^(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/.exec(text.slice(i));
53
+ if (!match) throw new PivotFormulaError("unknownChar", at, ch);
54
+ out.push({
55
+ type: "number",
56
+ text: match[0],
57
+ at
58
+ });
59
+ i += match[0].length;
60
+ } else if (ch === "[") {
61
+ const end = text.indexOf("]", i + 1);
62
+ if (end < 0) throw new PivotFormulaError("unclosedBracket", at);
63
+ const name = text.slice(i + 1, end).trim();
64
+ if (!name) throw new PivotFormulaError("emptyName", at);
65
+ out.push({
66
+ type: "name",
67
+ text: name,
68
+ at,
69
+ quoted: true
70
+ });
71
+ i = end + 1;
72
+ } else if (NAME_START.test(ch)) {
73
+ let j = i + 1;
74
+ while (j < text.length && NAME_PART.test(text[j])) j++;
75
+ out.push({
76
+ type: "name",
77
+ text: text.slice(i, j),
78
+ at
79
+ });
80
+ i = j;
81
+ } else if ("+-*/(),".includes(ch)) {
82
+ out.push({
83
+ type: "op",
84
+ text: ch,
85
+ at
86
+ });
87
+ i++;
88
+ } else throw new PivotFormulaError("unknownChar", at, ch);
89
+ }
90
+ out.push({
91
+ type: "end",
92
+ text: "",
93
+ at: text.length
94
+ });
95
+ return out;
96
+ }
97
+ /**
98
+ * Reads a formula. Throws a `PivotFormulaError` when it is not well formed.
99
+ * Field names are not checked here (see `computePivot`).
100
+ */
101
+ function parsePivotFormula(text) {
102
+ const tokens = tokenize(text);
103
+ const terms = [];
104
+ let pos = 0;
105
+ const peek = () => tokens[pos];
106
+ const next = () => tokens[pos++];
107
+ const expect = (op) => {
108
+ const t = next();
109
+ if (t.type !== "op" || t.text !== op) throw new PivotFormulaError("expected", t.at, op);
110
+ };
111
+ const term = (aggregate, field) => {
112
+ let index = terms.findIndex((t) => t.aggregate === aggregate && t.field === field);
113
+ if (index < 0) index = terms.push({
114
+ aggregate,
115
+ field
116
+ }) - 1;
117
+ return {
118
+ kind: "term",
119
+ index
120
+ };
121
+ };
122
+ function expression() {
123
+ let left = product();
124
+ for (let t = peek(); t.type === "op" && (t.text === "+" || t.text === "-"); t = peek()) {
125
+ next();
126
+ left = {
127
+ kind: "binary",
128
+ op: t.text,
129
+ left,
130
+ right: product()
131
+ };
132
+ }
133
+ return left;
134
+ }
135
+ function product() {
136
+ let left = unary();
137
+ for (let t = peek(); t.type === "op" && (t.text === "*" || t.text === "/"); t = peek()) {
138
+ next();
139
+ left = {
140
+ kind: "binary",
141
+ op: t.text,
142
+ left,
143
+ right: unary()
144
+ };
145
+ }
146
+ return left;
147
+ }
148
+ function unary() {
149
+ const t = peek();
150
+ if (t.type === "op" && (t.text === "-" || t.text === "+")) {
151
+ next();
152
+ const operand = unary();
153
+ return t.text === "-" ? {
154
+ kind: "negate",
155
+ operand
156
+ } : operand;
157
+ }
158
+ return primary();
159
+ }
160
+ function primary() {
161
+ const t = next();
162
+ if (t.type === "number") return {
163
+ kind: "number",
164
+ value: Number(t.text)
165
+ };
166
+ if (t.type === "op" && t.text === "(") {
167
+ const inner = expression();
168
+ expect(")");
169
+ return inner;
170
+ }
171
+ if (t.type === "name") {
172
+ const after = peek();
173
+ if (!t.quoted && after.type === "op" && after.text === "(") {
174
+ const name = t.text.toLowerCase();
175
+ if (!FUNCTIONS.has(name)) throw new PivotFormulaError("unknownFunction", t.at, t.text);
176
+ next();
177
+ const close = peek();
178
+ if (close.type === "op" && close.text === ")") {
179
+ if (name !== "count") throw new PivotFormulaError("needsField", close.at, t.text);
180
+ next();
181
+ return term("count", null);
182
+ }
183
+ const arg = next();
184
+ if (arg.type !== "name") throw new PivotFormulaError("needsName", arg.at);
185
+ expect(")");
186
+ return term(name, arg.text);
187
+ }
188
+ return term("sum", t.text);
189
+ }
190
+ if (t.type === "end") throw new PivotFormulaError("incomplete", t.at);
191
+ throw new PivotFormulaError("unexpected", t.at, t.text);
192
+ }
193
+ if (peek().type === "end") throw new PivotFormulaError("empty", 0);
194
+ const root = expression();
195
+ const rest = peek();
196
+ if (rest.type !== "end") throw new PivotFormulaError("unexpected", rest.at, rest.text);
197
+ const run = (node, values) => {
198
+ switch (node.kind) {
199
+ case "number": return node.value;
200
+ case "term": return values[node.index];
201
+ case "negate": return -run(node.operand, values);
202
+ case "binary": {
203
+ const a = run(node.left, values);
204
+ const b = run(node.right, values);
205
+ switch (node.op) {
206
+ case "+": return a + b;
207
+ case "-": return a - b;
208
+ case "*": return a * b;
209
+ case "/": return b === 0 ? NaN : a / b;
210
+ }
211
+ }
212
+ }
213
+ };
214
+ return {
215
+ source: text,
216
+ terms,
217
+ evaluate: (values) => {
218
+ const v = run(root, values);
219
+ return Number.isFinite(v) ? v : NaN;
220
+ }
221
+ };
222
+ }
223
+ export { PivotFormulaError, parsePivotFormula };
224
+
225
+ //# sourceMappingURL=formula.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formula.js","names":[],"sources":["../../src/engine/formula.ts"],"sourcesContent":["/**\n * Calculated values: a small expression language over the fields, read\n * without `eval`. `profit / amount` divides the sum of `profit` by the sum\n * of `amount` in each cell, so totals are ratios of totals, not sums of ratios.\n *\n * - numbers: `12`, `0.5`, `1e3`\n * - fields: a name (`amount`, `销售额`), or any name in brackets (`[unit price]`)\n * - `+ - * /`, parentheses and a leading minus\n * - `sum(f)`, `avg(f)`, `min(f)`, `max(f)`, `count(f)` (records where f is not empty) and `count()`\n *\n * A bare field name stands for `sum(name)`. Dividing by zero leaves the cell empty.\n */\n\n/** The ways a formula can sum up a field. */\nexport type PivotFormulaAggregate = 'sum' | 'avg' | 'min' | 'max' | 'count'\n\n/** A field a formula reads, and how. `field` is null for `count()`. */\nexport interface PivotFormulaTerm {\n aggregate: PivotFormulaAggregate\n field: string | null\n}\n\ntype Node =\n | { kind: 'number'; value: number }\n | { kind: 'term'; index: number }\n | { kind: 'negate'; operand: Node }\n | { kind: 'binary'; op: '+' | '-' | '*' | '/'; left: Node; right: Node }\n\n/** A formula read into its terms and a function of their values. */\nexport interface PivotFormula {\n source: string\n /** Each distinct field-and-aggregate the formula reads, in the order of `evaluate`'s input. */\n terms: PivotFormulaTerm[]\n /** The formula's value from its terms' values; `NaN` for an empty cell. */\n evaluate(values: ArrayLike<number>): number\n}\n\n/** Why a formula could not be read. */\nexport type PivotFormulaErrorCode =\n | 'empty'\n | 'incomplete'\n | 'unknownChar'\n | 'unexpected'\n | 'expected'\n | 'unclosedBracket'\n | 'emptyName'\n | 'unknownFunction'\n | 'needsField'\n | 'needsName'\n | 'unknownField'\n | 'notNumber'\n\nconst MESSAGES: Record<PivotFormulaErrorCode, string> = {\n empty: '公式是空的',\n incomplete: '公式不完整',\n unknownChar: '无法识别“{detail}”',\n unexpected: '这里不应出现“{detail}”',\n expected: '这里应当是“{detail}”',\n unclosedBracket: '缺少“]”',\n emptyName: '方括号里没有字段名',\n unknownFunction: '没有名为“{detail}”的函数',\n needsField: '{detail}() 需要一个字段',\n needsName: '这里应当是字段名',\n unknownField: '没有名为“{detail}”的字段',\n notNumber: '“{detail}”不是数字字段',\n}\n\n/**\n * Why a formula could not be read, and where: `at` is a character offset,\n * `detail` the text the message is about. `code` lets a page word it its own way.\n */\nexport class PivotFormulaError extends Error {\n constructor(\n readonly code: PivotFormulaErrorCode,\n readonly at: number,\n readonly detail = '',\n ) {\n super(`[@dou-ui/pivot] 计算值:${MESSAGES[code].replace('{detail}', detail)}`)\n this.name = 'PivotFormulaError'\n }\n}\n\nconst FUNCTIONS = new Set<PivotFormulaAggregate>(['sum', 'avg', 'min', 'max', 'count'])\n\ninterface Token {\n type: 'number' | 'name' | 'op' | 'end'\n text: string\n at: number\n /** A name written in brackets, so never a function. */\n quoted?: boolean\n}\n\nconst NAME_START = /[\\p{L}_$]/u\nconst NAME_PART = /[\\p{L}\\p{N}_$.]/u\n\nfunction tokenize(text: string): Token[] {\n const out: Token[] = []\n let i = 0\n while (i < text.length) {\n const ch = text[i]!\n if (/\\s/.test(ch)) {\n i++\n continue\n }\n const at = i\n if (/[0-9.]/.test(ch)) {\n const match = /^(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?/.exec(text.slice(i))\n if (!match) throw new PivotFormulaError('unknownChar', at, ch)\n out.push({ type: 'number', text: match[0], at })\n i += match[0].length\n } else if (ch === '[') {\n const end = text.indexOf(']', i + 1)\n if (end < 0) throw new PivotFormulaError('unclosedBracket', at)\n const name = text.slice(i + 1, end).trim()\n if (!name) throw new PivotFormulaError('emptyName', at)\n out.push({ type: 'name', text: name, at, quoted: true })\n i = end + 1\n } else if (NAME_START.test(ch)) {\n let j = i + 1\n while (j < text.length && NAME_PART.test(text[j]!)) j++\n out.push({ type: 'name', text: text.slice(i, j), at })\n i = j\n } else if ('+-*/(),'.includes(ch)) {\n out.push({ type: 'op', text: ch, at })\n i++\n } else {\n throw new PivotFormulaError('unknownChar', at, ch)\n }\n }\n out.push({ type: 'end', text: '', at: text.length })\n return out\n}\n\n/**\n * Reads a formula. Throws a `PivotFormulaError` when it is not well formed.\n * Field names are not checked here (see `computePivot`).\n */\nexport function parsePivotFormula(text: string): PivotFormula {\n const tokens = tokenize(text)\n const terms: PivotFormulaTerm[] = []\n let pos = 0\n const peek = () => tokens[pos]!\n const next = () => tokens[pos++]!\n const expect = (op: string) => {\n const t = next()\n if (t.type !== 'op' || t.text !== op) throw new PivotFormulaError('expected', t.at, op)\n }\n const term = (aggregate: PivotFormulaAggregate, field: string | null): Node => {\n let index = terms.findIndex((t) => t.aggregate === aggregate && t.field === field)\n if (index < 0) index = terms.push({ aggregate, field }) - 1\n return { kind: 'term', index }\n }\n\n // expression := product (('+' | '-') product)*\n function expression(): Node {\n let left = product()\n for (let t = peek(); t.type === 'op' && (t.text === '+' || t.text === '-'); t = peek()) {\n next()\n left = { kind: 'binary', op: t.text as '+' | '-', left, right: product() }\n }\n return left\n }\n // product := unary (('*' | '/') unary)*\n function product(): Node {\n let left = unary()\n for (let t = peek(); t.type === 'op' && (t.text === '*' || t.text === '/'); t = peek()) {\n next()\n left = { kind: 'binary', op: t.text as '*' | '/', left, right: unary() }\n }\n return left\n }\n function unary(): Node {\n const t = peek()\n if (t.type === 'op' && (t.text === '-' || t.text === '+')) {\n next()\n const operand = unary()\n return t.text === '-' ? { kind: 'negate', operand } : operand\n }\n return primary()\n }\n function primary(): Node {\n const t = next()\n if (t.type === 'number') return { kind: 'number', value: Number(t.text) }\n if (t.type === 'op' && t.text === '(') {\n const inner = expression()\n expect(')')\n return inner\n }\n if (t.type === 'name') {\n const after = peek()\n if (!t.quoted && after.type === 'op' && after.text === '(') {\n const name = t.text.toLowerCase() as PivotFormulaAggregate\n if (!FUNCTIONS.has(name)) throw new PivotFormulaError('unknownFunction', t.at, t.text)\n next()\n const close = peek()\n if (close.type === 'op' && close.text === ')') {\n if (name !== 'count') throw new PivotFormulaError('needsField', close.at, t.text)\n next()\n return term('count', null)\n }\n const arg = next()\n if (arg.type !== 'name') throw new PivotFormulaError('needsName', arg.at)\n expect(')')\n return term(name, arg.text)\n }\n return term('sum', t.text)\n }\n if (t.type === 'end') throw new PivotFormulaError('incomplete', t.at)\n throw new PivotFormulaError('unexpected', t.at, t.text)\n }\n\n if (peek().type === 'end') throw new PivotFormulaError('empty', 0)\n const root = expression()\n const rest = peek()\n if (rest.type !== 'end') throw new PivotFormulaError('unexpected', rest.at, rest.text)\n\n const run = (node: Node, values: ArrayLike<number>): number => {\n switch (node.kind) {\n case 'number':\n return node.value\n case 'term':\n return values[node.index]!\n case 'negate':\n return -run(node.operand, values)\n case 'binary': {\n const a = run(node.left, values)\n const b = run(node.right, values)\n switch (node.op) {\n case '+':\n return a + b\n case '-':\n return a - b\n case '*':\n return a * b\n case '/':\n return b === 0 ? Number.NaN : a / b\n }\n }\n }\n }\n return {\n source: text,\n terms,\n evaluate: (values) => {\n const v = run(root, values)\n return Number.isFinite(v) ? v : Number.NaN\n },\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ // src/engine/group.ts
2
+ /** The periods a date can be grouped by. */
3
+ var DATE_PERIODS = [
4
+ "year",
5
+ "quarter",
6
+ "month",
7
+ "week",
8
+ "day"
9
+ ];
10
+ /** A name for a grouping, to cache the grouped field under. */
11
+ function groupKey(by) {
12
+ if (by === void 0) return "";
13
+ if (typeof by === "string") return by;
14
+ return `step:${by.step}:${by.start ?? 0}`;
15
+ }
16
+ var pad = (n, width = 2) => String(n).padStart(width, "0");
17
+ /**
18
+ * A date out of a value: a `Date`, a time in ms, or text such as
19
+ * `'2026-03-15'` (read in local time, like the other parts of a day).
20
+ */
21
+ function toDate(value) {
22
+ if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
23
+ if (typeof value === "number") return Number.isFinite(value) ? new Date(value) : null;
24
+ if (typeof value === "string") {
25
+ const day = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(value.trim());
26
+ const date = day ? new Date(+day[1], +day[2] - 1, +day[3]) : new Date(value);
27
+ return Number.isNaN(date.getTime()) ? null : date;
28
+ }
29
+ return null;
30
+ }
31
+ /** The ISO week a day is in, and the year that week belongs to. */
32
+ function isoWeek(date) {
33
+ const day = new Date(date.getFullYear(), date.getMonth(), date.getDate());
34
+ const weekday = (day.getDay() + 6) % 7;
35
+ day.setDate(day.getDate() - weekday + 3);
36
+ const year = day.getFullYear();
37
+ const first = new Date(year, 0, 4);
38
+ const firstThursday = new Date(year, 0, 4 - (first.getDay() + 6) % 7 + 3);
39
+ return [year, 1 + Math.round((day.getTime() - firstThursday.getTime()) / 6048e5)];
40
+ }
41
+ /**
42
+ * The group a value falls in: plain data that sorts in order and can be
43
+ * saved in the config (filters, collapsed groups): a year is a number
44
+ * (`2026`); a quarter, month, week or day is text (`'2026-Q1'`,
45
+ * `'2026-03'`, `'2026-W12'`, `'2026-03-15'`); a range is its lowest
46
+ * number. `null` when the value has no group (empty, or not a date / number).
47
+ */
48
+ function bucketer(by) {
49
+ if (typeof by === "object") {
50
+ const step = by.step > 0 ? by.step : 1;
51
+ const start = by.start ?? 0;
52
+ return (value) => {
53
+ const n = typeof value === "number" ? value : value instanceof Date ? value.getTime() : NaN;
54
+ if (!Number.isFinite(n)) return null;
55
+ return +(Math.floor((n - start) / step) * step + start).toPrecision(12);
56
+ };
57
+ }
58
+ return (value) => {
59
+ const date = toDate(value);
60
+ if (!date) return null;
61
+ const year = date.getFullYear();
62
+ switch (by) {
63
+ case "year": return year;
64
+ case "quarter": return `${year}-Q${Math.floor(date.getMonth() / 3) + 1}`;
65
+ case "month": return `${year}-${pad(date.getMonth() + 1)}`;
66
+ case "week": {
67
+ const [y, w] = isoWeek(date);
68
+ return `${y}-W${pad(w)}`;
69
+ }
70
+ default: return `${year}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
71
+ }
72
+ };
73
+ }
74
+ /** The parts of a period's group, read back from its text. */
75
+ function readBucket(by, bucket) {
76
+ if (by === "year") {
77
+ const year = Number(bucket);
78
+ return Number.isFinite(year) ? {
79
+ year,
80
+ part: 0,
81
+ date: new Date(year, 0, 1)
82
+ } : null;
83
+ }
84
+ if (typeof bucket !== "string") return null;
85
+ const m = /^(\d{4})-(Q|W)?(\d{1,2})(?:-(\d{1,2}))?$/.exec(bucket);
86
+ if (!m) return null;
87
+ const year = +m[1];
88
+ const part = +m[3];
89
+ if (m[2] === "Q") return {
90
+ year,
91
+ part,
92
+ date: new Date(year, (part - 1) * 3, 1)
93
+ };
94
+ if (m[2] === "W") return {
95
+ year,
96
+ part,
97
+ date: new Date(year, 0, 4 + (part - 1) * 7)
98
+ };
99
+ return {
100
+ year,
101
+ part,
102
+ date: new Date(year, part - 1, m[4] ? +m[4] : 1)
103
+ };
104
+ }
105
+ export { DATE_PERIODS, bucketer, groupKey, isoWeek, readBucket, toDate };
106
+
107
+ //# sourceMappingURL=group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"group.js","names":[],"sources":["../../src/engine/group.ts"],"sourcesContent":["/**\n * How a field's values are put in groups: dates by a period, numbers in\n * ranges of `step` (starting at `start`, 0 by default).\n */\nexport type PivotGroupBy =\n 'year' | 'quarter' | 'month' | 'week' | 'day' | { step: number; start?: number }\n\n/** The periods a date can be grouped by. */\nexport const DATE_PERIODS = ['year', 'quarter', 'month', 'week', 'day'] as const\nexport type PivotDatePeriod = (typeof DATE_PERIODS)[number]\n\n/** A name for a grouping, to cache the grouped field under. */\nexport function groupKey(by: PivotGroupBy | undefined): string {\n if (by === undefined) return ''\n if (typeof by === 'string') return by\n return `step:${by.step}:${by.start ?? 0}`\n}\n\nconst pad = (n: number, width = 2) => String(n).padStart(width, '0')\n\n/**\n * A date out of a value: a `Date`, a time in ms, or text such as\n * `'2026-03-15'` (read in local time, like the other parts of a day).\n */\nexport function toDate(value: unknown): Date | null {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value\n if (typeof value === 'number') return Number.isFinite(value) ? new Date(value) : null\n if (typeof value === 'string') {\n const day = /^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/.exec(value.trim())\n // a bare date is midnight here, not in UTC\n const date = day ? new Date(+day[1]!, +day[2]! - 1, +day[3]!) : new Date(value)\n return Number.isNaN(date.getTime()) ? null : date\n }\n return null\n}\n\n/** The ISO week a day is in, and the year that week belongs to. */\nexport function isoWeek(date: Date): [year: number, week: number] {\n const day = new Date(date.getFullYear(), date.getMonth(), date.getDate())\n // the Thursday of the same week decides the year\n const weekday = (day.getDay() + 6) % 7\n day.setDate(day.getDate() - weekday + 3)\n const year = day.getFullYear()\n const first = new Date(year, 0, 4)\n const firstThursday = new Date(year, 0, 4 - ((first.getDay() + 6) % 7) + 3)\n const week = 1 + Math.round((day.getTime() - firstThursday.getTime()) / 604_800_000)\n return [year, week]\n}\n\n/**\n * The group a value falls in: plain data that sorts in order and can be\n * saved in the config (filters, collapsed groups): a year is a number\n * (`2026`); a quarter, month, week or day is text (`'2026-Q1'`,\n * `'2026-03'`, `'2026-W12'`, `'2026-03-15'`); a range is its lowest\n * number. `null` when the value has no group (empty, or not a date / number).\n */\nexport function bucketer(by: PivotGroupBy): (value: unknown) => number | string | null {\n if (typeof by === 'object') {\n const step = by.step > 0 ? by.step : 1\n const start = by.start ?? 0\n return (value) => {\n const n = typeof value === 'number' ? value : value instanceof Date ? value.getTime() : NaN\n if (!Number.isFinite(n)) return null\n // rounded so 0.1 steps do not come out as 0.30000000000000004\n return +(Math.floor((n - start) / step) * step + start).toPrecision(12)\n }\n }\n return (value) => {\n const date = toDate(value)\n if (!date) return null\n const year = date.getFullYear()\n switch (by) {\n case 'year':\n return year\n case 'quarter':\n return `${year}-Q${Math.floor(date.getMonth() / 3) + 1}`\n case 'month':\n return `${year}-${pad(date.getMonth() + 1)}`\n case 'week': {\n const [y, w] = isoWeek(date)\n return `${y}-W${pad(w)}`\n }\n default:\n return `${year}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n }\n }\n}\n\n/** The parts of a period's group, read back from its text. */\nexport function readBucket(\n by: PivotDatePeriod,\n bucket: unknown,\n): { year: number; part: number; date: Date } | null {\n if (by === 'year') {\n const year = Number(bucket)\n return Number.isFinite(year) ? { year, part: 0, date: new Date(year, 0, 1) } : null\n }\n if (typeof bucket !== 'string') return null\n const m = /^(\\d{4})-(Q|W)?(\\d{1,2})(?:-(\\d{1,2}))?$/.exec(bucket)\n if (!m) return null\n const year = +m[1]!\n const part = +m[3]!\n if (m[2] === 'Q') return { year, part, date: new Date(year, (part - 1) * 3, 1) }\n if (m[2] === 'W') return { year, part, date: new Date(year, 0, 4 + (part - 1) * 7) }\n return { year, part, date: new Date(year, part - 1, m[4] ? +m[4] : 1) }\n}\n"],"mappings":";;AAQA,IAAa,eAAe;CAAC;CAAQ;CAAW;CAAS;CAAQ;AAAK;;AAItE,SAAgB,SAAS,IAAsC;CAC7D,IAAI,OAAO,KAAA,GAAW,OAAO;CAC7B,IAAI,OAAO,OAAO,UAAU,OAAO;CACnC,OAAO,QAAQ,GAAG,KAAK,GAAG,GAAG,SAAS;AACxC;AAEA,IAAM,OAAO,GAAW,QAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,SAAS,OAAO,GAAG;;;;;AAMnE,SAAgB,OAAO,OAA6B;CAClD,IAAI,iBAAiB,MAAM,OAAO,OAAO,MAAM,MAAM,QAAQ,CAAC,IAAI,OAAO;CACzE,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,SAAS,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI;CACjF,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,MAAM,gCAAgC,KAAK,MAAM,KAAK,CAAC;EAE7D,MAAM,OAAO,MAAM,IAAI,KAAK,CAAC,IAAI,IAAK,CAAC,IAAI,KAAM,GAAG,CAAC,IAAI,EAAG,IAAI,IAAI,KAAK,KAAK;EAC9E,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;CAC/C;CACA,OAAO;AACT;;AAGA,SAAgB,QAAQ,MAA0C;CAChE,MAAM,MAAM,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,CAAC;CAExE,MAAM,WAAW,IAAI,OAAO,IAAI,KAAK;CACrC,IAAI,QAAQ,IAAI,QAAQ,IAAI,UAAU,CAAC;CACvC,MAAM,OAAO,IAAI,YAAY;CAC7B,MAAM,QAAQ,IAAI,KAAK,MAAM,GAAG,CAAC;CACjC,MAAM,gBAAgB,IAAI,KAAK,MAAM,GAAG,KAAM,MAAM,OAAO,IAAI,KAAK,IAAK,CAAC;CAE1E,OAAO,CAAC,MADK,IAAI,KAAK,OAAO,IAAI,QAAQ,IAAI,cAAc,QAAQ,KAAK,MAAW,CACjE;AACpB;;;;;;;;AASA,SAAgB,SAAS,IAA8D;CACrF,IAAI,OAAO,OAAO,UAAU;EAC1B,MAAM,OAAO,GAAG,OAAO,IAAI,GAAG,OAAO;EACrC,MAAM,QAAQ,GAAG,SAAS;EAC1B,QAAQ,UAAU;GAChB,MAAM,IAAI,OAAO,UAAU,WAAW,QAAQ,iBAAiB,OAAO,MAAM,QAAQ,IAAI;GACxF,IAAI,CAAC,OAAO,SAAS,CAAC,GAAG,OAAO;GAEhC,OAAO,EAAE,KAAK,OAAO,IAAI,SAAS,IAAI,IAAI,OAAO,MAAA,CAAO,YAAY,EAAE;EACxE;CACF;CACA,QAAQ,UAAU;EAChB,MAAM,OAAO,OAAO,KAAK;EACzB,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,OAAO,KAAK,YAAY;EAC9B,QAAQ,IAAR;GACE,KAAK,QACH,OAAO;GACT,KAAK,WACH,OAAO,GAAG,KAAK,IAAI,KAAK,MAAM,KAAK,SAAS,IAAI,CAAC,IAAI;GACvD,KAAK,SACH,OAAO,GAAG,KAAK,GAAG,IAAI,KAAK,SAAS,IAAI,CAAC;GAC3C,KAAK,QAAQ;IACX,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI;IAC3B,OAAO,GAAG,EAAE,IAAI,IAAI,CAAC;GACvB;GACA,SACE,OAAO,GAAG,KAAK,GAAG,IAAI,KAAK,SAAS,IAAI,CAAC,EAAE,GAAG,IAAI,KAAK,QAAQ,CAAC;EACpE;CACF;AACF;;AAGA,SAAgB,WACd,IACA,QACmD;CACnD,IAAI,OAAO,QAAQ;EACjB,MAAM,OAAO,OAAO,MAAM;EAC1B,OAAO,OAAO,SAAS,IAAI,IAAI;GAAE;GAAM,MAAM;GAAG,MAAM,IAAI,KAAK,MAAM,GAAG,CAAC;EAAE,IAAI;CACjF;CACA,IAAI,OAAO,WAAW,UAAU,OAAO;CACvC,MAAM,IAAI,2CAA2C,KAAK,MAAM;CAChE,IAAI,CAAC,GAAG,OAAO;CACf,MAAM,OAAO,CAAC,EAAE;CAChB,MAAM,OAAO,CAAC,EAAE;CAChB,IAAI,EAAE,OAAO,KAAK,OAAO;EAAE;EAAM;EAAM,MAAM,IAAI,KAAK,OAAO,OAAO,KAAK,GAAG,CAAC;CAAE;CAC/E,IAAI,EAAE,OAAO,KAAK,OAAO;EAAE;EAAM;EAAM,MAAM,IAAI,KAAK,MAAM,GAAG,KAAK,OAAO,KAAK,CAAC;CAAE;CACnF,OAAO;EAAE;EAAM;EAAM,MAAM,IAAI,KAAK,MAAM,OAAO,GAAG,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC;CAAE;AACxE"}