@inflexa-ai/harness 0.42.2 → 0.43.1

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 (199) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/sandbox/shared.d.ts +1 -6
  3. package/dist/agents/sandbox/shared.js +0 -15
  4. package/dist/app/chat-turn.js +13 -1
  5. package/dist/config/environment-stores.d.ts +4 -2
  6. package/dist/contracts/chat-events.d.ts +9 -1
  7. package/dist/contracts/chat-frame.d.ts +3 -3
  8. package/dist/contracts/chat-frame.js +8 -3
  9. package/dist/contracts/chat-parts.d.ts +4 -1
  10. package/dist/contracts/data-profile.d.ts +4 -6
  11. package/dist/contracts/index.d.ts +1 -1
  12. package/dist/contracts/report-blocks.d.ts +1364 -75
  13. package/dist/contracts/report-blocks.js +221 -29
  14. package/dist/contracts/report-reference.js +1 -1
  15. package/dist/contracts/schemas/chat-events.d.ts +13 -0
  16. package/dist/contracts/schemas/chat-events.js +5 -0
  17. package/dist/contracts/schemas/chat-parts.d.ts +2 -2
  18. package/dist/contracts/schemas/index.d.ts +1 -1
  19. package/dist/contracts/schemas/index.js +1 -1
  20. package/dist/execution/input-signature.d.ts +7 -13
  21. package/dist/execution/input-signature.js +0 -0
  22. package/dist/execution/run-canceler.d.ts +3 -2
  23. package/dist/execution/run-canceler.js +3 -2
  24. package/dist/execution/run-event-stream.d.ts +16 -2
  25. package/dist/execution/run-event-stream.js +54 -3
  26. package/dist/index.d.ts +1 -8
  27. package/dist/index.js +5 -16
  28. package/dist/input-scan/enrich.d.ts +0 -2
  29. package/dist/input-scan/enrich.js +0 -1
  30. package/dist/lib/metrics.js +6 -7
  31. package/dist/lib/otel-spans.d.ts +4 -9
  32. package/dist/lib/otel-spans.js +3 -8
  33. package/dist/loop/run-agent.d.ts +4 -2
  34. package/dist/loop/run-agent.js +38 -23
  35. package/dist/memory/thread-history.d.ts +1 -1
  36. package/dist/prompts/report-session.d.ts +1 -1
  37. package/dist/prompts/report-session.js +17 -0
  38. package/dist/provenance/exec-frame.d.ts +1 -1
  39. package/dist/report-model/authoring-grammar.d.ts +416 -17
  40. package/dist/report-model/authoring-grammar.js +25 -4
  41. package/dist/report-model/block-walk.d.ts +20 -4
  42. package/dist/report-model/block-walk.js +64 -7
  43. package/dist/report-model/draft-finish.d.ts +6 -2
  44. package/dist/report-model/draft-finish.js +6 -1
  45. package/dist/report-model/production-resolver.d.ts +8 -0
  46. package/dist/report-model/production-resolver.js +1 -1
  47. package/dist/report-model/validate.d.ts +20 -10
  48. package/dist/report-model/validate.js +29 -13
  49. package/dist/report-render/chart-export.d.ts +52 -0
  50. package/dist/report-render/chart-export.js +192 -0
  51. package/dist/report-render/chart-presets.d.ts +46 -47
  52. package/dist/report-render/chart-presets.js +31 -101
  53. package/dist/report-render/chart-renderers.d.ts +163 -0
  54. package/dist/report-render/chart-renderers.js +1055 -0
  55. package/dist/report-render/chart-toolbox.d.ts +124 -0
  56. package/dist/report-render/chart-toolbox.js +595 -0
  57. package/dist/report-render/chart.d.ts +60 -27
  58. package/dist/report-render/chart.js +2323 -524
  59. package/dist/report-render/design.d.ts +476 -16
  60. package/dist/report-render/design.js +390 -56
  61. package/dist/report-render/figures/common.d.ts +321 -0
  62. package/dist/report-render/figures/common.js +759 -0
  63. package/dist/report-render/figures/dendrogram.d.ts +36 -0
  64. package/dist/report-render/figures/dendrogram.js +130 -0
  65. package/dist/report-render/figures/dense.d.ts +111 -0
  66. package/dist/report-render/figures/dense.js +204 -0
  67. package/dist/report-render/figures/dotplot.d.ts +28 -0
  68. package/dist/report-render/figures/dotplot.js +234 -0
  69. package/dist/report-render/figures/embedding.d.ts +43 -0
  70. package/dist/report-render/figures/embedding.js +360 -0
  71. package/dist/report-render/figures/equal-units.d.ts +101 -0
  72. package/dist/report-render/figures/equal-units.js +215 -0
  73. package/dist/report-render/figures/forest.d.ts +20 -0
  74. package/dist/report-render/figures/forest.js +398 -0
  75. package/dist/report-render/figures/gsea.d.ts +30 -0
  76. package/dist/report-render/figures/gsea.js +391 -0
  77. package/dist/report-render/figures/heatmap.d.ts +40 -0
  78. package/dist/report-render/figures/heatmap.js +395 -0
  79. package/dist/report-render/figures/index.d.ts +135 -0
  80. package/dist/report-render/figures/index.js +100 -0
  81. package/dist/report-render/figures/km.d.ts +16 -0
  82. package/dist/report-render/figures/km.js +406 -0
  83. package/dist/report-render/figures/label-room.d.ts +130 -0
  84. package/dist/report-render/figures/label-room.js +341 -0
  85. package/dist/report-render/figures/locuszoom.d.ts +50 -0
  86. package/dist/report-render/figures/locuszoom.js +675 -0
  87. package/dist/report-render/figures/lollipop.d.ts +16 -0
  88. package/dist/report-render/figures/lollipop.js +247 -0
  89. package/dist/report-render/figures/ma.d.ts +20 -0
  90. package/dist/report-render/figures/ma.js +114 -0
  91. package/dist/report-render/figures/manhattan.d.ts +60 -0
  92. package/dist/report-render/figures/manhattan.js +343 -0
  93. package/dist/report-render/figures/oncoprint.d.ts +41 -0
  94. package/dist/report-render/figures/oncoprint.js +420 -0
  95. package/dist/report-render/figures/pca.d.ts +37 -0
  96. package/dist/report-render/figures/pca.js +241 -0
  97. package/dist/report-render/figures/qq.d.ts +30 -0
  98. package/dist/report-render/figures/qq.js +182 -0
  99. package/dist/report-render/figures/roc.d.ts +17 -0
  100. package/dist/report-render/figures/roc.js +116 -0
  101. package/dist/report-render/figures/sankey.d.ts +48 -0
  102. package/dist/report-render/figures/sankey.js +353 -0
  103. package/dist/report-render/figures/upset.d.ts +60 -0
  104. package/dist/report-render/figures/upset.js +316 -0
  105. package/dist/report-render/figures/volcano.d.ts +25 -0
  106. package/dist/report-render/figures/volcano.js +166 -0
  107. package/dist/report-render/hybrid-svg.d.ts +75 -0
  108. package/dist/report-render/hybrid-svg.js +504 -0
  109. package/dist/report-render/number-format.d.ts +19 -0
  110. package/dist/report-render/number-format.js +25 -1
  111. package/dist/report-render/page.d.ts +41 -4
  112. package/dist/report-render/page.js +247 -12
  113. package/dist/report-render/render.d.ts +13 -4
  114. package/dist/report-render/render.js +37 -6
  115. package/dist/report-render/types.d.ts +23 -2
  116. package/dist/report-render/value-bridge.d.ts +38 -3
  117. package/dist/report-render/value-bridge.js +137 -6
  118. package/dist/report-render/views/chart-view.d.ts +42 -6
  119. package/dist/report-render/views/chart-view.js +70 -9
  120. package/dist/report-render/views/page-view.js +9 -10
  121. package/dist/runtime/assemble.js +2 -2
  122. package/dist/sandbox/client.d.ts +23 -32
  123. package/dist/sandbox/client.js +3 -11
  124. package/dist/sandbox/create-sandbox.d.ts +9 -24
  125. package/dist/sandbox/create-sandbox.js +15 -30
  126. package/dist/sandbox/docker-client.d.ts +12 -22
  127. package/dist/sandbox/docker-client.js +29 -43
  128. package/dist/sandbox/exec.d.ts +58 -0
  129. package/dist/sandbox/exec.js +197 -0
  130. package/dist/sandbox/identity.d.ts +5 -5
  131. package/dist/sandbox/identity.js +7 -10
  132. package/dist/sandbox/k8s-client.d.ts +4 -10
  133. package/dist/sandbox/k8s-client.js +5 -12
  134. package/dist/sandbox/liveness.d.ts +5 -12
  135. package/dist/sandbox/liveness.js +5 -12
  136. package/dist/sandbox/notification-sweep.d.ts +4 -7
  137. package/dist/sandbox/notification-sweep.js +4 -7
  138. package/dist/sandbox/reaper.d.ts +3 -3
  139. package/dist/sandbox/reaper.js +3 -3
  140. package/dist/sandbox/sandbox-error.d.ts +10 -11
  141. package/dist/sandbox/sandbox-error.js +10 -11
  142. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  143. package/dist/sandbox/sandbox-step-translate.js +1 -1
  144. package/dist/sandbox/types.d.ts +31 -99
  145. package/dist/sandbox/types.js +17 -84
  146. package/dist/state/active-sandboxes.d.ts +7 -32
  147. package/dist/state/active-sandboxes.js +11 -46
  148. package/dist/state/index.d.ts +1 -2
  149. package/dist/state/index.js +1 -1
  150. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.d.ts +7 -0
  151. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.js +12 -0
  152. package/dist/state/migrations/index.js +2 -0
  153. package/dist/state/schema.d.ts +1 -5
  154. package/dist/state/schema.js +1 -6
  155. package/dist/state/step-executions.js +1 -2
  156. package/dist/tasks/data-profile.js +7 -20
  157. package/dist/tasks/derive-table-exec.d.ts +4 -14
  158. package/dist/tasks/derive-table-exec.js +9 -24
  159. package/dist/tasks/extract-values.d.ts +2 -2
  160. package/dist/tasks/extract-values.js +4 -7
  161. package/dist/tools/define-tool.d.ts +56 -13
  162. package/dist/tools/define-tool.js +28 -1
  163. package/dist/tools/execute-analysis.js +3 -3
  164. package/dist/tools/report-session/derive-table.d.ts +8 -9
  165. package/dist/tools/report-session/derive-table.js +3 -4
  166. package/dist/tools/report-session/preview-report.js +4 -49
  167. package/dist/tools/sandbox/list-available-packages.d.ts +1 -1
  168. package/dist/tools/sandbox/list-available-packages.js +5 -4
  169. package/dist/tools/workspace/edit-file.d.ts +5 -4
  170. package/dist/tools/workspace/edit-file.js +10 -13
  171. package/dist/tools/workspace/execute-command.d.ts +27 -42
  172. package/dist/tools/workspace/execute-command.js +42 -38
  173. package/dist/tools/workspace/index.d.ts +5 -6
  174. package/dist/tools/workspace/index.js +5 -6
  175. package/dist/tools/workspace/mutator.d.ts +43 -8
  176. package/dist/tools/workspace/mutator.js +45 -34
  177. package/dist/tools/workspace/run-exec.d.ts +3 -12
  178. package/dist/tools/workspace/run-exec.js +7 -24
  179. package/dist/tools/workspace/scan-inputs.d.ts +0 -3
  180. package/dist/tools/workspace/scan-inputs.js +0 -1
  181. package/dist/tools/workspace/write-file.d.ts +12 -3
  182. package/dist/tools/workspace/write-file.js +17 -13
  183. package/dist/workflows/sandbox-step.d.ts +7 -11
  184. package/dist/workflows/sandbox-step.js +24 -27
  185. package/package.json +5 -3
  186. package/dist/sandbox/await-exec.d.ts +0 -143
  187. package/dist/sandbox/await-exec.js +0 -417
  188. package/dist/sandbox/deliver-exec-event.d.ts +0 -25
  189. package/dist/sandbox/deliver-exec-event.js +0 -29
  190. package/dist/sandbox/digest.d.ts +0 -14
  191. package/dist/sandbox/digest.js +0 -17
  192. package/dist/sandbox/exec-id.d.ts +0 -12
  193. package/dist/sandbox/exec-id.js +0 -20
  194. package/dist/sandbox/hmac.d.ts +0 -62
  195. package/dist/sandbox/hmac.js +0 -72
  196. package/dist/sandbox/submit-exec.d.ts +0 -38
  197. package/dist/sandbox/submit-exec.js +0 -80
  198. package/dist/sandbox/watchdog.d.ts +0 -71
  199. package/dist/sandbox/watchdog.js +0 -161
