@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,173 @@
1
+ import { type PivotAggregator } from './aggregate';
2
+ import { type PivotFormula } from './formula';
3
+ import { IntIndex, type PivotIndexPacket } from './hash';
4
+ import { type PivotResolvedShow } from './show';
5
+ export type { PivotResolvedShow };
6
+ import type { PivotResolvedField, PivotSource } from './source';
7
+ import { PivotTree, type PivotTreePacket } from './tree';
8
+ import type { PivotConfig, PivotFormat, PivotMark, PivotShow, PivotShowAs, PivotValueSort } from './types';
9
+ /** A value of the config with everything filled in. */
10
+ export interface PivotResolvedValue {
11
+ field: PivotResolvedField<unknown> | null;
12
+ aggregate: string;
13
+ /** The custom aggregator, for names that are not built in. */
14
+ aggregator?: PivotAggregator;
15
+ /** As given; the component works out a header when there is none. */
16
+ label?: string;
17
+ format?: PivotFormat;
18
+ /** Whether the value is a count, written without decimals. */
19
+ integer: boolean;
20
+ /** Whether it stands in for an empty `values` (a count of records). */
21
+ implicit?: boolean;
22
+ /** A calculated value's formula, as written (`aggregate` is then `'formula'`). */
23
+ formula?: string;
24
+ /** How it is shown, as given (the axis is worked out by the result). */
25
+ show?: PivotShow;
26
+ mark?: Required<PivotMark>;
27
+ }
28
+ /** The ways of showing a value that write it as a percentage. */
29
+ export declare const PERCENT_SHOWS: ReadonlySet<PivotShowAs>;
30
+ /** A `show` as an object. */
31
+ export declare const showOf: (show: PivotShowAs | PivotShow | undefined) => PivotShow | undefined;
32
+ /** A `mark` with its tone filled in. */
33
+ export declare const markOf: (mark: "bar" | "scale" | PivotMark | undefined) => Required<PivotMark> | undefined;
34
+ /**
35
+ * Reads a calculated value's formula and finds its fields by name (or by
36
+ * label). Throws a `PivotFormulaError` when it is not well formed, names a
37
+ * field that is not there, or sums up one that is not a number.
38
+ */
39
+ export declare function checkPivotFormula<Row>(source: PivotSource<Row>, text: string): PivotFormula;
40
+ export interface PivotComputeOptions {
41
+ /** Aggregators by name, beside the built-in ones. */
42
+ aggregators?: Readonly<Record<string, PivotAggregator>>;
43
+ }
44
+ /** The fields of the config resolved against a source, without reading any records. */
45
+ export declare function resolveConfig(source: PivotSource<unknown>, config: PivotConfig, options?: PivotComputeOptions): {
46
+ rows: {
47
+ field: PivotResolvedField<unknown>;
48
+ sort: "asc" | "desc";
49
+ subtotal: boolean;
50
+ by: import("./group").PivotGroupBy | undefined;
51
+ }[];
52
+ columns: {
53
+ field: PivotResolvedField<unknown>;
54
+ sort: "asc" | "desc";
55
+ subtotal: boolean;
56
+ by: import("./group").PivotGroupBy | undefined;
57
+ }[];
58
+ values: PivotResolvedValue[];
59
+ formulas: (PivotFormula | null)[];
60
+ };
61
+ /**
62
+ * Groups the records by the config's row and column fields and sums up
63
+ * its values for every group, subtotal and total.
64
+ *
65
+ * Each record is placed once, in its innermost row group and innermost
66
+ * column group; the values are summed per such pair, and every subtotal
67
+ * is then merged from those pairs, never from the records again.
68
+ */
69
+ export declare function computePivot<Row>(source: PivotSource<Row>, config: PivotConfig, options?: PivotComputeOptions): PivotResult;
70
+ interface PivotResultInit {
71
+ rows: PivotTree;
72
+ columns: PivotTree;
73
+ values: PivotResolvedValue[];
74
+ matched: number;
75
+ cells: IntIndex;
76
+ width: number;
77
+ data: Float64Array[];
78
+ slotOf: Int32Array;
79
+ leafRow: Int32Array;
80
+ leafCol: Int32Array;
81
+ }
82
+ /**
83
+ * A `PivotResult` as data: typed arrays a worker moves to the page without
84
+ * copying, or plain arrays from JSON (a result summed up on a server).
85
+ */
86
+ export interface PivotPacket {
87
+ rows: PivotTreePacket;
88
+ columns: PivotTreePacket;
89
+ values: {
90
+ field: string | null;
91
+ aggregate: string;
92
+ integer: boolean;
93
+ implicit?: boolean;
94
+ label?: string;
95
+ formula?: string;
96
+ show?: PivotShow;
97
+ mark?: Required<PivotMark>;
98
+ }[];
99
+ matched: number;
100
+ cells: PivotIndexPacket;
101
+ width: number;
102
+ data: ArrayLike<number>[];
103
+ slotOf: ArrayLike<number>;
104
+ leafRow: ArrayLike<number>;
105
+ leafCol: ArrayLike<number>;
106
+ }
107
+ /** The groups on both axes and every cell's values. */
108
+ export declare class PivotResult {
109
+ readonly rows: PivotTree;
110
+ readonly columns: PivotTree;
111
+ readonly values: readonly PivotResolvedValue[];
112
+ /** How many records passed the filters. */
113
+ readonly matched: number;
114
+ private cells;
115
+ private width;
116
+ private data;
117
+ /** Each record's innermost cell, -1 when filtered out; and each such cell's groups. */
118
+ private slotOf;
119
+ private leafRow;
120
+ private leafCol;
121
+ constructor(init: PivotResultInit);
122
+ /**
123
+ * The result as data, to send from a worker or a server. With `plain`,
124
+ * plain arrays for `JSON.stringify` (typed arrays do not survive it);
125
+ * empty cells go as `null`.
126
+ */
127
+ pack({ plain }?: {
128
+ plain?: boolean;
129
+ }): PivotPacket;
130
+ private packTyped;
131
+ /** The typed arrays in a packet, to move them instead of copying (`postMessage`'s transfer list). */
132
+ static transferables(packet: PivotPacket): ArrayBuffer[];
133
+ /**
134
+ * A result made from `pack()`'s output. Fields are described by
135
+ * `source` (no record is read), formats come from `config`.
136
+ */
137
+ static unpack<Row>(packet: PivotPacket, source: PivotSource<Row>, config?: PivotConfig): PivotResult;
138
+ private showing;
139
+ private ranges;
140
+ private shownBy;
141
+ /**
142
+ * How a value is shown, its `show` with the axis worked out; null when as
143
+ * it is. `show` stands in for the value's own (`null` for none).
144
+ */
145
+ show(valueIndex?: number, show?: PivotShow | null): PivotResolvedShow | null;
146
+ /**
147
+ * The value as it is shown: a share, a difference, a running total or a
148
+ * rank when the value has a `show` (or one is given), the summed-up value
149
+ * otherwise. Nothing is summed up again.
150
+ */
151
+ shown(row: number, column: number, valueIndex?: number, show?: PivotShow | null): number;
152
+ /**
153
+ * The smallest and largest shown values of the innermost cells (those
154
+ * under no subtotal or total), which marks are drawn against.
155
+ */
156
+ range(valueIndex?: number, show?: PivotShow | null): {
157
+ min: number;
158
+ max: number;
159
+ };
160
+ /**
161
+ * The value at `valueIndex` (its place in `values`) of a row group and a
162
+ * column group; `NaN` when no record falls in both. The trees' `total`
163
+ * is the grand total.
164
+ */
165
+ get(row: number, column: number, valueIndex?: number): number;
166
+ /** The indexes of the records in a row group and a column group, for showing the details. */
167
+ indices(row: number, column: number): number[];
168
+ /**
169
+ * The children of every row group, reordered by a column's values (or as
170
+ * they are when `sort` is empty). Nothing is summed up again.
171
+ */
172
+ rowOrder(sort: PivotValueSort | null | undefined): Int32Array;
173
+ }
@@ -0,0 +1,29 @@
1
+ import { type PivotAggregator } from './aggregate';
2
+ import { type PivotResult } from './compute';
3
+ import type { PivotConfig } from './types';
4
+ import type { PivotSource } from './source';
5
+ export interface PivotComputeRequest {
6
+ /** Aggregators by name, beside the built-in ones. */
7
+ aggregators?: Readonly<Record<string, PivotAggregator>>;
8
+ /** Aborted when a newer config makes this one stale. */
9
+ signal?: AbortSignal;
10
+ }
11
+ /**
12
+ * Sums up the records somewhere else than in the page: in a worker
13
+ * (`createPivotWorker`), or on a server. `DouPivot` asks it for a result
14
+ * whenever the fields to sum up change, and shows only the newest one.
15
+ */
16
+ export interface PivotEngine {
17
+ compute<Row>(source: PivotSource<Row>, config: PivotConfig, request?: PivotComputeRequest): Promise<PivotResult>;
18
+ /** Lets go of what it holds (a worker, a connection) when the table goes away. */
19
+ dispose?(): void;
20
+ }
21
+ /**
22
+ * The fields a config reads, and how: grouped (`dimensions`: on an axis,
23
+ * filtered, counted) or as numbers (`measures`: summed and the like).
24
+ * No record is read.
25
+ */
26
+ export declare function neededColumns<Row>(source: PivotSource<Row>, config: PivotConfig, aggregators?: Readonly<Record<string, PivotAggregator>>): {
27
+ dimensions: string[];
28
+ measures: string[];
29
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Calculated values: a small expression language over the fields, read
3
+ * without `eval`. `profit / amount` divides the sum of `profit` by the sum
4
+ * of `amount` in each cell, so totals are ratios of totals, not sums of ratios.
5
+ *
6
+ * - numbers: `12`, `0.5`, `1e3`
7
+ * - fields: a name (`amount`, `销售额`), or any name in brackets (`[unit price]`)
8
+ * - `+ - * /`, parentheses and a leading minus
9
+ * - `sum(f)`, `avg(f)`, `min(f)`, `max(f)`, `count(f)` (records where f is not empty) and `count()`
10
+ *
11
+ * A bare field name stands for `sum(name)`. Dividing by zero leaves the cell empty.
12
+ */
13
+ /** The ways a formula can sum up a field. */
14
+ export type PivotFormulaAggregate = 'sum' | 'avg' | 'min' | 'max' | 'count';
15
+ /** A field a formula reads, and how. `field` is null for `count()`. */
16
+ export interface PivotFormulaTerm {
17
+ aggregate: PivotFormulaAggregate;
18
+ field: string | null;
19
+ }
20
+ /** A formula read into its terms and a function of their values. */
21
+ export interface PivotFormula {
22
+ source: string;
23
+ /** Each distinct field-and-aggregate the formula reads, in the order of `evaluate`'s input. */
24
+ terms: PivotFormulaTerm[];
25
+ /** The formula's value from its terms' values; `NaN` for an empty cell. */
26
+ evaluate(values: ArrayLike<number>): number;
27
+ }
28
+ /** Why a formula could not be read. */
29
+ export type PivotFormulaErrorCode = 'empty' | 'incomplete' | 'unknownChar' | 'unexpected' | 'expected' | 'unclosedBracket' | 'emptyName' | 'unknownFunction' | 'needsField' | 'needsName' | 'unknownField' | 'notNumber';
30
+ /**
31
+ * Why a formula could not be read, and where: `at` is a character offset,
32
+ * `detail` the text the message is about. `code` lets a page word it its own way.
33
+ */
34
+ export declare class PivotFormulaError extends Error {
35
+ readonly code: PivotFormulaErrorCode;
36
+ readonly at: number;
37
+ readonly detail: string;
38
+ constructor(code: PivotFormulaErrorCode, at: number, detail?: string);
39
+ }
40
+ /**
41
+ * Reads a formula. Throws a `PivotFormulaError` when it is not well formed.
42
+ * Field names are not checked here (see `computePivot`).
43
+ */
44
+ export declare function parsePivotFormula(text: string): PivotFormula;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * How a field's values are put in groups: dates by a period, numbers in
3
+ * ranges of `step` (starting at `start`, 0 by default).
4
+ */
5
+ export type PivotGroupBy = 'year' | 'quarter' | 'month' | 'week' | 'day' | {
6
+ step: number;
7
+ start?: number;
8
+ };
9
+ /** The periods a date can be grouped by. */
10
+ export declare const DATE_PERIODS: readonly ["year", "quarter", "month", "week", "day"];
11
+ export type PivotDatePeriod = (typeof DATE_PERIODS)[number];
12
+ /** A name for a grouping, to cache the grouped field under. */
13
+ export declare function groupKey(by: PivotGroupBy | undefined): string;
14
+ /**
15
+ * A date out of a value: a `Date`, a time in ms, or text such as
16
+ * `'2026-03-15'` (read in local time, like the other parts of a day).
17
+ */
18
+ export declare function toDate(value: unknown): Date | null;
19
+ /** The ISO week a day is in, and the year that week belongs to. */
20
+ export declare function isoWeek(date: Date): [year: number, week: number];
21
+ /**
22
+ * The group a value falls in: plain data that sorts in order and can be
23
+ * saved in the config (filters, collapsed groups): a year is a number
24
+ * (`2026`); a quarter, month, week or day is text (`'2026-Q1'`,
25
+ * `'2026-03'`, `'2026-W12'`, `'2026-03-15'`); a range is its lowest
26
+ * number. `null` when the value has no group (empty, or not a date / number).
27
+ */
28
+ export declare function bucketer(by: PivotGroupBy): (value: unknown) => number | string | null;
29
+ /** The parts of a period's group, read back from its text. */
30
+ export declare function readBucket(by: PivotDatePeriod, bucket: unknown): {
31
+ year: number;
32
+ part: number;
33
+ date: Date;
34
+ } | null;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * A table from whole numbers (0 to 2^53) to the order they were first seen
3
+ * in: open addressing over typed arrays, so millions of lookups allocate
4
+ * nothing and never touch a `Map`.
5
+ */
6
+ export declare class IntIndex {
7
+ /** The keys by slot; `-1` marks a free slot. */
8
+ private table;
9
+ /** What each slot's key maps to. */
10
+ private ids;
11
+ private mask;
12
+ /** The keys in the order they were added. */
13
+ keys: Float64Array;
14
+ size: number;
15
+ constructor(expected?: number);
16
+ /** The id of `key`, or -1. */
17
+ get(key: number): number;
18
+ /** The id of `key`, adding it with the next id when it is new. */
19
+ add(key: number): number;
20
+ /** Its arrays, to send to another thread (moved, not copied) or save. */
21
+ pack(): PivotIndexPacket;
22
+ /** An index made from `pack()`'s output; plain arrays (from JSON) work too. */
23
+ static unpack(packet: PivotIndexPacket): IntIndex;
24
+ private grow;
25
+ }
26
+ type TypedArrayOf = Float64ArrayConstructor | Int32ArrayConstructor | Uint32ArrayConstructor | Uint8ArrayConstructor;
27
+ /** The array as it is when it is already of that type (moved from a worker), else a typed copy (from JSON). */
28
+ export declare function typed<T extends TypedArrayOf>(Type: T, array: ArrayLike<number>): InstanceType<T>;
29
+ /** An `IntIndex` as data. */
30
+ export interface PivotIndexPacket {
31
+ table: ArrayLike<number>;
32
+ ids: ArrayLike<number>;
33
+ keys: ArrayLike<number>;
34
+ size: number;
35
+ }
36
+ export {};
@@ -0,0 +1,15 @@
1
+ export { checkPivotFormula, computePivot, PERCENT_SHOWS, PivotResult, resolveConfig, } from './compute';
2
+ export type { PivotComputeOptions, PivotPacket, PivotResolvedShow, PivotResolvedValue, } from './compute';
3
+ export { parsePivotFormula, PivotFormulaError } from './formula';
4
+ export type { PivotFormula, PivotFormulaAggregate, PivotFormulaErrorCode, PivotFormulaTerm, } from './formula';
5
+ export { neededColumns } from './engine';
6
+ export type { PivotComputeRequest, PivotEngine } from './engine';
7
+ export { defineAggregator } from './aggregate';
8
+ export type { PivotAggregator } from './aggregate';
9
+ export { compareValues, isColumns, isEmpty, PivotSource, toNumber } from './source';
10
+ export type { PivotColumns, PivotData, PivotDimensionColumn, PivotEncodedColumn, PivotResolvedField, PivotSourceOptions, } from './source';
11
+ export { PivotTree } from './tree';
12
+ export type { PivotLevel } from './tree';
13
+ export type * from './types';
14
+ export { bucketer, DATE_PERIODS, isoWeek, readBucket, toDate } from './group';
15
+ export type { PivotDatePeriod, PivotGroupBy } from './group';
@@ -0,0 +1,27 @@
1
+ import type { PivotTree } from './tree';
2
+ import type { PivotShow, PivotShowAs } from './types';
3
+ /** A way of showing a value with its axis worked out. */
4
+ export interface PivotResolvedShow {
5
+ as: PivotShowAs;
6
+ axis: 'rows' | 'columns';
7
+ }
8
+ /** The axis a way of showing works along: as given, or the default when that axis has fields. */
9
+ export declare function resolveShow(show: PivotShow, rows: PivotTree, columns: PivotTree): PivotResolvedShow;
10
+ /**
11
+ * Works out a value as it is shown, from the summed-up values (`get`).
12
+ * Groups come in their label order, whatever order the rows are shown in.
13
+ */
14
+ export declare class PivotShown {
15
+ readonly show: PivotResolvedShow;
16
+ private rows;
17
+ private columns;
18
+ private get;
19
+ private running;
20
+ private sorted;
21
+ constructor(show: PivotResolvedShow, rows: PivotTree, columns: PivotTree, get: (row: number, column: number) => number);
22
+ value(row: number, column: number): number;
23
+ /** The group before this one on the axis, or null for the first and for totals. */
24
+ private previous;
25
+ private runningTotal;
26
+ private rank;
27
+ }
@@ -0,0 +1,108 @@
1
+ import { type PivotGroupBy } from './group';
2
+ import type { PivotField, PivotFieldType } from './types';
3
+ /** A field's groups: each record's group number, and each group's value. */
4
+ export interface PivotDimensionColumn {
5
+ /** Each record's group. */
6
+ codes: Uint32Array;
7
+ /** Each group's value; `null` for the empty group. */
8
+ labels: unknown[];
9
+ /** The empty group's number, or -1 when every record has a value. */
10
+ empty: number;
11
+ /** Each group's place in the field's natural order (its `order`, then sorted, empty last). */
12
+ rank: Uint32Array;
13
+ /** The group of `value`, or -1 when no record has it. */
14
+ find: (value: unknown) => number;
15
+ }
16
+ /** A field with its type worked out. */
17
+ export interface PivotResolvedField<Row = unknown> extends PivotField<Row> {
18
+ label: string;
19
+ type: PivotFieldType;
20
+ }
21
+ export interface PivotSourceOptions<Row> {
22
+ fields?: readonly PivotField<Row>[];
23
+ /** For sorting group labels; the runtime's locale when left out. */
24
+ locale?: string;
25
+ }
26
+ /**
27
+ * Records given column by column: each field's values in one array (or
28
+ * typed array), all of the same length. A million records take far less
29
+ * memory this way than as a million objects.
30
+ */
31
+ export type PivotColumns = Readonly<Record<string, ArrayLike<unknown>>>;
32
+ /** The records: an array of objects, or their columns. */
33
+ export type PivotData<Row = Record<string, unknown>> = readonly Row[] | PivotColumns;
34
+ /** A field's groups before they are put in order: what a worker is sent. */
35
+ export interface PivotEncodedColumn {
36
+ codes: Uint32Array;
37
+ labels: unknown[];
38
+ empty: number;
39
+ }
40
+ export declare const isColumns: (data: unknown) => data is PivotColumns;
41
+ /**
42
+ * The records, read field by field into typed arrays the first time each
43
+ * field is used, and kept until the records change.
44
+ */
45
+ export declare class PivotSource<Row = Record<string, unknown>> {
46
+ /** The records as given: objects, or columns. */
47
+ readonly data: PivotData<Row>;
48
+ readonly length: number;
49
+ readonly fields: Map<string, PivotResolvedField<Row>>;
50
+ readonly locale: string | undefined;
51
+ private collator;
52
+ private dimensions;
53
+ private measures;
54
+ /** Groups read elsewhere (in the page, for a worker), waiting to be put in order. */
55
+ private given;
56
+ constructor(data: PivotData<Row>, options?: PivotSourceOptions<Row> & {
57
+ length?: number;
58
+ });
59
+ /** The record at `index`: the object given, or one made from the columns. */
60
+ record(index: number): Row;
61
+ /** How to read a field from record `i`. */
62
+ private reader;
63
+ /** Describes a field (or describes it again), as `fields` would have. */
64
+ define(field: PivotField<Row>): void;
65
+ /** Hands over groups read elsewhere, such as in the page for a worker. */
66
+ provide(name: string, column: PivotEncodedColumn): void;
67
+ /** Hands over a field's numbers read elsewhere. */
68
+ provideMeasure(name: string, values: Float64Array): void;
69
+ /** The field called `name`; one is made up for keys the fields do not list. */
70
+ field(name: string): PivotResolvedField<Row>;
71
+ /** The field's values, one per record. */
72
+ values(name: string): unknown[];
73
+ /**
74
+ * The field grouped by value, or by `by`: dates by a period, numbers in
75
+ * ranges. A grouping is worked out from the field's groups, not from the
76
+ * records, so it costs one pass over the group numbers.
77
+ */
78
+ dimension(name: string, by?: PivotGroupBy): PivotDimensionColumn;
79
+ private group;
80
+ /** The field as numbers, `NaN` where a record has none. */
81
+ measure(name: string): Float64Array;
82
+ /**
83
+ * Reads a field's numbers a slice at a time, for reading a large field
84
+ * without holding up the page. The array is new: the source keeps none.
85
+ */
86
+ measureSteps(name: string, copy?: boolean): Generator<void, Float64Array>;
87
+ private resolve;
88
+ private guess;
89
+ private encode;
90
+ /**
91
+ * Reads a field's groups a slice at a time, for reading a large field
92
+ * without holding up the page: each record's group number and each
93
+ * group's value, not yet in order.
94
+ */
95
+ encodeSteps(name: string): Generator<void, PivotEncodedColumn>;
96
+ /** Each group's place: the field's `order` first, then by value, the empty group last. */
97
+ private rank;
98
+ }
99
+ /** Empty: `null`, `undefined`, `''`, `NaN` and invalid dates all go in the empty group. */
100
+ export declare const isEmpty: (value: unknown) => boolean;
101
+ /** Natural order: numbers and dates by size, text by the locale (digits as numbers), empty last. */
102
+ export declare function compareValues(a: unknown, b: unknown, collator: Intl.Collator): number;
103
+ /** A value as a number: numbers, dates and numeric text; `NaN` for anything else. */
104
+ export declare function toNumber(value: unknown): number;
105
+ /** Runs reading in slices to the end, at once. */
106
+ export declare function run<T>(steps: Generator<void, T>): T;
107
+ /** Finds a group by its value; dates by their time. */
108
+ export declare function finder(labels: readonly unknown[], empty: number): (value: unknown) => number;
@@ -0,0 +1,87 @@
1
+ import type { PivotGroupBy } from './group';
2
+ import { IntIndex, type PivotIndexPacket } from './hash';
3
+ import { type PivotDimensionColumn, type PivotResolvedField } from './source';
4
+ /** A field on an axis, with what the config asked of it. */
5
+ export interface PivotLevel {
6
+ field: PivotResolvedField<unknown>;
7
+ column: PivotDimensionColumn;
8
+ sort: 'asc' | 'desc';
9
+ subtotal: boolean;
10
+ /** How the field's values are grouped, when not by each value. */
11
+ by?: PivotGroupBy;
12
+ }
13
+ /**
14
+ * The groups along one axis. Node 0 is the whole axis (the grand total);
15
+ * a node at depth `d` is a group of the `d`-th field inside its parent.
16
+ * Children are kept in label order, as compressed lists: the children of
17
+ * `node` are `children[childStart[node]]` up to `children[childStart[node + 1]]`.
18
+ */
19
+ export declare class PivotTree {
20
+ /** The root: the grand total, as a row or column group. */
21
+ readonly total = 0;
22
+ readonly size: number;
23
+ readonly levels: readonly PivotLevel[];
24
+ readonly parent: Int32Array;
25
+ readonly depth: Uint8Array;
26
+ /** The group number within its field (`-1` for the root). */
27
+ readonly code: Int32Array;
28
+ readonly childStart: Int32Array;
29
+ readonly children: Int32Array;
30
+ /** Where each node starts and ends in a walk of the tree, to tell descendants apart. */
31
+ readonly enter: Int32Array;
32
+ readonly exit: Int32Array;
33
+ private index;
34
+ private stride;
35
+ constructor(builder: PivotTreeBuilder, levels: readonly PivotLevel[]);
36
+ /** The tree as data: typed arrays to move to another thread, or to write as JSON. */
37
+ pack(): PivotTreePacket;
38
+ /** A tree made from `pack()`'s output, with fields described by `field`. */
39
+ static unpack(packet: PivotTreePacket, field: (name: string) => PivotResolvedField<unknown>): PivotTree;
40
+ /** The node's own value (its group label); `undefined` for the root. */
41
+ label(node: number): unknown;
42
+ /** The labels from the outermost group down to `node`. */
43
+ path(node: number): unknown[];
44
+ /** The node with these labels, or -1. */
45
+ find(path: readonly unknown[]): number;
46
+ /** Whether `node` has groups inside it. */
47
+ isGroup(node: number): boolean;
48
+ /** Whether `node` is `ancestor` or inside it. */
49
+ within(node: number, ancestor: number): boolean;
50
+ private walk;
51
+ }
52
+ /** A `PivotTree` as data. */
53
+ export interface PivotTreePacket {
54
+ size: number;
55
+ stride: number;
56
+ parent: ArrayLike<number>;
57
+ depth: ArrayLike<number>;
58
+ code: ArrayLike<number>;
59
+ childStart: ArrayLike<number>;
60
+ children: ArrayLike<number>;
61
+ enter: ArrayLike<number>;
62
+ exit: ArrayLike<number>;
63
+ index: PivotIndexPacket;
64
+ levels: {
65
+ field: string;
66
+ sort: 'asc' | 'desc';
67
+ subtotal: boolean;
68
+ by?: PivotGroupBy;
69
+ labels: unknown[];
70
+ empty: number;
71
+ rank: ArrayLike<number>;
72
+ }[];
73
+ }
74
+ /** Grows a tree one record at a time: each record walks down its groups. */
75
+ export declare class PivotTreeBuilder {
76
+ readonly stride: number;
77
+ parent: Int32Array<ArrayBuffer>;
78
+ depth: Uint8Array<ArrayBuffer>;
79
+ code: Int32Array<ArrayBuffer>;
80
+ size: number;
81
+ readonly index: IntIndex;
82
+ /** `stride` is more than any group number, so (parent, group) makes a unique key. */
83
+ constructor(stride: number);
84
+ /** The child of `node` for group `code`, made when new. */
85
+ child(node: number, code: number): number;
86
+ private grow;
87
+ }