@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
@@ -11,11 +11,7 @@
11
11
  */
12
12
 
13
13
  import type { DataType } from '../interfaces/resource-interfaces.js';
14
- import type {
15
- BaseResult,
16
- LinkDirection,
17
- ParseResult,
18
- } from '../types/queries.js';
14
+ import type { BaseResult, ParseResult } from '../types/queries.js';
19
15
 
20
16
  /**
21
17
  * This function reverses the encoding made by the "encodeClingoValue" function
@@ -28,25 +24,17 @@ export function decodeClingoValue(value: string) {
28
24
  return char;
29
25
  });
30
26
  }
27
+ // Enums and lists are handled by the query language
28
+ type FieldDataType = Omit<DataType, 'list' | 'enum'> | 'stringList';
31
29
 
32
30
  class ClingoParser {
33
31
  private keywords = [
34
32
  'queryError',
35
33
  'result',
36
34
  'childResult',
35
+ 'childObject',
37
36
  'field',
38
- 'enumField',
39
- 'listField',
40
- 'label',
41
- 'link',
42
- 'transitionDenied',
43
- 'movingCardDenied',
44
- 'deletingCardDenied',
45
- 'editingFieldDenied',
46
- 'editingContentDenied',
47
- 'notification',
48
- 'policyCheckFailure',
49
- 'policyCheckSuccess',
37
+ 'childResultCollection',
50
38
  'order',
51
39
  ];
52
40
 
@@ -62,6 +50,11 @@ class ClingoParser {
62
50
  childKey: string;
63
51
  collection: string;
64
52
  }[] = [];
53
+ private childObjectQueue: {
54
+ parentKey: string;
55
+ name: string;
56
+ collection: string;
57
+ }[] = [];
65
58
  private tempResults: { [key: string]: BaseResult } = {};
66
59
  private orderQueue: {
67
60
  level: number;
@@ -78,6 +71,7 @@ class ClingoParser {
78
71
  };
79
72
  this.resultQueue = [];
80
73
  this.childResultQueue = [];
74
+ this.childObjectQueue = [];
81
75
  this.tempResults = {};
82
76
  this.orderQueue = [];
83
77
  this.collections = new Set();
@@ -100,47 +94,20 @@ class ClingoParser {
100
94
  this.childResultQueue.push({ parentKey, childKey, collection });
101
95
  this.collections.add(collection);
102
96
  },
103
- enumField: async (
104
- key: string,
105
- fieldName: string,
106
- fieldValue: string,
107
- index: string,
108
- displayValue: string,
109
- ) => {
110
- const res = this.getOrInitResult(key);
111
- const decoded = decodeClingoValue(fieldValue);
112
- const parsedIndex = parseInt(index, 10);
113
- res[fieldName] = {
114
- value: decoded,
115
- index: parsedIndex,
116
- displayValue,
117
- };
118
- },
119
- // NOTE: Must be tested in INTDEV-623
120
- listField: async (
121
- key: string,
122
- fieldName: string,
123
- fieldValue: string,
124
- index: string,
125
- displayValue: string,
126
- ) => {
127
- const res = this.getOrInitResult(key);
128
- const decoded = decodeClingoValue(fieldValue);
129
- if (!res[fieldName] || !Array.isArray(res[fieldName])) {
130
- res[fieldName] = [];
97
+ childResultCollection: (parentKey: string, collection: string) => {
98
+ const parent = this.getOrInitResult(parentKey);
99
+ if (!parent[collection] || !Array.isArray(parent[collection])) {
100
+ parent[collection] = [];
131
101
  }
132
- const parsedIndex = parseInt(index, 10);
133
- (res[fieldName] as unknown[]).push({
134
- value: decoded,
135
- index: parsedIndex,
136
- displayValue,
137
- });
102
+ },
103
+ childObject: (parentKey: string, name: string, collection: string) => {
104
+ this.childObjectQueue.push({ parentKey, name, collection });
138
105
  },
139
106
  field: async (
140
107
  key: string,
141
108
  fieldName: string,
142
109
  fieldValue: string,
143
- dataType: DataType,
110
+ dataType: FieldDataType,
144
111
  ) => {
145
112
  const res = this.getOrInitResult(key);
146
113
  const decoded = decodeClingoValue(fieldValue);
@@ -161,89 +128,14 @@ class ClingoParser {
161
128
  case 'boolean':
162
129
  res[fieldName] = fieldValue === 'true';
163
130
  break;
131
+ case 'stringList':
132
+ if (!res[fieldName] || !Array.isArray(res[fieldName])) {
133
+ res[fieldName] = [];
134
+ }
135
+ (res[fieldName] as unknown[]).push(decoded);
136
+ break;
164
137
  }
165
138
  },
166
- label: (key: string, label: string) => {
167
- const res = this.getOrInitResult(key);
168
- res.labels.push(label);
169
- },
170
- link: (
171
- key: string, // key is the card itself
172
- cardKey: string, // cardKey is otherCard this is being linked to
173
- title: string,
174
- linkType: string,
175
- displayName: string,
176
- direction: LinkDirection,
177
- linkSource: 'user' | 'calculated',
178
- linkDescription?: string,
179
- ) => {
180
- const res = this.getOrInitResult(key);
181
- res.links.push({
182
- key: cardKey,
183
- linkType,
184
- displayName,
185
- linkDescription,
186
- direction,
187
- linkSource,
188
- title,
189
- });
190
- },
191
- transitionDenied: (
192
- key: string,
193
- transitionName: string,
194
- errorMessage: string,
195
- ) => {
196
- const res = this.getOrInitResult(key);
197
- res.deniedOperations.transition.push({ transitionName, errorMessage });
198
- },
199
- movingCardDenied: (key: string, errorMessage: string) => {
200
- const res = this.getOrInitResult(key);
201
- res.deniedOperations.move.push({ errorMessage });
202
- },
203
- deletingCardDenied: (key: string, errorMessage: string) => {
204
- const res = this.getOrInitResult(key);
205
- res.deniedOperations.delete.push({ errorMessage });
206
- },
207
- editingFieldDenied: (
208
- key: string,
209
- fieldName: string,
210
- errorMessage: string,
211
- ) => {
212
- const res = this.getOrInitResult(key);
213
- res.deniedOperations.editField.push({ fieldName, errorMessage });
214
- },
215
- editingContentDenied: (key: string, errorMessage: string) => {
216
- const res = this.getOrInitResult(key);
217
- res.deniedOperations.editContent.push({ errorMessage });
218
- },
219
- notification: (
220
- key: string,
221
- category: string,
222
- title: string,
223
- message: string,
224
- ) => {
225
- const res = this.getOrInitResult(key);
226
- res.notifications.push({ key, category, title, message });
227
- },
228
- policyCheckFailure: (
229
- key: string,
230
- category: string,
231
- title: string,
232
- errorMessage: string,
233
- fieldName?: string,
234
- ) => {
235
- const res = this.getOrInitResult(key);
236
- res.policyChecks.failures.push({
237
- category,
238
- title,
239
- errorMessage,
240
- fieldName,
241
- });
242
- },
243
- policyCheckSuccess: (key: string, category: string, title: string) => {
244
- const res = this.getOrInitResult(key);
245
- res.policyChecks.successes.push({ category, title });
246
- },
247
139
  order: (
248
140
  level: string,
249
141
  collection: string,
@@ -267,17 +159,6 @@ class ClingoParser {
267
159
  if (!this.tempResults[key]) {
268
160
  this.tempResults[key] = {
269
161
  key,
270
- labels: [],
271
- links: [],
272
- notifications: [],
273
- policyChecks: { successes: [], failures: [] },
274
- deniedOperations: {
275
- transition: [],
276
- move: [],
277
- delete: [],
278
- editField: [],
279
- editContent: [],
280
- },
281
162
  };
282
163
  }
283
164
  return this.tempResults[key];
@@ -379,6 +260,12 @@ class ClingoParser {
379
260
  (parent[collection] as unknown[]).push(child);
380
261
  });
381
262
 
263
+ this.childObjectQueue.forEach(({ parentKey, name, collection }) => {
264
+ const parent = this.getOrInitResult(parentKey);
265
+ const child = this.getOrInitResult(name);
266
+ parent[collection] = child;
267
+ });
268
+
382
269
  this.sortByLevel(this.result.results);
383
270
  }
384
271
 
@@ -15,6 +15,22 @@ import type { PredefinedCardMetadata } from '../interfaces/project-interfaces.js
15
15
 
16
16
  export const INT32_MAX = 2147483647; // 2^31-1
17
17
 
18
+ // Maximum level offset for includeMacro
19
+ export const MAX_LEVEL_OFFSET = 5;
20
+
21
+ /**
22
+ * These are file names that are valid for folder resources.
23
+ * Note that the folders might still contain other files, such as .schema files,
24
+ * but this is used for whitelisting the files that are allowed to be edited.
25
+ */
26
+ export const VALID_FOLDER_RESOURCE_FILES = [
27
+ 'index.adoc.hbs',
28
+ 'query.lp.hbs',
29
+ 'parameterSchema.json',
30
+ 'view.lp.hbs',
31
+ 'model.lp',
32
+ ];
33
+
18
34
  /**
19
35
  * These are field names that are non-custom fields that present in metadata
20
36
  */