@@ -0,0 +1,504 @@
1
+ /**
2
+ * The hybrid SVG of a dense chart: the vector axes, text, legend, and guides, over one raster layer of the points.
3
+ *
4
+ * A chart past the point bound of the export gets no staged SVG, because a vector file of many thousands of
5
+ * points is too large. The page builds its SVG on a click instead. It draws the export option with the SVG
6
+ * renderer and the point data emptied, it draws the points alone on a canvas at 300 DPI, and it puts the canvas
7
+ * image into the SVG at the rectangle of the grid, under the vector marks. The server has no canvas, thus only
8
+ * the page builds this file.
9
+ *
10
+ * The rule of a point layer and the composition of the file hold one rule each in two twins: the TypeScript
11
+ * function and the page function. A shared test vector runs both, thus the two cannot drift in silence. The
12
+ * option transforms and the two draws exist on the page alone, because the server never builds the file.
13
+ */
14
+ /**
15
+ * True when one series draws a point for each row: a `scatter` whose symbol draws and which shows no series
16
+ * label. A scatter of size zero, or one with a shown label, carries names, and names stay vector text.
17
+ */
18
+ export function isPointLayer(series) {
19
+ if (typeof series !== "object" || series === null)
20
+ return false;
21
+ const fields = series;
22
+ if (fields.type !== "scatter" || fields.symbolSize === 0 || fields.symbol === "none")
23
+ return false;
24
+ const label = fields.label;
25
+ return !(typeof label === "object" && label !== null && label.show === true);
26
+ }
27
+ /** True when an option holds a point layer. The page can then build the hybrid SVG of the option. */
28
+ export function holdsPointLayer(option) {
29
+ const series = option.series;
30
+ return Array.isArray(series) ? series.some(isPointLayer) : isPointLayer(series);
31
+ }
32
+ /**
33
+ * The SVG text with its root at the millimeter size of a column. The view box keeps the pixel space, thus a
34
+ * vector editor opens the file at the column width. A size with no millimeter box leaves the root as it is.
35
+ */
36
+ export function millimeterRoot(svg, size) {
37
+ if (size.widthMm === undefined || size.heightMm === undefined)
38
+ return svg;
39
+ return svg.replace(`<svg width="${size.widthPx}" height="${size.heightPx}"`, `<svg width="${size.widthMm}mm" height="${size.heightMm}mm"`);
40
+ }
41
+ /** The count of decimals of a coordinate of the layer. A thousandth of a pixel is past each display. */
42
+ const LAYER_DECIMALS = 1000;
43
+ /** One coordinate of the layer, rounded to the decimals of the layer. */
44
+ function layerNumber(value) {
45
+ return Math.round(value * LAYER_DECIMALS) / LAYER_DECIMALS;
46
+ }
47
+ /** One attribute value with each character that can close it written as an entity. */
48
+ function attributeText(value) {
49
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
50
+ }
51
+ /** The root tag of an SVG file, and the transparent background rectangle that the chart runtime writes first. */
52
+ const ROOT_TAG = /^<svg\b[^>]*>/;
53
+ const BACKGROUND_RECT = /^\s*<rect width="[^"]*" height="[^"]*" x="0" y="0"[^>]*><\/rect>/;
54
+ /**
55
+ * The hybrid SVG file: the vector file with one `<image>` element of the point layer, and the root at the
56
+ * millimeter size.
57
+ *
58
+ * The image goes first after the background rectangle, thus each vector mark draws over the points: the axes,
59
+ * the guides, the names, and the legend. The rectangle of the image is the grid rectangle, and the image
60
+ * stretches to it, because the raster drew the grid at that rectangle. A text that holds no SVG root passes
61
+ * through with no image.
62
+ */
63
+ export function composeHybridSvg(svg, layer, size) {
64
+ const root = ROOT_TAG.exec(svg);
65
+ if (root === null)
66
+ return svg;
67
+ let at = root[0].length;
68
+ const background = BACKGROUND_RECT.exec(svg.slice(at));
69
+ if (background !== null)
70
+ at += background[0].length;
71
+ const image = `\n<image href="${attributeText(layer.href)}" x="${layerNumber(layer.x)}" y="${layerNumber(layer.y)}" ` +
72
+ `width="${layerNumber(layer.width)}" height="${layerNumber(layer.height)}" preserveAspectRatio="none"></image>`;
73
+ return millimeterRoot(svg.slice(0, at) + image + svg.slice(at), size);
74
+ }
75
+ /**
76
+ * The count of halvings of the search for one edge of a grid. The chart is at most some thousand pixels wide,
77
+ * thus twenty halvings place the edge closer than a hundredth of a pixel.
78
+ */
79
+ const EDGE_SEARCH_STEPS = 20;
80
+ /** The symbol size of a scatter that states none, in pixels: the default of the chart runtime. */
81
+ const RUNTIME_SYMBOL_PX = 10;
82
+ /**
83
+ * The page twin of the point-layer rule and of the composition, and the page build of the hybrid file, as
84
+ * browser source text.
85
+ *
86
+ * `reportHybridSvg(runtime, option, size)` is the entry point. It reads the chart runtime and the document of
87
+ * the page, and it gives the SVG text, or `null` when the option holds no point layer or the runtime gives no
88
+ * grid rectangle. The fragment reads `reportExportOption` of the renderer fragment, thus the bootstrap inlines
89
+ * that fragment first.
90
+ *
91
+ * The draws run in this order:
92
+ *
93
+ * 1. The vector draw takes the export option with the rows of each point layer emptied. Each point layer keeps
94
+ * each row that carries its own label, and two anchors with no symbol at the least and the greatest value of
95
+ * each dimension. Thus each axis and each color scale keeps the extent of the full rows.
96
+ * 2. The rectangle of each grid that holds a point layer comes from the runtime: a halving search of each edge
97
+ * with `containPixel` from a point inside the grid. The extent of each continuous axis of such a grid comes
98
+ * from `convertFromPixel` at the two edges.
99
+ * 3. The raster draw takes the export option with the point layers alone. Each grid stands at its measured
100
+ * rectangle, each axis holds its measured extent and draws nothing, and the legend, the graphics, and the
101
+ * color scales draw nothing. Thus each point lands on the pixel where the vector axes place it.
102
+ * 4. The composition crops the raster to the union of the grid rectangles at 300 DPI, and it puts the PNG into
103
+ * the vector file. The crop reaches past each grid edge by half of the largest symbol of a layer or of a
104
+ * visual map of a layer, thus a point on an edge keeps its whole symbol, as it does on the page.
105
+ */
106
+ export const HYBRID_SVG_SOURCE = `function reportIsPointLayer(series) {
107
+ if (typeof series !== "object" || series === null) {
108
+ return false;
109
+ }
110
+ if (series.type !== "scatter" || series.symbolSize === 0 || series.symbol === "none") {
111
+ return false;
112
+ }
113
+ var label = series.label;
114
+ return !(typeof label === "object" && label !== null && label.show === true);
115
+ }
116
+ function reportMillimeterRoot(svg, size) {
117
+ if (size.widthMm === undefined || size.heightMm === undefined) {
118
+ return svg;
119
+ }
120
+ return svg.replace('<svg width="' + size.widthPx + '" height="' + size.heightPx + '"', '<svg width="' + size.widthMm + 'mm" height="' + size.heightMm + 'mm"');
121
+ }
122
+ function reportLayerNumber(value) {
123
+ return Math.round(value * ${LAYER_DECIMALS}) / ${LAYER_DECIMALS};
124
+ }
125
+ function reportAttributeText(value) {
126
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
127
+ }
128
+ function reportComposeHybridSvg(svg, layer, size) {
129
+ var root = ${String(ROOT_TAG)}.exec(svg);
130
+ if (root === null) {
131
+ return svg;
132
+ }
133
+ var at = root[0].length;
134
+ var background = ${String(BACKGROUND_RECT)}.exec(svg.slice(at));
135
+ if (background !== null) {
136
+ at += background[0].length;
137
+ }
138
+ var image =
139
+ '\\n<image href="' + reportAttributeText(layer.href) + '" x="' + reportLayerNumber(layer.x) + '" y="' + reportLayerNumber(layer.y) + '" ' +
140
+ 'width="' + reportLayerNumber(layer.width) + '" height="' + reportLayerNumber(layer.height) + '" preserveAspectRatio="none"></image>';
141
+ return reportMillimeterRoot(svg.slice(0, at) + image + svg.slice(at), size);
142
+ }
143
+ function reportList(member) {
144
+ if (member === undefined || member === null) {
145
+ return [];
146
+ }
147
+ return Array.isArray(member) ? member : [member];
148
+ }
149
+ function reportItemValue(item) {
150
+ return typeof item === "object" && item !== null && !Array.isArray(item) ? item.value : item;
151
+ }
152
+ function reportLabeledItem(item) {
153
+ return typeof item === "object" && item !== null && !Array.isArray(item) && item.label !== undefined;
154
+ }
155
+ function reportExtentAnchors(data) {
156
+ var least = [];
157
+ var most = [];
158
+ for (var i = 0; i < data.length; i++) {
159
+ var value = reportItemValue(data[i]);
160
+ if (!Array.isArray(value)) {
161
+ continue;
162
+ }
163
+ for (var d = 0; d < value.length; d++) {
164
+ var cell = value[d];
165
+ var number = typeof cell === "number" ? cell : typeof cell === "string" && cell.trim() !== "" ? Number(cell) : NaN;
166
+ if (!isFinite(number)) {
167
+ if (least[d] === undefined) {
168
+ least[d] = cell;
169
+ most[d] = cell;
170
+ }
171
+ continue;
172
+ }
173
+ if (least[d] === undefined || typeof least[d] !== "number" || number < least[d]) {
174
+ least[d] = number;
175
+ }
176
+ if (most[d] === undefined || typeof most[d] !== "number" || number > most[d]) {
177
+ most[d] = number;
178
+ }
179
+ }
180
+ }
181
+ if (least.length === 0) {
182
+ return [];
183
+ }
184
+ return [
185
+ { value: least, symbol: "none", label: { show: false } },
186
+ { value: most, symbol: "none", label: { show: false } }
187
+ ];
188
+ }
189
+ function reportHybridVectorOption(option) {
190
+ var out = Object.assign({}, option);
191
+ var series = reportList(option.series);
192
+ var drawn = [];
193
+ for (var s = 0; s < series.length; s++) {
194
+ if (!reportIsPointLayer(series[s])) {
195
+ drawn.push(series[s]);
196
+ continue;
197
+ }
198
+ var data = Array.isArray(series[s].data) ? series[s].data : [];
199
+ var kept = [];
200
+ for (var i = 0; i < data.length; i++) {
201
+ if (reportLabeledItem(data[i])) {
202
+ kept.push(data[i]);
203
+ }
204
+ }
205
+ drawn.push(Object.assign({}, series[s], { large: false, data: kept.concat(reportExtentAnchors(data)) }));
206
+ }
207
+ out.series = drawn;
208
+ return out;
209
+ }
210
+ function reportSeriesGrid(option, series) {
211
+ var axes = reportList(option.xAxis);
212
+ var axis = axes[typeof series.xAxisIndex === "number" ? series.xAxisIndex : 0];
213
+ return axis && typeof axis.gridIndex === "number" ? axis.gridIndex : 0;
214
+ }
215
+ function reportContinuousAxis(axis, kind) {
216
+ var type = axis.type === undefined ? (kind === "xAxis" ? "category" : "value") : axis.type;
217
+ return type === "value" || type === "log" || type === "time";
218
+ }
219
+ function reportGridBox(chart, gridIndex, seed, width, height) {
220
+ var finder = { gridIndex: gridIndex };
221
+ if (!chart.containPixel(finder, seed)) {
222
+ return null;
223
+ }
224
+ function edge(inside, outside, point) {
225
+ for (var step = 0; step < ${EDGE_SEARCH_STEPS}; step++) {
226
+ var middle = (inside + outside) / 2;
227
+ if (chart.containPixel(finder, point(middle))) {
228
+ inside = middle;
229
+ } else {
230
+ outside = middle;
231
+ }
232
+ }
233
+ return inside;
234
+ }
235
+ function alongX(x) {
236
+ return [x, seed[1]];
237
+ }
238
+ function alongY(y) {
239
+ return [seed[0], y];
240
+ }
241
+ var left = edge(seed[0], -1, alongX);
242
+ var right = edge(seed[0], width + 1, alongX);
243
+ var top = edge(seed[1], -1, alongY);
244
+ var bottom = edge(seed[1], height + 1, alongY);
245
+ return { x: left, y: top, width: right - left, height: bottom - top };
246
+ }
247
+ function reportSeed(chart, option, series, index, width, height) {
248
+ var data = Array.isArray(series.data) ? series.data : [];
249
+ if (data.length === 0) {
250
+ return null;
251
+ }
252
+ var first = null;
253
+ for (var i = 0; i < data.length && first === null; i++) {
254
+ var value = reportItemValue(data[i]);
255
+ first = Array.isArray(value) ? value : null;
256
+ }
257
+ if (first !== null) {
258
+ // A continuous axis covers the extent of its data, and a category axis draws each category inside the grid.
259
+ // Thus the middle of the extent of a continuous dimension, and the category of the first row of a category
260
+ // dimension, give a point inside the grid of the layer.
261
+ var anchors = reportExtentAnchors(data);
262
+ var axes = [reportList(option.xAxis)[typeof series.xAxisIndex === "number" ? series.xAxisIndex : 0], reportList(option.yAxis)[typeof series.yAxisIndex === "number" ? series.yAxisIndex : 0]];
263
+ var kinds = ["xAxis", "yAxis"];
264
+ var place = [];
265
+ for (var d = 0; d < 2; d++) {
266
+ var least = anchors[0].value[d];
267
+ var most = anchors[1].value[d];
268
+ var continuous = axes[d] !== undefined && reportContinuousAxis(axes[d], kinds[d]);
269
+ place.push(continuous && typeof least === "number" && typeof most === "number" ? (least + most) / 2 : first[d]);
270
+ }
271
+ var point = chart.convertToPixel({ seriesIndex: index }, place);
272
+ if (Array.isArray(point) && isFinite(point[0]) && isFinite(point[1])) {
273
+ return point;
274
+ }
275
+ }
276
+ return [width / 2, height / 2];
277
+ }
278
+ function reportLargestSize(size) {
279
+ if (typeof size === "number") {
280
+ return size;
281
+ }
282
+ if (!Array.isArray(size)) {
283
+ return null;
284
+ }
285
+ var largest = 0;
286
+ for (var i = 0; i < size.length; i++) {
287
+ largest = Math.max(largest, Number(size[i]) || 0);
288
+ }
289
+ return largest;
290
+ }
291
+ function reportMapAppliesTo(map, index) {
292
+ var named = map.seriesIndex;
293
+ if (named === undefined || named === null) {
294
+ return true;
295
+ }
296
+ return Array.isArray(named) ? named.indexOf(index) >= 0 : named === index;
297
+ }
298
+ function reportSymbolReach(option, series, index) {
299
+ var own = reportLargestSize(series.symbolSize);
300
+ var largest = own === null ? ${RUNTIME_SYMBOL_PX} : own;
301
+ var maps = reportList(option.visualMap);
302
+ for (var m = 0; m < maps.length; m++) {
303
+ if (typeof maps[m] !== "object" || maps[m] === null || !reportMapAppliesTo(maps[m], index)) {
304
+ continue;
305
+ }
306
+ var visuals = [maps[m].inRange, maps[m].outOfRange].concat(reportList(maps[m].pieces));
307
+ for (var v = 0; v < visuals.length; v++) {
308
+ var mapped = typeof visuals[v] === "object" && visuals[v] !== null ? reportLargestSize(visuals[v].symbolSize) : null;
309
+ if (mapped !== null) {
310
+ largest = Math.max(largest, mapped);
311
+ }
312
+ }
313
+ }
314
+ return largest / 2;
315
+ }
316
+ function reportPointLayerBox(chart, option, width, height) {
317
+ var series = reportList(option.series);
318
+ var boxes = {};
319
+ var found = false;
320
+ var reach = 0;
321
+ for (var s = 0; s < series.length; s++) {
322
+ if (!reportIsPointLayer(series[s])) {
323
+ continue;
324
+ }
325
+ reach = Math.max(reach, Math.ceil(reportSymbolReach(option, series[s], s)));
326
+ var grid = reportSeriesGrid(option, series[s]);
327
+ if (boxes[grid] !== undefined) {
328
+ continue;
329
+ }
330
+ // A layer with no row gives no place inside its grid. A facet panel can hold no row of one category, thus
331
+ // the grid takes its seed from the next layer that holds rows, and a grid of empty layers draws no point.
332
+ var seed = reportSeed(chart, option, series[s], s, width, height);
333
+ if (seed === null) {
334
+ continue;
335
+ }
336
+ var box = reportGridBox(chart, grid, seed, width, height);
337
+ if (box === null) {
338
+ return null;
339
+ }
340
+ boxes[grid] = box;
341
+ found = true;
342
+ }
343
+ if (!found) {
344
+ return null;
345
+ }
346
+ var union = null;
347
+ for (var key in boxes) {
348
+ var b = boxes[key];
349
+ if (union === null) {
350
+ union = { x: b.x, y: b.y, right: b.x + b.width, bottom: b.y + b.height };
351
+ } else {
352
+ union = { x: Math.min(union.x, b.x), y: Math.min(union.y, b.y), right: Math.max(union.right, b.x + b.width), bottom: Math.max(union.bottom, b.y + b.height) };
353
+ }
354
+ }
355
+ var extents = { xAxis: [], yAxis: [] };
356
+ var kinds = ["xAxis", "yAxis"];
357
+ for (var k = 0; k < kinds.length; k++) {
358
+ var axes = reportList(option[kinds[k]]);
359
+ for (var a = 0; a < axes.length; a++) {
360
+ var place = boxes[typeof axes[a].gridIndex === "number" ? axes[a].gridIndex : 0];
361
+ if (place === undefined || !reportContinuousAxis(axes[a], kinds[k])) {
362
+ continue;
363
+ }
364
+ var finder = {};
365
+ finder[kinds[k] + "Index"] = a;
366
+ var ends = kinds[k] === "xAxis" ? [place.x, place.x + place.width] : [place.y + place.height, place.y];
367
+ var first = chart.convertFromPixel(finder, ends[0]);
368
+ var last = chart.convertFromPixel(finder, ends[1]);
369
+ extents[kinds[k]][a] = { min: Math.min(first, last), max: Math.max(first, last) };
370
+ }
371
+ }
372
+ var left = Math.max(0, union.x - reach);
373
+ var top = Math.max(0, union.y - reach);
374
+ var right = Math.min(width, union.right + reach);
375
+ var bottom = Math.min(height, union.bottom + reach);
376
+ return { boxes: boxes, extents: extents, box: { x: left, y: top, width: right - left, height: bottom - top } };
377
+ }
378
+ function reportUnlabeledItem(item) {
379
+ if (!reportLabeledItem(item)) {
380
+ return item;
381
+ }
382
+ var copy = Object.assign({}, item);
383
+ delete copy.label;
384
+ return copy;
385
+ }
386
+ function reportHidden(member) {
387
+ if (Array.isArray(member)) {
388
+ var list = [];
389
+ for (var i = 0; i < member.length; i++) {
390
+ list.push(Object.assign({}, member[i], { show: false }));
391
+ }
392
+ return list;
393
+ }
394
+ return Object.assign({}, member, { show: false });
395
+ }
396
+ function reportHybridRasterOption(option, layer) {
397
+ var out = Object.assign({}, option);
398
+ delete out.graphic;
399
+ delete out.title;
400
+ if (out.legend !== undefined) {
401
+ out.legend = reportHidden(out.legend);
402
+ }
403
+ if (out.visualMap !== undefined) {
404
+ out.visualMap = reportHidden(out.visualMap);
405
+ }
406
+ var series = reportList(option.series);
407
+ var drawn = [];
408
+ for (var s = 0; s < series.length; s++) {
409
+ var copy = Object.assign({}, series[s], { label: { show: false }, progressive: 0 });
410
+ delete copy.markLine;
411
+ delete copy.markArea;
412
+ delete copy.markPoint;
413
+ if (reportIsPointLayer(series[s])) {
414
+ var data = Array.isArray(series[s].data) ? series[s].data : [];
415
+ var points = [];
416
+ for (var i = 0; i < data.length; i++) {
417
+ points.push(reportUnlabeledItem(data[i]));
418
+ }
419
+ copy.data = points;
420
+ } else {
421
+ copy.data = [];
422
+ }
423
+ drawn.push(copy);
424
+ }
425
+ out.series = drawn;
426
+ var grids = reportList(option.grid);
427
+ var placed = [];
428
+ var count = grids.length > 0 ? grids.length : 1;
429
+ for (var g = 0; g < count; g++) {
430
+ var grid = Object.assign({}, grids[g] || {});
431
+ var box = layer.boxes[g];
432
+ if (box !== undefined) {
433
+ delete grid.right;
434
+ delete grid.bottom;
435
+ grid.left = box.x;
436
+ grid.top = box.y;
437
+ grid.width = box.width;
438
+ grid.height = box.height;
439
+ grid.containLabel = false;
440
+ grid.outerBoundsMode = "none";
441
+ }
442
+ placed.push(grid);
443
+ }
444
+ out.grid = placed;
445
+ var kinds = ["xAxis", "yAxis"];
446
+ for (var k = 0; k < kinds.length; k++) {
447
+ if (option[kinds[k]] === undefined) {
448
+ continue;
449
+ }
450
+ var axes = reportList(option[kinds[k]]);
451
+ var pinned = [];
452
+ for (var a = 0; a < axes.length; a++) {
453
+ var axis = Object.assign({}, axes[a], { show: false });
454
+ var extent = layer.extents[kinds[k]][a];
455
+ if (extent !== undefined) {
456
+ axis.min = extent.min;
457
+ axis.max = extent.max;
458
+ }
459
+ pinned.push(axis);
460
+ }
461
+ out[kinds[k]] = Array.isArray(option[kinds[k]]) ? pinned : pinned[0];
462
+ }
463
+ return out;
464
+ }
465
+ function reportCroppedLayer(chart, box, ratio) {
466
+ var full = chart.renderToCanvas({ pixelRatio: ratio });
467
+ var crop = document.createElement("canvas");
468
+ crop.width = Math.max(1, Math.round(box.width * ratio));
469
+ crop.height = Math.max(1, Math.round(box.height * ratio));
470
+ crop.getContext("2d").drawImage(full, box.x * ratio, box.y * ratio, box.width * ratio, box.height * ratio, 0, 0, crop.width, crop.height);
471
+ return crop.toDataURL("image/png");
472
+ }
473
+ function reportHybridSvg(runtime, option, size) {
474
+ var exported = reportExportOption(option, size.textPx, size.width, size.height);
475
+ if (!reportList(exported.series).some(reportIsPointLayer)) {
476
+ return null;
477
+ }
478
+ var vector = runtime.init(null, size.theme, { renderer: "svg", ssr: true, width: size.width, height: size.height });
479
+ var svg;
480
+ var layer;
481
+ try {
482
+ vector.setOption(reportHybridVectorOption(exported));
483
+ layer = reportPointLayerBox(vector, exported, size.width, size.height);
484
+ svg = vector.renderToSVGString();
485
+ } finally {
486
+ vector.dispose();
487
+ }
488
+ if (layer === null) {
489
+ return null;
490
+ }
491
+ var raster = runtime.init(document.createElement("div"), size.theme, { renderer: "canvas", width: size.width, height: size.height, devicePixelRatio: size.pixelRatio });
492
+ var href;
493
+ try {
494
+ raster.setOption(reportHybridRasterOption(exported, layer));
495
+ href = reportCroppedLayer(raster, layer.box, size.pixelRatio);
496
+ } finally {
497
+ raster.dispose();
498
+ }
499
+ return reportComposeHybridSvg(
500
+ svg,
501
+ { href: href, x: layer.box.x, y: layer.box.y, width: layer.box.width, height: layer.box.height },
502
+ { widthPx: size.width, heightPx: size.height, widthMm: size.widthMm, heightMm: size.heightMm }
503
+ );
504
+ }`;
@@ -115,3 +115,22 @@ export declare function smallestPositiveValue(cells: readonly (string | number |
115
115
  * A text that carries no exponent, and a text that holds no finite number, both give false.
116
116
  */
117
117
  export declare function holdsADriftedExponent(text: string): boolean;
118
+ /**
119
+ * The text of a figure with each scientific form as a power of ten, for example `1.3 × 10⁻³` from `1.3e-3`.
120
+ *
121
+ * A publication figure prints the power of ten, and a table cell and a metric card keep the short form that
122
+ * `formatNumberCell` gives. Thus the chart canvas and the export read this, and the page text does not. The
123
+ * rewrite reads the shown text, thus each kind and each bound keeps its digits, and a text with no exponent
124
+ * stays as it is.
125
+ */
126
+ export declare function typographicExponent(text: string): string;
127
+ /**
128
+ * One shown form with the sign of its value as the typographic minus.
129
+ *
130
+ * The substitution reads the leading character alone. Thus the exponent of a form such as `-1.2e-4` keeps
131
+ * its own hyphen, and a reader of that exponent reads the notation that the module prints.
132
+ *
133
+ * The shown form then no longer parses back to the value, thus the caller carries the raw cell in the full
134
+ * form. A negative always names its stored digits beside the glyph.
135
+ */
136
+ export declare function shownMinus(text: string): string;
@@ -321,6 +321,30 @@ export function holdsADriftedExponent(text) {
321
321
  const shown = EXPONENT_PART.exec(formatNumberCell(value, "scientific").text);
322
322
  return shown !== null && shown[1] !== written[1];
323
323
  }
324
+ /**
325
+ * One scientific form inside a text: a coefficient with its sign, and an exponent. The coefficient stands
326
+ * alone, thus a name such as `rs1e5` holds no scientific form.
327
+ */
328
+ const SCIENTIFIC_IN_TEXT = /(?<![\w.])([−-]?\d+(?:\.\d+)?)e([+-]?\d+)(?![\w.])/g;
329
+ /** The superscript form of each decimal digit, in digit order. */
330
+ const SUPERSCRIPT_DIGITS = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"];
331
+ /** The superscript minus of a negative exponent. */
332
+ const SUPERSCRIPT_MINUS = "⁻";
333
+ /**
334
+ * The text of a figure with each scientific form as a power of ten, for example `1.3 × 10⁻³` from `1.3e-3`.
335
+ *
336
+ * A publication figure prints the power of ten, and a table cell and a metric card keep the short form that
337
+ * `formatNumberCell` gives. Thus the chart canvas and the export read this, and the page text does not. The
338
+ * rewrite reads the shown text, thus each kind and each bound keeps its digits, and a text with no exponent
339
+ * stays as it is.
340
+ */
341
+ export function typographicExponent(text) {
342
+ return text.replace(SCIENTIFIC_IN_TEXT, (_form, coefficient, exponent) => {
343
+ const power = Number(exponent);
344
+ const digits = [...String(Math.abs(power))].map((digit) => SUPERSCRIPT_DIGITS[Number(digit)]).join("");
345
+ return `${shownMinus(coefficient)} × 10${power < 0 ? SUPERSCRIPT_MINUS : ""}${digits}`;
346
+ });
347
+ }
324
348
  /**
325
349
  * The bound of a stored zero, as one significant digit that rounds up, for example `4e-4` from `0.00036`.
326
350
  *
@@ -394,7 +418,7 @@ function formatValue(value, kind) {
394
418
  * The shown form then no longer parses back to the value, thus the caller carries the raw cell in the full
395
419
  * form. A negative always names its stored digits beside the glyph.
396
420
  */
397
- function shownMinus(text) {
421
+ export function shownMinus(text) {
398
422
  return text.startsWith("-") ? TYPOGRAPHIC_MINUS + text.slice(1) : text;
399
423
  }
400
424
  /** The scientific form, for example `4.3e-5`. */
@@ -53,24 +53,61 @@ export declare const PAGE_READY_TIMEOUT_MS = 8000;
53
53
  *
54
54
  * The fragment writes its own constants, because a page script reads no module binding. Each rule here is
55
55
  * the twin of one rule of the server derivation: the number read of a cell, the four transforms, the
56
- * competition rank, the compare of a sort, and the three-way classification of a preset. A shared test
57
- * vector runs the transforms of both sides over one set of cells, thus the two cannot drift in silence.
56
+ * competition rank, the compare of a sort, the classification of a preset, and the item that adds
57
+ * the member of a continuous color and of a size after the pair. A shared test vector runs the transforms
58
+ * and the items of both sides over one set of cells, thus the two cannot drift in silence.
58
59
  *
59
60
  * The build reads the decoded rows of the payload. The decoder runs before this script, thus a row is a
60
61
  * record and a cell reads by its column name.
61
62
  */
62
63
  export declare const CHART_SERIES_BUILDER: string;
64
+ /**
65
+ * The window global that holds the option of each chart, keyed by the id of its container.
66
+ *
67
+ * The option is plain data: its rows are built, and each renderer is still a name. The export of a chart
68
+ * draws it again from this entry, thus the page and each exported file read one option.
69
+ */
70
+ export declare const CHART_OPTIONS_GLOBAL = "__REPORT_CHART_OPTIONS";
63
71
  /**
64
72
  * The page-side script that wires each chart. It finds every chart container, reads the option JSON from
65
73
  * the sibling `<script type="application/json">` element, and initializes ECharts with the registered
66
74
  * theme. The skeleton registers the theme before this script runs. A resize handler keeps each chart
67
- * fit to the window.
75
+ * fit to the window. It draws a chart again only when the container of the chart changes size. A capture past
76
+ * the viewport resizes the window and keeps each container, and a redraw there restarts the chunked render of
77
+ * a dense chart. A container of zero width or height keeps its chart as it is: ECharts 6.1.0 throws when a
78
+ * Sankey draws at a zero size (apache/echarts#21706), and a capture can give a container a zero width for one
79
+ * resize.
80
+ *
81
+ * A custom series names its renderer as a string, because the option is JSON. The script registers each named
82
+ * renderer with the chart runtime before the first chart initializes, and it keeps the option under the
83
+ * container id.
84
+ *
85
+ * The option carries the toolbox of the chart. Each handler of the toolbox is the name of a page function, and
86
+ * the script binds each function after the parse and before the chart initializes. The formatter of a genome axis
87
+ * is such a name too. After the init the script attaches the zoom handler of the toolbox to the chart. The
88
+ * download control opens the download menu of the card. The print hides the canvas layer of the toolbox of each
89
+ * chart, because the runtime draws the toolbox inside the chart body, and the end of the print shows the layer
90
+ * again. The print sets no option, because a new option starts the chunked draw of a dense chart again.
91
+ *
92
+ * A click on a PNG entry of the menu draws the kept option again on a detached element, at the CSS size of the
93
+ * export and its pixel ratio, in the theme of its text size. The entry states the height of its export, because
94
+ * a taller chart body grows the height of a column export. Each series draws in one pass, because the script
95
+ * reads the PNG in the same task and a chunked draw ends in a later frame. Then the script reads the PNG and
96
+ * downloads it through an anchor. An entry that names no kept chart, or no export size, draws nothing.
97
+ *
98
+ * A click on a hybrid SVG entry builds the SVG of a dense chart from the kept option: the vector draw, the raster
99
+ * draw of the point layer at 300 DPI, and the composition. Then the script downloads the text through an anchor.
100
+ * A build that gives no file keeps the menu open and shows its fault note, thus the reader sees why the entry gave
101
+ * no file and can take a PNG.
68
102
  *
69
103
  * An option that carries the data-source member holds no row. The script then reads the registered payload
70
104
  * of the artifact and builds the data of each series from the descriptors. A mount whose payload the
71
105
  * registry does not hold keeps its empty card, and the walk continues.
72
106
  *
73
- * The script signals readiness when the bootstrap completes, and immediately when no chart exists. It sets
107
+ * The script signals readiness when each chart that it set fires its first `finished` event, and immediately
108
+ * when no chart exists. A dense scatter draws in chunks over some frames, and the runtime fires `finished`
109
+ * after the last chunk. Thus a capture that keys on the signal sees each point. A chart whose option throws
110
+ * counts as finished, thus one fault never withholds the signal. It sets
74
111
  * the `window.__inflexaThemeReady` sentinel and dispatches the `inflexa-theme-ready` event on the document.
75
112
  * A reader that captures the page keys on this signal, thus the capture returns when the page is ready and
76
113
  * not at a timeout. The sentinel guards a listener that registers after the dispatch, thus a late listener