@epxing/utils 0.0.0-stage → 5.3.0-beta.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 (230) hide show
  1. package/API.md +602 -0
  2. package/README.md +22 -2
  3. package/dist/_vendor/.pnpm/jsencrypt@3.5.4/_vendor/jsencrypt/bin/jsencrypt.min.js +1691 -0
  4. package/dist/_virtual/_commonjsHelpers.js +6 -0
  5. package/dist/_virtual/jsencrypt.min.js +31 -0
  6. package/dist/_virtual/jsencrypt.min2.js +4 -0
  7. package/dist/_virtual/preload-helper.js +88 -0
  8. package/dist/assets/ai-BBFn3QRy.png +0 -0
  9. package/dist/assets/ai_import-BxQ7Ohn6.png +0 -0
  10. package/dist/assets/app-DBNIokDP.png +0 -0
  11. package/dist/assets/approval-DGcBv-re.png +0 -0
  12. package/dist/assets/create_market_system-BH__UVbt.png +0 -0
  13. package/dist/assets/create_system-irg--ePh.png +0 -0
  14. package/dist/assets/custom-C-ujlHz1.png +0 -0
  15. package/dist/assets/default-icon-2193FMjv.png +0 -0
  16. package/dist/assets/ex_link-4fYPd9nh.png +0 -0
  17. package/dist/assets/excel-BYqRm2Y8.png +0 -0
  18. package/dist/assets/folder-CFVsNbjj.png +0 -0
  19. package/dist/assets/form-DD9HV-jN.png +0 -0
  20. package/dist/assets/import-tfKWbWVS.png +0 -0
  21. package/dist/assets/meta-Qorpi70B.png +0 -0
  22. package/dist/assets/module-DQrs7VAS.png +0 -0
  23. package/dist/assets/null-B2An29h4.png +0 -0
  24. package/dist/assets/option-CG02tIgh.svg +1 -0
  25. package/dist/assets/photo-uscRzRXF.png +0 -0
  26. package/dist/assets/process-Dcndu9m2.png +0 -0
  27. package/dist/assets/rule-DcYhYse0.png +0 -0
  28. package/dist/assets/service-CLYLpPl3.png +0 -0
  29. package/dist/assets/single_file-B3TJtJli.png +0 -0
  30. package/dist/assets/snapshot-history-BsVY9cVj.png +0 -0
  31. package/dist/assets/snapshot-manual-DBRfFHYI.png +0 -0
  32. package/dist/assets/snapshot-realtime-DjHnJI6C.png +0 -0
  33. package/dist/assets/staff-Bn_-_00l.png +0 -0
  34. package/dist/assets/sync_append-Bm8mtvZs.png +0 -0
  35. package/dist/assets/sync_append_update-DzjxqJ_U.png +0 -0
  36. package/dist/assets/sync_loading-D7LoNPFP.png +0 -0
  37. package/dist/assets/sync_replace-Cbbzz327.png +0 -0
  38. package/dist/assets/sync_update-Birao6Cr.png +0 -0
  39. package/dist/assets/userRole-D1LAdM6N.png +0 -0
  40. package/dist/assets/user_bg-BFHtaZjz.png +0 -0
  41. package/dist/src/Config.js +25 -0
  42. package/dist/src/asset-images.js +125 -0
  43. package/dist/src/assets/images/add.png.js +4 -0
  44. package/dist/src/assets/images/ai-button.png.js +4 -0
  45. package/dist/src/assets/images/ai.png.js +4 -0
  46. package/dist/src/assets/images/ai_import.png.js +4 -0
  47. package/dist/src/assets/images/app.png.js +4 -0
  48. package/dist/src/assets/images/approval.png.js +4 -0
  49. package/dist/src/assets/images/book.png.js +4 -0
  50. package/dist/src/assets/images/canvas-editor/alignment.svg.js +4 -0
  51. package/dist/src/assets/images/canvas-editor/arrow-left.svg.js +4 -0
  52. package/dist/src/assets/images/canvas-editor/arrow-right.svg.js +4 -0
  53. package/dist/src/assets/images/canvas-editor/block.svg.js +4 -0
  54. package/dist/src/assets/images/canvas-editor/bold.svg.js +4 -0
  55. package/dist/src/assets/images/canvas-editor/catalog.svg.js +4 -0
  56. package/dist/src/assets/images/canvas-editor/center.svg.js +4 -0
  57. package/dist/src/assets/images/canvas-editor/checkbox.svg.js +4 -0
  58. package/dist/src/assets/images/canvas-editor/close.svg.js +4 -0
  59. package/dist/src/assets/images/canvas-editor/codeblock.svg.js +4 -0
  60. package/dist/src/assets/images/canvas-editor/color.svg.js +4 -0
  61. package/dist/src/assets/images/canvas-editor/control.svg.js +4 -0
  62. package/dist/src/assets/images/canvas-editor/date.svg.js +4 -0
  63. package/dist/src/assets/images/canvas-editor/exit-fullscreen.svg.js +4 -0
  64. package/dist/src/assets/images/canvas-editor/format.svg.js +4 -0
  65. package/dist/src/assets/images/canvas-editor/highlight.svg.js +4 -0
  66. package/dist/src/assets/images/canvas-editor/hyperlink.svg.js +4 -0
  67. package/dist/src/assets/images/canvas-editor/image.svg.js +4 -0
  68. package/dist/src/assets/images/canvas-editor/italic.svg.js +4 -0
  69. package/dist/src/assets/images/canvas-editor/justify.svg.js +4 -0
  70. package/dist/src/assets/images/canvas-editor/latex.svg.js +4 -0
  71. package/dist/src/assets/images/canvas-editor/left.svg.js +4 -0
  72. package/dist/src/assets/images/canvas-editor/line-dash-dot-dot.svg.js +4 -0
  73. package/dist/src/assets/images/canvas-editor/line-dash-dot.svg.js +4 -0
  74. package/dist/src/assets/images/canvas-editor/line-dash-large-gap.svg.js +4 -0
  75. package/dist/src/assets/images/canvas-editor/line-dash-small-gap.svg.js +4 -0
  76. package/dist/src/assets/images/canvas-editor/line-dot.svg.js +4 -0
  77. package/dist/src/assets/images/canvas-editor/line-double.svg.js +4 -0
  78. package/dist/src/assets/images/canvas-editor/line-single.svg.js +4 -0
  79. package/dist/src/assets/images/canvas-editor/line-wavy.svg.js +4 -0
  80. package/dist/src/assets/images/canvas-editor/list.svg.js +4 -0
  81. package/dist/src/assets/images/canvas-editor/option.svg.js +4 -0
  82. package/dist/src/assets/images/canvas-editor/page-break.svg.js +4 -0
  83. package/dist/src/assets/images/canvas-editor/page-mode.svg.js +4 -0
  84. package/dist/src/assets/images/canvas-editor/page-scale-add.svg.js +4 -0
  85. package/dist/src/assets/images/canvas-editor/page-scale-minus.svg.js +4 -0
  86. package/dist/src/assets/images/canvas-editor/painter.svg.js +4 -0
  87. package/dist/src/assets/images/canvas-editor/paper-direction.svg.js +4 -0
  88. package/dist/src/assets/images/canvas-editor/paper-margin.svg.js +4 -0
  89. package/dist/src/assets/images/canvas-editor/paper-size.svg.js +4 -0
  90. package/dist/src/assets/images/canvas-editor/print.svg.js +4 -0
  91. package/dist/src/assets/images/canvas-editor/radio.svg.js +4 -0
  92. package/dist/src/assets/images/canvas-editor/redo.svg.js +4 -0
  93. package/dist/src/assets/images/canvas-editor/request-fullscreen.svg.js +4 -0
  94. package/dist/src/assets/images/canvas-editor/right.svg.js +4 -0
  95. package/dist/src/assets/images/canvas-editor/row-margin.svg.js +4 -0
  96. package/dist/src/assets/images/canvas-editor/search.svg.js +4 -0
  97. package/dist/src/assets/images/canvas-editor/separator.svg.js +4 -0
  98. package/dist/src/assets/images/canvas-editor/signature-undo.svg.js +4 -0
  99. package/dist/src/assets/images/canvas-editor/signature.svg.js +4 -0
  100. package/dist/src/assets/images/canvas-editor/size-add.svg.js +4 -0
  101. package/dist/src/assets/images/canvas-editor/size-minus.svg.js +4 -0
  102. package/dist/src/assets/images/canvas-editor/strikeout.svg.js +4 -0
  103. package/dist/src/assets/images/canvas-editor/subscript.svg.js +4 -0
  104. package/dist/src/assets/images/canvas-editor/superscript.svg.js +4 -0
  105. package/dist/src/assets/images/canvas-editor/table.svg.js +4 -0
  106. package/dist/src/assets/images/canvas-editor/title.svg.js +4 -0
  107. package/dist/src/assets/images/canvas-editor/trash.svg.js +4 -0
  108. package/dist/src/assets/images/canvas-editor/underline.svg.js +4 -0
  109. package/dist/src/assets/images/canvas-editor/undo.svg.js +4 -0
  110. package/dist/src/assets/images/canvas-editor/watermark.svg.js +4 -0
  111. package/dist/src/assets/images/canvas-editor/word-tool.svg.js +4 -0
  112. package/dist/src/assets/images/clear.png.js +4 -0
  113. package/dist/src/assets/images/create_market_system.png.js +4 -0
  114. package/dist/src/assets/images/create_system.png.js +4 -0
  115. package/dist/src/assets/images/custom.png.js +4 -0
  116. package/dist/src/assets/images/default-icon.png.js +4 -0
  117. package/dist/src/assets/images/ex_link.png.js +4 -0
  118. package/dist/src/assets/images/excel.png.js +4 -0
  119. package/dist/src/assets/images/file.png.js +4 -0
  120. package/dist/src/assets/images/folder.png.js +4 -0
  121. package/dist/src/assets/images/hall/form.png.js +4 -0
  122. package/dist/src/assets/images/hall/meta.png.js +4 -0
  123. package/dist/src/assets/images/hall/process.png.js +4 -0
  124. package/dist/src/assets/images/hall/rule.png.js +4 -0
  125. package/dist/src/assets/images/hall/service.png.js +4 -0
  126. package/dist/src/assets/images/hall/userRole.png.js +4 -0
  127. package/dist/src/assets/images/hr.png.js +4 -0
  128. package/dist/src/assets/images/import.png.js +4 -0
  129. package/dist/src/assets/images/jian.png.js +4 -0
  130. package/dist/src/assets/images/module.png.js +4 -0
  131. package/dist/src/assets/images/null.png.js +4 -0
  132. package/dist/src/assets/images/photo.png.js +4 -0
  133. package/dist/src/assets/images/qq.png.js +4 -0
  134. package/dist/src/assets/images/robot.png.js +4 -0
  135. package/dist/src/assets/images/single_file.png.js +4 -0
  136. package/dist/src/assets/images/snapshot-history.png.js +4 -0
  137. package/dist/src/assets/images/snapshot-manual.png.js +4 -0
  138. package/dist/src/assets/images/snapshot-realtime.png.js +4 -0
  139. package/dist/src/assets/images/staff.png.js +4 -0
  140. package/dist/src/assets/images/switch_app.png.js +4 -0
  141. package/dist/src/assets/images/sync_append.png.js +4 -0
  142. package/dist/src/assets/images/sync_append_update.png.js +4 -0
  143. package/dist/src/assets/images/sync_loading.png.js +4 -0
  144. package/dist/src/assets/images/sync_replace.png.js +4 -0
  145. package/dist/src/assets/images/sync_update.png.js +4 -0
  146. package/dist/src/assets/images/user_bg.png.js +4 -0
  147. package/dist/src/assets/images/weixin.png.js +4 -0
  148. package/dist/src/chart-config-update.js +17 -0
  149. package/dist/src/chart-data-adapters.js +112 -0
  150. package/dist/src/chart-option-override.js +128 -0
  151. package/dist/src/chart-option-paths.js +64 -0
  152. package/dist/src/chart-registry.js +46 -0
  153. package/dist/src/chart-render-host.js +57 -0
  154. package/dist/src/chart-request-broker.js +176 -0
  155. package/dist/src/chartTheme.js +683 -0
  156. package/dist/src/collection.js +25 -0
  157. package/dist/src/date-helper.js +60 -0
  158. package/dist/src/dom-helper.js +22 -0
  159. package/dist/src/eval-with.js +14 -0
  160. package/dist/src/fieldFactory.js +5 -0
  161. package/dist/src/formula.js +365 -0
  162. package/dist/src/hljs-lite.js +29 -0
  163. package/dist/src/index.js +24 -0
  164. package/dist/src/lazy-jsencrypt.js +13 -0
  165. package/dist/src/legacy.js +25 -0
  166. package/dist/src/locale.js +88 -0
  167. package/dist/src/menu-open.js +43 -0
  168. package/dist/src/mermaid.js +79 -0
  169. package/dist/src/meta.js +4 -0
  170. package/dist/src/mobile-chart-appearance.js +148 -0
  171. package/dist/src/moment-compat.js +558 -0
  172. package/dist/src/nav-history.js +184 -0
  173. package/dist/src/page.js +116 -0
  174. package/dist/src/pdf.viewer.js +4 -0
  175. package/dist/src/placeholder.js +64 -0
  176. package/dist/src/public.js +49 -0
  177. package/dist/src/security.js +26 -0
  178. package/dist/src/storage.js +107 -0
  179. package/dist/src/token-storage.js +108 -0
  180. package/dist/src/util.js +4 -0
  181. package/package.json +109 -3
  182. package/src/Config.js +25 -0
  183. package/src/asset-images.js +16 -0
  184. package/src/chart-config-update.js +16 -0
  185. package/src/chart-data-adapters.js +106 -0
  186. package/src/chart-option-override.js +126 -0
  187. package/src/chart-option-paths.js +63 -0
  188. package/src/chart-registry.js +41 -0
  189. package/src/chart-render-host.js +56 -0
  190. package/src/chart-request-broker.js +171 -0
  191. package/src/chartTheme.js +711 -0
  192. package/src/collection.js +28 -0
  193. package/src/date-helper.js +72 -0
  194. package/src/dom-helper.js +26 -0
  195. package/src/eval-with.js +21 -0
  196. package/src/fieldFactory.js +3 -0
  197. package/src/formula.js +362 -0
  198. package/src/hljs-lite.js +41 -0
  199. package/src/index.js +2 -0
  200. package/src/lazy-jsencrypt.js +36 -0
  201. package/src/legacy.js +29 -0
  202. package/src/locale.js +104 -0
  203. package/src/menu-open.js +72 -0
  204. package/src/mermaid.js +115 -0
  205. package/src/meta.js +2 -0
  206. package/src/mobile-chart-appearance.js +147 -0
  207. package/src/moment-compat.d.ts +91 -0
  208. package/src/moment-compat.js +744 -0
  209. package/src/nav-history.js +274 -0
  210. package/src/page.js +129 -0
  211. package/src/pdf.viewer.js +2 -0
  212. package/src/placeholder.js +107 -0
  213. package/src/public.js +11 -0
  214. package/src/security.js +29 -0
  215. package/src/storage.js +135 -0
  216. package/src/token-storage.js +120 -0
  217. package/src/util.js +2 -0
  218. package/types/Config.d.ts +4 -0
  219. package/types/collection.d.ts +40 -0
  220. package/types/date-helper.d.ts +11 -0
  221. package/types/date-time.d.ts +2 -0
  222. package/types/date.d.ts +1 -0
  223. package/types/dom-helper.d.ts +3 -0
  224. package/types/dom.d.ts +1 -0
  225. package/types/index.d.ts +1 -0
  226. package/types/moment-compat.d.ts +91 -0
  227. package/types/page.d.ts +56 -0
  228. package/types/placeholder.d.ts +42 -0
  229. package/types/public.d.ts +10 -0
  230. package/types/storage.d.ts +31 -0
