@things-factory/kpi 10.1.248 → 10.1.249

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 (409) hide show
  1. package/dist-client/bootstrap.d.ts +2 -0
  2. package/dist-client/bootstrap.js +7 -0
  3. package/dist-client/bootstrap.js.map +1 -0
  4. package/dist-client/charts/kpi-boxplot-chart.d.ts +24 -0
  5. package/dist-client/charts/kpi-boxplot-chart.js +324 -0
  6. package/dist-client/charts/kpi-boxplot-chart.js.map +1 -0
  7. package/dist-client/charts/kpi-mini-trend-chart.d.ts +14 -0
  8. package/dist-client/charts/kpi-mini-trend-chart.js +148 -0
  9. package/dist-client/charts/kpi-mini-trend-chart.js.map +1 -0
  10. package/dist-client/charts/kpi-radar-chart.d.ts +16 -0
  11. package/dist-client/charts/kpi-radar-chart.js +138 -0
  12. package/dist-client/charts/kpi-radar-chart.js.map +1 -0
  13. package/dist-client/charts/kpi-trend-chart.d.ts +25 -0
  14. package/dist-client/charts/kpi-trend-chart.js +186 -0
  15. package/dist-client/charts/kpi-trend-chart.js.map +1 -0
  16. package/dist-client/google-map/common-google-map.d.ts +34 -0
  17. package/dist-client/google-map/common-google-map.js +333 -0
  18. package/dist-client/google-map/common-google-map.js.map +1 -0
  19. package/dist-client/google-map/google-map-loader.d.ts +8 -0
  20. package/dist-client/google-map/google-map-loader.js +22 -0
  21. package/dist-client/google-map/google-map-loader.js.map +1 -0
  22. package/dist-client/index.d.ts +1 -0
  23. package/dist-client/index.js +2 -0
  24. package/dist-client/index.js.map +1 -0
  25. package/dist-client/pages/kpi/kpi-grade-editor.d.ts +35 -0
  26. package/dist-client/pages/kpi/kpi-grade-editor.js +165 -0
  27. package/dist-client/pages/kpi/kpi-grade-editor.js.map +1 -0
  28. package/dist-client/pages/kpi/kpi-importer.d.ts +23 -0
  29. package/dist-client/pages/kpi/kpi-importer.js +92 -0
  30. package/dist-client/pages/kpi/kpi-importer.js.map +1 -0
  31. package/dist-client/pages/kpi/kpi-list-page.d.ts +136 -0
  32. package/dist-client/pages/kpi/kpi-list-page.js +948 -0
  33. package/dist-client/pages/kpi/kpi-list-page.js.map +1 -0
  34. package/dist-client/pages/kpi/kpi-overview-sample.d.ts +36 -0
  35. package/dist-client/pages/kpi/kpi-overview-sample.js +264 -0
  36. package/dist-client/pages/kpi/kpi-overview-sample.js.map +1 -0
  37. package/dist-client/pages/kpi/kpi-overview.d.ts +14 -0
  38. package/dist-client/pages/kpi/kpi-overview.js +361 -0
  39. package/dist-client/pages/kpi/kpi-overview.js.map +1 -0
  40. package/dist-client/pages/kpi/kpi-tree-page.d.ts +51 -0
  41. package/dist-client/pages/kpi/kpi-tree-page.js +355 -0
  42. package/dist-client/pages/kpi/kpi-tree-page.js.map +1 -0
  43. package/dist-client/pages/kpi/kpi-view.d.ts +12 -0
  44. package/dist-client/pages/kpi/kpi-view.js +193 -0
  45. package/dist-client/pages/kpi/kpi-view.js.map +1 -0
  46. package/dist-client/pages/kpi/kpi-viz-editor.d.ts +19 -0
  47. package/dist-client/pages/kpi/kpi-viz-editor.js +562 -0
  48. package/dist-client/pages/kpi/kpi-viz-editor.js.map +1 -0
  49. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.d.ts +17 -0
  50. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js +279 -0
  51. package/dist-client/pages/kpi-dashboard/cards/kpi-level1-card.js.map +1 -0
  52. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.d.ts +19 -0
  53. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js +385 -0
  54. package/dist-client/pages/kpi-dashboard/cards/kpi-level2-comparison.js.map +1 -0
  55. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.d.ts +23 -0
  56. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js +465 -0
  57. package/dist-client/pages/kpi-dashboard/cards/kpi-level3-comparison.js.map +1 -0
  58. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.d.ts +8 -0
  59. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js +78 -0
  60. package/dist-client/pages/kpi-dashboard/components/kpi-chart-toggle.js.map +1 -0
  61. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.d.ts +24 -0
  62. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js +440 -0
  63. package/dist-client/pages/kpi-dashboard/components/kpi-left-panel.js.map +1 -0
  64. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.d.ts +33 -0
  65. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js +444 -0
  66. package/dist-client/pages/kpi-dashboard/components/kpi-map-panel.js.map +1 -0
  67. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.d.ts +23 -0
  68. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js +369 -0
  69. package/dist-client/pages/kpi-dashboard/components/kpi-region-popup.js.map +1 -0
  70. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.d.ts +18 -0
  71. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js +128 -0
  72. package/dist-client/pages/kpi-dashboard/kpi-alert-panel.js.map +1 -0
  73. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.d.ts +31 -0
  74. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js +493 -0
  75. package/dist-client/pages/kpi-dashboard/kpi-dashboard-map.js.map +1 -0
  76. package/dist-client/pages/kpi-dashboard/kpi-dashboard.d.ts +50 -0
  77. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js +884 -0
  78. package/dist-client/pages/kpi-dashboard/kpi-dashboard.js.map +1 -0
  79. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.d.ts +12 -0
  80. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js +82 -0
  81. package/dist-client/pages/kpi-dashboard/kpi-grade-visualization.js.map +1 -0
  82. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.d.ts +11 -0
  83. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js +65 -0
  84. package/dist-client/pages/kpi-dashboard/kpi-history-viewer.js.map +1 -0
  85. package/dist-client/pages/kpi-dashboard/kpi-list-summary.d.ts +13 -0
  86. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js +115 -0
  87. package/dist-client/pages/kpi-dashboard/kpi-list-summary.js.map +1 -0
  88. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.d.ts +15 -0
  89. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js +146 -0
  90. package/dist-client/pages/kpi-dashboard/kpi-performance-summary.js.map +1 -0
  91. package/dist-client/pages/kpi-dashboard/kpi-value-entry.d.ts +7 -0
  92. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js +86 -0
  93. package/dist-client/pages/kpi-dashboard/kpi-value-entry.js.map +1 -0
  94. package/dist-client/pages/kpi-history/kpi-history-list-page.d.ts +21 -0
  95. package/dist-client/pages/kpi-history/kpi-history-list-page.js +160 -0
  96. package/dist-client/pages/kpi-history/kpi-history-list-page.js.map +1 -0
  97. package/dist-client/pages/kpi-metric/kpi-metric-importer.d.ts +23 -0
  98. package/dist-client/pages/kpi-metric/kpi-metric-importer.js +92 -0
  99. package/dist-client/pages/kpi-metric/kpi-metric-importer.js.map +1 -0
  100. package/dist-client/pages/kpi-metric/kpi-metric-list-page.d.ts +65 -0
  101. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js +415 -0
  102. package/dist-client/pages/kpi-metric/kpi-metric-list-page.js.map +1 -0
  103. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.d.ts +52 -0
  104. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js +678 -0
  105. package/dist-client/pages/kpi-metric-value/kpi-metric-value-editor-page.js.map +1 -0
  106. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.d.ts +23 -0
  107. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js +75 -0
  108. package/dist-client/pages/kpi-metric-value/kpi-metric-value-importer.js.map +1 -0
  109. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.d.ts +64 -0
  110. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js +311 -0
  111. package/dist-client/pages/kpi-metric-value/kpi-metric-value-list-page.js.map +1 -0
  112. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.d.ts +12 -0
  113. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js +175 -0
  114. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-form.js.map +1 -0
  115. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.d.ts +35 -0
  116. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js +161 -0
  117. package/dist-client/pages/kpi-metric-value/kpi-metric-value-manual-entry-page.js.map +1 -0
  118. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.d.ts +47 -0
  119. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js +655 -0
  120. package/dist-client/pages/kpi-statistic/kpi-statistic-editor-page.js.map +1 -0
  121. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.d.ts +23 -0
  122. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.js +92 -0
  123. package/dist-client/pages/kpi-statistic/kpi-statistic-importer.js.map +1 -0
  124. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.d.ts +65 -0
  125. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js +416 -0
  126. package/dist-client/pages/kpi-statistic/kpi-statistic-list-page.js.map +1 -0
  127. package/dist-client/pages/kpi-value/kpi-value-editor-page.d.ts +50 -0
  128. package/dist-client/pages/kpi-value/kpi-value-editor-page.js +700 -0
  129. package/dist-client/pages/kpi-value/kpi-value-editor-page.js.map +1 -0
  130. package/dist-client/pages/kpi-value/kpi-value-importer.d.ts +23 -0
  131. package/dist-client/pages/kpi-value/kpi-value-importer.js +92 -0
  132. package/dist-client/pages/kpi-value/kpi-value-importer.js.map +1 -0
  133. package/dist-client/pages/kpi-value/kpi-value-list-page.d.ts +73 -0
  134. package/dist-client/pages/kpi-value/kpi-value-list-page.js +403 -0
  135. package/dist-client/pages/kpi-value/kpi-value-list-page.js.map +1 -0
  136. package/dist-client/route.d.ts +1 -0
  137. package/dist-client/route.js +47 -0
  138. package/dist-client/route.js.map +1 -0
  139. package/dist-client/tsconfig.tsbuildinfo +1 -0
  140. package/dist-client/viewparts/kpi-metric-input.d.ts +23 -0
  141. package/dist-client/viewparts/kpi-metric-input.js +140 -0
  142. package/dist-client/viewparts/kpi-metric-input.js.map +1 -0
  143. package/dist-client/viewparts/kpi-metric-meta-editor.d.ts +36 -0
  144. package/dist-client/viewparts/kpi-metric-meta-editor.js +321 -0
  145. package/dist-client/viewparts/kpi-metric-meta-editor.js.map +1 -0
  146. package/dist-client/viewparts/metric-input-hint.d.ts +26 -0
  147. package/dist-client/viewparts/metric-input-hint.js +19 -0
  148. package/dist-client/viewparts/metric-input-hint.js.map +1 -0
  149. package/dist-client/viewparts/metric-input.test.d.ts +1 -0
  150. package/dist-client/viewparts/metric-input.test.js +43 -0
  151. package/dist-client/viewparts/metric-input.test.js.map +1 -0
  152. package/dist-client/viewparts/metric-renderer-registry.d.ts +18 -0
  153. package/dist-client/viewparts/metric-renderer-registry.js +29 -0
  154. package/dist-client/viewparts/metric-renderer-registry.js.map +1 -0
  155. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.d.ts +19 -0
  156. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.js +76 -0
  157. package/dist-client/viewparts/ox-grist-editor-metric-input-hint.js.map +1 -0
  158. package/dist-server/calculator/calculator.test.d.ts +1 -0
  159. package/dist-server/calculator/calculator.test.js +126 -0
  160. package/dist-server/calculator/calculator.test.js.map +1 -0
  161. package/dist-server/calculator/evaluator.d.ts +8 -0
  162. package/dist-server/calculator/evaluator.js +42 -0
  163. package/dist-server/calculator/evaluator.js.map +1 -0
  164. package/dist-server/calculator/functions.d.ts +3 -0
  165. package/dist-server/calculator/functions.js +62 -0
  166. package/dist-server/calculator/functions.js.map +1 -0
  167. package/dist-server/calculator/index.d.ts +6 -0
  168. package/dist-server/calculator/index.js +10 -0
  169. package/dist-server/calculator/index.js.map +1 -0
  170. package/dist-server/calculator/parser.d.ts +34 -0
  171. package/dist-server/calculator/parser.js +185 -0
  172. package/dist-server/calculator/parser.js.map +1 -0
  173. package/dist-server/calculator/provider.d.ts +8 -0
  174. package/dist-server/calculator/provider.js +13 -0
  175. package/dist-server/calculator/provider.js.map +1 -0
  176. package/dist-server/calculator/score.d.ts +21 -0
  177. package/dist-server/calculator/score.js +36 -0
  178. package/dist-server/calculator/score.js.map +1 -0
  179. package/dist-server/calculator/score.test.d.ts +1 -0
  180. package/dist-server/calculator/score.test.js +47 -0
  181. package/dist-server/calculator/score.test.js.map +1 -0
  182. package/dist-server/calculator/validate.d.ts +15 -0
  183. package/dist-server/calculator/validate.js +30 -0
  184. package/dist-server/calculator/validate.js.map +1 -0
  185. package/dist-server/calculator/validate.test.d.ts +1 -0
  186. package/dist-server/calculator/validate.test.js +45 -0
  187. package/dist-server/calculator/validate.test.js.map +1 -0
  188. package/dist-server/controllers/index.d.ts +2 -0
  189. package/dist-server/controllers/index.js +6 -0
  190. package/dist-server/controllers/index.js.map +1 -0
  191. package/dist-server/controllers/kpi-metric-value-provider.d.ts +11 -0
  192. package/dist-server/controllers/kpi-metric-value-provider.js +97 -0
  193. package/dist-server/controllers/kpi-metric-value-provider.js.map +1 -0
  194. package/dist-server/controllers/kpi-value-provider.d.ts +11 -0
  195. package/dist-server/controllers/kpi-value-provider.js +50 -0
  196. package/dist-server/controllers/kpi-value-provider.js.map +1 -0
  197. package/dist-server/index.d.ts +5 -0
  198. package/dist-server/index.js +9 -0
  199. package/dist-server/index.js.map +1 -0
  200. package/dist-server/migrations/1752190849680-seed-kpi-metrics.d.ts +6 -0
  201. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js +102 -0
  202. package/dist-server/migrations/1752190849680-seed-kpi-metrics.js.map +1 -0
  203. package/dist-server/migrations/1752190849681-seed-kpi.d.ts +5 -0
  204. package/dist-server/migrations/1752190849681-seed-kpi.js +315 -0
  205. package/dist-server/migrations/1752190849681-seed-kpi.js.map +1 -0
  206. package/dist-server/migrations/1752192090123-add-grades-to-kpi.d.ts +7 -0
  207. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js +51 -0
  208. package/dist-server/migrations/1752192090123-add-grades-to-kpi.js.map +1 -0
  209. package/dist-server/migrations/1752192090124-add-kpi-statistics.d.ts +5 -0
  210. package/dist-server/migrations/1752192090124-add-kpi-statistics.js +710 -0
  211. package/dist-server/migrations/1752192090124-add-kpi-statistics.js.map +1 -0
  212. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.d.ts +6 -0
  213. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js +111 -0
  214. package/dist-server/migrations/1752192090128-seed-kpi-org-scope.js.map +1 -0
  215. package/dist-server/migrations/1752192090129-seed-kpi-values.d.ts +6 -0
  216. package/dist-server/migrations/1752192090129-seed-kpi-values.js +187 -0
  217. package/dist-server/migrations/1752192090129-seed-kpi-values.js.map +1 -0
  218. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.d.ts +10 -0
  219. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.js +26 -0
  220. package/dist-server/migrations/1752192090200-add-meta-to-kpi-metric.js.map +1 -0
  221. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.d.ts +11 -0
  222. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.js +54 -0
  223. package/dist-server/migrations/1752192090201-backfill-kpi-metric-meta.js.map +1 -0
  224. package/dist-server/migrations/grade-data/x11-performance-table.json +962 -0
  225. package/dist-server/migrations/grade-data/x12-performance-table.json +611 -0
  226. package/dist-server/migrations/grade-data/x14-performance-table.json +42 -0
  227. package/dist-server/migrations/grade-data/x21-performance-table.json +889 -0
  228. package/dist-server/migrations/grade-data/x22-performance-table.json +1064 -0
  229. package/dist-server/migrations/grade-data/x23-performance-table.json +42 -0
  230. package/dist-server/migrations/grade-data/x31-performance-table.json +644 -0
  231. package/dist-server/migrations/grade-data/x32-performance-table.json +993 -0
  232. package/dist-server/migrations/grade-data/x33-performance-table.json +195 -0
  233. package/dist-server/migrations/grade-data/x34-performance-table.json +12 -0
  234. package/dist-server/migrations/grade-data/x35-performance-table.json +42 -0
  235. package/dist-server/migrations/grade-data/x41-performance-table.json +825 -0
  236. package/dist-server/migrations/grade-data/x42-performance-table.json +786 -0
  237. package/dist-server/migrations/grade-data/x43-performance-table.json +12 -0
  238. package/dist-server/migrations/grade-data/x44-performance-table.json +42 -0
  239. package/dist-server/migrations/grade-data/x51-performance-table.json +924 -0
  240. package/dist-server/migrations/grade-data/x52-performance-table.json +42 -0
  241. package/dist-server/migrations/grade-data/x61-performance-table.json +261 -0
  242. package/dist-server/migrations/grade-data/x62-performance-table.json +42 -0
  243. package/dist-server/migrations/index.d.ts +1 -0
  244. package/dist-server/migrations/index.js +12 -0
  245. package/dist-server/migrations/index.js.map +1 -0
  246. package/dist-server/migrations/seed-data/kpi-metrics-seed.json +517 -0
  247. package/dist-server/migrations/seed-data/kpi-org-scope-seed.json +1676 -0
  248. package/dist-server/migrations/seed-data/kpi-scopes-seed.json +121 -0
  249. package/dist-server/migrations/seed-data/kpi-values-seed.json +402 -0
  250. package/dist-server/migrations/seed-data/kpis-seed.json +488 -0
  251. package/dist-server/migrations/seed-data/scope-definitions-seed.json +90 -0
  252. package/dist-server/routes.d.ts +1 -0
  253. package/dist-server/routes.js +72 -0
  254. package/dist-server/routes.js.map +1 -0
  255. package/dist-server/service/index.d.ts +15 -0
  256. package/dist-server/service/index.js +49 -0
  257. package/dist-server/service/index.js.map +1 -0
  258. package/dist-server/service/kpi/aggregate-kpi.d.ts +8 -0
  259. package/dist-server/service/kpi/aggregate-kpi.js +123 -0
  260. package/dist-server/service/kpi/aggregate-kpi.js.map +1 -0
  261. package/dist-server/service/kpi/event-subscriber.d.ts +9 -0
  262. package/dist-server/service/kpi/event-subscriber.js +31 -0
  263. package/dist-server/service/kpi/event-subscriber.js.map +1 -0
  264. package/dist-server/service/kpi/index.d.ts +8 -0
  265. package/dist-server/service/kpi/index.js +12 -0
  266. package/dist-server/service/kpi/index.js.map +1 -0
  267. package/dist-server/service/kpi/kpi-formula.service.d.ts +49 -0
  268. package/dist-server/service/kpi/kpi-formula.service.js +165 -0
  269. package/dist-server/service/kpi/kpi-formula.service.js.map +1 -0
  270. package/dist-server/service/kpi/kpi-grade.types.d.ts +22 -0
  271. package/dist-server/service/kpi/kpi-grade.types.js +3 -0
  272. package/dist-server/service/kpi/kpi-grade.types.js.map +1 -0
  273. package/dist-server/service/kpi/kpi-history.d.ts +29 -0
  274. package/dist-server/service/kpi/kpi-history.js +148 -0
  275. package/dist-server/service/kpi/kpi-history.js.map +1 -0
  276. package/dist-server/service/kpi/kpi-mutation.d.ts +14 -0
  277. package/dist-server/service/kpi/kpi-mutation.js +553 -0
  278. package/dist-server/service/kpi/kpi-mutation.js.map +1 -0
  279. package/dist-server/service/kpi/kpi-query.d.ts +24 -0
  280. package/dist-server/service/kpi/kpi-query.js +309 -0
  281. package/dist-server/service/kpi/kpi-query.js.map +1 -0
  282. package/dist-server/service/kpi/kpi-type.d.ts +48 -0
  283. package/dist-server/service/kpi/kpi-type.js +221 -0
  284. package/dist-server/service/kpi/kpi-type.js.map +1 -0
  285. package/dist-server/service/kpi/kpi.d.ts +130 -0
  286. package/dist-server/service/kpi/kpi.js +356 -0
  287. package/dist-server/service/kpi/kpi.js.map +1 -0
  288. package/dist-server/service/kpi-alert/index.d.ts +2 -0
  289. package/dist-server/service/kpi-alert/index.js +6 -0
  290. package/dist-server/service/kpi-alert/index.js.map +1 -0
  291. package/dist-server/service/kpi-alert/kpi-alert-query.d.ts +4 -0
  292. package/dist-server/service/kpi-alert/kpi-alert-query.js +72 -0
  293. package/dist-server/service/kpi-alert/kpi-alert-query.js.map +1 -0
  294. package/dist-server/service/kpi-alert/kpi-alert-type.d.ts +8 -0
  295. package/dist-server/service/kpi-alert/kpi-alert-type.js +33 -0
  296. package/dist-server/service/kpi-alert/kpi-alert-type.js.map +1 -0
  297. package/dist-server/service/kpi-metric/aggregate-kpi-metric.d.ts +8 -0
  298. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js +126 -0
  299. package/dist-server/service/kpi-metric/aggregate-kpi-metric.js.map +1 -0
  300. package/dist-server/service/kpi-metric/index.d.ts +6 -0
  301. package/dist-server/service/kpi-metric/index.js +10 -0
  302. package/dist-server/service/kpi-metric/index.js.map +1 -0
  303. package/dist-server/service/kpi-metric/kpi-metric-meta.d.ts +46 -0
  304. package/dist-server/service/kpi-metric/kpi-metric-meta.js +27 -0
  305. package/dist-server/service/kpi-metric/kpi-metric-meta.js.map +1 -0
  306. package/dist-server/service/kpi-metric/kpi-metric-meta.test.d.ts +1 -0
  307. package/dist-server/service/kpi-metric/kpi-metric-meta.test.js +43 -0
  308. package/dist-server/service/kpi-metric/kpi-metric-meta.test.js.map +1 -0
  309. package/dist-server/service/kpi-metric/kpi-metric-mutation.d.ts +10 -0
  310. package/dist-server/service/kpi-metric/kpi-metric-mutation.js +296 -0
  311. package/dist-server/service/kpi-metric/kpi-metric-mutation.js.map +1 -0
  312. package/dist-server/service/kpi-metric/kpi-metric-query.d.ts +14 -0
  313. package/dist-server/service/kpi-metric/kpi-metric-query.js +126 -0
  314. package/dist-server/service/kpi-metric/kpi-metric-query.js.map +1 -0
  315. package/dist-server/service/kpi-metric/kpi-metric-type.d.ts +45 -0
  316. package/dist-server/service/kpi-metric/kpi-metric-type.js +177 -0
  317. package/dist-server/service/kpi-metric/kpi-metric-type.js.map +1 -0
  318. package/dist-server/service/kpi-metric/kpi-metric.d.ts +39 -0
  319. package/dist-server/service/kpi-metric/kpi-metric.js +174 -0
  320. package/dist-server/service/kpi-metric/kpi-metric.js.map +1 -0
  321. package/dist-server/service/kpi-metric-value/index.d.ts +6 -0
  322. package/dist-server/service/kpi-metric-value/index.js +10 -0
  323. package/dist-server/service/kpi-metric-value/index.js.map +1 -0
  324. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.d.ts +11 -0
  325. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js +283 -0
  326. package/dist-server/service/kpi-metric-value/kpi-metric-value-mutation.js.map +1 -0
  327. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.d.ts +13 -0
  328. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js +106 -0
  329. package/dist-server/service/kpi-metric-value/kpi-metric-value-query.js.map +1 -0
  330. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.d.ts +26 -0
  331. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js +112 -0
  332. package/dist-server/service/kpi-metric-value/kpi-metric-value-type.js.map +1 -0
  333. package/dist-server/service/kpi-metric-value/kpi-metric-value.d.ts +23 -0
  334. package/dist-server/service/kpi-metric-value/kpi-metric-value.js +107 -0
  335. package/dist-server/service/kpi-metric-value/kpi-metric-value.js.map +1 -0
  336. package/dist-server/service/kpi-org-scope/index.d.ts +5 -0
  337. package/dist-server/service/kpi-org-scope/index.js +9 -0
  338. package/dist-server/service/kpi-org-scope/index.js.map +1 -0
  339. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.d.ts +8 -0
  340. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js +170 -0
  341. package/dist-server/service/kpi-org-scope/kpi-org-scope-mutation.js.map +1 -0
  342. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.d.ts +14 -0
  343. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js +152 -0
  344. package/dist-server/service/kpi-org-scope/kpi-org-scope-query.js.map +1 -0
  345. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.d.ts +26 -0
  346. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js +101 -0
  347. package/dist-server/service/kpi-org-scope/kpi-org-scope-type.js.map +1 -0
  348. package/dist-server/service/kpi-org-scope/kpi-org-scope.d.ts +26 -0
  349. package/dist-server/service/kpi-org-scope/kpi-org-scope.js +135 -0
  350. package/dist-server/service/kpi-org-scope/kpi-org-scope.js.map +1 -0
  351. package/dist-server/service/kpi-scope/index.d.ts +9 -0
  352. package/dist-server/service/kpi-scope/index.js +14 -0
  353. package/dist-server/service/kpi-scope/index.js.map +1 -0
  354. package/dist-server/service/kpi-scope/kpi-scope-mutation.d.ts +9 -0
  355. package/dist-server/service/kpi-scope/kpi-scope-mutation.js +140 -0
  356. package/dist-server/service/kpi-scope/kpi-scope-mutation.js.map +1 -0
  357. package/dist-server/service/kpi-scope/kpi-scope-query.d.ts +11 -0
  358. package/dist-server/service/kpi-scope/kpi-scope-query.js +89 -0
  359. package/dist-server/service/kpi-scope/kpi-scope-query.js.map +1 -0
  360. package/dist-server/service/kpi-scope/kpi-scope-type.d.ts +35 -0
  361. package/dist-server/service/kpi-scope/kpi-scope-type.js +138 -0
  362. package/dist-server/service/kpi-scope/kpi-scope-type.js.map +1 -0
  363. package/dist-server/service/kpi-scope/kpi-scope.d.ts +38 -0
  364. package/dist-server/service/kpi-scope/kpi-scope.js +144 -0
  365. package/dist-server/service/kpi-scope/kpi-scope.js.map +1 -0
  366. package/dist-server/service/kpi-statistic/index.d.ts +6 -0
  367. package/dist-server/service/kpi-statistic/index.js +10 -0
  368. package/dist-server/service/kpi-statistic/index.js.map +1 -0
  369. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.d.ts +43 -0
  370. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.js +181 -0
  371. package/dist-server/service/kpi-statistic/kpi-statistic-batch.service.js.map +1 -0
  372. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.d.ts +50 -0
  373. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.js +324 -0
  374. package/dist-server/service/kpi-statistic/kpi-statistic-calculation.service.js.map +1 -0
  375. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.d.ts +14 -0
  376. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.js +279 -0
  377. package/dist-server/service/kpi-statistic/kpi-statistic-mutation.js.map +1 -0
  378. package/dist-server/service/kpi-statistic/kpi-statistic-query.d.ts +17 -0
  379. package/dist-server/service/kpi-statistic/kpi-statistic-query.js +183 -0
  380. package/dist-server/service/kpi-statistic/kpi-statistic-query.js.map +1 -0
  381. package/dist-server/service/kpi-statistic/kpi-statistic-type.d.ts +59 -0
  382. package/dist-server/service/kpi-statistic/kpi-statistic-type.js +200 -0
  383. package/dist-server/service/kpi-statistic/kpi-statistic-type.js.map +1 -0
  384. package/dist-server/service/kpi-statistic/kpi-statistic.d.ts +42 -0
  385. package/dist-server/service/kpi-statistic/kpi-statistic.js +210 -0
  386. package/dist-server/service/kpi-statistic/kpi-statistic.js.map +1 -0
  387. package/dist-server/service/kpi-value/index.d.ts +6 -0
  388. package/dist-server/service/kpi-value/index.js +10 -0
  389. package/dist-server/service/kpi-value/index.js.map +1 -0
  390. package/dist-server/service/kpi-value/kpi-value-mutation.d.ts +13 -0
  391. package/dist-server/service/kpi-value/kpi-value-mutation.js +447 -0
  392. package/dist-server/service/kpi-value/kpi-value-mutation.js.map +1 -0
  393. package/dist-server/service/kpi-value/kpi-value-query.d.ts +22 -0
  394. package/dist-server/service/kpi-value/kpi-value-query.js +149 -0
  395. package/dist-server/service/kpi-value/kpi-value-query.js.map +1 -0
  396. package/dist-server/service/kpi-value/kpi-value-score.service.d.ts +24 -0
  397. package/dist-server/service/kpi-value/kpi-value-score.service.js +61 -0
  398. package/dist-server/service/kpi-value/kpi-value-score.service.js.map +1 -0
  399. package/dist-server/service/kpi-value/kpi-value-type.d.ts +33 -0
  400. package/dist-server/service/kpi-value/kpi-value-type.js +156 -0
  401. package/dist-server/service/kpi-value/kpi-value-type.js.map +1 -0
  402. package/dist-server/service/kpi-value/kpi-value.d.ts +32 -0
  403. package/dist-server/service/kpi-value/kpi-value.js +175 -0
  404. package/dist-server/service/kpi-value/kpi-value.js.map +1 -0
  405. package/dist-server/service/utils/value-date-util.d.ts +4 -0
  406. package/dist-server/service/utils/value-date-util.js +117 -0
  407. package/dist-server/service/utils/value-date-util.js.map +1 -0
  408. package/dist-server/tsconfig.tsbuildinfo +1 -0
  409. package/package.json +3 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-input.test.js","sourceRoot":"","sources":["../../client/viewparts/metric-input.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { resolveInputHint } from './metric-input-hint'\nimport { MetricRendererRegistry } from './metric-renderer-registry'\n\ndescribe('resolveInputHint (client copy)', () => {\n it('meta 없음 → number 폴백', () => {\n expect(resolveInputHint(null)).toEqual({ widget: 'number', readonly: false })\n expect(resolveInputHint({ collectType: 'AUTO' })).toEqual({ widget: 'number', readonly: true })\n })\n it('rating 기본값(max 5, step 1)', () => {\n expect(resolveInputHint({ meta: { input: { widget: 'rating' } } })).toEqual({\n widget: 'rating',\n max: 5,\n step: 1,\n readonly: false\n })\n })\n it('readonly 명시 false 는 AUTO 라도 존중', () => {\n expect(resolveInputHint({ collectType: 'AUTO', meta: { input: { widget: 'number', readonly: false } } }).readonly).toBe(\n false\n )\n })\n})\n\ndescribe('MetricRendererRegistry', () => {\n const dummy: any = () => null\n beforeEach(() => MetricRendererRegistry.clear())\n\n it('매칭 없으면 undefined (→ 제네릭)', () => {\n expect(MetricRendererRegistry.resolve({ meta: {} } as any)).toBeUndefined()\n })\n\n it('predicate 매칭 시 렌더러 반환, 먼저 등록된 것 우선', () => {\n const r1: any = () => 'r1'\n const r2: any = () => 'r2'\n MetricRendererRegistry.register((m: any) => m.name === 'X', r1)\n MetricRendererRegistry.register((m: any) => m.name === 'X', r2)\n expect(MetricRendererRegistry.resolve({ name: 'X' } as any)).toBe(r1)\n expect(MetricRendererRegistry.resolve({ name: 'Y' } as any)).toBeUndefined()\n })\n\n it('predicate 예외는 매칭 실패로 처리(다음으로 진행)', () => {\n MetricRendererRegistry.register(() => {\n throw new Error('boom')\n }, dummy)\n const ok: any = () => 'ok'\n MetricRendererRegistry.register((m: any) => m.name === 'Z', ok)\n expect(MetricRendererRegistry.resolve({ name: 'Z' } as any)).toBe(ok)\n })\n})\n"]}
