@cyberismo/data-handler 0.0.8 → 0.0.10

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 (258) hide show
  1. package/dist/command-handler.d.ts +11 -2
  2. package/dist/command-handler.js +61 -18
  3. package/dist/command-handler.js.map +1 -1
  4. package/dist/command-manager.js +8 -8
  5. package/dist/command-manager.js.map +1 -1
  6. package/dist/commands/calculate.d.ts +7 -44
  7. package/dist/commands/calculate.js +8 -389
  8. package/dist/commands/calculate.js.map +1 -1
  9. package/dist/commands/create.d.ts +6 -3
  10. package/dist/commands/create.js +27 -5
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/edit.d.ts +15 -3
  13. package/dist/commands/edit.js +52 -9
  14. package/dist/commands/edit.js.map +1 -1
  15. package/dist/commands/export.d.ts +11 -9
  16. package/dist/commands/export.js +80 -28
  17. package/dist/commands/export.js.map +1 -1
  18. package/dist/commands/import.d.ts +7 -0
  19. package/dist/commands/import.js +13 -0
  20. package/dist/commands/import.js.map +1 -1
  21. package/dist/commands/move.d.ts +11 -12
  22. package/dist/commands/move.js +12 -13
  23. package/dist/commands/move.js.map +1 -1
  24. package/dist/commands/remove.d.ts +1 -3
  25. package/dist/commands/remove.js +4 -6
  26. package/dist/commands/remove.js.map +1 -1
  27. package/dist/commands/rename.d.ts +1 -3
  28. package/dist/commands/rename.js +3 -6
  29. package/dist/commands/rename.js.map +1 -1
  30. package/dist/commands/show.d.ts +37 -5
  31. package/dist/commands/show.js +89 -8
  32. package/dist/commands/show.js.map +1 -1
  33. package/dist/commands/transition.d.ts +1 -3
  34. package/dist/commands/transition.js +3 -5
  35. package/dist/commands/transition.js.map +1 -1
  36. package/dist/commands/update.d.ts +5 -1
  37. package/dist/commands/update.js +7 -1
  38. package/dist/commands/update.js.map +1 -1
  39. package/dist/commands/validate.d.ts +7 -0
  40. package/dist/commands/validate.js +31 -4
  41. package/dist/commands/validate.js.map +1 -1
  42. package/dist/containers/card-container.d.ts +6 -0
  43. package/dist/containers/card-container.js +61 -0
  44. package/dist/containers/card-container.js.map +1 -1
  45. package/dist/containers/project/calculation-engine.d.ts +90 -0
  46. package/dist/containers/project/calculation-engine.js +402 -0
  47. package/dist/containers/project/calculation-engine.js.map +1 -0
  48. package/dist/containers/project/resource-collector.js +9 -13
  49. package/dist/containers/project/resource-collector.js.map +1 -1
  50. package/dist/containers/project.d.ts +18 -1
  51. package/dist/containers/project.js +28 -55
  52. package/dist/containers/project.js.map +1 -1
  53. package/dist/containers/template.d.ts +5 -0
  54. package/dist/containers/template.js +9 -0
  55. package/dist/containers/template.js.map +1 -1
  56. package/dist/index.d.ts +5 -2
  57. package/dist/index.js +5 -1
  58. package/dist/index.js.map +1 -1
  59. package/dist/interfaces/macros.d.ts +4 -2
  60. package/dist/interfaces/project-interfaces.d.ts +21 -0
  61. package/dist/interfaces/project-interfaces.js +4 -0
  62. package/dist/interfaces/project-interfaces.js.map +1 -1
  63. package/dist/interfaces/resource-interfaces.d.ts +4 -2
  64. package/dist/interfaces/resource-interfaces.js.map +1 -1
  65. package/dist/macros/base-macro.d.ts +2 -1
  66. package/dist/macros/base-macro.js +14 -2
  67. package/dist/macros/base-macro.js.map +1 -1
  68. package/dist/macros/common.d.ts +16 -9
  69. package/dist/macros/common.js +22 -9
  70. package/dist/macros/common.js.map +1 -1
  71. package/dist/macros/createCards/index.d.ts +2 -2
  72. package/dist/macros/createCards/index.js +4 -0
  73. package/dist/macros/createCards/index.js.map +1 -1
  74. package/dist/macros/graph/index.d.ts +1 -3
  75. package/dist/macros/graph/index.js +1 -6
  76. package/dist/macros/graph/index.js.map +1 -1
  77. package/dist/macros/image/index.d.ts +39 -0
  78. package/dist/macros/image/index.js +82 -0
  79. package/dist/macros/image/index.js.map +1 -0
  80. package/dist/macros/image/metadata.d.ts +18 -0
  81. package/dist/macros/image/metadata.js +22 -0
  82. package/dist/macros/image/metadata.js.map +1 -0
  83. package/dist/macros/include/index.d.ts +31 -0
  84. package/dist/macros/include/index.js +94 -0
  85. package/dist/macros/include/index.js.map +1 -0
  86. package/dist/macros/include/metadata.d.ts +15 -0
  87. package/dist/macros/include/metadata.js +19 -0
  88. package/dist/macros/include/metadata.js.map +1 -0
  89. package/dist/macros/index.d.ts +33 -31
  90. package/dist/macros/index.js +142 -71
  91. package/dist/macros/index.js.map +1 -1
  92. package/dist/macros/percentage/index.d.ts +28 -0
  93. package/dist/macros/percentage/index.js +33 -0
  94. package/dist/macros/percentage/index.js.map +1 -0
  95. package/dist/macros/percentage/metadata.d.ts +15 -0
  96. package/dist/macros/percentage/metadata.js +19 -0
  97. package/dist/macros/percentage/metadata.js.map +1 -0
  98. package/dist/macros/report/index.d.ts +2 -6
  99. package/dist/macros/report/index.js +3 -7
  100. package/dist/macros/report/index.js.map +1 -1
  101. package/dist/macros/scoreCard/index.d.ts +14 -15
  102. package/dist/macros/scoreCard/index.js +14 -18
  103. package/dist/macros/scoreCard/index.js.map +1 -1
  104. package/dist/macros/vega/index.d.ts +28 -0
  105. package/dist/macros/vega/index.js +27 -0
  106. package/dist/macros/vega/index.js.map +1 -0
  107. package/dist/macros/vega/metadata.d.ts +15 -0
  108. package/dist/macros/vega/metadata.js +7 -0
  109. package/dist/macros/vega/metadata.js.map +1 -0
  110. package/dist/macros/vegalite/index.d.ts +26 -0
  111. package/dist/macros/vegalite/index.js +24 -0
  112. package/dist/macros/vegalite/index.js.map +1 -0
  113. package/dist/macros/vegalite/metadata.d.ts +15 -0
  114. package/dist/macros/vegalite/metadata.js +7 -0
  115. package/dist/macros/vegalite/metadata.js.map +1 -0
  116. package/dist/macros/xref/index.d.ts +26 -0
  117. package/dist/macros/xref/index.js +53 -0
  118. package/dist/macros/xref/index.js.map +1 -0
  119. package/dist/macros/xref/metadata.d.ts +15 -0
  120. package/dist/macros/xref/metadata.js +19 -0
  121. package/dist/macros/xref/metadata.js.map +1 -0
  122. package/dist/module-manager.d.ts +1 -0
  123. package/dist/module-manager.js +14 -4
  124. package/dist/module-manager.js.map +1 -1
  125. package/dist/permissions/action-guard.d.ts +2 -2
  126. package/dist/permissions/action-guard.js +1 -1
  127. package/dist/permissions/action-guard.js.map +1 -1
  128. package/dist/resources/card-type-resource.d.ts +2 -0
  129. package/dist/resources/card-type-resource.js +63 -0
  130. package/dist/resources/card-type-resource.js.map +1 -1
  131. package/dist/resources/file-resource.d.ts +2 -0
  132. package/dist/resources/file-resource.js +12 -4
  133. package/dist/resources/file-resource.js.map +1 -1
  134. package/dist/resources/folder-resource.d.ts +19 -0
  135. package/dist/resources/folder-resource.js +51 -2
  136. package/dist/resources/folder-resource.js.map +1 -1
  137. package/dist/resources/graph-model-resource.js +1 -1
  138. package/dist/resources/graph-model-resource.js.map +1 -1
  139. package/dist/resources/graph-view-resource.js +1 -1
  140. package/dist/resources/graph-view-resource.js.map +1 -1
  141. package/dist/resources/report-resource.js +1 -1
  142. package/dist/resources/report-resource.js.map +1 -1
  143. package/dist/resources/resource-object.d.ts +8 -0
  144. package/dist/resources/resource-object.js +10 -1
  145. package/dist/resources/resource-object.js.map +1 -1
  146. package/dist/resources/template-resource.js +1 -1
  147. package/dist/resources/template-resource.js.map +1 -1
  148. package/dist/resources/workflow-resource.d.ts +2 -0
  149. package/dist/resources/workflow-resource.js +53 -9
  150. package/dist/resources/workflow-resource.js.map +1 -1
  151. package/dist/svg/index.d.ts +15 -0
  152. package/dist/svg/index.js +16 -0
  153. package/dist/svg/index.js.map +1 -0
  154. package/dist/svg/lib.d.ts +9 -0
  155. package/dist/svg/lib.js +26 -0
  156. package/dist/svg/lib.js.map +1 -0
  157. package/dist/svg/percentage.d.ts +25 -0
  158. package/dist/svg/percentage.js +90 -0
  159. package/dist/svg/percentage.js.map +1 -0
  160. package/dist/svg/scoreCard.d.ts +19 -0
  161. package/dist/svg/scoreCard.js +55 -0
  162. package/dist/svg/scoreCard.js.map +1 -0
  163. package/dist/types/queries.d.ts +8 -7
  164. package/dist/types/queries.js.map +1 -1
  165. package/dist/utils/card-utils.d.ts +6 -0
  166. package/dist/utils/card-utils.js +12 -0
  167. package/dist/utils/card-utils.js.map +1 -1
  168. package/dist/utils/clingo-facts.d.ts +2 -1
  169. package/dist/utils/clingo-facts.js +19 -2
  170. package/dist/utils/clingo-facts.js.map +1 -1
  171. package/dist/utils/clingo-parser.d.ts +1 -0
  172. package/dist/utils/clingo-parser.js +22 -100
  173. package/dist/utils/clingo-parser.js.map +1 -1
  174. package/dist/utils/constants.d.ts +7 -0
  175. package/dist/utils/constants.js +14 -0
  176. package/dist/utils/constants.js.map +1 -1
  177. package/dist/utils/csv.js.map +1 -1
  178. package/dist/utils/report.d.ts +17 -3
  179. package/dist/utils/report.js +38 -2
  180. package/dist/utils/report.js.map +1 -1
  181. package/dist/utils/resource-utils.d.ts +2 -1
  182. package/dist/utils/resource-utils.js +12 -3
  183. package/dist/utils/resource-utils.js.map +1 -1
  184. package/dist/utils/user-preferences.d.ts +1 -11
  185. package/dist/utils/user-preferences.js +30 -13
  186. package/dist/utils/user-preferences.js.map +1 -1
  187. package/dist/utils/validate.d.ts +2 -3
  188. package/dist/utils/validate.js +2 -2
  189. package/dist/utils/validate.js.map +1 -1
  190. package/package.json +8 -6
  191. package/src/command-handler.ts +96 -17
  192. package/src/command-manager.ts +8 -8
  193. package/src/commands/calculate.ts +11 -525
  194. package/src/commands/create.ts +35 -6
  195. package/src/commands/edit.ts +94 -11
  196. package/src/commands/export.ts +104 -31
  197. package/src/commands/import.ts +16 -0
  198. package/src/commands/move.ts +12 -15
  199. package/src/commands/remove.ts +4 -8
  200. package/src/commands/rename.ts +3 -12
  201. package/src/commands/show.ts +126 -9
  202. package/src/commands/transition.ts +3 -7
  203. package/src/commands/update.ts +6 -0
  204. package/src/commands/validate.ts +41 -13
  205. package/src/containers/card-container.ts +74 -0
  206. package/src/containers/project/calculation-engine.ts +535 -0
  207. package/src/containers/project/resource-collector.ts +13 -15
  208. package/src/containers/project.ts +30 -66
  209. package/src/containers/template.ts +16 -0
  210. package/src/index.ts +13 -2
  211. package/src/interfaces/macros.ts +4 -1
  212. package/src/interfaces/project-interfaces.ts +27 -0
  213. package/src/interfaces/resource-interfaces.ts +5 -2
  214. package/src/macros/base-macro.ts +19 -4
  215. package/src/macros/common.ts +22 -9
  216. package/src/macros/createCards/index.ts +6 -2
  217. package/src/macros/graph/index.ts +6 -10
  218. package/src/macros/image/index.ts +128 -0
  219. package/src/macros/image/metadata.ts +25 -0
  220. package/src/macros/include/index.ts +143 -0
  221. package/src/macros/include/metadata.ts +22 -0
  222. package/src/macros/index.ts +150 -98
  223. package/src/macros/percentage/index.ts +50 -0
  224. package/src/macros/percentage/metadata.ts +22 -0
  225. package/src/macros/report/index.ts +4 -12
  226. package/src/macros/scoreCard/index.ts +21 -25
  227. package/src/macros/vega/index.ts +55 -0
  228. package/src/macros/vega/metadata.ts +21 -0
  229. package/src/macros/vegalite/index.ts +46 -0
  230. package/src/macros/vegalite/metadata.ts +21 -0
  231. package/src/macros/xref/index.ts +73 -0
  232. package/src/macros/xref/metadata.ts +22 -0
  233. package/src/module-manager.ts +15 -5
  234. package/src/permissions/action-guard.ts +3 -3
  235. package/src/resources/card-type-resource.ts +100 -0
  236. package/src/resources/file-resource.ts +16 -4
  237. package/src/resources/folder-resource.ts +59 -2
  238. package/src/resources/graph-model-resource.ts +1 -1
  239. package/src/resources/graph-view-resource.ts +1 -1
  240. package/src/resources/report-resource.ts +1 -1
  241. package/src/resources/resource-object.ts +19 -1
  242. package/src/resources/template-resource.ts +1 -1
  243. package/src/resources/workflow-resource.ts +68 -13
  244. package/src/svg/index.ts +15 -0
  245. package/src/svg/lib.ts +31 -0
  246. package/src/svg/percentage.ts +97 -0
  247. package/src/svg/scoreCard.ts +88 -0
  248. package/src/types/queries.ts +8 -7
  249. package/src/types/string-pixel-width.d.ts +23 -0
  250. package/src/utils/card-utils.ts +13 -0
  251. package/src/utils/clingo-facts.ts +65 -3
  252. package/src/utils/clingo-parser.ts +31 -144
  253. package/src/utils/constants.ts +16 -0
  254. package/src/utils/csv.ts +1 -1
  255. package/src/utils/report.ts +45 -4
  256. package/src/utils/resource-utils.ts +12 -2
  257. package/src/utils/user-preferences.ts +32 -14
  258. package/src/utils/validate.ts +3 -3