@@ -0,0 +1,112 @@
1
+ function excludeBoxplotMissingValues(params) {
2
+ var _a;
3
+ const fields = [...new Set((((_a = params.chartData) == null ? void 0 : _a.statisticalList) || []).map((item) => item.fieldCode).filter(Boolean))];
4
+ if (!fields.length) return;
5
+ const scopes = JSON.parse(params.scopeParams || "[]").map((item) => ({ ...item }));
6
+ if (scopes.length) {
7
+ scopes[0].lb = "(" + (scopes[0].lb || "");
8
+ const last = scopes[scopes.length - 1];
9
+ last.rb = (last.rb || "") + ")";
10
+ last.link = "and";
11
+ }
12
+ fields.forEach((field) => scopes.push({ field, mode: "not_null", link: "and" }));
13
+ scopes[scopes.length - 1].link = "";
14
+ params.scopeParams = JSON.stringify(scopes);
15
+ }
16
+ const numeric = (value) => {
17
+ if (value === void 0 || value === null || String(value).trim() === "") return null;
18
+ const number = typeof value === "number" ? value : Number(String(value ?? "").replace(/%$/, ""));
19
+ return Number.isFinite(number) && value !== null && value !== "" ? number : null;
20
+ };
21
+ const failure = (message) => ({ hasData: false, message });
22
+ const quantile = (sorted, p) => {
23
+ const index = (sorted.length - 1) * p;
24
+ const lower = Math.floor(index);
25
+ return sorted[lower] + (sorted[Math.ceil(index)] - sorted[lower]) * (index - lower);
26
+ };
27
+ function summarizeBoxplot(values) {
28
+ const sorted = values.map(numeric).filter((value) => value !== null).sort((a, b) => a - b);
29
+ if (!sorted.length) return null;
30
+ const q1 = quantile(sorted, 0.25);
31
+ const median = quantile(sorted, 0.5);
32
+ const q3 = quantile(sorted, 0.75);
33
+ const gap = (q3 - q1) * 1.5;
34
+ const retained = sorted.filter((value) => value >= q1 - gap && value <= q3 + gap);
35
+ return { value: [retained[0], q1, median, q3, retained[retained.length - 1]], outliers: sorted.filter((value) => value < q1 - gap || value > q3 + gap), count: sorted.length };
36
+ }
37
+ function buildAdvancedChartOption(type, data, config = {}, chartData = {}, theme = "") {
38
+ var _a, _b, _c, _d;
39
+ const option = Object.fromEntries(Object.entries(config).filter(([key]) => key !== "title" && !key.startsWith("series-") && key !== "echartsOptionOverride"));
40
+ option.tooltip = { trigger: "item", confine: true, ...option.tooltip };
41
+ if ((_a = option.legend) == null ? void 0 : _a._orient) {
42
+ const { direction = "bottom", horizontal = "center", vertical = "center" } = option.legend._orient;
43
+ const across = direction === "top" || direction === "bottom";
44
+ option.legend = { ...option.legend, orient: across ? "horizontal" : "vertical", top: direction === "top" ? "20px" : !across && vertical === "top" ? "20px" : !across && vertical === "center" ? "center" : "auto", bottom: direction === "bottom" || !across && vertical === "bottom" ? "20px" : "auto", left: direction === "left" || across && horizontal === "left" ? "20px" : across && horizontal === "center" ? "center" : "auto", right: direction === "right" || across && horizontal === "right" ? "20px" : "auto" };
45
+ delete option.legend._orient;
46
+ }
47
+ if ((_b = option.dataZoom) == null ? void 0 : _b.show) {
48
+ option.dataZoom = [{ type: "slider", startValue: 0, ...option.dataZoom, endValue: Number(option.dataZoom.endValue || 5) - 1 }];
49
+ } else if (option.dataZoom && !Array.isArray(option.dataZoom)) delete option.dataZoom;
50
+ if (type === "boxplot") {
51
+ if (((_c = chartData.categoryList) == null ? void 0 : _c.length) || ((_d = chartData.statisticalList) == null ? void 0 : _d.length) !== 2) return failure("箱线图需要两个数字统计字段,并且不设置分类维度");
52
+ if (chartData.statisticalList.some((item) => item.type !== "indexField" || !item.fieldCode || item.fieldCode === "record")) return failure("箱线图请使用数字字段,不支持记录数或自定义统计项");
53
+ const rows = data == null ? void 0 : data.data;
54
+ if (!Array.isArray(rows) || !rows.length) return failure();
55
+ if (rows.some((row) => !Array.isArray(row) || row.length !== 2)) return failure("箱线图需要原始数字对数据");
56
+ const summaries = [0, 1].map((index) => summarizeBoxplot(rows.map((row) => row[index])));
57
+ if (summaries.some((item) => !item)) return failure();
58
+ const names = chartData.statisticalList.map((item, index) => item.name || `指标 ${index + 1}`);
59
+ option.grid = { containLabel: true, left: 30, right: 20, top: 30, bottom: 30, ...option.grid };
60
+ option.xAxis = { ...option.xAxis, type: "category", data: names };
61
+ option.yAxis = { type: "value", ...option.yAxis };
62
+ option.series = [{ type: "boxplot", name: "箱线", ...config["series-boxplot"], data: summaries.map((item, index) => ({ name: names[index], value: item.value })) }];
63
+ const outliers = summaries.flatMap((item, index) => item.outliers.map((value) => [index, value]));
64
+ option.series.push({ type: "scatter", name: "离群值", data: outliers });
65
+ return { hasData: true, option };
66
+ }
67
+ const series = data == null ? void 0 : data.series;
68
+ if (!Array.isArray(series) || !series.length || series.every((item) => {
69
+ var _a2;
70
+ return !((_a2 = item.data) == null ? void 0 : _a2.length);
71
+ })) return failure();
72
+ if (series.some((row) => !Array.isArray(row.data) || row.data.some((item) => numeric(item.value) === null))) return failure("当前统计结果包含非数值,不能生成此图表");
73
+ if (type === "gauge") {
74
+ const cells = series.flatMap((row) => row.data);
75
+ if (cells.length !== 1) return failure("仪表盘需要单个统计值;请设置一个指标且不拆分分类");
76
+ const cell = cells[0];
77
+ const value = numeric(cell.value);
78
+ option.series = [{ type: "gauge", min: Math.min(0, value), max: Math.max(100, value), progress: { show: true }, detail: { formatter: "{value}" }, ...config["series-gauge"], data: [{ ...cell, value }] }];
79
+ if (["dark", "technology"].includes(theme)) {
80
+ const gauge = option.series[0];
81
+ gauge.axisLabel = { color: "#d9e1ec", ...gauge.axisLabel };
82
+ gauge.detail = { color: "#d9e1ec", ...gauge.detail };
83
+ gauge.title = { color: "#d9e1ec", ...gauge.title };
84
+ }
85
+ if (!(Number(option.series[0].max) > Number(option.series[0].min))) return failure("仪表盘最大刻度必须大于最小刻度");
86
+ delete option.xAxis;
87
+ delete option.yAxis;
88
+ delete option.grid;
89
+ } else if (type === "treemap") {
90
+ if (series.some((row) => row.data.some((item) => numeric(item.value) < 0))) return failure("矩形树图的统计值不能为负数");
91
+ option.series = [{ type: "treemap", roam: false, breadcrumb: { show: true }, ...config["series-treemap"], data: series.map((row, index) => ({ name: row.name || `指标 ${index + 1}`, children: row.data.map((cell) => ({ ...cell, value: numeric(cell.value) })) })) }];
92
+ delete option.xAxis;
93
+ delete option.yAxis;
94
+ delete option.grid;
95
+ } else if (type === "heatmap") {
96
+ const categories = series[0].data.map((item) => item.name || "");
97
+ if (series.some((row) => row.data.length !== categories.length || row.data.some((cell, index) => (cell.name || "") !== categories[index]))) return failure("热力图要求各指标使用同一组分类维度");
98
+ const cells = series.flatMap((row, rowIndex) => row.data.map((cell, colIndex) => ({ ...cell, value: [colIndex, rowIndex, numeric(cell.value)] })));
99
+ const values = cells.map((cell) => cell.value[2]);
100
+ option.grid = { containLabel: true, left: 30, right: 30, top: 30, bottom: 60, ...option.grid };
101
+ option.xAxis = { type: "category", splitArea: { show: true }, ...option.xAxis, data: categories };
102
+ option.yAxis = { type: "category", splitArea: { show: true }, ...option.yAxis, data: series.map((row, index) => row.name || `指标 ${index + 1}`) };
103
+ option.visualMap = { min: values.reduce((min, value) => Math.min(min, value), Infinity), max: values.reduce((max, value) => Math.max(max, value), 1), calculable: true, orient: "horizontal", left: "center", bottom: 0, ...option.visualMap };
104
+ option.series = [{ type: "heatmap", label: { show: false }, ...config["series-heatmap"], data: cells }];
105
+ } else return failure("不支持的图表类型");
106
+ return { hasData: true, option };
107
+ }
108
+ export {
109
+ buildAdvancedChartOption,
110
+ excludeBoxplotMissingValues,
111
+ summarizeBoxplot
112
+ };
@@ -0,0 +1,128 @@
1
+ import { getChartType } from "./chart-registry.js";
2
+ const own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
3
+ const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
4
+ const unsafeKeys = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
5
+ const MAX_OVERRIDE_BYTES = 64 * 1024;
6
+ function validateChartOptionOverride(override, baseOption = {}, chartType = "") {
7
+ const errors = [];
8
+ if (!object(override)) return [{ path: "$", message: "覆盖层必须是 JSON 对象" }];
9
+ let encoded;
10
+ try {
11
+ encoded = JSON.stringify(override);
12
+ } catch {
13
+ return [{ path: "$", message: "覆盖层必须是可序列化的 JSON 对象" }];
14
+ }
15
+ const size = new TextEncoder().encode(encoded).length;
16
+ if (size > MAX_OVERRIDE_BYTES) errors.push({ path: "$", message: "覆盖层不能超过 64 KB" });
17
+ const visit = (value, path, depth = 0) => {
18
+ if (depth > 64) {
19
+ errors.push({ path, message: "配置层级不能超过 64 层" });
20
+ return;
21
+ }
22
+ if (Array.isArray(value)) {
23
+ value.forEach((item, index) => visit(item, `${path}[${index}]`, depth + 1));
24
+ return;
25
+ }
26
+ if (!object(value)) return;
27
+ for (const [key, child] of Object.entries(value)) {
28
+ const childPath = path === "$" ? key : `${path}.${key}`;
29
+ if (unsafeKeys.has(key)) errors.push({ path: childPath, message: "不支持的属性名" });
30
+ if (key === "source" && (path === "dataset" || /^dataset\[\d+\]$/.test(path))) errors.push({ path: childPath, message: "数据源由平台维护" });
31
+ if (key === "data" && /^series\[\d+\]$/.test(path)) errors.push({ path: childPath, message: "系列数据由平台维护" });
32
+ visit(child, childPath, depth + 1);
33
+ }
34
+ };
35
+ visit(override, "$");
36
+ if (own(override, "series")) {
37
+ const baseSeries = Array.isArray(baseOption.series) ? baseOption.series : [baseOption.series].filter(Boolean);
38
+ if (!Array.isArray(override.series) || override.series.length !== baseSeries.length || !override.series.every(object)) {
39
+ errors.push({ path: "series", message: `系列覆盖必须与当前 ${baseSeries.length} 个系列逐项对应` });
40
+ } else {
41
+ override.series.forEach((series, index) => {
42
+ var _a, _b, _c;
43
+ if (own(series, "type") && series.type !== ((_a = baseSeries[index]) == null ? void 0 : _a.type)) errors.push({ path: `series[${index}].type`, message: "不能改变平台系列类型" });
44
+ if (own(series, "coordinateSystem")) {
45
+ const coordinate = ((_b = baseSeries[index]) == null ? void 0 : _b.coordinateSystem) || ((_c = getChartType(chartType)) == null ? void 0 : _c.coordinate);
46
+ if (series.coordinateSystem !== coordinate) errors.push({ path: `series[${index}].coordinateSystem`, message: "不能改变平台坐标系" });
47
+ }
48
+ });
49
+ }
50
+ }
51
+ if (Array.isArray(override.dataset)) errors.push({ path: "dataset", message: "暂不支持替换数据集数组" });
52
+ if (own(override, "dataset") && (!object(override.dataset) || Array.isArray(baseOption.dataset))) errors.push({ path: "dataset", message: "不能替换平台数据集结构" });
53
+ for (const axis of ["xAxis", "yAxis"]) {
54
+ if (own(override, axis) && !(object(override[axis]) || Array.isArray(override[axis]) && override[axis].length && override[axis].every(object))) {
55
+ errors.push({ path: axis, message: "坐标轴必须是对象或非空对象数组" });
56
+ }
57
+ }
58
+ if (getChartType(chartType) && getChartType(chartType).coordinate !== "cartesian2d") {
59
+ for (const axis of ["xAxis", "yAxis", "grid", "dataZoom"]) {
60
+ if (own(override, axis)) errors.push({ path: axis, message: "当前图表类型不使用直角坐标系" });
61
+ }
62
+ }
63
+ return errors;
64
+ }
65
+ function mergeObject(base, patch) {
66
+ const result = object(base) ? { ...base } : {};
67
+ for (const [key, value] of Object.entries(patch)) {
68
+ if (object(value)) result[key] = mergeObject(result[key], value);
69
+ else if (Array.isArray(value)) result[key] = value.map((item) => object(item) ? mergeObject({}, item) : item);
70
+ else result[key] = value;
71
+ }
72
+ return result;
73
+ }
74
+ function applyChartOptionOverride(baseOption, override, chartType = "") {
75
+ if (override === void 0) return baseOption;
76
+ const errors = validateChartOptionOverride(override, baseOption, chartType);
77
+ if (errors.length) return baseOption;
78
+ const { series, ...other } = override;
79
+ const result = mergeObject(baseOption, other);
80
+ for (const key of ["xAxis", "yAxis", "grid", "legend", "visualMap", "dataZoom"]) {
81
+ if (Array.isArray(other[key])) {
82
+ const base = Array.isArray(baseOption[key]) ? baseOption[key] : [baseOption[key]].filter(Boolean);
83
+ result[key] = Array.from({ length: Math.max(base.length, other[key].length) }, (_, index) => mergeObject(base[index], other[key][index] || {}));
84
+ } else if (object(other[key]) && Array.isArray(baseOption[key])) {
85
+ result[key] = baseOption[key].map((item, index) => index === 0 ? mergeObject(item, other[key]) : item);
86
+ }
87
+ }
88
+ if (series) {
89
+ result.series = baseOption.series.map((item, index) => mergeObject(item, series[index]));
90
+ }
91
+ return result;
92
+ }
93
+ function setChartOption(host, baseOption, override) {
94
+ var _a;
95
+ host.chartOption = applyChartOptionOverride(baseOption, override, host.chartType);
96
+ if (host.designMode && ((_a = host.$refs) == null ? void 0 : _a.container)) {
97
+ host.$refs.container.dispatchEvent(new CustomEvent("epx-chart-option-built", {
98
+ bubbles: true,
99
+ detail: { base: baseOption, effective: host.chartOption }
100
+ }));
101
+ }
102
+ }
103
+ function validateChartOptionRendering(option, echarts) {
104
+ var _a;
105
+ if (!echarts) return [{ path: "$", message: "等待图表加载后再预览" }];
106
+ const element = document.createElement("div");
107
+ element.style.cssText = "position:fixed;left:-10000px;top:0;width:800px;height:400px;visibility:hidden;pointer-events:none";
108
+ document.body.appendChild(element);
109
+ let chart;
110
+ try {
111
+ chart = echarts.init(element);
112
+ chart.setOption(option, { notMerge: true });
113
+ const expected = Array.isArray(option.series) ? option.series.length : option.series ? 1 : 0;
114
+ if (chart.getOption && (((_a = chart.getOption().series) == null ? void 0 : _a.length) || 0) !== expected) throw new Error("当前 ECharts 未能加载全部系列类型");
115
+ return [];
116
+ } catch (error) {
117
+ return [{ path: "$", message: `图表预览失败:${error.message}` }];
118
+ } finally {
119
+ if (chart) chart.dispose();
120
+ element.remove();
121
+ }
122
+ }
123
+ export {
124
+ applyChartOptionOverride,
125
+ setChartOption,
126
+ validateChartOptionOverride,
127
+ validateChartOptionRendering
128
+ };
@@ -0,0 +1,64 @@
1
+ function chartOverridePaths(key, base = {}, patch = {}) {
2
+ if (key === "title" || key.startsWith("title.")) return [];
3
+ if (key.startsWith("series-")) {
4
+ const [group, ...parts2] = key.split(".");
5
+ const type = group.slice(7) === "wordcloud" ? "wordCloud" : group.slice(7);
6
+ if (["total", "totalText"].includes(parts2[0])) return [];
7
+ const native = parts2[0] === "showArea" ? ["areaStyle"] : parts2[0] === "barType" ? ["stack"] : parts2.join(".") === "label.customFormatter" ? ["label", "formatter"] : parts2;
8
+ return (base.series || []).flatMap((series, index) => series.type === type ? [["series", index, ...native]] : []);
9
+ }
10
+ if (/^yAxis\.(leftAxis|rightAxis)\./.test(key)) {
11
+ const [, side, ...parts2] = key.split(".");
12
+ return [["yAxis", side === "leftAxis" ? 0 : 1, ...parts2]];
13
+ }
14
+ if (["yAxis.leftName", "yAxis.rightName"].includes(key)) return [["yAxis", key === "yAxis.leftName" ? 0 : 1, "name"]];
15
+ if (key.startsWith("legend._orient.")) {
16
+ const fields = key.endsWith(".horizontal") ? ["left", "right"] : key.endsWith(".vertical") ? ["top", "bottom"] : ["orient", "left", "right", "top", "bottom"];
17
+ return fields.map((field) => ["legend", field]);
18
+ }
19
+ const [root, ...parts] = key.split(".");
20
+ if (Array.isArray(patch[root])) return patch[root].map((_, index) => [root, index, ...parts]);
21
+ return [[root, ...parts]];
22
+ }
23
+ const readPath = (value, path) => {
24
+ if (!path.length) return value;
25
+ if (Array.isArray(value) && typeof path[0] !== "number") return value.map((item) => readPath(item, path)).find((item) => item !== void 0);
26
+ if (!Array.isArray(value) && typeof path[0] === "number") return path[0] === 0 ? readPath(value, path.slice(1)) : void 0;
27
+ return readPath(value == null ? void 0 : value[path[0]], path.slice(1));
28
+ };
29
+ function isChartPathOverridden(patch, key, base) {
30
+ return chartOverridePaths(key, base, patch).some((path) => readPath(patch, path) !== void 0);
31
+ }
32
+ function clearChartOverridePath(patch, key, base) {
33
+ const remove = (value, path) => {
34
+ if (!value || !path.length) return;
35
+ if (Array.isArray(value) && typeof path[0] !== "number") {
36
+ value.forEach((item) => remove(item, path));
37
+ return;
38
+ }
39
+ if (!Array.isArray(value) && typeof path[0] === "number") {
40
+ if (path[0] === 0) remove(value, path.slice(1));
41
+ return;
42
+ }
43
+ const [part, ...rest] = path;
44
+ if (!rest.length) {
45
+ if (Array.isArray(value)) value[part] = {};
46
+ else delete value[part];
47
+ } else {
48
+ remove(value[part], rest);
49
+ if (value[part] && !Array.isArray(value[part]) && typeof value[part] === "object" && !Object.keys(value[part]).length && !Array.isArray(value)) delete value[part];
50
+ }
51
+ };
52
+ const paths = chartOverridePaths(key, base, patch);
53
+ for (const path of paths) remove(patch, path);
54
+ for (const root of new Set(paths.map((path) => path[0]))) {
55
+ const value = patch[root];
56
+ if (Array.isArray(value) && value.every((item) => item && typeof item === "object" && !Object.keys(item).length)) delete patch[root];
57
+ }
58
+ return patch;
59
+ }
60
+ export {
61
+ chartOverridePaths,
62
+ clearChartOverridePath,
63
+ isChartPathOverridden
64
+ };
@@ -0,0 +1,46 @@
1
+ const chartTypes = [
2
+ { type: "table", text: "统计表", icon: "epx-icon-tongjibiao", component: "chart-table", requestType: "table", coordinate: "none" },
3
+ { type: "pie", text: "饼状图", icon: "epx-icon-bingzhuangtu", component: "chart-common", requestType: "pie", coordinate: "none" },
4
+ { type: "circularPie", text: "环形饼图", icon: "epx-icon-bingzhuangtu", component: "chart-common", requestType: "pie", coordinate: "none" },
5
+ { type: "line", text: "折线图", icon: "epx-icon-zhexiantu", component: "chart-common", requestType: "line", coordinate: "cartesian2d" },
6
+ { type: "column", text: "柱状图", icon: "epx-icon-zhuzhuangtu", component: "chart-common", requestType: "bar", coordinate: "cartesian2d" },
7
+ { type: "horiColumn", text: "横向柱图", icon: "epx-icon-zhuzhuangtu", component: "chart-common", requestType: "bar", cellScopeType: "column", coordinate: "cartesian2d" },
8
+ { type: "funnel", text: "漏斗图", icon: "epx-icon-loudoutu", component: "chart-common", requestType: "funnel", coordinate: "none" },
9
+ { type: "wordcloud", text: "词云", icon: "epx-icon-ciyun", component: "chart-wordcloud", requestType: "wordCloud", coordinate: "none" },
10
+ { type: "radar", text: "雷达图", icon: "epx-icon-leidatu", component: "chart-radar", requestType: "radar", coordinate: "radar" },
11
+ { type: "columnAndLine", text: "折柱混合", icon: "epx-icon-zhezhutu", component: "chart-common", requestType: "bar", coordinate: "cartesian2d" },
12
+ { type: "scatter", text: "散点图", icon: "epx-icon-sandiantu", component: "chart-scatter", requestType: "scatter", coordinate: "cartesian2d", binding: "numericPairs", drill: false },
13
+ { type: "map", text: "地图", icon: "epx-icon-ditu", component: "chart-map", requestType: "map", coordinate: "geo" },
14
+ { type: "gauge", text: "仪表盘", icon: "epx-icon-leidatu", component: "chart-advanced", requestType: "bar", cellScopeType: "column", coordinate: "none", dataHint: "单个统计值;设置一个指标且不拆分分类。" },
15
+ { type: "treemap", text: "矩形树图", icon: "epx-icon-tongjibiao", component: "chart-advanced", requestType: "bar", cellScopeType: "column", coordinate: "none", dataHint: "按指标、分类组成两层矩形树,使用非负统计值;叶子支持钻取。" },
16
+ { type: "heatmap", text: "热力图", icon: "epx-icon-zhuzhuangtu", component: "chart-advanced", requestType: "bar", cellScopeType: "column", coordinate: "cartesian2d", dataHint: "横轴为分类,纵轴为指标;各指标使用同一组分类。" },
17
+ { type: "boxplot", text: "箱线图", selectable: false, icon: "epx-icon-zhexiantu", component: "chart-advanced", requestType: "scatter", coordinate: "cartesian2d", binding: "numericPairs", drill: false, dataHint: "选择两个数字统计字段,不设置分类;使用原始值计算四分位数与 1.5 倍四分位距的离群值,不支持钻取。" }
18
+ ];
19
+ const selectableChartTypes = chartTypes.filter((item) => item.selectable !== false);
20
+ function getChartType(type) {
21
+ return chartTypes.find((item) => item.type === (type === "bar" ? "column" : type));
22
+ }
23
+ const chartConfigCategories = [
24
+ { key: "all", label: "全部" },
25
+ { key: "appearance", label: "外观" },
26
+ { key: "axis", label: "坐标与刻度" },
27
+ { key: "shape", label: "图形" },
28
+ { key: "label", label: "标签与提示" },
29
+ { key: "interaction", label: "交互" },
30
+ { key: "advanced", label: "高级" }
31
+ ];
32
+ function getChartConfigCategory(key) {
33
+ if (["title", "grid", "color", "backgroundColor"].includes(key)) return "appearance";
34
+ if (["xAxis", "yAxis", "dualAxes", "dataZoom"].includes(key)) return "axis";
35
+ if (key.startsWith("series-") || ["series.map", "radar", "scatter", "table", "visualMap"].includes(key)) return "shape";
36
+ if (["legend", "tooltip"].includes(key)) return "label";
37
+ if (key === "toolbox") return "interaction";
38
+ return "advanced";
39
+ }
40
+ export {
41
+ chartConfigCategories,
42
+ chartTypes,
43
+ getChartConfigCategory,
44
+ getChartType,
45
+ selectableChartTypes
46
+ };
@@ -0,0 +1,57 @@
1
+ import { getChartType } from "./chart-registry.js";
2
+ const registeredThemes = /* @__PURE__ */ new WeakSet();
3
+ function registerChartThemes(echarts, themes) {
4
+ if (registeredThemes.has(echarts)) return;
5
+ for (const key in themes) echarts.registerTheme(key, themes[key]);
6
+ registeredThemes.add(echarts);
7
+ }
8
+ function disposeChartHost(host) {
9
+ var _a;
10
+ if (host.observedChartDom) {
11
+ (_a = host.resizeObserver) == null ? void 0 : _a.unobserve(host.observedChartDom);
12
+ host.observedChartDom = null;
13
+ }
14
+ if (!host.myChart) return;
15
+ host.myChart.off("click", host.openPivotPage);
16
+ host.myChart.dispose();
17
+ host.myChart = null;
18
+ host.renderedChartTheme = null;
19
+ }
20
+ function renderChartHost(host, option, settings) {
21
+ var _a, _b, _c, _d, _e;
22
+ const element = (_a = host.$refs) == null ? void 0 : _a.chart;
23
+ if (!element || !host.echarts || !option) return false;
24
+ const { width, height } = element.getBoundingClientRect();
25
+ if (width <= 0 || height <= 0) return false;
26
+ const staleDom = host.myChart && host.myChart.getDom && host.myChart.getDom() !== element;
27
+ const theme = settings && Object.prototype.hasOwnProperty.call(settings, "theme") ? settings.theme : host.chartTheme;
28
+ const changedTheme = host.myChart && host.renderedChartTheme !== theme;
29
+ if (staleDom || changedTheme) disposeChartHost(host);
30
+ if (!host.myChart) {
31
+ host.myChart = host.echarts.init(element, theme);
32
+ host.renderedChartTheme = theme;
33
+ if (host.openClickEvent) host.myChart.on("click", host.openPivotPage);
34
+ }
35
+ if (host.resizeObserver && host.observedChartDom !== element) {
36
+ if (host.observedChartDom) host.resizeObserver.unobserve(host.observedChartDom);
37
+ host.resizeObserver.observe(element);
38
+ host.observedChartDom = element;
39
+ }
40
+ try {
41
+ host.myChart.setOption(option, { notMerge: true });
42
+ const expected = Array.isArray(option.series) ? option.series.length : option.series ? 1 : 0;
43
+ const enforceSeries = ((_b = getChartType(host.chartType)) == null ? void 0 : _b.component) === "chart-advanced" || ((_d = (_c = host.chartConfigs) == null ? void 0 : _c.chartConfig) == null ? void 0 : _d.echartsOptionOverride) !== void 0;
44
+ if (enforceSeries && host.myChart.getOption && (((_e = host.myChart.getOption().series) == null ? void 0 : _e.length) || 0) !== expected) throw new Error("未能加载全部系列类型");
45
+ } catch (error) {
46
+ disposeChartHost(host);
47
+ host.error = true;
48
+ host.chartErrorText = `图表配置无法渲染:${error.message}`;
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ export {
54
+ disposeChartHost,
55
+ registerChartThemes,
56
+ renderChartHost
57
+ };
@@ -0,0 +1,176 @@
1
+ const stable = (value) => {
2
+ if (Array.isArray(value)) return value.map(stable);
3
+ if (value && typeof value === "object") return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
4
+ return value;
5
+ };
6
+ const encode = (value) => JSON.stringify(stable(value));
7
+ function createChartRequestBroker({ concurrency = 6, ttl = 3e4, maxEntries = 64, maxBytes = 2 * 1024 * 1024, now = Date.now } = {}) {
8
+ const cache = /* @__PURE__ */ new Map();
9
+ const jobs = /* @__PURE__ */ new Set();
10
+ const inFlight = /* @__PURE__ */ new Map();
11
+ const queue = [];
12
+ const counters = { hits: 0, misses: 0, coalesced: 0, cancelled: 0, peakActive: 0 };
13
+ let active = 0;
14
+ let bytes = 0;
15
+ let context = null;
16
+ let expiryTimer = null;
17
+ let disposed = false;
18
+ const remove = (key) => {
19
+ const entry = cache.get(key);
20
+ if (entry) bytes -= entry.bytes;
21
+ cache.delete(key);
22
+ };
23
+ const expire = () => {
24
+ if (expiryTimer) clearTimeout(expiryTimer);
25
+ expiryTimer = null;
26
+ for (const [key, entry] of cache) if (entry.expires <= now()) remove(key);
27
+ if (cache.size) {
28
+ const next = Math.min(...Array.from(cache.values(), (entry) => entry.expires));
29
+ expiryTimer = setTimeout(expire, Math.max(1, next - now()));
30
+ }
31
+ };
32
+ const clear = () => {
33
+ cache.clear();
34
+ bytes = 0;
35
+ if (expiryTimer) clearTimeout(expiryTimer);
36
+ expiryTimer = null;
37
+ };
38
+ const forget = (job) => {
39
+ jobs.delete(job);
40
+ if (inFlight.get(job.key) === job) inFlight.delete(job.key);
41
+ };
42
+ const cancel = (job) => {
43
+ var _a;
44
+ if (job.cancelled) return;
45
+ job.cancelled = true;
46
+ job.invalidated = true;
47
+ for (const consumer of job.consumers) consumer.resolve(null);
48
+ job.consumers.clear();
49
+ (_a = job.controller) == null ? void 0 : _a.abort();
50
+ const index = queue.indexOf(job);
51
+ if (index !== -1) queue.splice(index, 1);
52
+ if (!job.started) forget(job);
53
+ counters.cancelled++;
54
+ };
55
+ const syncContext = (current) => {
56
+ if (context && context.principal !== current.principal) {
57
+ clear();
58
+ for (const job of [...jobs]) cancel(job);
59
+ } else if (context && context.credential !== current.credential) {
60
+ clear();
61
+ }
62
+ context = current;
63
+ };
64
+ const invalidate = (reportId) => {
65
+ for (const [key, entry] of cache) if (!reportId || entry.reportId === reportId) remove(key);
66
+ for (const job of jobs) if (!reportId || job.reportId === reportId) job.invalidated = true;
67
+ expire();
68
+ };
69
+ const pump = () => {
70
+ if (disposed) return;
71
+ while (active < concurrency && queue.length) {
72
+ const job = queue.shift();
73
+ syncContext(job.getContext());
74
+ if (job.cancelled || !job.consumers.size) {
75
+ forget(job);
76
+ continue;
77
+ }
78
+ job.started = true;
79
+ job.credential = context.credential;
80
+ job.version = job.getVersion();
81
+ job.cacheKey = encode([job.componentId, job.params, job.version]);
82
+ job.controller = new AbortController();
83
+ active++;
84
+ counters.peakActive = Math.max(counters.peakActive, active);
85
+ Promise.resolve().then(() => job.execute(job.controller.signal)).then((data) => {
86
+ if (disposed || job.cancelled) return;
87
+ const current = job.getContext();
88
+ syncContext(current);
89
+ if (job.cancelled) return;
90
+ job.settled = true;
91
+ const encoded = JSON.stringify(data);
92
+ const size = encoded ? (encoded.length + job.cacheKey.length) * 2 : 0;
93
+ if (job.cacheable && !job.invalidated && current.credential === job.credential && job.getVersion() === job.version && encoded && size <= maxBytes / 2) {
94
+ remove(job.cacheKey);
95
+ cache.set(job.cacheKey, { encoded, bytes: size, expires: now() + ttl, reportId: job.reportId });
96
+ bytes += size;
97
+ for (const cachedKey of cache.keys()) {
98
+ if (cache.size <= maxEntries && bytes <= maxBytes) break;
99
+ remove(cachedKey);
100
+ }
101
+ expire();
102
+ }
103
+ for (const consumer of job.consumers) consumer.resolve(encoded === void 0 ? data : JSON.parse(encoded));
104
+ }).catch((error) => {
105
+ job.settled = true;
106
+ if (!job.cancelled && !disposed) for (const consumer of job.consumers) consumer.reject(error);
107
+ }).finally(() => {
108
+ job.consumers.clear();
109
+ forget(job);
110
+ active--;
111
+ pump();
112
+ });
113
+ }
114
+ };
115
+ return {
116
+ request({ params, componentId = params.reportId, execute, getContext, getVersion = () => "", cacheable = false, force = false }) {
117
+ if (disposed) return { promise: Promise.resolve(null), cancel: () => {
118
+ } };
119
+ const current = getContext();
120
+ syncContext(current);
121
+ expire();
122
+ const version = getVersion();
123
+ const key = encode([componentId, params, version]);
124
+ const reportId = params.reportId;
125
+ if (force) invalidate(reportId);
126
+ const entry = cache.get(key);
127
+ if (cacheable && current.credential && !force && entry) {
128
+ counters.hits++;
129
+ cache.delete(key);
130
+ cache.set(key, entry);
131
+ return {
132
+ promise: Promise.resolve().then(() => {
133
+ const latest = getContext();
134
+ return latest.principal === current.principal && latest.credential === current.credential ? JSON.parse(entry.encoded) : null;
135
+ }),
136
+ cancel: () => {
137
+ }
138
+ };
139
+ }
140
+ let job = !force && inFlight.get(key);
141
+ if (job && !job.settled && !job.cancelled && !job.invalidated && job.credential === current.credential) counters.coalesced++;
142
+ else {
143
+ counters.misses++;
144
+ job = { key, componentId, params, reportId, execute, getContext, getVersion, version, credential: current.credential, cacheable: cacheable && !!current.credential, consumers: /* @__PURE__ */ new Set() };
145
+ jobs.add(job);
146
+ inFlight.set(key, job);
147
+ queue.push(job);
148
+ }
149
+ const consumer = {};
150
+ const promise = new Promise((resolve, reject) => Object.assign(consumer, { resolve, reject }));
151
+ job.consumers.add(consumer);
152
+ pump();
153
+ return {
154
+ promise,
155
+ cancel: () => {
156
+ if (!job.consumers.delete(consumer)) return;
157
+ consumer.resolve(null);
158
+ if (!job.consumers.size) cancel(job);
159
+ }
160
+ };
161
+ },
162
+ invalidate,
163
+ stats() {
164
+ return { ...counters, active, queued: queue.length, entries: cache.size, bytes, disposed };
165
+ },
166
+ dispose() {
167
+ disposed = true;
168
+ clear();
169
+ for (const job of [...jobs]) cancel(job);
170
+ context = null;
171
+ }
172
+ };
173
+ }
174
+ export {
175
+ createChartRequestBroker
176
+ };