@jarenjs/charts 0.34.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 (56) hide show
  1. package/README.md +293 -0
  2. package/dist/types/component/index.d.ts +95 -0
  3. package/dist/types/core/axis.d.ts +77 -0
  4. package/dist/types/core/cartesian.d.ts +127 -0
  5. package/dist/types/core/chart.d.ts +58 -0
  6. package/dist/types/core/domain.d.ts +96 -0
  7. package/dist/types/core/marks.d.ts +86 -0
  8. package/dist/types/core/palette.d.ts +72 -0
  9. package/dist/types/core/scale.d.ts +59 -0
  10. package/dist/types/core/session.d.ts +85 -0
  11. package/dist/types/core/stream-adapter.d.ts +187 -0
  12. package/dist/types/index.d.ts +35 -0
  13. package/dist/types/transforms/benchmark-adapter.d.ts +169 -0
  14. package/dist/types/transforms/mermaid-adapter.d.ts +30 -0
  15. package/dist/types/types/bar.d.ts +213 -0
  16. package/dist/types/types/boxplot.d.ts +116 -0
  17. package/dist/types/types/candlestick.d.ts +218 -0
  18. package/dist/types/types/gauge.d.ts +68 -0
  19. package/dist/types/types/heatmap.d.ts +104 -0
  20. package/dist/types/types/line.d.ts +272 -0
  21. package/dist/types/types/map.d.ts +137 -0
  22. package/dist/types/types/pie.d.ts +146 -0
  23. package/dist/types/types/radar.d.ts +89 -0
  24. package/dist/types/types/sankey.d.ts +100 -0
  25. package/dist/types/types/scatter.d.ts +80 -0
  26. package/dist/types/types/streamgraph.d.ts +75 -0
  27. package/dist/types/types/treemap.d.ts +118 -0
  28. package/package.json +76 -0
  29. package/schemas/chart-definition.schema.json +448 -0
  30. package/src/component/index.js +125 -0
  31. package/src/core/axis.js +221 -0
  32. package/src/core/cartesian.js +192 -0
  33. package/src/core/chart.js +101 -0
  34. package/src/core/domain.js +123 -0
  35. package/src/core/marks.js +110 -0
  36. package/src/core/palette.js +126 -0
  37. package/src/core/scale.js +106 -0
  38. package/src/core/session.js +0 -0
  39. package/src/core/stream-adapter.js +613 -0
  40. package/src/index.js +40 -0
  41. package/src/transforms/benchmark-adapter.js +298 -0
  42. package/src/transforms/mermaid-adapter.js +19 -0
  43. package/src/types/bar.js +276 -0
  44. package/src/types/boxplot.js +216 -0
  45. package/src/types/candlestick.js +274 -0
  46. package/src/types/gauge.js +140 -0
  47. package/src/types/heatmap.js +176 -0
  48. package/src/types/line.js +349 -0
  49. package/src/types/map.js +378 -0
  50. package/src/types/pie.js +163 -0
  51. package/src/types/radar.js +224 -0
  52. package/src/types/sankey.js +391 -0
  53. package/src/types/scatter.js +148 -0
  54. package/src/types/streamgraph.js +158 -0
  55. package/src/types/treemap.js +322 -0
  56. package/styles/charts.css +83 -0