@@ -0,0 +1,18 @@
1
+ import type { TemplateResult } from 'lit';
2
+ import type { KpiMetricLike } from './metric-input-hint';
3
+ /** 특정 metric 에 대한 커스텀 입력 렌더러. 제네릭 위젯으로 표현 못 하는 예외용. */
4
+ export type MetricInputRenderer = (metric: KpiMetricLike, value: any, onChange: (value: any) => void) => TemplateResult;
5
+ /**
6
+ * 커스텀 렌더러 레지스트리 (80/20 탈출구).
7
+ * 제네릭 렌더러가 대부분을 처리하고, 특수 UI 만 predicate 로 등록해 우선 적용한다.
8
+ */
9
+ declare class Registry {
10
+ private entries;
11
+ register(predicate: (metric: KpiMetricLike) => boolean, renderer: MetricInputRenderer): void;
12
+ /** 가장 먼저 매칭되는 커스텀 렌더러(없으면 undefined → 제네릭 사용). */
13
+ resolve(metric: KpiMetricLike): MetricInputRenderer | undefined;
14
+ /** 테스트/리셋용. */
15
+ clear(): void;
16
+ }
17
+ export declare const MetricRendererRegistry: Registry;
18
+ export {};
@@ -0,0 +1,29 @@
1
+ /**
2
+ * 커스텀 렌더러 레지스트리 (80/20 탈출구).
3
+ * 제네릭 렌더러가 대부분을 처리하고, 특수 UI 만 predicate 로 등록해 우선 적용한다.
4
+ */
5
+ class Registry {
6
+ constructor() {
7
+ this.entries = [];
8
+ }
9
+ register(predicate, renderer) {
10
+ this.entries.push({ predicate, renderer });
11
+ }
12
+ /** 가장 먼저 매칭되는 커스텀 렌더러(없으면 undefined → 제네릭 사용). */
13
+ resolve(metric) {
14
+ return this.entries.find(e => {
15
+ try {
16
+ return e.predicate(metric);
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ })?.renderer;
22
+ }
23
+ /** 테스트/리셋용. */
24
+ clear() {
25
+ this.entries = [];
26
+ }
27
+ }
28
+ export const MetricRendererRegistry = new Registry();
29
+ //# sourceMappingURL=metric-renderer-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metric-renderer-registry.js","sourceRoot":"","sources":["../../client/viewparts/metric-renderer-registry.ts"],"names":[],"mappings":"AAYA;;;GAGG;AACH,MAAM,QAAQ;IAAd;QACU,YAAO,GAAY,EAAE,CAAA;IAqB/B,CAAC;IAnBC,QAAQ,CAAC,SAA6C,EAAE,QAA6B;QACnF,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAA;IAC5C,CAAC;IAED,kDAAkD;IAClD,OAAO,CAAC,MAAqB;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YAC3B,IAAI,CAAC;gBACH,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAA;YACd,CAAC;QACH,CAAC,CAAC,EAAE,QAAQ,CAAA;IACd,CAAC;IAED,eAAe;IACf,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,EAAE,CAAA;IACnB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,QAAQ,EAAE,CAAA","sourcesContent":["import type { TemplateResult } from 'lit'\nimport type { KpiMetricLike } from './metric-input-hint'\n\n/** 특정 metric 에 대한 커스텀 입력 렌더러. 제네릭 위젯으로 표현 못 하는 예외용. */\nexport type MetricInputRenderer = (\n metric: KpiMetricLike,\n value: any,\n onChange: (value: any) => void\n) => TemplateResult\n\ntype Entry = { predicate: (metric: KpiMetricLike) => boolean; renderer: MetricInputRenderer }\n\n/**\n * 커스텀 렌더러 레지스트리 (80/20 탈출구).\n * 제네릭 렌더러가 대부분을 처리하고, 특수 UI 만 predicate 로 등록해 우선 적용한다.\n */\nclass Registry {\n private entries: Entry[] = []\n\n register(predicate: (metric: KpiMetricLike) => boolean, renderer: MetricInputRenderer): void {\n this.entries.push({ predicate, renderer })\n }\n\n /** 가장 먼저 매칭되는 커스텀 렌더러(없으면 undefined → 제네릭 사용). */\n resolve(metric: KpiMetricLike): MetricInputRenderer | undefined {\n return this.entries.find(e => {\n try {\n return e.predicate(metric)\n } catch {\n return false\n }\n })?.renderer\n }\n\n /** 테스트/리셋용. */\n clear(): void {\n this.entries = []\n }\n}\n\nexport const MetricRendererRegistry = new Registry()\n"]}
@@ -0,0 +1,19 @@
1
+ import { OxGristEditor } from '@operato/data-grist';
2
+ import './kpi-metric-meta-editor';
3
+ /**
4
+ * KpiMetric.meta 컬럼용 grist 커스텀 에디터.
5
+ *
6
+ * 셀을 클릭/엔터하면 일반 텍스트 에디터 대신 구조화된 <kpi-metric-meta-editor> 팝업을 연다.
7
+ * (json5 에디터가 ox-popup-code-input 팝업을 여는 것과 동일한 패턴)
8
+ * 저장 시 field-change 로 새 meta 객체를 grist 에 되돌려 dirty 처리 → 목록의 저장 버튼으로 반영.
9
+ *
10
+ * 등록: registerEditor('metric-input-hint', OxGristEditorMetricInputHint)
11
+ * 컬럼: { type: 'metric-input-hint', name: 'meta', record: { editable: true } }
12
+ */
13
+ export declare class OxGristEditorMetricInputHint extends OxGristEditor {
14
+ get editorTemplate(): import("lit-html").TemplateResult<1>;
15
+ private _summary;
16
+ _onclick(e: Event): void;
17
+ _onkeydown(e: Event): void;
18
+ private _openEditor;
19
+ }
@@ -0,0 +1,76 @@
1
+ import { __decorate } from "tslib";
2
+ import { html } from 'lit';
3
+ import { customElement } from 'lit/decorators.js';
4
+ import { openPopup } from '@operato/layout';
5
+ import { OxGristEditor } from '@operato/data-grist';
6
+ import './kpi-metric-meta-editor';
7
+ /**
8
+ * KpiMetric.meta 컬럼용 grist 커스텀 에디터.
9
+ *
10
+ * 셀을 클릭/엔터하면 일반 텍스트 에디터 대신 구조화된 <kpi-metric-meta-editor> 팝업을 연다.
11
+ * (json5 에디터가 ox-popup-code-input 팝업을 여는 것과 동일한 패턴)
12
+ * 저장 시 field-change 로 새 meta 객체를 grist 에 되돌려 dirty 처리 → 목록의 저장 버튼으로 반영.
13
+ *
14
+ * 등록: registerEditor('metric-input-hint', OxGristEditorMetricInputHint)
15
+ * 컬럼: { type: 'metric-input-hint', name: 'meta', record: { editable: true } }
16
+ */
17
+ let OxGristEditorMetricInputHint = class OxGristEditorMetricInputHint extends OxGristEditor {
18
+ get editorTemplate() {
19
+ return html `<div tabindex="0">${this._summary(this.value)}</div>`;
20
+ }
21
+ _summary(meta) {
22
+ const input = meta?.input;
23
+ if (!input?.widget)
24
+ return '';
25
+ const extra = [
26
+ input.max !== undefined ? `max ${input.max}` : '',
27
+ input.step !== undefined ? `step ${input.step}` : '',
28
+ input.readonly ? 'RO' : ''
29
+ ]
30
+ .filter(Boolean)
31
+ .join('·');
32
+ return extra ? `${input.widget} (${extra})` : input.widget;
33
+ }
34
+ _onclick(e) {
35
+ e.stopPropagation();
36
+ this._openEditor();
37
+ }
38
+ _onkeydown(e) {
39
+ if (e.key === 'Enter') {
40
+ e.stopPropagation();
41
+ this._openEditor();
42
+ }
43
+ }
44
+ _openEditor() {
45
+ // 이 컬럼의 value = record.meta. 에디터는 metric.meta 를 읽으므로 record 에 현재 value 를 얹어 전달.
46
+ const metric = { ...(this.record || {}), meta: this.value };
47
+ const change = (meta) => {
48
+ this.dispatchEvent(new CustomEvent('field-change', {
49
+ bubbles: true,
50
+ composed: true,
51
+ detail: {
52
+ before: this.value,
53
+ after: meta,
54
+ column: this.column,
55
+ record: this.record,
56
+ row: this.row
57
+ }
58
+ }));
59
+ };
60
+ const popup = openPopup(html `
61
+ <kpi-metric-meta-editor
62
+ .metric=${metric}
63
+ @metric-meta-save=${(ev) => {
64
+ change(ev.detail.meta);
65
+ popup.close();
66
+ }}
67
+ @metric-meta-cancel=${() => popup.close()}
68
+ ></kpi-metric-meta-editor>
69
+ `, { backdrop: true, title: `입력 힌트 · ${this.record?.name || ''}`, size: 'medium' });
70
+ }
71
+ };
72
+ OxGristEditorMetricInputHint = __decorate([
73
+ customElement('ox-grist-editor-metric-input-hint')
74
+ ], OxGristEditorMetricInputHint);
75
+ export { OxGristEditorMetricInputHint };
76
+ //# sourceMappingURL=ox-grist-editor-metric-input-hint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-grist-editor-metric-input-hint.js","sourceRoot":"","sources":["../../client/viewparts/ox-grist-editor-metric-input-hint.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,OAAO,0BAA0B,CAAA;AAEjC;;;;;;;;;GASG;AAEI,IAAM,4BAA4B,GAAlC,MAAM,4BAA6B,SAAQ,aAAa;IAC7D,IAAI,cAAc;QAChB,OAAO,IAAI,CAAA,qBAAqB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;IACnE,CAAC;IAEO,QAAQ,CAAC,IAAS;QACxB,MAAM,KAAK,GAAG,IAAI,EAAE,KAAK,CAAA;QACzB,IAAI,CAAC,KAAK,EAAE,MAAM;YAAE,OAAO,EAAE,CAAA;QAC7B,MAAM,KAAK,GAAG;YACZ,KAAK,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE;YACjD,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;YACpD,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;SAC3B;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,GAAG,CAAC,CAAA;QACZ,OAAO,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAA;IAC5D,CAAC;IAED,QAAQ,CAAC,CAAQ;QACf,CAAC,CAAC,eAAe,EAAE,CAAA;QACnB,IAAI,CAAC,WAAW,EAAE,CAAA;IACpB,CAAC;IAED,UAAU,CAAC,CAAQ;QACjB,IAAK,CAAmB,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;YACzC,CAAC,CAAC,eAAe,EAAE,CAAA;YACnB,IAAI,CAAC,WAAW,EAAE,CAAA;QACpB,CAAC;IACH,CAAC;IAEO,WAAW;QACjB,gFAAgF;QAChF,MAAM,MAAM,GAAG,EAAE,GAAG,CAAE,IAAI,CAAC,MAAc,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;QAEpE,MAAM,MAAM,GAAG,CAAC,IAAS,EAAE,EAAE;YAC3B,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,cAAc,EAAE;gBAC9B,OAAO,EAAE,IAAI;gBACb,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE;oBACN,MAAM,EAAE,IAAI,CAAC,KAAK;oBAClB,KAAK,EAAE,IAAI;oBACX,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,MAAM,EAAE,IAAI,CAAC,MAAM;oBACnB,GAAG,EAAE,IAAI,CAAC,GAAG;iBACd;aACF,CAAC,CACH,CAAA;QACH,CAAC,CAAA;QAED,MAAM,KAAK,GAAG,SAAS,CACrB,IAAI,CAAA;;oBAEU,MAAM;8BACI,CAAC,EAAe,EAAE,EAAE;YACtC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;YACtB,KAAK,CAAC,KAAK,EAAE,CAAA;QACf,CAAC;gCACqB,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE;;OAE5C,EACD,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,WAAY,IAAI,CAAC,MAAc,EAAE,IAAI,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CACzF,CAAA;IACH,CAAC;CACF,CAAA;AAhEY,4BAA4B;IADxC,aAAa,CAAC,mCAAmC,CAAC;GACtC,4BAA4B,CAgExC","sourcesContent":["import { html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\nimport { openPopup } from '@operato/layout'\nimport { OxGristEditor } from '@operato/data-grist'\n\nimport './kpi-metric-meta-editor'\n\n/**\n * KpiMetric.meta 컬럼용 grist 커스텀 에디터.\n *\n * 셀을 클릭/엔터하면 일반 텍스트 에디터 대신 구조화된 <kpi-metric-meta-editor> 팝업을 연다.\n * (json5 에디터가 ox-popup-code-input 팝업을 여는 것과 동일한 패턴)\n * 저장 시 field-change 로 새 meta 객체를 grist 에 되돌려 dirty 처리 → 목록의 저장 버튼으로 반영.\n *\n * 등록: registerEditor('metric-input-hint', OxGristEditorMetricInputHint)\n * 컬럼: { type: 'metric-input-hint', name: 'meta', record: { editable: true } }\n */\n@customElement('ox-grist-editor-metric-input-hint')\nexport class OxGristEditorMetricInputHint extends OxGristEditor {\n get editorTemplate() {\n return html`<div tabindex=\"0\">${this._summary(this.value)}</div>`\n }\n\n private _summary(meta: any): string {\n const input = meta?.input\n if (!input?.widget) return ''\n const extra = [\n input.max !== undefined ? `max ${input.max}` : '',\n input.step !== undefined ? `step ${input.step}` : '',\n input.readonly ? 'RO' : ''\n ]\n .filter(Boolean)\n .join('·')\n return extra ? `${input.widget} (${extra})` : input.widget\n }\n\n _onclick(e: Event) {\n e.stopPropagation()\n this._openEditor()\n }\n\n _onkeydown(e: Event) {\n if ((e as KeyboardEvent).key === 'Enter') {\n e.stopPropagation()\n this._openEditor()\n }\n }\n\n private _openEditor() {\n // 이 컬럼의 value = record.meta. 에디터는 metric.meta 를 읽으므로 record 에 현재 value 를 얹어 전달.\n const metric = { ...((this.record as any) || {}), meta: this.value }\n\n const change = (meta: any) => {\n this.dispatchEvent(\n new CustomEvent('field-change', {\n bubbles: true,\n composed: true,\n detail: {\n before: this.value,\n after: meta,\n column: this.column,\n record: this.record,\n row: this.row\n }\n })\n )\n }\n\n const popup = openPopup(\n html`\n <kpi-metric-meta-editor\n .metric=${metric}\n @metric-meta-save=${(ev: CustomEvent) => {\n change(ev.detail.meta)\n popup.close()\n }}\n @metric-meta-cancel=${() => popup.close()}\n ></kpi-metric-meta-editor>\n `,\n { backdrop: true, title: `입력 힌트 · ${(this.record as any)?.name || ''}`, size: 'medium' }\n )\n }\n}\n"]}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const parser_1 = require("./parser");
4
+ const evaluator_1 = require("./evaluator");
5
+ const functions_1 = require("./functions");
6
+ const provider_1 = require("./provider");
7
+ /** 테스트 헬퍼: 수식 + 변수값 맵 → 평가 결과 */
8
+ async function evalWith(formula, values = {}) {
9
+ const ast = (0, parser_1.parseFormula)(formula);
10
+ return (0, evaluator_1.evaluateFormula)(ast, { functions: functions_1.builtinFunctions, provider: new provider_1.ObjectValueProvider(values) });
11
+ }
12
+ describe('parser (parseFormula)', () => {
13
+ it('숫자/소수를 파싱한다', () => {
14
+ expect((0, parser_1.parseFormula)('42')).toEqual({ type: 'number', value: 42 });
15
+ expect((0, parser_1.parseFormula)('3.14')).toEqual({ type: 'number', value: 3.14 });
16
+ });
17
+ it('대괄호 변수(한글·공백 포함)를 파싱하고 대괄호를 벗긴다', () => {
18
+ expect((0, parser_1.parseFormula)('[재해 건수]')).toEqual({ type: 'variable', name: '재해 건수' });
19
+ });
20
+ it('bare 식별자를 변수로 파싱한다', () => {
21
+ expect((0, parser_1.parseFormula)('x11')).toEqual({ type: 'variable', name: 'x11' });
22
+ });
23
+ it('사칙연산 우선순위(*,/ 가 +,- 보다 높음)를 지킨다', () => {
24
+ const ast = (0, parser_1.parseFormula)('1 + 2 * 3');
25
+ // + 가 최상위, 오른쪽이 (2*3)
26
+ expect(ast).toMatchObject({ type: 'binary', op: '+', right: { type: 'binary', op: '*' } });
27
+ });
28
+ it('괄호로 우선순위를 바꾼다', () => {
29
+ const ast = (0, parser_1.parseFormula)('(1 + 2) * 3');
30
+ expect(ast).toMatchObject({ type: 'binary', op: '*', left: { type: 'binary', op: '+' } });
31
+ });
32
+ it('단항 마이너스를 파싱한다', () => {
33
+ expect((0, parser_1.parseFormula)('-5')).toEqual({ type: 'unary', op: '-', arg: { type: 'number', value: 5 } });
34
+ });
35
+ it('함수 호출을 파싱한다', () => {
36
+ const ast = (0, parser_1.parseFormula)('sum(1, 2, 3)');
37
+ expect(ast).toMatchObject({ type: 'function', name: 'sum' });
38
+ expect(ast.args).toHaveLength(3);
39
+ });
40
+ it('잘못된 토큰/불완전 수식은 throw 한다', () => {
41
+ expect(() => (0, parser_1.parseFormula)('1 @ 2')).toThrow();
42
+ expect(() => (0, parser_1.parseFormula)('[a] +')).toThrow();
43
+ expect(() => (0, parser_1.parseFormula)('(1 + 2')).toThrow();
44
+ });
45
+ });
46
+ describe('collectVariableNames', () => {
47
+ it('대괄호 한글 변수명을 정확히 수집한다 (정규식이 놓치는 케이스)', () => {
48
+ const ast = (0, parser_1.parseFormula)('[실제공사기간] / [연면적]');
49
+ expect((0, parser_1.collectVariableNames)(ast).sort()).toEqual(['실제공사기간', '연면적'].sort());
50
+ });
51
+ it('중복을 제거한다', () => {
52
+ const ast = (0, parser_1.parseFormula)('([계획공사비] - [계획공사비]) / [계획공사비]');
53
+ expect((0, parser_1.collectVariableNames)(ast)).toEqual(['계획공사비']);
54
+ });
55
+ it('함수 인자 안의 변수도 수집한다', () => {
56
+ const ast = (0, parser_1.parseFormula)('round([a] / [b], 2)');
57
+ expect((0, parser_1.collectVariableNames)(ast).sort()).toEqual(['a', 'b']);
58
+ });
59
+ it('변수가 없으면 빈 배열', () => {
60
+ expect((0, parser_1.collectVariableNames)((0, parser_1.parseFormula)('1 + 2'))).toEqual([]);
61
+ });
62
+ });
63
+ describe('evaluator — 연산', () => {
64
+ it('사칙연산과 우선순위', async () => {
65
+ expect(await evalWith('1 + 2 * 3')).toBe(7);
66
+ expect(await evalWith('(1 + 2) * 3')).toBe(9);
67
+ expect(await evalWith('10 / 4')).toBe(2.5);
68
+ expect(await evalWith('-5 + 3')).toBe(-2);
69
+ });
70
+ it('변수를 provider 로 해석한다 (대괄호 한글 포함)', async () => {
71
+ expect(await evalWith('[a] / [b]', { a: 10, b: 2 })).toBe(5);
72
+ expect(await evalWith('[재해 건수] / [연간 근로자 수] * 100', { '재해 건수': 5, '연간 근로자 수': 1000 })).toBeCloseTo(0.5);
73
+ });
74
+ it('알 수 없는 함수는 throw', async () => {
75
+ await expect(evalWith('nope(1)')).rejects.toThrow(/Unknown function/);
76
+ });
77
+ });
78
+ describe('builtinFunctions', () => {
79
+ it('sum/avg/min/max/round/if', async () => {
80
+ expect(await evalWith('sum(1, 2, 3)')).toBe(6);
81
+ expect(await evalWith('avg(2, 4, 6)')).toBe(4);
82
+ expect(await evalWith('min(3, 1, 2)')).toBe(1);
83
+ expect(await evalWith('max(3, 1, 2)')).toBe(3);
84
+ expect(await evalWith('round(3.14159, 2)')).toBe(3.14);
85
+ expect(await evalWith('if(1, 10, 20)')).toBe(10);
86
+ expect(await evalWith('if(0, 10, 20)')).toBe(20);
87
+ });
88
+ });
89
+ /**
90
+ * 회귀 방어: kpi 모듈 seed(kpis-seed.json)의 실제 formula 코퍼스.
91
+ * 이 formula들은 dkpi 런타임에서 AST 엔진으로 평가되므로, 파싱·변수추출·평가가
92
+ * 깨지면 dkpi 가 깨진다. (P0-1: aggregate 경로도 이제 이 엔진을 씀)
93
+ */
94
+ describe('seed formula 코퍼스 (회귀 방어)', () => {
95
+ const SEED_FORMULAS = [
96
+ '[실제공사기간] / [연면적]',
97
+ '([실제공사기간] - [계획공사기간]) / [계획공사기간]',
98
+ '[일정 이탈 수준]',
99
+ '[실제공사비] / [연면적]',
100
+ '([실제공사비]-[계획공사비]) / [계획공사비]',
101
+ '[품질시험 불합격 건수] / [연면적]',
102
+ '[재해 건수] / [연간 근로자 수] * 100',
103
+ '[노동손실일수] / ( [총 근로자수] * [1인당 연간 근로 시간] ) * 1000',
104
+ '[총 건설 폐기물 발생량] / [연면적]',
105
+ '[투입인력] / [연면적]'
106
+ ];
107
+ it.each(SEED_FORMULAS)('파싱되고 변수추출된다: %s', formula => {
108
+ const ast = (0, parser_1.parseFormula)(formula);
109
+ const vars = (0, parser_1.collectVariableNames)(ast);
110
+ expect(Array.isArray(vars)).toBe(true);
111
+ // 단일 변수 formula 도 최소 1개 이상
112
+ expect(vars.length).toBeGreaterThanOrEqual(1);
113
+ });
114
+ it('대표 formula 들이 올바른 수치를 낸다', async () => {
115
+ expect(await evalWith('[실제공사기간] / [연면적]', { 실제공사기간: 300, 연면적: 1500 })).toBeCloseTo(0.2);
116
+ expect(await evalWith('([실제공사비]-[계획공사비]) / [계획공사비]', { 실제공사비: 1200, 계획공사비: 1000 })).toBeCloseTo(0.2);
117
+ expect(await evalWith('[노동손실일수] / ( [총 근로자수] * [1인당 연간 근로 시간] ) * 1000', {
118
+ 노동손실일수: 10,
119
+ '총 근로자수': 100,
120
+ '1인당 연간 근로 시간': 2000
121
+ })).toBeCloseTo(0.05);
122
+ // 단일 변수 pass-through
123
+ expect(await evalWith('[일정 이탈 수준]', { '일정 이탈 수준': 3 })).toBe(3);
124
+ });
125
+ });
126
+ //# sourceMappingURL=calculator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calculator.test.js","sourceRoot":"","sources":["../../server/calculator/calculator.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { parseFormula, collectVariableNames } from './parser'\nimport { evaluateFormula } from './evaluator'\nimport { builtinFunctions } from './functions'\nimport { ObjectValueProvider } from './provider'\n\n/** 테스트 헬퍼: 수식 + 변수값 맵 → 평가 결과 */\nasync function evalWith(formula: string, values: Record<string, any> = {}): Promise<any> {\n const ast = parseFormula(formula)\n return evaluateFormula(ast, { functions: builtinFunctions, provider: new ObjectValueProvider(values) })\n}\n\ndescribe('parser (parseFormula)', () => {\n it('숫자/소수를 파싱한다', () => {\n expect(parseFormula('42')).toEqual({ type: 'number', value: 42 })\n expect(parseFormula('3.14')).toEqual({ type: 'number', value: 3.14 })\n })\n\n it('대괄호 변수(한글·공백 포함)를 파싱하고 대괄호를 벗긴다', () => {\n expect(parseFormula('[재해 건수]')).toEqual({ type: 'variable', name: '재해 건수' })\n })\n\n it('bare 식별자를 변수로 파싱한다', () => {\n expect(parseFormula('x11')).toEqual({ type: 'variable', name: 'x11' })\n })\n\n it('사칙연산 우선순위(*,/ 가 +,- 보다 높음)를 지킨다', () => {\n const ast = parseFormula('1 + 2 * 3')\n // + 가 최상위, 오른쪽이 (2*3)\n expect(ast).toMatchObject({ type: 'binary', op: '+', right: { type: 'binary', op: '*' } })\n })\n\n it('괄호로 우선순위를 바꾼다', () => {\n const ast = parseFormula('(1 + 2) * 3')\n expect(ast).toMatchObject({ type: 'binary', op: '*', left: { type: 'binary', op: '+' } })\n })\n\n it('단항 마이너스를 파싱한다', () => {\n expect(parseFormula('-5')).toEqual({ type: 'unary', op: '-', arg: { type: 'number', value: 5 } })\n })\n\n it('함수 호출을 파싱한다', () => {\n const ast = parseFormula('sum(1, 2, 3)')\n expect(ast).toMatchObject({ type: 'function', name: 'sum' })\n expect((ast as any).args).toHaveLength(3)\n })\n\n it('잘못된 토큰/불완전 수식은 throw 한다', () => {\n expect(() => parseFormula('1 @ 2')).toThrow()\n expect(() => parseFormula('[a] +')).toThrow()\n expect(() => parseFormula('(1 + 2')).toThrow()\n })\n})\n\ndescribe('collectVariableNames', () => {\n it('대괄호 한글 변수명을 정확히 수집한다 (정규식이 놓치는 케이스)', () => {\n const ast = parseFormula('[실제공사기간] / [연면적]')\n expect(collectVariableNames(ast).sort()).toEqual(['실제공사기간', '연면적'].sort())\n })\n\n it('중복을 제거한다', () => {\n const ast = parseFormula('([계획공사비] - [계획공사비]) / [계획공사비]')\n expect(collectVariableNames(ast)).toEqual(['계획공사비'])\n })\n\n it('함수 인자 안의 변수도 수집한다', () => {\n const ast = parseFormula('round([a] / [b], 2)')\n expect(collectVariableNames(ast).sort()).toEqual(['a', 'b'])\n })\n\n it('변수가 없으면 빈 배열', () => {\n expect(collectVariableNames(parseFormula('1 + 2'))).toEqual([])\n })\n})\n\ndescribe('evaluator — 연산', () => {\n it('사칙연산과 우선순위', async () => {\n expect(await evalWith('1 + 2 * 3')).toBe(7)\n expect(await evalWith('(1 + 2) * 3')).toBe(9)\n expect(await evalWith('10 / 4')).toBe(2.5)\n expect(await evalWith('-5 + 3')).toBe(-2)\n })\n\n it('변수를 provider 로 해석한다 (대괄호 한글 포함)', async () => {\n expect(await evalWith('[a] / [b]', { a: 10, b: 2 })).toBe(5)\n expect(await evalWith('[재해 건수] / [연간 근로자 수] * 100', { '재해 건수': 5, '연간 근로자 수': 1000 })).toBeCloseTo(0.5)\n })\n\n it('알 수 없는 함수는 throw', async () => {\n await expect(evalWith('nope(1)')).rejects.toThrow(/Unknown function/)\n })\n})\n\ndescribe('builtinFunctions', () => {\n it('sum/avg/min/max/round/if', async () => {\n expect(await evalWith('sum(1, 2, 3)')).toBe(6)\n expect(await evalWith('avg(2, 4, 6)')).toBe(4)\n expect(await evalWith('min(3, 1, 2)')).toBe(1)\n expect(await evalWith('max(3, 1, 2)')).toBe(3)\n expect(await evalWith('round(3.14159, 2)')).toBe(3.14)\n expect(await evalWith('if(1, 10, 20)')).toBe(10)\n expect(await evalWith('if(0, 10, 20)')).toBe(20)\n })\n})\n\n/**\n * 회귀 방어: kpi 모듈 seed(kpis-seed.json)의 실제 formula 코퍼스.\n * 이 formula들은 dkpi 런타임에서 AST 엔진으로 평가되므로, 파싱·변수추출·평가가\n * 깨지면 dkpi 가 깨진다. (P0-1: aggregate 경로도 이제 이 엔진을 씀)\n */\ndescribe('seed formula 코퍼스 (회귀 방어)', () => {\n const SEED_FORMULAS = [\n '[실제공사기간] / [연면적]',\n '([실제공사기간] - [계획공사기간]) / [계획공사기간]',\n '[일정 이탈 수준]',\n '[실제공사비] / [연면적]',\n '([실제공사비]-[계획공사비]) / [계획공사비]',\n '[품질시험 불합격 건수] / [연면적]',\n '[재해 건수] / [연간 근로자 수] * 100',\n '[노동손실일수] / ( [총 근로자수] * [1인당 연간 근로 시간] ) * 1000',\n '[총 건설 폐기물 발생량] / [연면적]',\n '[투입인력] / [연면적]'\n ]\n\n it.each(SEED_FORMULAS)('파싱되고 변수추출된다: %s', formula => {\n const ast = parseFormula(formula)\n const vars = collectVariableNames(ast)\n expect(Array.isArray(vars)).toBe(true)\n // 단일 변수 formula 도 최소 1개 이상\n expect(vars.length).toBeGreaterThanOrEqual(1)\n })\n\n it('대표 formula 들이 올바른 수치를 낸다', async () => {\n expect(await evalWith('[실제공사기간] / [연면적]', { 실제공사기간: 300, 연면적: 1500 })).toBeCloseTo(0.2)\n expect(\n await evalWith('([실제공사비]-[계획공사비]) / [계획공사비]', { 실제공사비: 1200, 계획공사비: 1000 })\n ).toBeCloseTo(0.2)\n expect(\n await evalWith('[노동손실일수] / ( [총 근로자수] * [1인당 연간 근로 시간] ) * 1000', {\n 노동손실일수: 10,\n '총 근로자수': 100,\n '1인당 연간 근로 시간': 2000\n })\n ).toBeCloseTo(0.05)\n // 단일 변수 pass-through\n expect(await evalWith('[일정 이탈 수준]', { '일정 이탈 수준': 3 })).toBe(3)\n })\n})\n"]}
@@ -0,0 +1,8 @@
1
+ import type { FormulaNode } from './parser';
2
+ import type { FormulaFunctionMap } from './functions';
3
+ import type { ValueProvider } from './provider';
4
+ export interface EvalContext {
5
+ functions: FormulaFunctionMap;
6
+ provider: ValueProvider;
7
+ }
8
+ export declare function evaluateFormula(node: FormulaNode, ctx: EvalContext): Promise<any>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.evaluateFormula = evaluateFormula;
4
+ // 비동기 evaluator만 유지, 함수명은 evaluateFormula로 단순화
5
+ async function evaluateFormula(node, ctx) {
6
+ switch (node.type) {
7
+ case 'number':
8
+ return node.value;
9
+ case 'variable':
10
+ return await ctx.provider.get(node.name);
11
+ case 'function': {
12
+ const fn = ctx.functions[node.name];
13
+ if (!fn)
14
+ throw new Error('Unknown function: ' + node.name);
15
+ const args = await Promise.all(node.args.map(arg => evaluateFormula(arg, ctx)));
16
+ return fn(...args);
17
+ }
18
+ case 'binary': {
19
+ const l = await evaluateFormula(node.left, ctx);
20
+ const r = await evaluateFormula(node.right, ctx);
21
+ switch (node.op) {
22
+ case '+':
23
+ return l + r;
24
+ case '-':
25
+ return l - r;
26
+ case '*':
27
+ return l * r;
28
+ case '/':
29
+ return l / r;
30
+ default:
31
+ throw new Error('Unknown operator: ' + node.op);
32
+ }
33
+ }
34
+ case 'unary':
35
+ if (node.op === '-')
36
+ return -(await evaluateFormula(node.arg, ctx));
37
+ throw new Error('Unknown unary operator: ' + node.op);
38
+ default:
39
+ throw new Error('Unknown node type: ' + node.type);
40
+ }
41
+ }
42
+ //# sourceMappingURL=evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../server/calculator/evaluator.ts"],"names":[],"mappings":";;AAUA,0CAkCC;AAnCD,+CAA+C;AACxC,KAAK,UAAU,eAAe,CAAC,IAAiB,EAAE,GAAgB;IACvE,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,QAAQ;YACX,OAAO,IAAI,CAAC,KAAK,CAAA;QACnB,KAAK,UAAU;YACb,OAAO,MAAM,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC1C,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnC,IAAI,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC/E,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;QACpB,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;YAC/C,MAAM,CAAC,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;YAChD,QAAQ,IAAI,CAAC,EAAE,EAAE,CAAC;gBAChB,KAAK,GAAG;oBACN,OAAO,CAAC,GAAG,CAAC,CAAA;gBACd,KAAK,GAAG;oBACN,OAAO,CAAC,GAAG,CAAC,CAAA;gBACd,KAAK,GAAG;oBACN,OAAO,CAAC,GAAG,CAAC,CAAA;gBACd,KAAK,GAAG;oBACN,OAAO,CAAC,GAAG,CAAC,CAAA;gBACd;oBACE,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;YACnD,CAAC;QACH,CAAC;QACD,KAAK,OAAO;YACV,IAAI,IAAI,CAAC,EAAE,KAAK,GAAG;gBAAE,OAAO,CAAC,CAAC,MAAM,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;YACnE,MAAM,IAAI,KAAK,CAAC,0BAA0B,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;QACvD;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAI,IAAY,CAAC,IAAI,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC","sourcesContent":["import type { FormulaNode } from './parser'\nimport type { FormulaFunctionMap } from './functions'\nimport type { ValueProvider } from './provider'\n\nexport interface EvalContext {\n functions: FormulaFunctionMap\n provider: ValueProvider\n}\n\n// 비동기 evaluator만 유지, 함수명은 evaluateFormula로 단순화\nexport async function evaluateFormula(node: FormulaNode, ctx: EvalContext): Promise<any> {\n switch (node.type) {\n case 'number':\n return node.value\n case 'variable':\n return await ctx.provider.get(node.name)\n case 'function': {\n const fn = ctx.functions[node.name]\n if (!fn) throw new Error('Unknown function: ' + node.name)\n const args = await Promise.all(node.args.map(arg => evaluateFormula(arg, ctx)))\n return fn(...args)\n }\n case 'binary': {\n const l = await evaluateFormula(node.left, ctx)\n const r = await evaluateFormula(node.right, ctx)\n switch (node.op) {\n case '+':\n return l + r\n case '-':\n return l - r\n case '*':\n return l * r\n case '/':\n return l / r\n default:\n throw new Error('Unknown operator: ' + node.op)\n }\n }\n case 'unary':\n if (node.op === '-') return -(await evaluateFormula(node.arg, ctx))\n throw new Error('Unknown unary operator: ' + node.op)\n default:\n throw new Error('Unknown node type: ' + (node as any).type)\n }\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export type FormulaFunction = (...args: any[]) => any;
2
+ export type FormulaFunctionMap = Record<string, FormulaFunction>;
3
+ export declare const builtinFunctions: FormulaFunctionMap;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.builtinFunctions = void 0;
4
+ exports.builtinFunctions = {
5
+ sum: (...args) => args.reduce((a, b) => a + b, 0),
6
+ avg: (...args) => (args.length ? args.reduce((a, b) => a + b, 0) / args.length : 0),
7
+ min: (...args) => Math.min(...args),
8
+ max: (...args) => Math.max(...args),
9
+ round: (v, d = 0) => Number(v.toFixed(d)),
10
+ if: (cond, t, f) => (cond ? t : f),
11
+ // 성과 지수 계산을 위한 수치 적분 함수들
12
+ integrate: (func, a, b, n = 1000) => {
13
+ // 사다리꼴 적분법 (Trapezoidal Rule)
14
+ const h = (b - a) / n;
15
+ let sum = (func(a) + func(b)) / 2;
16
+ for (let i = 1; i < n; i++) {
17
+ sum += func(a + i * h);
18
+ }
19
+ return sum * h;
20
+ },
21
+ beta_integrand: (t, alpha, beta) => {
22
+ // 베타 분포 피적분함수: t^(α-1) × (1-t)^(β-1)
23
+ return Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1);
24
+ },
25
+ incomplete_beta: (x, alpha, beta) => {
26
+ // 불완전 베타 함수 계산
27
+ const func = (t) => Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1);
28
+ const h = x / 1000;
29
+ let sum = (func(0) + func(x)) / 2;
30
+ for (let i = 1; i < 1000; i++) {
31
+ sum += func(i * h);
32
+ }
33
+ return sum * h;
34
+ },
35
+ complete_beta: (alpha, beta) => {
36
+ // 완전 베타 함수 계산
37
+ const func = (t) => Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1);
38
+ const h = 1 / 1000;
39
+ let sum = (func(0) + func(1)) / 2;
40
+ for (let i = 1; i < 1000; i++) {
41
+ sum += func(i * h);
42
+ }
43
+ return sum * h;
44
+ },
45
+ performance_index: (x, alpha1, beta1, alpha2, beta2) => {
46
+ // 성과 지수 계산: 1 - (불완전 베타 / 완전 베타)
47
+ const numerator = exports.builtinFunctions.incomplete_beta(x, alpha1, beta1);
48
+ const denominator = exports.builtinFunctions.complete_beta(alpha2, beta2);
49
+ return 1 - numerator / denominator;
50
+ },
51
+ // 지수 함수들
52
+ exp: (x) => Math.exp(x),
53
+ log: (x) => Math.log(x),
54
+ pow: (x, y) => Math.pow(x, y),
55
+ // 지수 감쇠 성과 지수
56
+ exponential_decay: (value, scale, power) => {
57
+ // exp(-(value / scale)^power)
58
+ return Math.exp(-Math.pow(value / scale, power));
59
+ }
60
+ // 필요시 확장
61
+ };
62
+ //# sourceMappingURL=functions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.js","sourceRoot":"","sources":["../../server/calculator/functions.ts"],"names":[],"mappings":"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","sourcesContent":["export type FormulaFunction = (...args: any[]) => any\nexport type FormulaFunctionMap = Record<string, FormulaFunction>\n\nexport const builtinFunctions: FormulaFunctionMap = {\n sum: (...args: any[]) => args.reduce((a, b) => a + b, 0),\n avg: (...args: any[]) => (args.length ? args.reduce((a, b) => a + b, 0) / args.length : 0),\n min: (...args: any[]) => Math.min(...args),\n max: (...args: any[]) => Math.max(...args),\n round: (v: number, d: number = 0) => Number(v.toFixed(d)),\n if: (cond: any, t: any, f: any) => (cond ? t : f),\n // 성과 지수 계산을 위한 수치 적분 함수들\n integrate: (func: Function, a: number, b: number, n: number = 1000) => {\n // 사다리꼴 적분법 (Trapezoidal Rule)\n const h = (b - a) / n\n let sum = (func(a) + func(b)) / 2\n for (let i = 1; i < n; i++) {\n sum += func(a + i * h)\n }\n return sum * h\n },\n\n beta_integrand: (t: number, alpha: number, beta: number) => {\n // 베타 분포 피적분함수: t^(α-1) × (1-t)^(β-1)\n return Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1)\n },\n\n incomplete_beta: (x: number, alpha: number, beta: number) => {\n // 불완전 베타 함수 계산\n const func = (t: number) => Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1)\n const h = x / 1000\n let sum = (func(0) + func(x)) / 2\n for (let i = 1; i < 1000; i++) {\n sum += func(i * h)\n }\n return sum * h\n },\n\n complete_beta: (alpha: number, beta: number) => {\n // 완전 베타 함수 계산\n const func = (t: number) => Math.pow(t, alpha - 1) * Math.pow(1 - t, beta - 1)\n const h = 1 / 1000\n let sum = (func(0) + func(1)) / 2\n for (let i = 1; i < 1000; i++) {\n sum += func(i * h)\n }\n return sum * h\n },\n\n performance_index: (x: number, alpha1: number, beta1: number, alpha2: number, beta2: number) => {\n // 성과 지수 계산: 1 - (불완전 베타 / 완전 베타)\n const numerator = builtinFunctions.incomplete_beta(x, alpha1, beta1)\n const denominator = builtinFunctions.complete_beta(alpha2, beta2)\n return 1 - numerator / denominator\n },\n\n // 지수 함수들\n exp: (x: number) => Math.exp(x),\n log: (x: number) => Math.log(x),\n pow: (x: number, y: number) => Math.pow(x, y),\n\n // 지수 감쇠 성과 지수\n exponential_decay: (value: number, scale: number, power: number) => {\n // exp(-(value / scale)^power)\n return Math.exp(-Math.pow(value / scale, power))\n }\n // 필요시 확장\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export * from './parser.js';
2
+ export * from './evaluator.js';
3
+ export * from './functions.js';
4
+ export * from './provider.js';
5
+ export * from './validate.js';
6
+ export * from './score.js';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./parser.js"), exports);
5
+ tslib_1.__exportStar(require("./evaluator.js"), exports);
6
+ tslib_1.__exportStar(require("./functions.js"), exports);
7
+ tslib_1.__exportStar(require("./provider.js"), exports);
8
+ tslib_1.__exportStar(require("./validate.js"), exports);
9
+ tslib_1.__exportStar(require("./score.js"), exports);
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/calculator/index.ts"],"names":[],"mappings":";;;AAAA,sDAA2B;AAC3B,yDAA8B;AAC9B,yDAA8B;AAC9B,wDAA6B;AAC7B,wDAA6B;AAC7B,qDAA0B","sourcesContent":["export * from './parser.js'\nexport * from './evaluator.js'\nexport * from './functions.js'\nexport * from './provider.js'\nexport * from './validate.js'\nexport * from './score.js'\n"]}
@@ -0,0 +1,34 @@
1
+ export type FormulaNode = {
2
+ type: 'number';
3
+ value: number;
4
+ } | {
5
+ type: 'variable';
6
+ name: string;
7
+ } | {
8
+ type: 'function';
9
+ name: string;
10
+ args: FormulaNode[];
11
+ } | {
12
+ type: 'binary';
13
+ op: string;
14
+ left: FormulaNode;
15
+ right: FormulaNode;
16
+ } | {
17
+ type: 'unary';
18
+ op: string;
19
+ arg: FormulaNode;
20
+ };
21
+ export declare function parseFormula(formula: string): FormulaNode;
22
+ /**
23
+ * AST 안의 모든 변수명을 (중복 제거하여) 수집한다.
24
+ *
25
+ * 정규식 기반 추출(예: `[a-zA-Z_]\w*`)은 `[한글 변수명]`·공백 포함 이름을 놓치지만,
26
+ * 파서가 만든 AST 의 variable 노드는 대괄호가 벗겨진 실제 이름을 담으므로 정확하다.
27
+ * aggregate 등에서 "이 수식이 참조하는 metric 이름들"을 얻는 신뢰 가능한 경로.
28
+ */
29
+ export declare function collectVariableNames(node: FormulaNode): string[];
30
+ /**
31
+ * AST 안의 모든 함수명을 (중복 제거하여) 수집한다.
32
+ * formula 검증에서 "알 수 없는 함수" 를 잡는 데 쓴다.
33
+ */
34
+ export declare function collectFunctionNames(node: FormulaNode): string[];