package/src/utils/csv.ts CHANGED
@@ -45,7 +45,7 @@ export async function readCsvFile(file: string): Promise<CSVRowRaw[]> {
45
45
  if (!Array.isArray(row)) {
46
46
  throw new Error('Row is not an array');
47
47
  }
48
- return headers.reduce((acc, header, index) => {
48
+ return headers.reduce((acc: Record<string, string>, header, index) => {
49
49
  acc[header] = row[index];
50
50
  return acc;
51
51
  }, {});
@@ -10,8 +10,10 @@
10
10
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
11
11
  */
12
12
  import Handlebars from 'handlebars';
13
- import type { Calculate } from '../commands/index.js';
13
+ import type { CalculationEngine } from '../containers/project/calculation-engine.js';
14
14
  import { registerEmptyMacros } from '../macros/index.js';
15
+ import type { Context } from '../interfaces/project-interfaces.js';
16
+ import { resourceName } from './resource-utils.js';
15
17
 
16
18
  /**
17
19
  * Formats a value from a logic program for use to graphviz
@@ -30,15 +32,51 @@ export function formatAttributeValue(value?: string) {
30
32
  return `"${value}"`;
31
33
  }
32
34
 
35
+ /**
36
+ * Checks if a field is a custom field
37
+ * @param field - The field to check
38
+ * @returns True if the field is a custom field, false otherwise
39
+ */
40
+ export function isCustomField(field: string) {
41
+ try {
42
+ const { type } = resourceName(field, true);
43
+ return type === 'fieldTypes';
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ /**
49
+ * Formats a value for display in a report
50
+ * @param value - The value to format
51
+ * @returns The formatted value
52
+ */
53
+ export function formatValue(value: unknown): string {
54
+ if (typeof value === 'object') {
55
+ if (Array.isArray(value)) {
56
+ return value.map((v) => formatValue(v)).join(', ');
57
+ }
58
+ if (
59
+ value != null &&
60
+ 'displayValue' in value &&
61
+ typeof value.displayValue === 'string'
62
+ ) {
63
+ return value.displayValue;
64
+ }
65
+ return JSON.stringify(value, null, 2);
66
+ }
67
+ return value?.toString() ?? '';
68
+ }
69
+
33
70
  /**
34
71
  * Parameters for the core generation function
35
72
  */
36
73
  interface GenerateReportContentParams {
37
- calculate: Calculate;
74
+ calculate: CalculationEngine;
38
75
  contentTemplate: string;
39
76
  queryTemplate: string;
40
- options: Record<string, string>;
77
+ options: Record<string, string | undefined | boolean>;
41
78
  graph?: boolean;
79
+ context: Context;
42
80
  }
43
81
 
44
82
  /**
@@ -58,6 +96,7 @@ export async function generateReportContent(
58
96
  queryTemplate,
59
97
  graph,
60
98
  options, // Destructure options
99
+ context,
61
100
  } = params;
62
101
 
63
102
  const handlebars = Handlebars.create();
@@ -67,7 +106,7 @@ export async function generateReportContent(
67
106
  strict: true,
68
107
  });
69
108
 
70
- const result = await calculate.runLogicProgram(template(options));
109
+ const result = await calculate.runLogicProgram(template(options), context);
71
110
 
72
111
  if (result.error) {
73
112
  throw new Error(result.error);
@@ -78,6 +117,8 @@ export async function generateReportContent(
78
117
  if (graph) {
79
118
  handlebars.registerHelper('formatAttributeValue', formatAttributeValue);
80
119
  }
120
+ handlebars.registerHelper('isCustomField', isCustomField);
121
+ handlebars.registerHelper('formatValue', formatValue);
81
122
 
82
123
  return handlebars.compile(contentTemplate)({
83
124
  ...options,
@@ -29,7 +29,16 @@ const TYPE_INDEX = 1;
29
29
  const IDENTIFIER_INDEX = 2;
30
30
  // Valid resource name has three parts
31
31
  const RESOURCE_NAME_PARTS = 3;
32
+ const RESOURCE_FOLDER_TYPES = [
33
+ 'graphModels',
34
+ 'graphViews',
35
+ 'reports',
36
+ 'templates',
37
+ ];
32
38
 
39
+ export function isResourceFolderType(type: string): boolean {
40
+ return RESOURCE_FOLDER_TYPES.includes(type);
41
+ }
33
42
  // Checks if name is valid (3 parts, separated by '/').
34
43
  export function isResourceName(name: string): boolean {
35
44
  const partsCount = name.split('/').length;
@@ -84,19 +93,20 @@ export function resourceName(
84
93
  export function resourceNameToPath(
85
94
  project: Project,
86
95
  resourceName: ResourceName,
96
+ extension: string = '.json',
87
97
  ): string {
88
98
  if (project.projectPrefix === resourceName.prefix) {
89
99
  return join(
90
100
  project.paths.resourcesFolder,
91
101
  resourceName.type,
92
- resourceName.identifier + '.json',
102
+ resourceName.identifier + extension,
93
103
  );
94
104
  } else if (resourceName.prefix !== '') {
95
105
  return join(
96
106
  project.paths.modulesFolder,
97
107
  resourceName.prefix,
98
108
  resourceName.type,
99
- resourceName.identifier + '.json',
109
+ resourceName.identifier + extension,
100
110
  );
101
111
  }
102
112
  throw new Error('resourceName does not contain prefix');
@@ -9,10 +9,11 @@
9
9
  You should have received a copy of the GNU Affero General Public
10
10
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
11
11
  */
12
+ import { dirname } from 'node:path';
13
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
12
14
 
13
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
14
15
  import { formatJson } from './json.js';
15
- import { dirname } from 'path';
16
+ import { getChildLogger } from '../utils/log-utils.js';
16
17
 
17
18
  export interface UserPreferencesObject {
18
19
  editCommand: {
@@ -95,24 +96,41 @@ export class UserPreferences {
95
96
  };
96
97
 
97
98
  constructor(private prefsFilePath: string) {
98
- if (!existsSync(this.prefsFilePath)) {
99
- // Create the preferences directory based on prefsFilePath dirname
100
- const prefsDir = dirname(this.prefsFilePath);
99
+ // Create the preferences directory based on prefsFilePath dirname
100
+ const prefsDir = dirname(this.prefsFilePath);
101
101
 
102
- try {
103
- if (!existsSync(prefsDir)) {
104
- mkdirSync(prefsDir, { recursive: true });
102
+ try {
103
+ // Ensure directory exists first
104
+ if (!existsSync(prefsDir)) {
105
+ mkdirSync(prefsDir, { recursive: true });
106
+ }
107
+
108
+ // Try to create file exclusively using 'wx' flag
109
+ // This will fail atomically if file already exists
110
+ writeFileSync(this.prefsFilePath, formatJson(UserPreferences.defaults), {
111
+ flag: 'wx',
112
+ });
113
+ } catch (error) {
114
+ if (error instanceof Error) {
115
+ const err = error as NodeJS.ErrnoException;
116
+ // If file already exists (EEXIST), that's fine - we'll use the existing file
117
+ if (err?.code !== 'EEXIST') {
118
+ throw new Error(
119
+ `Error creating preferences file '${this.prefsFilePath}': ${error}`,
120
+ );
121
+ } else {
122
+ this.logger.warn('Preferences file already exists');
105
123
  }
106
- // File does not exist, create it with default content
107
- writeFileSync(this.prefsFilePath, formatJson(UserPreferences.defaults));
108
- } catch (error) {
109
- throw new Error(
110
- `Error creating preferences file '${this.prefsFilePath}': ${error}`,
111
- );
112
124
  }
113
125
  }
114
126
  }
115
127
 
128
+ private get logger() {
129
+ return getChildLogger({
130
+ module: 'userPreferences',
131
+ });
132
+ }
133
+
116
134
  public getPreferences(): UserPreferencesObject {
117
135
  // Read and parse the preferences file
118
136
  try {
@@ -13,11 +13,13 @@ import { type Schema, Validator } from 'jsonschema';
13
13
  import { DHValidationError, SchemaNotFound } from '../exceptions/index.js';
14
14
  import { schemas } from '@cyberismo/assets';
15
15
 
16
+ let validator: Validator | null = null;
17
+
16
18
  /**
17
19
  * Validates a JSON object against a schema
18
20
  * @param object The object to validate
19
21
  * @param schemaId The id of the schema to validate against
20
- * @param validator An optional validator to use. If validator is not provided or does not contain any schemas, project schemas will be used
22
+ * @param schema The schema to validate against. If schema is not provided, the schema with the given id will be used
21
23
  * @returns The object casted to the type T if it is valid
22
24
  * @throws DHValidationError if the object is not valid
23
25
  * @throws SchemaNotFound if the schema with the given id is not found
@@ -27,11 +29,9 @@ export function validateJson<T>(
27
29
  options: {
28
30
  schemaId?: string;
29
31
  schema?: Schema;
30
- validator?: Validator;
31
32
  },
32
33
  ): T {
33
34
  const { schemaId, schema } = options;
34
- let validator = options.validator;
35
35
 
36
36
  if (!schema && !schemaId) {
37
37
  throw new Error('Must either specify schema or schemaId');