@@ -0,0 +1,169 @@
1
+ /**
2
+ * @file Benchmark interop: pure functions from the published benchmark
3
+ * data shapes (the jaren website's generated `benchmarks/*.json`) to
4
+ * `compileChart`-shaped `{config, data}` pairs. No formatting, no
5
+ * vnodes, no fetching — data in, chart definition out, so every
6
+ * function is unit-testable against a vendored slice of the real data.
7
+ *
8
+ * The suite-wide ratio convention holds: ratio > 1 means "Jaren is N×
9
+ * faster", and the win/loss semantic tones follow it.
10
+ */
11
+ export type ChartPair = {
12
+ config: Record<string, any>;
13
+ data: Record<string, any>;
14
+ };
15
+ /**
16
+ * @typedef {{config: Record<string, any>, data: Record<string, any>}} ChartPair
17
+ */
18
+ /**
19
+ * The ratio-distribution bar chart: success-only tests bucketed by
20
+ * ratio. Buckets carry their own predicate and tone.
21
+ * @param {{ratio: number|null, isSuccessTest?: boolean}[]} results
22
+ * @param {{label: string, test: (r: number) => boolean, tone: 'win'|'loss'}[]} buckets
23
+ * @param {string} [title]
24
+ * @returns {ChartPair}
25
+ */
26
+ export declare function ratioDistributionBars(results: {
27
+ ratio: number | null;
28
+ isSuccessTest?: boolean;
29
+ }[], buckets: {
30
+ label: string;
31
+ test: (r: number) => boolean;
32
+ tone: 'win' | 'loss';
33
+ }[], title?: string): ChartPair;
34
+ /**
35
+ * The ratio scatter: every success-only test as one point, ranked
36
+ * fastest-ratio first, log-scale y, reference line at parity.
37
+ * @param {{ratio: number|null, isSuccessTest?: boolean}[]} results
38
+ * @param {string} [title]
39
+ * @returns {ChartPair}
40
+ */
41
+ export declare function ratioScatter(results: {
42
+ ratio: number | null;
43
+ isSuccessTest?: boolean;
44
+ }[], title?: string): ChartPair;
45
+ /**
46
+ * Per-draft conformance: grouped bars of passed tests per engine.
47
+ * @param {Record<string, Record<string, {passed: number}>>} engineStats
48
+ * engine → draft → {passed, failed, errors}
49
+ * @param {string} [title]
50
+ * @returns {ChartPair}
51
+ */
52
+ export declare function conformanceBars(engineStats: Record<string, Record<string, {
53
+ passed: number;
54
+ }>>, title?: string): ChartPair;
55
+ /**
56
+ * Generic engine-comparison bars over `{name, results: {engine: value}}`
57
+ * profile rows (the toml/markdown/mermaid profile shape).
58
+ * @param {{name: string, results: Record<string, number>}[]} rows
59
+ * @param {string[]} engines series order (first = jaren)
60
+ * @param {{title?: string, log?: boolean, valLabel?: string}} [options]
61
+ * @returns {ChartPair}
62
+ */
63
+ export declare function profileBars(rows: {
64
+ name: string;
65
+ results: Record<string, number>;
66
+ }[], engines: string[], options?: {
67
+ title?: string;
68
+ log?: boolean;
69
+ valLabel?: string;
70
+ }): ChartPair;
71
+ /**
72
+ * Scenario-matrix bars over `{scenario|title, engines: {key: nsPerOp}}`
73
+ * rows (the jsonquery/jslt shape). Log axis — rival engines span orders
74
+ * of magnitude.
75
+ * @param {{scenario?: string, title?: string, engines: Record<string, number>}[]} rows
76
+ * @param {{title?: string, valLabel?: string}} [options]
77
+ * @returns {ChartPair}
78
+ */
79
+ export declare function matrixBars(rows: {
80
+ scenario?: string;
81
+ title?: string;
82
+ engines: Record<string, number>;
83
+ }[], options?: {
84
+ title?: string;
85
+ valLabel?: string;
86
+ }): ChartPair;
87
+ /**
88
+ * Suite pass-count bars over an `{engine: {pass, total}}` map (the
89
+ * toml-compliance / markdown-scorecard shape); the highlighted engine
90
+ * (ours) carries the win tone.
91
+ * @param {Record<string, {pass: number, total: number}>} scorecard
92
+ * @param {{title?: string, highlight?: string, valLabel?: string}} [options]
93
+ * @returns {ChartPair}
94
+ */
95
+ export declare function passCountBars(scorecard: Record<string, {
96
+ pass: number;
97
+ total: number;
98
+ }>, options?: {
99
+ title?: string;
100
+ highlight?: string;
101
+ valLabel?: string;
102
+ }): ChartPair;
103
+ /**
104
+ * The jsonpath per-query profile: horizontal grouped bars for the
105
+ * top-N queries by jaren-vs-rival spread (the rest stay in the table).
106
+ * @param {{name: string, engines: Record<string, number>}[]} rows
107
+ * @param {string} rival the comparison engine key (e.g. 'json-p3')
108
+ * @param {number} topN
109
+ * @param {string} [title]
110
+ * @returns {ChartPair}
111
+ */
112
+ export declare function querySpreadBars(rows: {
113
+ name: string;
114
+ engines: Record<string, number>;
115
+ }[], rival: string, topN: number, title?: string): ChartPair;
116
+ /**
117
+ * Bars over a pointer/patch-style result table:
118
+ * `{columns, rows: [{name, results: number[]}]}`.
119
+ * @param {{title?: string, columns: string[], rows: {name: string, results: number[]}[]}} table
120
+ * @param {{title?: string, log?: boolean, valLabel?: string}} [options]
121
+ * @returns {ChartPair}
122
+ */
123
+ export declare function resultTableBars(table: {
124
+ title?: string;
125
+ columns: string[];
126
+ rows: {
127
+ name: string;
128
+ results: number[];
129
+ }[];
130
+ }, options?: {
131
+ title?: string;
132
+ log?: boolean;
133
+ valLabel?: string;
134
+ }): ChartPair;
135
+ /**
136
+ * Horizontal bars over `{label, ns}` timing rows (the view/charts
137
+ * benchmark shape). One series in one color: the bars are *nominal*
138
+ * categories — engines or scenarios — so their identity comes from the
139
+ * axis label, not from a hue, and the length is the whole message.
140
+ * Semantic win/loss tones are deliberately not used: on a timing chart
141
+ * "ours" is not automatically good, and docs/DESIGN.md reserves those tokens
142
+ * for genuine status.
143
+ * @param {{label: string, ns: number}[]} rows
144
+ * @param {{title?: string, log?: boolean, valLabel?: string}} [options]
145
+ * @returns {ChartPair}
146
+ */
147
+ export declare function timingBars(rows: {
148
+ label: string;
149
+ ns: number;
150
+ }[], options?: {
151
+ title?: string;
152
+ log?: boolean;
153
+ valLabel?: string;
154
+ }): ChartPair;
155
+ /**
156
+ * Cross-suite ratio bars for the benchmarks overview: one bar per suite
157
+ * headline, tone by which side of parity it lands on — here the tones
158
+ * ARE semantic (a ratio below 1 is a genuine loss, reported as one).
159
+ * @param {{key: string, label: string, ratio: number|null}[]} headlines
160
+ * @param {{title?: string}} [options]
161
+ * @returns {ChartPair}
162
+ */
163
+ export declare function headlineRatioBars(headlines: {
164
+ key: string;
165
+ label: string;
166
+ ratio: number | null;
167
+ }[], options?: {
168
+ title?: string;
169
+ }): ChartPair;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file Mermaid interop: map a mermaid pie AST (`{title, showData,
3
+ * slices}`) onto a chart definition + data pair. Lives in charts so the
4
+ * dependency arrow stays one-way — `@jarenjs/mermaid` imports this,
5
+ * never the reverse; nothing here touches mermaid code.
6
+ */
7
+ /**
8
+ * Convert a mermaid pie AST to `compileChart`-shaped inputs.
9
+ * @param {{title?: string|null, showData?: boolean, slices: {label: string, value: number}[]}} ast
10
+ * @returns {{config: {type: 'pie', title: string|null}, data: {slices: {label: string, value: number}[]}}}
11
+ */
12
+ export declare function mermaidPieToChartAST(ast: {
13
+ title?: string | null;
14
+ showData?: boolean;
15
+ slices: {
16
+ label: string;
17
+ value: number;
18
+ }[];
19
+ }): {
20
+ config: {
21
+ type: 'pie';
22
+ title: string | null;
23
+ };
24
+ data: {
25
+ slices: {
26
+ label: string;
27
+ value: number;
28
+ }[];
29
+ };
30
+ };
@@ -0,0 +1,213 @@
1
+ /**
2
+ * @file The bar chart type: grouped or stacked, vertical or horizontal,
3
+ * linear or log value axis. Data shape:
4
+ *
5
+ * data = { categories: string[],
6
+ * series: [{ name, values: number[],
7
+ * tone?: 'win'|'loss', tones?: (('win'|'loss'|null)[]) }] }
8
+ * config = { type:'bar', title?, stacked?, log?, orient?: 'v'|'h',
9
+ * catLabel?, valLabel? }
10
+ *
11
+ * The AST is orientation-agnostic: `u` runs along the category axis,
12
+ * `v` along the value axis; the render maps them to x/y per `orient`.
13
+ * Category lookups are hoisted out of the series loop (index-driven,
14
+ * never `categories.indexOf` per cell — that is O(n²) for wide charts).
15
+ */
16
+ export type BarAST = {
17
+ type: 'bar';
18
+ title: string | null;
19
+ orient: 'v' | 'h';
20
+ cat: {
21
+ ticks: {
22
+ pos: number;
23
+ label: string;
24
+ }[];
25
+ label: string | null;
26
+ };
27
+ val: {
28
+ ticks: {
29
+ pos: number;
30
+ label: string;
31
+ }[];
32
+ label: string | null;
33
+ };
34
+ legend: {
35
+ name: string;
36
+ swatch: number;
37
+ }[] | null;
38
+ bars: BarMarkAST[];
39
+ /**
40
+ * number of categories
41
+ */
42
+ count: number;
43
+ /**
44
+ * resolved value-axis bounds
45
+ */
46
+ domain: [number, number];
47
+ };
48
+ export type BarMarkAST = {
49
+ u0: number;
50
+ /**
51
+ * category-axis band
52
+ */
53
+ u1: number;
54
+ v0: number;
55
+ /**
56
+ * value-axis extent
57
+ */
58
+ v1: number;
59
+ /**
60
+ * series index
61
+ */
62
+ series: number;
63
+ tone: 'win' | 'loss' | null;
64
+ /**
65
+ * the category this bar stands in
66
+ */
67
+ label: string;
68
+ /**
69
+ * the series name
70
+ */
71
+ name: string;
72
+ /**
73
+ * the drawn value (hover text reports it exactly)
74
+ */
75
+ value: number;
76
+ };
77
+ /**
78
+ * @typedef {object} BarAST
79
+ * @property {'bar'} type
80
+ * @property {string|null} title
81
+ * @property {'v'|'h'} orient
82
+ * @property {{ticks: {pos:number,label:string}[], label: string|null}} cat
83
+ * @property {{ticks: {pos:number,label:string}[], label: string|null}} val
84
+ * @property {{name: string, swatch: number}[]|null} legend
85
+ * @property {BarMarkAST[]} bars
86
+ * @property {number} count number of categories
87
+ * @property {[number, number]} domain resolved value-axis bounds
88
+ */
89
+ /**
90
+ * @typedef {object} BarMarkAST
91
+ * @property {number} u0 @property {number} u1 category-axis band
92
+ * @property {number} v0 @property {number} v1 value-axis extent
93
+ * @property {number} series series index
94
+ * @property {'win'|'loss'|null} tone
95
+ * @property {string} label the category this bar stands in
96
+ * @property {string} name the series name
97
+ * @property {number} value the drawn value (hover text reports it exactly)
98
+ */
99
+ /**
100
+ * Scan the drawn values for the extremes the value axis is resolved
101
+ * from: the largest bar (a stacked chart's per-category total) and the
102
+ * smallest positive value a log axis needs for its bottom decade.
103
+ *
104
+ * Exported because the incremental session must reach the same bounds
105
+ * decision from the same numbers — one implementation, no drift.
106
+ * @param {any} data
107
+ * @param {boolean} stacked @param {boolean} log
108
+ * @returns {{maxVal: number, minPos: number}}
109
+ */
110
+ export declare function scanBarExtremes(data: any, stacked: boolean, log: boolean): {
111
+ maxVal: number;
112
+ minPos: number;
113
+ };
114
+ /**
115
+ * Resolve the value-axis bounds and tick values from the scanned
116
+ * extremes: a nice-number top over a zero base, or whole decades under
117
+ * `log`. The AST records the bounds so a later build — or the session —
118
+ * can detect "unchanged".
119
+ * @param {{maxVal: number, minPos: number}} ext
120
+ * @param {boolean} log
121
+ * @returns {{domain: [number, number], tickValues: number[]}}
122
+ */
123
+ export declare function resolveBarDomains(ext: {
124
+ maxVal: number;
125
+ minPos: number;
126
+ }, log: boolean): {
127
+ domain: [number, number];
128
+ tickValues: number[];
129
+ };
130
+ /**
131
+ * The value scale over a resolved domain — reconstructable by the
132
+ * session from the AST's domain alone.
133
+ * @param {[number, number]} domain @param {boolean} log
134
+ * @returns {(v: number) => number}
135
+ */
136
+ export declare function barScale(domain: [number, number], log: boolean): (v: number) => number;
137
+ /**
138
+ * Build the geometry-free bar AST.
139
+ * @param {any} data
140
+ * @param {any} [config]
141
+ * @returns {BarAST}
142
+ */
143
+ export declare function buildBarAST(data: any, config?: any): BarAST;
144
+ /**
145
+ * Render one bar as its `<rect>` value mark — the replaceable unit the
146
+ * incremental session re-emits when a live count changes.
147
+ * @param {BarMarkAST} bar
148
+ * @param {BarAST} ast
149
+ * @param {{x:number,y:number,w:number,h:number}} plot
150
+ * @param {{tokens: Record<string,string>}} theme
151
+ * @param {readonly string[]} palette
152
+ * @param {import('../core/marks.js').ChartTooltip|null} [tooltip]
153
+ * @returns {any}
154
+ */
155
+ export declare function barMarkRender(bar: BarMarkAST, ast: BarAST, plot: {
156
+ x: number;
157
+ y: number;
158
+ w: number;
159
+ h: number;
160
+ }, theme: {
161
+ tokens: Record<string, string>;
162
+ }, palette: readonly string[], tooltip?: import('../core/marks.js').ChartTooltip | null): any;
163
+ /**
164
+ * Render a bar AST and return the svg WITH the geometry a session needs
165
+ * to replace one bar in place: the plot rect and how many chrome
166
+ * children precede the bars.
167
+ * @param {BarAST} ast
168
+ * @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
169
+ * @param {string} hash
170
+ * @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[], width?: number,
171
+ * tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
172
+ * @returns {{svg: any, plot: {x:number,y:number,w:number,h:number}, chromeLen: number}}
173
+ */
174
+ export declare function buildBarRender(ast: BarAST, theme: {
175
+ tokens: Record<string, string>;
176
+ cssVars: Record<string, string>;
177
+ }, hash: string, options?: {
178
+ rootClass?: string;
179
+ keyPrefix?: string;
180
+ palette?: readonly string[];
181
+ width?: number;
182
+ tooltip?: import('../core/marks.js').ChartTooltipSpec;
183
+ }): {
184
+ svg: any;
185
+ plot: {
186
+ x: number;
187
+ y: number;
188
+ w: number;
189
+ h: number;
190
+ };
191
+ chromeLen: number;
192
+ };
193
+ /**
194
+ * Render a bar AST to a pure-vnode SVG. Each bar rect carries a
195
+ * `<title>` naming its series, category and exact value — the axis
196
+ * shows the rounded tick scale, the hover text shows the datum.
197
+ * @param {BarAST} ast
198
+ * @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
199
+ * @param {string} hash
200
+ * @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[], width?: number,
201
+ * tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
202
+ * @returns {any}
203
+ */
204
+ export declare function renderBarAST(ast: BarAST, theme: {
205
+ tokens: Record<string, string>;
206
+ cssVars: Record<string, string>;
207
+ }, hash: string, options?: {
208
+ rootClass?: string;
209
+ keyPrefix?: string;
210
+ palette?: readonly string[];
211
+ width?: number;
212
+ tooltip?: import('../core/marks.js').ChartTooltipSpec;
213
+ }): any;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * @file The boxplot chart type: five-number summaries per category with
3
+ * Tukey whiskers and outlier dots. Data shape (two forms per box):
4
+ *
5
+ * data = { boxes: [{ label, values: number[] } // raw samples
6
+ * | { label, min, q1, med, q3, max, outliers? }] } // precomputed
7
+ * config = { type:'boxplot', title?, catLabel?, valLabel? }
8
+ *
9
+ * Raw samples get the standard treatment: quartiles by linear
10
+ * interpolation over the sorted values, whiskers at the most extreme
11
+ * samples inside the 1.5·IQR fences, everything outside them an
12
+ * outlier. Precomputed summaries are trusted as given (their whiskers
13
+ * are the stated min/max). The AST is unit-space: `u` along the
14
+ * category axis, `v` along the value axis.
15
+ */
16
+ export type BoxAST = {
17
+ label: string;
18
+ u0: number;
19
+ u1: number;
20
+ /**
21
+ * whisker low
22
+ */
23
+ loV: number;
24
+ q1V: number;
25
+ medV: number;
26
+ q3V: number;
27
+ /**
28
+ * whisker high
29
+ */
30
+ hiV: number;
31
+ outliersV: number[];
32
+ stats: {
33
+ min: number;
34
+ q1: number;
35
+ med: number;
36
+ q3: number;
37
+ max: number;
38
+ };
39
+ };
40
+ export type BoxplotAST = {
41
+ type: 'boxplot';
42
+ title: string | null;
43
+ cat: {
44
+ ticks: {
45
+ pos: number;
46
+ label: string;
47
+ }[];
48
+ label: string | null;
49
+ };
50
+ val: {
51
+ ticks: {
52
+ pos: number;
53
+ label: string;
54
+ }[];
55
+ label: string | null;
56
+ };
57
+ boxes: BoxAST[];
58
+ /**
59
+ * number of categories
60
+ */
61
+ count: number;
62
+ };
63
+ /**
64
+ * @typedef {object} BoxAST
65
+ * @property {string} label
66
+ * @property {number} u0 @property {number} u1
67
+ * @property {number} loV whisker low @property {number} q1V
68
+ * @property {number} medV @property {number} q3V
69
+ * @property {number} hiV whisker high
70
+ * @property {number[]} outliersV
71
+ * @property {{min:number, q1:number, med:number, q3:number, max:number}} stats
72
+ */
73
+ /**
74
+ * @typedef {object} BoxplotAST
75
+ * @property {'boxplot'} type
76
+ * @property {string|null} title
77
+ * @property {{ticks: {pos:number,label:string}[], label: string|null}} cat
78
+ * @property {{ticks: {pos:number,label:string}[], label: string|null}} val
79
+ * @property {BoxAST[]} boxes
80
+ * @property {number} count number of categories
81
+ */
82
+ /**
83
+ * Quantile of an ascending-sorted sample by linear interpolation.
84
+ * @param {number[]} sorted - Ascending finite samples (non-empty)
85
+ * @param {number} p - Quantile in [0, 1]
86
+ * @returns {number}
87
+ */
88
+ export declare function quantileSorted(sorted: number[], p: number): number;
89
+ /**
90
+ * Build the geometry-free boxplot AST.
91
+ * @param {any} data
92
+ * @param {any} [config]
93
+ * @returns {BoxplotAST}
94
+ */
95
+ export declare function buildBoxplotAST(data: any, config?: any): BoxplotAST;
96
+ /**
97
+ * Render a boxplot AST to a pure-vnode SVG: capped whiskers, a
98
+ * translucent box with a full-strength median line, outlier dots, and
99
+ * a summary `<title>` per box.
100
+ * @param {BoxplotAST} ast
101
+ * @param {{tokens: Record<string,string>, cssVars: Record<string,string>}} theme
102
+ * @param {string} hash
103
+ * @param {{rootClass?: string, keyPrefix?: string, palette?: readonly string[], width?: number,
104
+ * tooltip?: import('../core/marks.js').ChartTooltipSpec}} [options]
105
+ * @returns {any}
106
+ */
107
+ export declare function renderBoxplotAST(ast: BoxplotAST, theme: {
108
+ tokens: Record<string, string>;
109
+ cssVars: Record<string, string>;
110
+ }, hash: string, options?: {
111
+ rootClass?: string;
112
+ keyPrefix?: string;
113
+ palette?: readonly string[];
114
+ width?: number;
115
+ tooltip?: import('../core/marks.js').ChartTooltipSpec;
116
+ }): any;