@@ -1,28 +1,30 @@
1
1
  /**
2
- Cyberismo
3
- Copyright © Cyberismo Ltd and contributors 2024
4
-
5
- This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
6
-
7
- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
8
-
9
- You should have received a copy of the GNU Affero General Public
10
- License along with this program. If not, see <https://www.gnu.org/licenses/>.
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2024
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU Affero General Public License version 3 as published by
7
+ the Free Software Foundation. This program is distributed in the hope that it
8
+ will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
+ See the GNU Affero General Public License for more details.
11
+ You should have received a copy of the GNU Affero General Public
12
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
11
13
  */
12
14
 
13
- import type { MacroOptions } from '../index.js';
14
- import { createHtmlPlaceholder, validateMacroContent } from '../index.js';
15
+ import { createImage, validateMacroContent } from '../index.js';
15
16
 
16
17
  import type { MacroGenerationContext } from '../../interfaces/macros.js';
17
18
  import macroMetadata from './metadata.js';
18
19
  import BaseMacro from '../base-macro.js';
19
20
  import type TaskQueue from '../task-queue.js';
21
+ import { scoreCard } from '../../svg/index.js';
20
22
 
21
- export interface ScoreCardOptions extends MacroOptions {
22
- title?: string;
23
+ export interface ScoreCardOptions {
23
24
  value: number;
24
- unit?: string;
25
25
  legend?: string;
26
+ title?: string;
27
+ unit?: string;
26
28
  }
27
29
 
28
30
  class ScoreCardMacro extends BaseMacro {
@@ -33,23 +35,17 @@ class ScoreCardMacro extends BaseMacro {
33
35
  this.validate(data);
34
36
  };
35
37
 
36
- handleStatic = async (context: MacroGenerationContext, input: unknown) => {
37
- const options = this.validate(input);
38
- return this.createAsciidocElement(options);
39
- };
40
-
41
- handleInject = async (_: MacroGenerationContext, input: unknown) => {
38
+ handleStatic = async (_: MacroGenerationContext, input: unknown) => {
42
39
  const options = this.validate(input);
43
- return createHtmlPlaceholder(this.metadata, options);
40
+ return createImage(
41
+ Buffer.from(scoreCard(options)).toString('base64'),
42
+ false,
43
+ );
44
44
  };
45
45
 
46
46
  private validate(input: unknown): ScoreCardOptions {
47
47
  return validateMacroContent<ScoreCardOptions>(this.metadata, input);
48
48
  }
49
-
50
- private createAsciidocElement(options: ScoreCardOptions) {
51
- return `\n----\n${options.title}: ${options.value} ${options.unit ?? ''} ${options.legend ?? ''}\n----\n`;
52
- }
53
49
  }
54
50
 
55
51
  export default ScoreCardMacro;
@@ -0,0 +1,55 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2024
4
+
5
+ This program is free software: you can redistribute it and/or modify it under
6
+ the terms of the GNU Affero General Public License version 3 as published by
7
+ the Free Software Foundation. This program is distributed in the hope that it
8
+ will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
+ See the GNU Affero General Public License for more details.
11
+ You should have received a copy of the GNU Affero General Public
12
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
13
+ */
14
+ import type { MacroGenerationContext } from '../../interfaces/macros.js';
15
+ import BaseMacro from '../base-macro.js';
16
+ import macroMetadata from './metadata.js';
17
+ import type TaskQueue from '../task-queue.js';
18
+ import {
19
+ createHtmlPlaceholder,
20
+ createImage,
21
+ validateMacroContent,
22
+ } from '../index.js';
23
+ import * as vega from 'vega';
24
+
25
+ export interface VegaMacroInput {
26
+ spec: vega.Spec;
27
+ }
28
+
29
+ class VegaMacro extends BaseMacro {
30
+ constructor(tasksQueue: TaskQueue) {
31
+ super(macroMetadata, tasksQueue);
32
+ }
33
+
34
+ handleValidate = (input: unknown) => {
35
+ this.validate(input);
36
+ };
37
+
38
+ handleStatic = async (_: MacroGenerationContext, input: unknown) => {
39
+ const options = this.validate(input) as VegaMacroInput;
40
+ const view = new vega.View(vega.parse(options.spec), { renderer: 'none' });
41
+ const svg = await view.toSVG();
42
+ return createImage(Buffer.from(svg).toString('base64'), false);
43
+ };
44
+
45
+ handleInject = async (_: MacroGenerationContext, input: unknown) => {
46
+ const options = this.validate(input) as VegaMacroInput;
47
+ return createHtmlPlaceholder(this.metadata, options);
48
+ };
49
+
50
+ private validate(input: unknown): VegaMacroInput {
51
+ return validateMacroContent<VegaMacroInput>(this.metadata, input);
52
+ }
53
+ }
54
+
55
+ export default VegaMacro;
@@ -0,0 +1,21 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+ import type { MacroMetadata } from '../../interfaces/macros.js';
14
+
15
+ const macroMetadata: MacroMetadata = {
16
+ name: 'vega',
17
+ tagName: 'vega',
18
+ schema: 'vegaMacroSchema',
19
+ };
20
+
21
+ export default macroMetadata;
@@ -0,0 +1,46 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+ import type { MacroGenerationContext } from '../../interfaces/macros.js';
14
+ import BaseMacro from '../base-macro.js';
15
+ import macroMetadata from './metadata.js';
16
+ import type TaskQueue from '../task-queue.js';
17
+ import * as vegaLite from 'vega-lite';
18
+ import { createMacro, validateMacroContent } from '../index.js';
19
+
20
+ export interface VegaLiteMacroInput {
21
+ spec: vegaLite.TopLevelSpec;
22
+ }
23
+
24
+ class VegaLiteMacro extends BaseMacro {
25
+ constructor(tasksQueue: TaskQueue) {
26
+ super(macroMetadata, tasksQueue);
27
+ }
28
+
29
+ handleValidate = (input: unknown) => {
30
+ this.validate(input);
31
+ };
32
+
33
+ handleStatic = async (_: MacroGenerationContext, input: unknown) => {
34
+ const options = this.validate(input) as VegaLiteMacroInput;
35
+ const compiled = vegaLite.compile(options.spec).spec;
36
+ return createMacro('vega', {
37
+ spec: compiled,
38
+ });
39
+ };
40
+
41
+ private validate(input: unknown): VegaLiteMacroInput {
42
+ return validateMacroContent<VegaLiteMacroInput>(this.metadata, input);
43
+ }
44
+ }
45
+
46
+ export default VegaLiteMacro;
@@ -0,0 +1,21 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+ import type { MacroMetadata } from '../../interfaces/macros.js';
14
+
15
+ const macroMetadata: MacroMetadata = {
16
+ name: 'vegaLite',
17
+ tagName: 'vegaLite',
18
+ schema: 'vegaLiteMacroSchema',
19
+ };
20
+
21
+ export default macroMetadata;
@@ -0,0 +1,73 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+
14
+ import { validateMacroContent } from '../index.js';
15
+
16
+ import type { MacroGenerationContext } from '../../interfaces/macros.js';
17
+ import macroMetadata from './metadata.js';
18
+ import BaseMacro from '../base-macro.js';
19
+ import type TaskQueue from '../task-queue.js';
20
+
21
+ export interface XrefMacroOptions {
22
+ cardKey: string;
23
+ }
24
+
25
+ export default class XrefMacro extends BaseMacro {
26
+ constructor(tasksQueue: TaskQueue) {
27
+ super(macroMetadata, tasksQueue);
28
+ }
29
+
30
+ handleValidate = (input: unknown) => {
31
+ this.validate(input);
32
+ };
33
+
34
+ handleStatic = async (
35
+ context: MacroGenerationContext,
36
+ input: unknown,
37
+ ): Promise<string> => {
38
+ const options = this.validate(input);
39
+ const card = await this.getCard(options.cardKey, context);
40
+
41
+ if (!card || !card.metadata) {
42
+ throw new Error(`Card key ${options.cardKey} not found`);
43
+ }
44
+
45
+ // in static mode we need to use internal references
46
+ return `<<${options.cardKey}>>`;
47
+ };
48
+
49
+ handleInject = async (context: MacroGenerationContext, input: unknown) => {
50
+ const options = this.validate(input);
51
+ const card = await this.getCard(options.cardKey, context);
52
+
53
+ if (!card || !card.metadata) {
54
+ throw new Error(`Card key ${options.cardKey} not found`);
55
+ }
56
+
57
+ return `xref:${options.cardKey}.adoc[${card.metadata.title}]`;
58
+ };
59
+
60
+ private async getCard(cardKey: string, context: MacroGenerationContext) {
61
+ const card = await context.project.cardDetailsById(cardKey, {
62
+ metadata: true,
63
+ });
64
+ if (!card || !card.metadata) {
65
+ throw new Error(`Card key ${cardKey} not found`);
66
+ }
67
+ return card;
68
+ }
69
+
70
+ private validate(input: unknown): XrefMacroOptions {
71
+ return validateMacroContent<XrefMacroOptions>(this.metadata, input);
72
+ }
73
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2025
4
+ This program is free software: you can redistribute it and/or modify it under
5
+ the terms of the GNU Affero General Public License version 3 as published by
6
+ the Free Software Foundation.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. You should have received a copy of the GNU Affero General Public
11
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
+ */
13
+
14
+ import type { MacroMetadata } from '../../interfaces/macros.js';
15
+
16
+ const macroMetadata: MacroMetadata = {
17
+ name: 'xref',
18
+ tagName: 'xref',
19
+ schema: 'xrefMacroSchema',
20
+ };
21
+
22
+ export default macroMetadata;
@@ -31,9 +31,6 @@ import { Validate } from './commands/index.js';
31
31
  const FILE_PROTOCOL = 'file:';
32
32
  const HTTPS_PROTOCOL = 'https:';
33
33
 
34
- // timeout in milliseconds for git client (no stdout / stderr activity)
35
- const DEFAULT_TIMEOUT = 10000;
36
-
37
34
  // When dependencies are built to a map, use map that has
38
35
  // key: module name,
39
36
  // value: list of unique prefixes
@@ -144,7 +141,7 @@ export class ModuleManager {
144
141
 
145
142
  const git: SimpleGit = simpleGit({
146
143
  timeout: {
147
- block: DEFAULT_TIMEOUT,
144
+ block: this.gitTimeout(),
148
145
  },
149
146
  });
150
147
 
@@ -201,7 +198,7 @@ export class ModuleManager {
201
198
  if (pathExists(destinationPath)) {
202
199
  const git: SimpleGit = simpleGit({
203
200
  timeout: {
204
- block: DEFAULT_TIMEOUT,
201
+ block: this.gitTimeout(),
205
202
  },
206
203
  });
207
204
  const options = ['--abbrev-ref', 'HEAD'];
@@ -231,6 +228,19 @@ export class ModuleManager {
231
228
  : new Set();
232
229
  }
233
230
 
231
+ // Increase timeout for CI environments and add platform-specific adjustments
232
+ private gitTimeout(): number {
233
+ const baseTimeout = 15000;
234
+ const isCI = process.env.CI;
235
+ const isWindows = process.platform === 'win32';
236
+
237
+ let timeout = baseTimeout;
238
+ if (isCI) timeout *= 2; // Double timeout in CI
239
+ if (isWindows) timeout *= 1.5; // 50% more time on Windows
240
+
241
+ return timeout;
242
+ }
243
+
234
244
  // Collects one module's dependency prefixes to 'this.modules'.
235
245
  // Note that there can be duplicate entries.
236
246
  private async doCollectModulePrefix(
@@ -10,7 +10,7 @@
10
10
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
11
11
  */
12
12
 
13
- import type { Calculate } from '../commands/index.js';
13
+ import type { CalculationEngine } from '../containers/project/calculation-engine.js';
14
14
  import type { DeniedOperationCollection } from '../types/queries.js';
15
15
 
16
16
  export type Action = keyof DeniedOperationCollection;
@@ -25,7 +25,7 @@ function checkOperation<T extends { errorMessage: string }>(data: Array<T>) {
25
25
  * This class is used to guard actions from being used without permissions
26
26
  */
27
27
  export class ActionGuard {
28
- constructor(private calculate: Calculate) {}
28
+ constructor(private calculate: CalculationEngine) {}
29
29
 
30
30
  /**
31
31
  * Checks whether an action can be done
@@ -39,7 +39,7 @@ export class ActionGuard {
39
39
  param?: string,
40
40
  ) {
41
41
  await this.calculate.generate();
42
- const cards = await this.calculate.runQuery('card', {
42
+ const cards = await this.calculate.runQuery('card', 'localApp', {
43
43
  cardKey,
44
44
  });
45
45
  if (cards.length === 0) {
@@ -153,6 +153,50 @@ export class CardTypeResource extends FileResource {
153
153
  }
154
154
  }
155
155
 
156
+ // Apply state mapping to all cards using this card type.
157
+ // Checks that all states in the current workflow are updated.
158
+ private async handleWorkflowChange<Type>(
159
+ stateMapping: Record<string, string>,
160
+ op: ChangeOperation<Type>,
161
+ ) {
162
+ await this.verifyStateMapping(stateMapping, op);
163
+ const cards = await this.collectCards(
164
+ {
165
+ metadata: true,
166
+ content: true,
167
+ },
168
+ this.content.name,
169
+ );
170
+
171
+ const unmappedStates: string[] = [];
172
+
173
+ // Update each card's workflowState if it has a mapping
174
+ const updatePromises = cards.map(async (card) => {
175
+ if (card.metadata && card.metadata.workflowState) {
176
+ const currentState = card.metadata.workflowState as string;
177
+ const newState = stateMapping[currentState];
178
+
179
+ if (newState && newState !== currentState) {
180
+ this.logger.info(
181
+ `Updating card '${card.key}': ${currentState} -> ${newState}`,
182
+ );
183
+ card.metadata.workflowState = newState;
184
+ await this.project.updateCardMetadata(card, card.metadata);
185
+ } else if (!newState && !unmappedStates.includes(currentState)) {
186
+ unmappedStates.push(currentState);
187
+ }
188
+ }
189
+ });
190
+
191
+ await Promise.all(updatePromises);
192
+
193
+ if (unmappedStates.length > 0) {
194
+ this.logger.warn(
195
+ `Found unmapped states that were not updated: ${unmappedStates.join(', ')}`,
196
+ );
197
+ }
198
+ }
199
+
156
200
  // Checks if field type exists in this card type.
157
201
  private async hasFieldType(field: Partial<CustomField>): Promise<boolean> {
158
202
  return this.data.customFields.some((item) => item.name === field.name);
@@ -315,6 +359,57 @@ export class CardTypeResource extends FileResource {
315
359
  }
316
360
  }
317
361
 
362
+ // Verifies that:
363
+ // - all states in the current workflow are covered in the state mapping
364
+ // - the states are correct
365
+ private async verifyStateMapping<Type>(
366
+ stateMapping: Record<string, string>,
367
+ op: ChangeOperation<Type>,
368
+ ) {
369
+ const currentWorkflowName = op.target as string;
370
+ const currentWorkflow =
371
+ await this.project.resource<Workflow>(currentWorkflowName);
372
+ if (!currentWorkflow) {
373
+ throw new Error(
374
+ `Workflow '${currentWorkflowName}' does not exist in the project`,
375
+ );
376
+ }
377
+
378
+ const newWorkflow = await this.project.resource<Workflow>(op.to as string);
379
+ if (!newWorkflow) {
380
+ throw new Error(`Workflow '${op.to}' does not exist in the project`);
381
+ }
382
+
383
+ const currentWorkflowStates = currentWorkflow.states.map(
384
+ (state) => state.name,
385
+ );
386
+ const mappedSourceStates = Object.keys(stateMapping);
387
+ const unmappedCurrentStates = currentWorkflowStates.filter(
388
+ (stateName) => !mappedSourceStates.includes(stateName),
389
+ );
390
+
391
+ if (unmappedCurrentStates.length > 0) {
392
+ throw new Error(
393
+ `State mapping validation failed: The following states exist in the current workflow '${currentWorkflowName}' ` +
394
+ `but are not mapped from in the state mapping JSON file: ${unmappedCurrentStates.join(', ')}. ` +
395
+ `Please ensure all states in the current workflow are accounted for in the mapping to ensure all cards are properly updated.`,
396
+ );
397
+ }
398
+
399
+ // Also verify that all target states exist in the new workflow
400
+ const newWorkflowStates = newWorkflow.states.map((state) => state.name);
401
+ const mappedTargetStates = Object.values(stateMapping);
402
+ const invalidTargetStates = mappedTargetStates.filter(
403
+ (stateName) => !newWorkflowStates.includes(stateName),
404
+ );
405
+
406
+ if (invalidTargetStates.length > 0) {
407
+ throw new Error(
408
+ `State mapping validation failed: The following target states in the mapping do not exist in the new workflow '${op.to}': ${invalidTargetStates.join(', ')}.`,
409
+ );
410
+ }
411
+ }
412
+
318
413
  /**
319
414
  * Creates a new card type object. Base class writes the object to disk automatically.
320
415
  * @param workflowName Workflow name that this card type uses.
@@ -404,7 +499,12 @@ export class CardTypeResource extends FileResource {
404
499
  content.optionallyVisibleFields as Type[],
405
500
  ) as string[];
406
501
  } else if (key === 'workflow') {
502
+ const changeOp = op as ChangeOperation<string>;
503
+ const stateMapping = changeOp.mappingTable?.stateMapping || {};
407
504
  content.workflow = super.handleScalar(op) as string;
505
+ if (Object.keys(stateMapping).length > 0) {
506
+ await this.handleWorkflowChange(stateMapping, changeOp);
507
+ }
408
508
  } else if (key === 'customFields') {
409
509
  await this.validateFieldType(key, op);
410
510
  content.customFields = super.handleArray(
@@ -137,6 +137,16 @@ export class FileResource extends ResourceObject {
137
137
  return cards;
138
138
  }
139
139
 
140
+ // Get (resource folder) type name
141
+ protected get getType() {
142
+ return super.getType;
143
+ }
144
+
145
+ // Get logger instance
146
+ protected get logger() {
147
+ return super.getLogger(this.getType);
148
+ }
149
+
140
150
  // Initialize the resource.
141
151
  protected initialize() {
142
152
  if (this.resourceName.type === '') {
@@ -301,9 +311,9 @@ export class FileResource extends ResourceObject {
301
311
  ) {
302
312
  function toValue(op: Operation<Type>) {
303
313
  if (op.name === 'rank') return op.newIndex;
304
- if (op.name === 'add') return op.target;
305
- if (op.name === 'remove') return op.target;
306
- if (op.name === 'change') return op.to;
314
+ if (op.name === 'add') return JSON.stringify(op.target);
315
+ if (op.name === 'remove') return JSON.stringify(op.target);
316
+ if (op.name === 'change') return JSON.stringify(op.to);
307
317
  }
308
318
 
309
319
  // Check that new name is valid.
@@ -320,7 +330,9 @@ export class FileResource extends ResourceObject {
320
330
  } catch (error) {
321
331
  if (error instanceof Error) {
322
332
  const errorValue = typeof op === 'object' ? toValue(op) : op;
323
- throw new Error(`Cannot ${op.name} '${key}' --> '${errorValue}'`);
333
+ throw new Error(
334
+ `Cannot ${op.name} '${key}' --> '${errorValue}: ${error.message}'`,
335
+ );
324
336
  }
325
337
  }
326
338
 
@@ -11,8 +11,10 @@
11
11
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
12
  */
13
13
 
14
- import { basename, join } from 'node:path';
15
- import { mkdir, rename, rm } from 'node:fs/promises';
14
+ import { basename, dirname, join, normalize } from 'node:path';
15
+ import { mkdir, readdir, readFile, rename, rm } from 'node:fs/promises';
16
+
17
+ import { writeFileSafe } from '../utils/file-utils.js';
16
18
 
17
19
  import type { ResourceFolderType } from '../interfaces/project-interfaces.js';
18
20
  import {
@@ -27,6 +29,7 @@ import {
27
29
  sortCards,
28
30
  } from './file-resource.js';
29
31
  import type { ResourceContent } from '../interfaces/resource-interfaces.js';
32
+ import { VALID_FOLDER_RESOURCE_FILES } from '../utils/constants.js';
30
33
 
31
34
  export {
32
35
  type Card,
@@ -73,6 +76,15 @@ export class FolderResource extends FileResource {
73
76
  await rm(this.internalFolder, { recursive: true, force: true });
74
77
  }
75
78
 
79
+ // Get (resource folder) type name
80
+ protected get getType() {
81
+ return super.getType;
82
+ }
83
+
84
+ protected get logger() {
85
+ return super.getLogger(this.getType);
86
+ }
87
+
76
88
  protected initialize(): void {
77
89
  super.initialize();
78
90
 
@@ -98,6 +110,51 @@ export class FolderResource extends FileResource {
98
110
  return super.show();
99
111
  }
100
112
 
113
+ /**
114
+ * Shows the content of a file in the resource.
115
+ * @param fileName Name of the file to show.
116
+ * @returns the content of the file.
117
+ */
118
+ public async showFile(fileName: string): Promise<string> {
119
+ const filePath = join(this.internalFolder, fileName);
120
+ return readFile(filePath, 'utf8');
121
+ }
122
+
123
+ /**
124
+ * Shows all file names in the resource.
125
+ * @returns all file names in the resource.
126
+ */
127
+ public async showFileNames(): Promise<string[]> {
128
+ const files = await readdir(this.internalFolder);
129
+ return files.filter((file) => VALID_FOLDER_RESOURCE_FILES.includes(file));
130
+ }
131
+
132
+ /**
133
+ * Updates a file in the resource.
134
+ * @param fileName The name of the file to update.
135
+ * @param changedContent The new content for the file.
136
+ */
137
+ public async updateFile(fileName: string, changedContent: string) {
138
+ const filePath = join(this.internalFolder, fileName);
139
+
140
+ // Do not allow updating file in other directories
141
+ const normalizedFilePath = normalize(filePath);
142
+ const normalizedInternalFilePath = normalize(this.internalFolder);
143
+ if (dirname(normalizedFilePath) !== normalizedInternalFilePath) {
144
+ throw new Error(`File '${fileName}' is not in the resource`);
145
+ }
146
+
147
+ // This makes sure that the file is in the resource folder.
148
+ if (basename(normalizedFilePath) !== fileName) {
149
+ throw new Error(`File '${fileName}' is not in the resource`);
150
+ }
151
+ // check if the file is whitelisted
152
+ if (!VALID_FOLDER_RESOURCE_FILES.includes(fileName)) {
153
+ throw new Error(`File '${fileName}' is not whitelisted`);
154
+ }
155
+
156
+ await writeFileSafe(filePath, changedContent, { flag: 'w' });
157
+ }
101
158
  /**
102
159
  * Updates resource.
103
160
  * @param key Key to modify
@@ -150,7 +150,7 @@ export class GraphModelResource extends FolderResource {
150
150
 
151
151
  await super.update(key, op);
152
152
 
153
- const content = { ...(this.content as GraphModel) };
153
+ const content = structuredClone(this.content) as GraphModel;
154
154
 
155
155
  if (key === 'name') {
156
156
  content.name = super.handleScalar(op) as string;
@@ -144,7 +144,7 @@ export class GraphViewResource extends FolderResource {
144
144
 
145
145
  await super.update(key, op);
146
146
 
147
- const content = { ...(this.content as GraphView) };
147
+ const content = structuredClone(this.content) as GraphView;
148
148
 
149
149
  if (key === 'name') {
150
150
  content.name = super.handleScalar(op) as string;
@@ -179,7 +179,7 @@ export class ReportResource extends FolderResource {
179
179
 
180
180
  await super.update(key, op);
181
181
 
182
- const content = { ...(this.content as ReportMetadata) };
182
+ const content = structuredClone(this.content) as ReportMetadata;
183
183
 
184
184
  if (key === 'name') {
185
185
  content.name = super.handleScalar(op) as string;