@intentius/chant-lexicon-grafana 0.97.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/README.md +15 -5
  2. package/dist/actions/grafana.d.ts +24 -0
  3. package/dist/actions/grafana.d.ts.map +1 -0
  4. package/dist/actions/index.d.ts +2 -0
  5. package/dist/actions/index.d.ts.map +1 -0
  6. package/dist/alerting-build.d.ts +128 -0
  7. package/dist/alerting-build.d.ts.map +1 -0
  8. package/dist/alerting.d.ts +273 -0
  9. package/dist/alerting.d.ts.map +1 -0
  10. package/dist/api/apply.d.ts +156 -0
  11. package/dist/api/apply.d.ts.map +1 -0
  12. package/dist/api/bind.d.ts +32 -0
  13. package/dist/api/bind.d.ts.map +1 -0
  14. package/dist/api/client.d.ts +76 -0
  15. package/dist/api/client.d.ts.map +1 -0
  16. package/dist/api/converge.d.ts +33 -0
  17. package/dist/api/converge.d.ts.map +1 -0
  18. package/dist/api/dashboards.d.ts +102 -0
  19. package/dist/api/dashboards.d.ts.map +1 -0
  20. package/dist/api/datasources.d.ts +26 -0
  21. package/dist/api/datasources.d.ts.map +1 -0
  22. package/dist/api/fake-grafana-writes.d.ts +41 -0
  23. package/dist/api/fake-grafana-writes.d.ts.map +1 -0
  24. package/dist/api/fake-grafana.d.ts +61 -0
  25. package/dist/api/fake-grafana.d.ts.map +1 -0
  26. package/dist/api/folders.d.ts +110 -0
  27. package/dist/api/folders.d.ts.map +1 -0
  28. package/dist/api/library-panels.d.ts +52 -0
  29. package/dist/api/library-panels.d.ts.map +1 -0
  30. package/dist/build.d.ts +30 -2
  31. package/dist/build.d.ts.map +1 -1
  32. package/dist/catalog.d.ts +1 -1
  33. package/dist/catalog.d.ts.map +1 -1
  34. package/dist/codegen/docs.d.ts.map +1 -1
  35. package/dist/codegen/schema-types.d.ts +3 -3
  36. package/dist/codegen/schema-types.d.ts.map +1 -1
  37. package/dist/composites/agent-dashboard.d.ts.map +1 -1
  38. package/dist/composites/catalog.d.ts.map +1 -1
  39. package/dist/composites/index.d.ts +4 -2
  40. package/dist/composites/index.d.ts.map +1 -1
  41. package/dist/composites/red-dashboard.d.ts +21 -2
  42. package/dist/composites/red-dashboard.d.ts.map +1 -1
  43. package/dist/composites/shared.d.ts +7 -0
  44. package/dist/composites/shared.d.ts.map +1 -1
  45. package/dist/composites/slo-alert-rules.d.ts +92 -0
  46. package/dist/composites/slo-alert-rules.d.ts.map +1 -0
  47. package/dist/config.d.ts +111 -0
  48. package/dist/config.d.ts.map +1 -0
  49. package/dist/contact-point-secrets.d.ts +17 -0
  50. package/dist/contact-point-secrets.d.ts.map +1 -0
  51. package/dist/dashboard.d.ts +16 -2
  52. package/dist/dashboard.d.ts.map +1 -1
  53. package/dist/datasource-refs.d.ts +95 -0
  54. package/dist/datasource-refs.d.ts.map +1 -0
  55. package/dist/datasource.d.ts +29 -0
  56. package/dist/datasource.d.ts.map +1 -1
  57. package/dist/deep-observe-hooks.d.ts +64 -0
  58. package/dist/deep-observe-hooks.d.ts.map +1 -0
  59. package/dist/deep-observe.d.ts +42 -0
  60. package/dist/deep-observe.d.ts.map +1 -0
  61. package/dist/describe-resources.d.ts +49 -0
  62. package/dist/describe-resources.d.ts.map +1 -0
  63. package/dist/detect.d.ts +28 -1
  64. package/dist/detect.d.ts.map +1 -1
  65. package/dist/export-resources.d.ts +38 -0
  66. package/dist/export-resources.d.ts.map +1 -0
  67. package/dist/import/alerting.d.ts +40 -0
  68. package/dist/import/alerting.d.ts.map +1 -0
  69. package/dist/import/edits.d.ts +47 -0
  70. package/dist/import/edits.d.ts.map +1 -0
  71. package/dist/import/embedded.d.ts +14 -0
  72. package/dist/import/embedded.d.ts.map +1 -0
  73. package/dist/import/generator.d.ts +60 -0
  74. package/dist/import/generator.d.ts.map +1 -0
  75. package/dist/import/live-export.d.ts +108 -0
  76. package/dist/import/live-export.d.ts.map +1 -0
  77. package/dist/import/mappings.d.ts +83 -0
  78. package/dist/import/mappings.d.ts.map +1 -0
  79. package/dist/import/model.d.ts +98 -0
  80. package/dist/import/model.d.ts.map +1 -0
  81. package/dist/import/normalize-alerting.d.ts +26 -0
  82. package/dist/import/normalize-alerting.d.ts.map +1 -0
  83. package/dist/import/normalize.d.ts +74 -0
  84. package/dist/import/normalize.d.ts.map +1 -0
  85. package/dist/import/parser.d.ts +110 -0
  86. package/dist/import/parser.d.ts.map +1 -0
  87. package/dist/import/report.d.ts +26 -0
  88. package/dist/import/report.d.ts.map +1 -0
  89. package/dist/import/testdata/fixtures.d.ts +35 -0
  90. package/dist/import/testdata/fixtures.d.ts.map +1 -0
  91. package/dist/import/v2.d.ts +72 -0
  92. package/dist/import/v2.d.ts.map +1 -0
  93. package/dist/index.d.ts +26 -9
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/integrity.json +18 -10
  96. package/dist/k8s.d.ts +107 -0
  97. package/dist/k8s.d.ts.map +1 -0
  98. package/dist/lint/audit-catalog.d.ts +2 -1
  99. package/dist/lint/audit-catalog.d.ts.map +1 -1
  100. package/dist/lint/post-synth/graf101.d.ts +2 -2
  101. package/dist/lint/post-synth/graf102.d.ts +1 -1
  102. package/dist/lint/post-synth/graf107.d.ts +1 -1
  103. package/dist/lint/post-synth/graf108.d.ts +8 -0
  104. package/dist/lint/post-synth/graf108.d.ts.map +1 -0
  105. package/dist/lint/post-synth/graf109.d.ts +8 -0
  106. package/dist/lint/post-synth/graf109.d.ts.map +1 -0
  107. package/dist/lint/post-synth/graf111.d.ts +8 -0
  108. package/dist/lint/post-synth/graf111.d.ts.map +1 -0
  109. package/dist/lint/post-synth/graf112.d.ts +8 -0
  110. package/dist/lint/post-synth/graf112.d.ts.map +1 -0
  111. package/dist/lint/post-synth/graf113.d.ts +8 -0
  112. package/dist/lint/post-synth/graf113.d.ts.map +1 -0
  113. package/dist/lint/post-synth/graf114.d.ts +8 -0
  114. package/dist/lint/post-synth/graf114.d.ts.map +1 -0
  115. package/dist/lint/post-synth/graf115.d.ts +8 -0
  116. package/dist/lint/post-synth/graf115.d.ts.map +1 -0
  117. package/dist/lint/post-synth/grafana-helpers.d.ts +7 -5
  118. package/dist/lint/post-synth/grafana-helpers.d.ts.map +1 -1
  119. package/dist/lint/post-synth/index.d.ts.map +1 -1
  120. package/dist/lint/rules/literal-secret.d.ts +7 -3
  121. package/dist/lint/rules/literal-secret.d.ts.map +1 -1
  122. package/dist/lsp/hover.d.ts.map +1 -1
  123. package/dist/manifest.json +1 -1
  124. package/dist/members.d.ts +27 -0
  125. package/dist/members.d.ts.map +1 -0
  126. package/dist/meta.json +135 -0
  127. package/dist/okf/index.md +36 -2
  128. package/dist/okf/rules/GRAF002.md +3 -2
  129. package/dist/okf/rules/GRAF101.md +3 -2
  130. package/dist/okf/rules/GRAF102.md +1 -0
  131. package/dist/okf/rules/GRAF108.md +11 -0
  132. package/dist/okf/rules/GRAF109.md +15 -0
  133. package/dist/okf/rules/GRAF111.md +11 -0
  134. package/dist/okf/rules/GRAF112.md +16 -0
  135. package/dist/okf/rules/GRAF113.md +16 -0
  136. package/dist/okf/rules/GRAF114.md +11 -0
  137. package/dist/okf/rules/GRAF115.md +11 -0
  138. package/dist/okf/types/AlertListPanel.md +9 -0
  139. package/dist/okf/types/AlertQuery.md +9 -0
  140. package/dist/okf/types/AlertRule.md +9 -0
  141. package/dist/okf/types/AlertRuleGroup.md +9 -0
  142. package/dist/okf/types/BarChartPanel.md +9 -0
  143. package/dist/okf/types/BarGaugePanel.md +9 -0
  144. package/dist/okf/types/CanvasPanel.md +9 -0
  145. package/dist/okf/types/ClassicConditionsExpression.md +9 -0
  146. package/dist/okf/types/ContactPoint.md +14 -0
  147. package/dist/okf/types/Dashboard.md +1 -0
  148. package/dist/okf/types/Datasource.md +3 -2
  149. package/dist/okf/types/ExternalDatasource.md +15 -0
  150. package/dist/okf/types/FlameGraphPanel.md +9 -0
  151. package/dist/okf/types/GeomapPanel.md +9 -0
  152. package/dist/okf/types/HistogramPanel.md +9 -0
  153. package/dist/okf/types/MathExpression.md +9 -0
  154. package/dist/okf/types/MuteTiming.md +13 -0
  155. package/dist/okf/types/NodeGraphPanel.md +9 -0
  156. package/dist/okf/types/NotificationPolicy.md +9 -0
  157. package/dist/okf/types/NotificationTemplate.md +9 -0
  158. package/dist/okf/types/PieChartPanel.md +9 -0
  159. package/dist/okf/types/ReduceExpression.md +9 -0
  160. package/dist/okf/types/ResampleExpression.md +9 -0
  161. package/dist/okf/types/SqlExpression.md +9 -0
  162. package/dist/okf/types/StateTimelinePanel.md +9 -0
  163. package/dist/okf/types/StatusHistoryPanel.md +9 -0
  164. package/dist/okf/types/ThresholdExpression.md +9 -0
  165. package/dist/okf/types/TrendPanel.md +9 -0
  166. package/dist/okf/types/XYChartPanel.md +9 -0
  167. package/dist/op/activities/grafana-apply.d.ts +75 -0
  168. package/dist/op/activities/grafana-apply.d.ts.map +1 -0
  169. package/dist/op/activities/index.d.ts +9 -0
  170. package/dist/op/activities/index.d.ts.map +1 -0
  171. package/dist/op/builders.d.ts +24 -0
  172. package/dist/op/builders.d.ts.map +1 -0
  173. package/dist/ownership.d.ts +67 -0
  174. package/dist/ownership.d.ts.map +1 -0
  175. package/dist/panel-options.d.ts +65 -0
  176. package/dist/panel-options.d.ts.map +1 -0
  177. package/dist/panels.d.ts +46 -9
  178. package/dist/panels.d.ts.map +1 -1
  179. package/dist/pin.d.ts +29 -7
  180. package/dist/pin.d.ts.map +1 -1
  181. package/dist/plugin.d.ts.map +1 -1
  182. package/dist/promql-check.d.ts +51 -0
  183. package/dist/promql-check.d.ts.map +1 -0
  184. package/dist/query.d.ts +9 -8
  185. package/dist/query.d.ts.map +1 -1
  186. package/dist/rules/graf101.ts +3 -3
  187. package/dist/rules/graf102.ts +1 -1
  188. package/dist/rules/graf107.ts +1 -1
  189. package/dist/rules/graf108.ts +17 -0
  190. package/dist/rules/graf109.ts +17 -0
  191. package/dist/rules/graf111.ts +17 -0
  192. package/dist/rules/graf112.ts +17 -0
  193. package/dist/rules/graf113.ts +17 -0
  194. package/dist/rules/graf114.ts +17 -0
  195. package/dist/rules/graf115.ts +17 -0
  196. package/dist/rules/grafana-helpers.ts +15 -8
  197. package/dist/rules/literal-secret.ts +60 -6
  198. package/dist/schema/barchart.gen.d.ts +198 -0
  199. package/dist/schema/barchart.gen.d.ts.map +1 -0
  200. package/dist/schema/bargauge.gen.d.ts +97 -0
  201. package/dist/schema/bargauge.gen.d.ts.map +1 -0
  202. package/dist/schema/canvas.gen.d.ts +152 -0
  203. package/dist/schema/canvas.gen.d.ts.map +1 -0
  204. package/dist/schema/dashboard.gen.d.ts +196 -21
  205. package/dist/schema/dashboard.gen.d.ts.map +1 -1
  206. package/dist/schema/expr.gen.d.ts +606 -0
  207. package/dist/schema/expr.gen.d.ts.map +1 -0
  208. package/dist/schema/gauge.gen.d.ts.map +1 -1
  209. package/dist/schema/geomap.gen.d.ts +100 -0
  210. package/dist/schema/geomap.gen.d.ts.map +1 -0
  211. package/dist/schema/heatmap.gen.d.ts.map +1 -1
  212. package/dist/schema/histogram.gen.d.ts +132 -0
  213. package/dist/schema/histogram.gen.d.ts.map +1 -0
  214. package/dist/schema/index.d.ts +12 -0
  215. package/dist/schema/index.d.ts.map +1 -1
  216. package/dist/schema/logs.gen.d.ts +1 -0
  217. package/dist/schema/logs.gen.d.ts.map +1 -1
  218. package/dist/schema/loki.gen.d.ts.map +1 -1
  219. package/dist/schema/nodegraph.gen.d.ts +49 -0
  220. package/dist/schema/nodegraph.gen.d.ts.map +1 -0
  221. package/dist/schema/piechart.gen.d.ts +127 -0
  222. package/dist/schema/piechart.gen.d.ts.map +1 -0
  223. package/dist/schema/prometheus.gen.d.ts.map +1 -1
  224. package/dist/schema/stat.gen.d.ts.map +1 -1
  225. package/dist/schema/statetimeline.gen.d.ts +124 -0
  226. package/dist/schema/statetimeline.gen.d.ts.map +1 -0
  227. package/dist/schema/statushistory.gen.d.ts +114 -0
  228. package/dist/schema/statushistory.gen.d.ts.map +1 -0
  229. package/dist/schema/table.gen.d.ts +22 -3
  230. package/dist/schema/table.gen.d.ts.map +1 -1
  231. package/dist/schema/tempo.gen.d.ts.map +1 -1
  232. package/dist/schema/text.gen.d.ts.map +1 -1
  233. package/dist/schema/timeseries.gen.d.ts +5 -1
  234. package/dist/schema/timeseries.gen.d.ts.map +1 -1
  235. package/dist/schema/trend.gen.d.ts +180 -0
  236. package/dist/schema/trend.gen.d.ts.map +1 -0
  237. package/dist/schema/xychart.gen.d.ts +145 -0
  238. package/dist/schema/xychart.gen.d.ts.map +1 -0
  239. package/dist/schema-validate.d.ts +30 -4
  240. package/dist/schema-validate.d.ts.map +1 -1
  241. package/dist/serializer.d.ts +11 -3
  242. package/dist/serializer.d.ts.map +1 -1
  243. package/dist/skill-defs.d.ts.map +1 -1
  244. package/dist/skills/chant-grafana-alerting.md +49 -0
  245. package/dist/skills/chant-grafana-provisioning.md +3 -3
  246. package/dist/skills/chant-grafana.md +12 -6
  247. package/dist/spec/fetch-units-cli.d.ts +3 -0
  248. package/dist/spec/fetch-units-cli.d.ts.map +1 -0
  249. package/dist/spec/overlay.d.ts +43 -0
  250. package/dist/spec/overlay.d.ts.map +1 -0
  251. package/dist/spec/schemas.d.ts +13 -7
  252. package/dist/spec/schemas.d.ts.map +1 -1
  253. package/dist/spec/units.d.ts +35 -0
  254. package/dist/spec/units.d.ts.map +1 -0
  255. package/dist/spec/units.gen.d.ts +2 -0
  256. package/dist/spec/units.gen.d.ts.map +1 -0
  257. package/dist/transformations.d.ts +459 -0
  258. package/dist/transformations.d.ts.map +1 -0
  259. package/dist/util.d.ts +6 -0
  260. package/dist/util.d.ts.map +1 -1
  261. package/dist/validate-alerting.d.ts +65 -0
  262. package/dist/validate-alerting.d.ts.map +1 -0
  263. package/dist/validate-output.d.ts +49 -9
  264. package/dist/validate-output.d.ts.map +1 -1
  265. package/dist/validate.d.ts.map +1 -1
  266. package/dist/variables.d.ts +7 -2
  267. package/dist/variables.d.ts.map +1 -1
  268. package/package.json +12 -4
  269. package/src/actions/actions.test.ts +24 -0
  270. package/src/actions/grafana.ts +40 -0
  271. package/src/actions/index.ts +1 -0
  272. package/src/alerting-build.ts +376 -0
  273. package/src/alerting.e2e.test.ts +212 -0
  274. package/src/alerting.test.ts +272 -0
  275. package/src/alerting.ts +435 -0
  276. package/src/api/apply.test.ts +238 -0
  277. package/src/api/apply.ts +384 -0
  278. package/src/api/bind.ts +58 -0
  279. package/src/api/client.ts +148 -0
  280. package/src/api/converge.ts +63 -0
  281. package/src/api/dashboards.ts +247 -0
  282. package/src/api/datasources.ts +33 -0
  283. package/src/api/fake-grafana-writes.ts +201 -0
  284. package/src/api/fake-grafana.ts +186 -0
  285. package/src/api/folders.ts +265 -0
  286. package/src/api/library-panels.ts +101 -0
  287. package/src/build.test.ts +210 -5
  288. package/src/build.ts +180 -43
  289. package/src/catalog.ts +86 -2
  290. package/src/codegen/docs.ts +42 -9
  291. package/src/codegen/schema-types.ts +16 -6
  292. package/src/composites/agent-dashboard.ts +6 -3
  293. package/src/composites/catalog.test.ts +2 -2
  294. package/src/composites/catalog.ts +82 -0
  295. package/src/composites/composites.test.ts +73 -9
  296. package/src/composites/index.ts +4 -2
  297. package/src/composites/queries.e2e.test.ts +374 -0
  298. package/src/composites/red-dashboard.ts +83 -12
  299. package/src/composites/shared.ts +11 -0
  300. package/src/composites/slo-alert-rules.ts +149 -0
  301. package/src/config.test.ts +61 -0
  302. package/src/config.ts +138 -0
  303. package/src/contact-point-secrets.ts +63 -0
  304. package/src/dashboard.ts +16 -2
  305. package/src/datasource-refs.test.ts +56 -0
  306. package/src/datasource-refs.ts +189 -0
  307. package/src/datasource.ts +52 -0
  308. package/src/deep-observe-hooks.ts +252 -0
  309. package/src/deep-observe.test.ts +265 -0
  310. package/src/deep-observe.ts +164 -0
  311. package/src/describe-resources.test.ts +255 -0
  312. package/src/describe-resources.ts +209 -0
  313. package/src/detect.ts +79 -2
  314. package/src/export-resources.test.ts +129 -0
  315. package/src/export-resources.ts +84 -0
  316. package/src/generated/lexicon-grafana.json +135 -0
  317. package/src/import/alerting-roundtrip.test.ts +161 -0
  318. package/src/import/alerting.ts +500 -0
  319. package/src/import/edits.ts +95 -0
  320. package/src/import/embedded.test.ts +45 -0
  321. package/src/import/embedded.ts +47 -0
  322. package/src/import/generated-types.e2e.test.ts +118 -0
  323. package/src/import/generator.test.ts +210 -0
  324. package/src/import/generator.ts +462 -0
  325. package/src/import/live-export.ts +264 -0
  326. package/src/import/mappings.ts +264 -0
  327. package/src/import/model.ts +110 -0
  328. package/src/import/normalize-alerting.ts +101 -0
  329. package/src/import/normalize.test.ts +117 -0
  330. package/src/import/normalize.ts +364 -0
  331. package/src/import/parser.test.ts +440 -0
  332. package/src/import/parser.ts +1236 -0
  333. package/src/import/report.ts +62 -0
  334. package/src/import/roundtrip.test.ts +468 -0
  335. package/src/import/testdata/fixtures.ts +129 -0
  336. package/src/import/v2.test.ts +292 -0
  337. package/src/import/v2.ts +803 -0
  338. package/src/import.e2e.test.ts +31 -84
  339. package/src/import.test.ts +9 -3
  340. package/src/index.ts +190 -5
  341. package/src/k8s.test.ts +98 -0
  342. package/src/k8s.ts +197 -0
  343. package/src/lint/audit-catalog.ts +60 -3
  344. package/src/lint/core-lint.test.ts +43 -0
  345. package/src/lint/post-synth/graf101.ts +3 -3
  346. package/src/lint/post-synth/graf102.ts +1 -1
  347. package/src/lint/post-synth/graf107.ts +1 -1
  348. package/src/lint/post-synth/graf108.ts +17 -0
  349. package/src/lint/post-synth/graf109.ts +17 -0
  350. package/src/lint/post-synth/graf111.ts +17 -0
  351. package/src/lint/post-synth/graf112.ts +17 -0
  352. package/src/lint/post-synth/graf113.ts +17 -0
  353. package/src/lint/post-synth/graf114.ts +17 -0
  354. package/src/lint/post-synth/graf115.ts +17 -0
  355. package/src/lint/post-synth/grafana-helpers.ts +15 -8
  356. package/src/lint/post-synth/index.ts +14 -0
  357. package/src/lint/post-synth/post-synth.test.ts +235 -11
  358. package/src/lint/rules/literal-secret.ts +60 -6
  359. package/src/lint/rules/rules.test.ts +27 -0
  360. package/src/lsp/completions.test.ts +5 -0
  361. package/src/lsp/hover.test.ts +7 -0
  362. package/src/lsp/hover.ts +8 -1
  363. package/src/members.ts +68 -0
  364. package/src/observe.e2e.test.ts +255 -0
  365. package/src/op/activities/grafana-apply.e2e.test.ts +175 -0
  366. package/src/op/activities/grafana-apply.test.ts +229 -0
  367. package/src/op/activities/grafana-apply.ts +171 -0
  368. package/src/op/activities/index.ts +8 -0
  369. package/src/op/builders.test.ts +40 -0
  370. package/src/op/builders.ts +34 -0
  371. package/src/ownership.ts +103 -0
  372. package/src/panel-options.ts +66 -0
  373. package/src/panels.test.ts +51 -0
  374. package/src/panels.ts +148 -10
  375. package/src/pin.ts +57 -6
  376. package/src/plugin.test.ts +5 -2
  377. package/src/plugin.ts +66 -0
  378. package/src/promql-check.test.ts +108 -0
  379. package/src/promql-check.ts +189 -0
  380. package/src/query.ts +13 -8
  381. package/src/schema/barchart.gen.ts +221 -0
  382. package/src/schema/bargauge.gen.ts +111 -0
  383. package/src/schema/canvas.gen.ts +176 -0
  384. package/src/schema/dashboard.gen.ts +206 -22
  385. package/src/schema/expr.gen.ts +618 -0
  386. package/src/schema/gauge.gen.ts +2 -1
  387. package/src/schema/geomap.gen.ts +112 -0
  388. package/src/schema/heatmap.gen.ts +2 -1
  389. package/src/schema/histogram.gen.ts +151 -0
  390. package/src/schema/index.ts +12 -0
  391. package/src/schema/logs.gen.ts +3 -1
  392. package/src/schema/loki.gen.ts +2 -1
  393. package/src/schema/nodegraph.gen.ts +58 -0
  394. package/src/schema/piechart.gen.ts +146 -0
  395. package/src/schema/prometheus.gen.ts +2 -1
  396. package/src/schema/stat.gen.ts +2 -1
  397. package/src/schema/statetimeline.gen.ts +143 -0
  398. package/src/schema/statushistory.gen.ts +132 -0
  399. package/src/schema/table.gen.ts +27 -4
  400. package/src/schema/tempo.gen.ts +2 -1
  401. package/src/schema/text.gen.ts +2 -1
  402. package/src/schema/timeseries.gen.ts +7 -2
  403. package/src/schema/trend.gen.ts +208 -0
  404. package/src/schema/xychart.gen.ts +167 -0
  405. package/src/schema-overlay.test.ts +282 -0
  406. package/src/schema-validate.ts +141 -50
  407. package/src/schema.test.ts +4 -2
  408. package/src/serializer.test.ts +13 -1
  409. package/src/serializer.ts +11 -3
  410. package/src/skill-defs.ts +17 -0
  411. package/src/skills/chant-grafana-alerting.md +49 -0
  412. package/src/skills/chant-grafana-provisioning.md +3 -3
  413. package/src/skills/chant-grafana.md +12 -6
  414. package/src/spec/fetch-cli.ts +3 -3
  415. package/src/spec/fetch-units-cli.ts +37 -0
  416. package/src/spec/overlay/canvas.overlay.json +142 -0
  417. package/src/spec/overlay/dashboard.overlay.json +378 -0
  418. package/src/spec/overlay/expr.overlay.json +14 -0
  419. package/src/spec/overlay/geomap.overlay.json +35 -0
  420. package/src/spec/overlay/logs.overlay.json +14 -0
  421. package/src/spec/overlay/nodegraph.overlay.json +31 -0
  422. package/src/spec/overlay/piechart.overlay.json +17 -0
  423. package/src/spec/overlay/table.overlay.json +84 -0
  424. package/src/spec/overlay/timeseries.overlay.json +21 -0
  425. package/src/spec/overlay/trend.overlay.json +17 -0
  426. package/src/spec/overlay/xychart.overlay.json +16 -0
  427. package/src/spec/overlay.ts +105 -0
  428. package/src/spec/schemas/barchart.jsonschema.json +419 -0
  429. package/src/spec/schemas/bargauge.jsonschema.json +224 -0
  430. package/src/spec/schemas/canvas.jsonschema.json +356 -0
  431. package/src/spec/schemas/dashboardv2.jsonschema.json +3387 -0
  432. package/src/spec/schemas/expr.jsonschema.json +987 -0
  433. package/src/spec/schemas/geomap.jsonschema.json +220 -0
  434. package/src/spec/schemas/histogram.jsonschema.json +308 -0
  435. package/src/spec/schemas/nodegraph.jsonschema.json +77 -0
  436. package/src/spec/schemas/piechart.jsonschema.json +275 -0
  437. package/src/spec/schemas/statetimeline.jsonschema.json +324 -0
  438. package/src/spec/schemas/statushistory.jsonschema.json +292 -0
  439. package/src/spec/schemas/trend.jsonschema.json +449 -0
  440. package/src/spec/schemas/xychart.jsonschema.json +428 -0
  441. package/src/spec/schemas.ts +22 -10
  442. package/src/spec/units.gen.ts +281 -0
  443. package/src/spec/units.ts +77 -0
  444. package/src/transformations.test.ts +65 -0
  445. package/src/transformations.ts +574 -0
  446. package/src/util.ts +8 -0
  447. package/src/validate-alerting.test.ts +255 -0
  448. package/src/validate-alerting.ts +428 -0
  449. package/src/validate-output.ts +332 -101
  450. package/src/validate.ts +14 -0
  451. package/src/variables.ts +7 -2
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Live Grafana objects -> chant's vocabulary, pure (#2946).
3
+ *
4
+ * Two consumers, one mapping:
5
+ *
6
+ * - live export (`../export-resources.ts`) turns dashboards and
7
+ * datasources read over the API into `TemplateIR` that feeds
8
+ * `templateGenerator()` unchanged;
9
+ * - deep observation (`../deep-observe.ts`) turns one live dashboard into
10
+ * the property tree core diffs against the declaration.
11
+ *
12
+ * Both go through the importer (`./parser.ts`), so a dashboard read from
13
+ * Grafana and a dashboard file given to `chant import` become the same
14
+ * declarations. The importer is not changed here; this module only reads
15
+ * the plan it makes.
16
+ *
17
+ * ## Why the drift tree is in chant's vocabulary, not Grafana's
18
+ *
19
+ * Core diffs a declaration's `props` (with property-kind declarables, which
20
+ * panels, rows, queries and variables are, inlined as their own props)
21
+ * against the tree a reader returns. A `Dashboard`'s props are what the
22
+ * author wrote: `graphTooltip: "sharedCrosshair"`, `panels: [Row, ...]`, a
23
+ * query with no `refId`. The JSON Grafana stores is what the build wrote
24
+ * from them: `graphTooltip: 1`, a flat panel list, `refId: "A"`. So the
25
+ * live side has to be put into the author's vocabulary, and the importer
26
+ * is exactly that translation, already tested to round-trip. Reading the
27
+ * plan back as one tree (every reference replaced by what it refers to)
28
+ * gives the live counterpart of the declared tree.
29
+ *
30
+ * What the translation cannot decide on its own (a panel `id` the build
31
+ * numbered, a `gridPos` it laid out, the built-in annotation Grafana adds)
32
+ * is noise, and noise is named in `../deep-observe-hooks.ts`, which core
33
+ * applies to both trees.
34
+ */
35
+
36
+ import type { ResourceIR, TemplateIR } from "@intentius/chant/import/parser";
37
+ import { isDeclRef, type Declaration, type Plan } from "./model";
38
+ import {
39
+ DASHBOARD_RESOURCE_TYPE,
40
+ PROVISIONING_RESOURCE_TYPE,
41
+ planDashboard,
42
+ planDatasourceProvisioning,
43
+ type DashboardResourceMetadata,
44
+ type PlanResourceProperties,
45
+ } from "./parser";
46
+
47
+ type Json = Record<string, unknown>;
48
+
49
+ function isObject(v: unknown): v is Json {
50
+ return typeof v === "object" && v !== null && !Array.isArray(v);
51
+ }
52
+
53
+ /**
54
+ * The dashboard declaration of a plan as one property tree: each reference
55
+ * replaced by the props (or, for a `DatasourceRef` const, the value) of the
56
+ * declaration it names, the way core inlines a property-kind declarable.
57
+ */
58
+ export function planTree(plan: Plan): Json {
59
+ const byId = new Map<string, Declaration>(plan.declarations.map((d) => [d.id, d]));
60
+ const resolve = (value: unknown, seen: ReadonlySet<string>): unknown => {
61
+ if (isDeclRef(value)) {
62
+ const decl = byId.get(value.$decl);
63
+ if (!decl || seen.has(decl.id)) return undefined;
64
+ const next = new Set(seen).add(decl.id);
65
+ return resolve(decl.kind === "value" ? decl.value : (decl.props ?? {}), next);
66
+ }
67
+ if (Array.isArray(value)) return value.map((v) => resolve(v, seen)).filter((v) => v !== undefined);
68
+ if (isObject(value)) {
69
+ const out: Json = {};
70
+ for (const [k, v] of Object.entries(value)) {
71
+ const r = resolve(v, seen);
72
+ if (r !== undefined) out[k] = r;
73
+ }
74
+ return out;
75
+ }
76
+ return value;
77
+ };
78
+ const dashboard = byId.get("dashboard");
79
+ if (!dashboard) return {};
80
+ return resolve(dashboard.props ?? {}, new Set(["dashboard"])) as Json;
81
+ }
82
+
83
+ /** One live dashboard (classic JSON) as the property tree core diffs a `Dashboard` declaration against. */
84
+ export function dashboardTree(dashboard: Json): { tree: Json; warnings: string[] } {
85
+ const { plan, warnings } = planDashboard(dashboard);
86
+ return { tree: planTree(plan), warnings };
87
+ }
88
+
89
+ /** The keys a datasource's props take (`DatasourceProps`), in the order they are written. */
90
+ export const DATASOURCE_PROP_KEYS: readonly string[] = [
91
+ "name",
92
+ "type",
93
+ "uid",
94
+ "url",
95
+ "access",
96
+ "isDefault",
97
+ "basicAuth",
98
+ "basicAuthUser",
99
+ "user",
100
+ "database",
101
+ "withCredentials",
102
+ "jsonData",
103
+ "secureJsonData",
104
+ "editable",
105
+ "orgId",
106
+ "version",
107
+ ];
108
+
109
+ /**
110
+ * Grafana's value for a datasource key the API always returns, where it
111
+ * means "not set". Export leaves these out so the generated source says what
112
+ * somebody chose, as a provisioning file would.
113
+ */
114
+ export const DATASOURCE_API_DEFAULTS: Readonly<Json> = {
115
+ access: "proxy",
116
+ isDefault: false,
117
+ basicAuth: false,
118
+ basicAuthUser: "",
119
+ user: "",
120
+ database: "",
121
+ withCredentials: false,
122
+ jsonData: {},
123
+ };
124
+
125
+ /**
126
+ * One datasource from `GET /api/datasources[/uid/<uid>]` in `DatasourceProps`
127
+ * vocabulary.
128
+ *
129
+ * - `readOnly` (the API's word) becomes `editable` (the provisioning file's).
130
+ * - `secureJsonFields` names which secrets are set and never their values;
131
+ * they become `secureJsonData` keys whose value is `[REDACTED]`, so the
132
+ * key set compares and nothing secret is ever held.
133
+ * - `id`, `orgId`, `version`, `typeName`, `typeLogoUrl`, `apiVersion` and the
134
+ * rest are the server's own and are left out.
135
+ *
136
+ * `keepDefaults` keeps keys at the API's "not set" value (`--verbatim`).
137
+ */
138
+ export function datasourceProps(live: Json, options: { keepDefaults?: boolean } = {}): Json {
139
+ const out: Json = {};
140
+ for (const key of DATASOURCE_PROP_KEYS) {
141
+ if (key === "secureJsonData" || key === "editable" || key === "orgId" || key === "version") continue;
142
+ const v = live[key];
143
+ if (v === undefined || v === null) continue;
144
+ if (!options.keepDefaults && key in DATASOURCE_API_DEFAULTS && deepEqualJson(v, DATASOURCE_API_DEFAULTS[key])) continue;
145
+ out[key] = v;
146
+ }
147
+ const secure = isObject(live.secureJsonFields) ? Object.keys(live.secureJsonFields).filter((k) => live.secureJsonFields && (live.secureJsonFields as Json)[k] === true) : [];
148
+ if (secure.length > 0) out.secureJsonData = Object.fromEntries(secure.sort().map((k) => [k, "[REDACTED]"]));
149
+ if (typeof live.readOnly === "boolean") {
150
+ const editable = !live.readOnly;
151
+ if (editable || options.keepDefaults) out.editable = editable;
152
+ }
153
+ return out;
154
+ }
155
+
156
+ function deepEqualJson(a: unknown, b: unknown): boolean {
157
+ return JSON.stringify(a) === JSON.stringify(b);
158
+ }
159
+
160
+ // ── export ──────────────────────────────────────────────────────────
161
+
162
+ /**
163
+ * A dashboard plan whose `ExternalDatasource`s for the given uids are
164
+ * written as plain `{ type, uid }` refs instead.
165
+ *
166
+ * The importer declares an `ExternalDatasource` for each datasource a
167
+ * dashboard names, because a dashboard file alone does not say where its
168
+ * datasources come from. A live export does know, when it exports the
169
+ * datasources too: they become `Datasource` declarations, and an
170
+ * `ExternalDatasource` with the same uid beside them fails the build (two
171
+ * datasources, one uid). A plain ref is what the importer itself writes when
172
+ * it cannot declare an external one (`settleExternals`), and GRAF101 still
173
+ * checks it against the declared `Datasource`.
174
+ */
175
+ export function referDeclaredDatasources(plan: Plan, uids: ReadonlySet<string>): Plan {
176
+ const replaced = new Set<string>();
177
+ const declarations = plan.declarations.map((d): Declaration => {
178
+ if (d.kind !== "new" || d.className !== "ExternalDatasource") return d;
179
+ const { type, uid } = (d.props ?? {}) as { type?: unknown; uid?: unknown };
180
+ if (typeof type !== "string" || typeof uid !== "string" || !uids.has(uid)) return d;
181
+ replaced.add(d.id);
182
+ return {
183
+ id: d.id,
184
+ kind: "value",
185
+ value: { type, uid },
186
+ type: { text: `DatasourceRef<${JSON.stringify(type)}>`, imports: ["DatasourceRef"] },
187
+ name: d.name,
188
+ module: d.module,
189
+ comment: [`// Declared as a Datasource in datasources.ts, which this export also writes.`],
190
+ };
191
+ });
192
+ if (replaced.size === 0) return plan;
193
+ return { ...plan, declarations, exports: plan.exports.filter((id) => !replaced.has(id)) };
194
+ }
195
+
196
+ function logicalIdFor(text: string): string {
197
+ const w = text.split(/[^A-Za-z0-9]+/).filter((x) => x !== "");
198
+ const id = w.map((x, i) => (i === 0 ? x.charAt(0).toLowerCase() + x.slice(1) : x.charAt(0).toUpperCase() + x.slice(1))).join("");
199
+ return id === "" || /^[0-9]/.test(id) ? `dashboard${id.charAt(0).toUpperCase()}${id.slice(1)}` : id;
200
+ }
201
+
202
+ /**
203
+ * Live dashboards and datasources as import IR, for `chant import --from`.
204
+ *
205
+ * Each dashboard is planned by the importer exactly as a dashboard file
206
+ * would be, so the generated TypeScript is what `chant import` writes for
207
+ * the same JSON, except that a datasource exported alongside it is referred
208
+ * to by `{ type, uid }` (see `referDeclaredDatasources`). The datasources are
209
+ * planned as one provisioning file, with
210
+ * the secrets Grafana holds written as `[REDACTED]`: the generated source
211
+ * shows which secrets are set and must be filled in by hand (as
212
+ * `$__env{NAME}` references, which GRAF002 asks for).
213
+ */
214
+ export function exportTemplate(input: {
215
+ dashboards: Array<{ json: Json; warnings?: string[] }>;
216
+ datasources: Json[];
217
+ keepDefaults?: boolean;
218
+ }): TemplateIR {
219
+ const resources: ResourceIR[] = [];
220
+ const warnings: string[] = [];
221
+ const taken = new Set<string>();
222
+ const unique = (base: string): string => {
223
+ let id = base;
224
+ for (let n = 2; taken.has(id); n++) id = `${base}${n}`;
225
+ taken.add(id);
226
+ return id;
227
+ };
228
+
229
+ const exportedUids = new Set(input.datasources.map((ds) => ds.uid).filter((u): u is string => typeof u === "string"));
230
+ for (const d of input.dashboards) {
231
+ warnings.push(...(d.warnings ?? []));
232
+ const planned = planDashboard(d.json);
233
+ const { edits, warnings: planWarnings } = planned;
234
+ const plan = referDeclaredDatasources(planned.plan, exportedUids);
235
+ const title = typeof d.json.title === "string" && d.json.title !== "" ? d.json.title : String(d.json.uid ?? "dashboard");
236
+ const uid = typeof d.json.uid === "string" ? d.json.uid : title;
237
+ warnings.push(...planWarnings.map((w) => `dashboard ${uid}: ${w}`));
238
+ const metadata: DashboardResourceMetadata = { source: d.json, edits };
239
+ const properties: PlanResourceProperties = { plan };
240
+ resources.push({
241
+ logicalId: unique(logicalIdFor(title)),
242
+ type: DASHBOARD_RESOURCE_TYPE,
243
+ properties: properties as unknown as Json,
244
+ metadata: metadata as unknown as Json,
245
+ });
246
+ }
247
+
248
+ if (input.datasources.length > 0) {
249
+ const entries = input.datasources.map((ds) => datasourceProps(ds, { keepDefaults: input.keepDefaults }));
250
+ const redacted = entries.filter((e) => isObject(e.secureJsonData)).map((e) => `"${String(e.name)}"`);
251
+ if (redacted.length > 0) {
252
+ warnings.push(
253
+ `datasources: Grafana does not return secret values, so the secureJsonData of ${redacted.join(", ")} is written as [REDACTED]; ` +
254
+ "replace each with a $__env{NAME} or $__file{path} reference before building",
255
+ );
256
+ }
257
+ const { plan, warnings: dsWarnings } = planDatasourceProvisioning({ apiVersion: 1, datasources: entries });
258
+ warnings.push(...dsWarnings);
259
+ const properties: PlanResourceProperties = { plan };
260
+ resources.push({ logicalId: unique("datasources"), type: PROVISIONING_RESOURCE_TYPE, properties: properties as unknown as Json });
261
+ }
262
+
263
+ return { resources, parameters: [], warnings };
264
+ }
@@ -0,0 +1,264 @@
1
+ /**
2
+ * What each piece of classic dashboard JSON becomes: the tables the
3
+ * importer's parser reads. They are the extension points for the issues
4
+ * that teach the importer more of Grafana.
5
+ *
6
+ * - Panel types (#2950): a built-in panel class is found in the panel
7
+ * registry (`registeredPanels()`), so a class added with `builtin: true`
8
+ * in `panels.ts` is used by the importer with no change here. Any other
9
+ * type is declared in the imported source with `definePanel`.
10
+ * - Query types (#2951): the same, through `registeredQueries()`, keyed by
11
+ * datasource plugin type; any other type gets a `defineQuery`.
12
+ * - Variable types (#2952): `VARIABLE_MAPPINGS` has one entry per type the
13
+ * lexicon has a class for. A type with no entry (adhoc, groupby, switch)
14
+ * is reported and left out. Add an entry when the class lands.
15
+ * - Dashboard and panel fields (#2953 annotations, and any new prop):
16
+ * `DASHBOARD_FIELDS`, `PANEL_FIELDS` and `ROW_FIELDS` list the JSON keys
17
+ * copied onto a prop as they are. A key in none of the tables, and not
18
+ * handled by the parser, is reported and left out, unless it is at the
19
+ * value Grafana assumes when it is missing (see `./normalize.ts`).
20
+ */
21
+
22
+ import { registeredPanels, type PanelDefinition } from "../panels";
23
+ import { registeredQueries, type QueryDefinition } from "../query";
24
+ import type { VariableHide } from "../variables";
25
+ import { splitValues } from "./normalize";
26
+
27
+ type Json = Record<string, unknown>;
28
+
29
+ /** Dashboard JSON keys carried onto the `Dashboard` prop of the same name, as they are. */
30
+ export const DASHBOARD_FIELDS: readonly string[] = [
31
+ "title",
32
+ "uid",
33
+ "description",
34
+ "tags",
35
+ "time",
36
+ "refresh",
37
+ "timezone",
38
+ "weekStart",
39
+ "fiscalYearStartMonth",
40
+ "liveNow",
41
+ "timepicker",
42
+ "editable",
43
+ "links",
44
+ ];
45
+
46
+ /** Panel JSON keys carried onto the panel prop of the same name, as they are. */
47
+ export const PANEL_FIELDS: readonly string[] = [
48
+ "id",
49
+ "title",
50
+ "description",
51
+ "gridPos",
52
+ "options",
53
+ "fieldConfig",
54
+ "transformations",
55
+ "links",
56
+ "repeatDirection",
57
+ "maxPerRow",
58
+ "maxDataPoints",
59
+ "interval",
60
+ "timeFrom",
61
+ "timeShift",
62
+ "hideTimeOverride",
63
+ "transparent",
64
+ "pluginVersion",
65
+ ];
66
+
67
+ /**
68
+ * Row JSON keys carried onto the `Row` prop of the same name. A row's
69
+ * `gridPos` is not among them: only its `y` is carried (Grafana draws a row
70
+ * header full width and one line high), so the row stays on its line even
71
+ * where the build would place it elsewhere, such as below an empty band.
72
+ */
73
+ export const ROW_FIELDS: readonly string[] = ["id", "title", "collapsed"];
74
+
75
+ /** `graphTooltip` as Grafana stores it, and as `Dashboard` takes it. */
76
+ export const GRAPH_TOOLTIP: Readonly<Record<number, "default" | "sharedCrosshair" | "sharedTooltip">> = {
77
+ 0: "default",
78
+ 1: "sharedCrosshair",
79
+ 2: "sharedTooltip",
80
+ };
81
+
82
+ /** A variable's `hide` as Grafana stores it, and as the variable classes take it. */
83
+ export const VARIABLE_HIDE: Readonly<Record<number, VariableHide>> = { 0: "label", 1: "valueOnly", 2: "hidden" };
84
+
85
+ /** A query variable's `refresh` as Grafana stores it, and as `QueryVariable` takes it. */
86
+ export const QUERY_REFRESH: Readonly<Record<number, "never" | "onLoad" | "onTimeRangeChange">> = {
87
+ 0: "never",
88
+ 1: "onLoad",
89
+ 2: "onTimeRangeChange",
90
+ };
91
+
92
+ /** The class a panel of this plugin type is declared with, when chant ships one. */
93
+ export function builtinPanelFor(type: string): PanelDefinition | undefined {
94
+ return registeredPanels().find((d) => d.builtin && d.type === type);
95
+ }
96
+
97
+ /** The class a query to a datasource of this plugin type is declared with, when chant ships one. */
98
+ export function builtinQueryFor(datasourceType: string): QueryDefinition | undefined {
99
+ return registeredQueries().find((d) => d.builtin && d.datasourceType === datasourceType);
100
+ }
101
+
102
+ /**
103
+ * The datasource type a query with no datasource of its own, on a panel
104
+ * with none, is declared under. Grafana sends it to the default datasource;
105
+ * the class exists only to hold the query model.
106
+ */
107
+ export const DEFAULT_DATASOURCE_TYPE = "default";
108
+
109
+ /** What converting one variable needs from the rest of the import. */
110
+ export interface VariableContext {
111
+ /** The variable's JSON. */
112
+ readonly json: Json;
113
+ /** Its JSON pointer, for edits. */
114
+ readonly path: string;
115
+ /** Resolve a `datasource` value to a prop value, reporting what cannot be resolved. */
116
+ datasource(value: unknown, path: string): unknown;
117
+ /** Report a key that is not carried; `why` is the end of the sentence, after "not carried". */
118
+ drop(key: string, why?: string): void;
119
+ /** Report the whole variable as not carried. */
120
+ dropVariable(why: string): void;
121
+ /** Record that `key` is written differently but means the same, or with the given warning. */
122
+ replace(key: string, value: unknown, why?: string): void;
123
+ }
124
+
125
+ /** One variable type the lexicon has a class for: which class, and how its JSON becomes props. */
126
+ export interface VariableMapping {
127
+ readonly className: string;
128
+ /** JSON keys the mapping reads, whether it carries them or derives them. Any other key is reported. */
129
+ readonly keys: readonly string[];
130
+ /** The type-specific props, or undefined when the variable cannot be carried (after `ctx.dropVariable`). */
131
+ convert(ctx: VariableContext): Json | undefined;
132
+ }
133
+
134
+ function str(v: unknown): string | undefined {
135
+ return typeof v === "string" ? v : undefined;
136
+ }
137
+
138
+ function nonEmpty(v: unknown): boolean {
139
+ if (v === undefined || v === null || v === "" || v === false) return false;
140
+ if (Array.isArray(v)) return v.length > 0;
141
+ if (typeof v === "object") return Object.keys(v as object).length > 0;
142
+ return true;
143
+ }
144
+
145
+ /** Split a custom or interval variable's `query` the way Grafana does: on commas not escaped as `\\,`, trimmed. */
146
+ export const valuesOf = splitValues;
147
+
148
+ function multiValue(json: Json): Json {
149
+ const out: Json = {};
150
+ if (json.multi === true) out.multi = true;
151
+ if (json.includeAll === true) out.includeAll = true;
152
+ if (nonEmpty(json.allValue)) out.allValue = json.allValue;
153
+ return out;
154
+ }
155
+
156
+ function current(json: Json): Json {
157
+ return nonEmpty(json.current) ? { current: json.current } : {};
158
+ }
159
+
160
+ const MULTI_KEYS = ["multi", "includeAll", "allValue"];
161
+
162
+ /** Per Grafana variable type, the class and props it becomes. */
163
+ export const VARIABLE_MAPPINGS: Readonly<Record<string, VariableMapping>> = {
164
+ query: {
165
+ className: "QueryVariable",
166
+ keys: ["datasource", "query", "definition", "regex", "refresh", "sort", "options", "current", ...MULTI_KEYS],
167
+ convert(ctx) {
168
+ const { json } = ctx;
169
+ let query = str(json.query);
170
+ if (query === undefined && json.query !== null && typeof json.query === "object") {
171
+ const obj = json.query as Json;
172
+ query = str(obj.query);
173
+ if (query === undefined) {
174
+ ctx.dropVariable("its query is an object with no query string, which QueryVariable cannot hold yet (#2952)");
175
+ return undefined;
176
+ }
177
+ // refId is the editor's own id for the query, which Grafana gives the string form back.
178
+ const rest = Object.keys(obj).filter((k) => k !== "query" && k !== "refId");
179
+ ctx.replace(
180
+ "query",
181
+ query,
182
+ rest.length === 0 ? undefined : `is an object; it is written as its query string, and its ${rest.join(" and ")} ${rest.length === 1 ? "is" : "are"} not carried (#2952)`,
183
+ );
184
+ }
185
+ query ??= "";
186
+ if (nonEmpty(json.definition) && json.definition !== query) ctx.drop("definition", `(it differs from the query, which is kept)`);
187
+ const refresh = typeof json.refresh === "number" ? json.refresh : 1;
188
+ if (refresh === 0 && nonEmpty(json.options)) {
189
+ ctx.drop("options", "(QueryVariable does not store options; with refresh never, Grafana shows none until it is refreshed)");
190
+ }
191
+ const out: Json = { datasource: ctx.datasource(json.datasource, `${ctx.path}/datasource`), query };
192
+ if (out.datasource === undefined) {
193
+ ctx.dropVariable("it has no datasource chant can refer to, and QueryVariable needs one");
194
+ return undefined;
195
+ }
196
+ if (nonEmpty(json.regex)) out.regex = json.regex;
197
+ if (refresh !== 1 && QUERY_REFRESH[refresh]) out.refresh = QUERY_REFRESH[refresh];
198
+ if (typeof json.sort === "number" && json.sort !== 0) out.sort = json.sort;
199
+ return { ...out, ...multiValue(json), ...current(json) };
200
+ },
201
+ },
202
+ custom: {
203
+ className: "CustomVariable",
204
+ keys: ["query", "options", "current", ...MULTI_KEYS],
205
+ convert(ctx) {
206
+ const { json } = ctx;
207
+ return { values: valuesOf(str(json.query) ?? ""), ...multiValue(json), ...current(json) };
208
+ },
209
+ },
210
+ interval: {
211
+ className: "IntervalVariable",
212
+ keys: ["query", "options", "current", "refresh", "auto", "auto_count", "auto_min"],
213
+ convert(ctx) {
214
+ const { json } = ctx;
215
+ const out: Json = { values: valuesOf(str(json.query) ?? "") };
216
+ if (json.auto === true) out.auto = true;
217
+ if (typeof json.auto_count === "number" && json.auto_count !== 30) out.autoCount = json.auto_count;
218
+ if (typeof json.auto_min === "string" && json.auto_min !== "10s") out.autoMin = json.auto_min;
219
+ return { ...out, ...current(json) };
220
+ },
221
+ },
222
+ datasource: {
223
+ className: "DatasourceVariable",
224
+ keys: ["query", "regex", "refresh", "options", "current", ...MULTI_KEYS],
225
+ convert(ctx) {
226
+ const { json } = ctx;
227
+ const pluginType = str(json.query);
228
+ if (!pluginType) {
229
+ ctx.dropVariable("it names no datasource plugin type");
230
+ return undefined;
231
+ }
232
+ const out: Json = { pluginType };
233
+ if (nonEmpty(json.regex)) out.regex = json.regex;
234
+ return { ...out, ...multiValue(json), ...current(json) };
235
+ },
236
+ },
237
+ constant: {
238
+ className: "ConstantVariable",
239
+ keys: ["query", "options", "current", "hide"],
240
+ convert(ctx) {
241
+ const { json } = ctx;
242
+ if (json.hide !== undefined && json.hide !== 2) {
243
+ ctx.replace("hide", 2, "is not 2: chant always writes a constant hidden, as Grafana shows it");
244
+ }
245
+ return { value: str(json.query) ?? "" };
246
+ },
247
+ },
248
+ textbox: {
249
+ className: "TextboxVariable",
250
+ keys: ["query", "options", "current"],
251
+ convert(ctx) {
252
+ const { json } = ctx;
253
+ const value = str(json.query) ?? "";
254
+ const cur = json.current as Json | undefined;
255
+ if (nonEmpty(cur) && cur!.value !== value) {
256
+ ctx.drop("current", `(the box's value "${String(cur!.value)}"; TextboxVariable starts at its default, "${value}")`);
257
+ }
258
+ return value === "" ? {} : { value };
259
+ },
260
+ },
261
+ };
262
+
263
+ /** Keys every variable type reads: the ones `CommonVariableProps` has, and `type`. */
264
+ export const COMMON_VARIABLE_KEYS: readonly string[] = ["type", "name", "label", "description", "hide", "skipUrlSync"];
@@ -0,0 +1,110 @@
1
+ /**
2
+ * The plan `chant import` hands from the parser to the generator: the
3
+ * declarations one dashboard becomes, with the references between them.
4
+ *
5
+ * The parser decides what each piece of dashboard JSON becomes (which
6
+ * class, which props, what cannot be carried) using the tables in
7
+ * `./mappings.ts`. The generator decides only how the plan is written:
8
+ * names, modules, imports, lifted consts. It knows nothing about Grafana,
9
+ * so live export (#2946) can build a plan from a dashboard read over the
10
+ * API and write it with the same generator.
11
+ */
12
+
13
+ /** A value in a declaration's props that refers to another declaration, written as that declaration's variable. */
14
+ export interface DeclRef {
15
+ readonly $decl: string;
16
+ }
17
+
18
+ export function declRef(id: string): DeclRef {
19
+ return { $decl: id };
20
+ }
21
+
22
+ export function isDeclRef(v: unknown): v is DeclRef {
23
+ return typeof v === "object" && v !== null && typeof (v as DeclRef).$decl === "string" && Object.keys(v).length === 1;
24
+ }
25
+
26
+ /**
27
+ * A value written as a call to a function the package exports, e.g.
28
+ * `customTransformation("sortBy", { ... })` for a transformation the typed
29
+ * form can't hold. The arguments are values like any other.
30
+ */
31
+ export interface CallValue {
32
+ readonly $call: string;
33
+ readonly args: readonly unknown[];
34
+ }
35
+
36
+ export function callValue(fn: string, args: readonly unknown[]): CallValue {
37
+ return { $call: fn, args };
38
+ }
39
+
40
+ export function isCallValue(v: unknown): v is CallValue {
41
+ return typeof v === "object" && v !== null && typeof (v as CallValue).$call === "string" && Array.isArray((v as CallValue).args) && Object.keys(v).length === 2;
42
+ }
43
+
44
+ /** Where a declaration's variable name comes from: a text to camelCase, or another declaration's name plus a suffix. */
45
+ export type NameHint = string | { readonly of: string; readonly suffix: string };
46
+
47
+ /**
48
+ * One declaration.
49
+ *
50
+ * - `new`: `const name = new ClassName(props);`, a declarable.
51
+ * - `value`: `const name: type = value;`, a plain value other declarations
52
+ * refer to (a `DatasourceRef`).
53
+ */
54
+ export interface Declaration {
55
+ /** Unique in the plan, e.g. `panel:4`, `query:4:A`, `variable:job`, `datasource:prometheus:prom`, `dashboard`. */
56
+ readonly id: string;
57
+ readonly kind: "new" | "value";
58
+ /** For `new`: the class. A package export unless `customClass` says the import declares it. */
59
+ readonly className?: string;
60
+ /** For `new`: the id of the `CustomClass` declaring `className`, when it is not a package export. */
61
+ readonly customClass?: string;
62
+ /** For `new`: the constructor's props, in source order. */
63
+ readonly props?: Record<string, unknown>;
64
+ /** For `value`: the value, and its type annotation with the package types it names. */
65
+ readonly value?: unknown;
66
+ readonly type?: { readonly text: string; readonly imports: readonly string[] };
67
+ readonly name: NameHint;
68
+ /** The module group it is written to (see `Plan.modules`). */
69
+ readonly module: string;
70
+ /**
71
+ * Declarations with the same unit stay in the same file when a module is
72
+ * split (a panel and its queries). Defaults to the id.
73
+ */
74
+ readonly unit?: string;
75
+ /** Comment lines written above it. */
76
+ readonly comment?: readonly string[];
77
+ }
78
+
79
+ /** A panel or query class the import declares, for a plugin chant has no class for. */
80
+ export interface CustomClass {
81
+ /** e.g. `panel-class:grafana-clock-panel`, `query-class:elasticsearch`. */
82
+ readonly id: string;
83
+ readonly className: string;
84
+ /** `definePanel` or `defineQuery`. */
85
+ readonly factory: "definePanel" | "defineQuery";
86
+ /** The definition object passed to the factory. */
87
+ readonly definition: Record<string, unknown>;
88
+ readonly comment: readonly string[];
89
+ }
90
+
91
+ /** One module group: a base file name and the doc comment at its top. */
92
+ export interface ModuleSpec {
93
+ readonly key: string;
94
+ /** File name without `.ts`; `-1`, `-2`, ... is added when the group is split. */
95
+ readonly file: string;
96
+ readonly summary: string;
97
+ }
98
+
99
+ /** Everything one dashboard becomes. */
100
+ export interface Plan {
101
+ /** The directory its modules are written to, relative to the output directory. `""` for none. */
102
+ readonly directory: string;
103
+ /** Modules in the order they are written. */
104
+ readonly modules: readonly ModuleSpec[];
105
+ /** Declarations in dependency order: a declaration only refers to ones before it. */
106
+ readonly declarations: readonly Declaration[];
107
+ readonly customClasses: readonly CustomClass[];
108
+ /** Declarations exported even when no other module imports them (the dashboard). */
109
+ readonly exports: readonly string[];
110
+ }