@cyberismo/data-handler 0.0.7 → 0.0.9

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 (265) 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 +7 -4
  10. package/dist/commands/create.js +42 -15
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/edit.d.ts +9 -3
  13. package/dist/commands/edit.js +33 -9
  14. package/dist/commands/edit.js.map +1 -1
  15. package/dist/commands/export.d.ts +13 -11
  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 +21 -2
  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 +2 -4
  25. package/dist/commands/remove.js +8 -16
  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 +85 -7
  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 -8
  40. package/dist/commands/validate.js +30 -35
  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.d.ts +2 -1
  49. package/dist/containers/project/resource-collector.js +41 -33
  50. package/dist/containers/project/resource-collector.js.map +1 -1
  51. package/dist/containers/project.d.ts +18 -6
  52. package/dist/containers/project.js +37 -72
  53. package/dist/containers/project.js.map +1 -1
  54. package/dist/containers/template.d.ts +5 -0
  55. package/dist/containers/template.js +9 -0
  56. package/dist/containers/template.js.map +1 -1
  57. package/dist/exceptions/index.d.ts +20 -0
  58. package/dist/exceptions/index.js +16 -0
  59. package/dist/exceptions/index.js.map +1 -1
  60. package/dist/index.d.ts +5 -2
  61. package/dist/index.js +5 -1
  62. package/dist/index.js.map +1 -1
  63. package/dist/interfaces/macros.d.ts +7 -2
  64. package/dist/interfaces/project-interfaces.d.ts +21 -0
  65. package/dist/interfaces/project-interfaces.js +4 -0
  66. package/dist/interfaces/project-interfaces.js.map +1 -1
  67. package/dist/interfaces/resource-interfaces.d.ts +1 -1
  68. package/dist/interfaces/resource-interfaces.js.map +1 -1
  69. package/dist/macros/base-macro.d.ts +2 -0
  70. package/dist/macros/base-macro.js +66 -19
  71. package/dist/macros/base-macro.js.map +1 -1
  72. package/dist/macros/common.d.ts +16 -9
  73. package/dist/macros/common.js +22 -9
  74. package/dist/macros/common.js.map +1 -1
  75. package/dist/macros/createCards/index.d.ts +1 -2
  76. package/dist/macros/createCards/index.js.map +1 -1
  77. package/dist/macros/graph/index.d.ts +1 -3
  78. package/dist/macros/graph/index.js +11 -9
  79. package/dist/macros/graph/index.js.map +1 -1
  80. package/dist/macros/image/index.d.ts +39 -0
  81. package/dist/macros/image/index.js +78 -0
  82. package/dist/macros/image/index.js.map +1 -0
  83. package/dist/macros/image/metadata.d.ts +18 -0
  84. package/dist/macros/image/metadata.js +22 -0
  85. package/dist/macros/image/metadata.js.map +1 -0
  86. package/dist/macros/include/index.d.ts +32 -0
  87. package/dist/macros/include/index.js +97 -0
  88. package/dist/macros/include/index.js.map +1 -0
  89. package/dist/macros/include/metadata.d.ts +15 -0
  90. package/dist/macros/include/metadata.js +19 -0
  91. package/dist/macros/include/metadata.js.map +1 -0
  92. package/dist/macros/index.d.ts +39 -31
  93. package/dist/macros/index.js +167 -73
  94. package/dist/macros/index.js.map +1 -1
  95. package/dist/macros/percentage/index.d.ts +29 -0
  96. package/dist/macros/percentage/index.js +36 -0
  97. package/dist/macros/percentage/index.js.map +1 -0
  98. package/dist/macros/percentage/metadata.d.ts +15 -0
  99. package/dist/macros/percentage/metadata.js +19 -0
  100. package/dist/macros/percentage/metadata.js.map +1 -0
  101. package/dist/macros/report/index.d.ts +2 -5
  102. package/dist/macros/report/index.js +20 -12
  103. package/dist/macros/report/index.js.map +1 -1
  104. package/dist/macros/scoreCard/index.d.ts +15 -15
  105. package/dist/macros/scoreCard/index.js +16 -17
  106. package/dist/macros/scoreCard/index.js.map +1 -1
  107. package/dist/macros/vega/index.d.ts +28 -0
  108. package/dist/macros/vega/index.js +27 -0
  109. package/dist/macros/vega/index.js.map +1 -0
  110. package/dist/macros/vega/metadata.d.ts +15 -0
  111. package/dist/macros/vega/metadata.js +7 -0
  112. package/dist/macros/vega/metadata.js.map +1 -0
  113. package/dist/macros/vegalite/index.d.ts +27 -0
  114. package/dist/macros/vegalite/index.js +27 -0
  115. package/dist/macros/vegalite/index.js.map +1 -0
  116. package/dist/macros/vegalite/metadata.d.ts +15 -0
  117. package/dist/macros/vegalite/metadata.js +7 -0
  118. package/dist/macros/vegalite/metadata.js.map +1 -0
  119. package/dist/macros/xref/index.d.ts +26 -0
  120. package/dist/macros/xref/index.js +53 -0
  121. package/dist/macros/xref/index.js.map +1 -0
  122. package/dist/macros/xref/metadata.d.ts +15 -0
  123. package/dist/macros/xref/metadata.js +19 -0
  124. package/dist/macros/xref/metadata.js.map +1 -0
  125. package/dist/module-manager.d.ts +17 -4
  126. package/dist/module-manager.js +192 -58
  127. package/dist/module-manager.js.map +1 -1
  128. package/dist/permissions/action-guard.d.ts +2 -2
  129. package/dist/permissions/action-guard.js +1 -1
  130. package/dist/permissions/action-guard.js.map +1 -1
  131. package/dist/project-settings.js +2 -8
  132. package/dist/project-settings.js.map +1 -1
  133. package/dist/resources/card-type-resource.d.ts +2 -0
  134. package/dist/resources/card-type-resource.js +63 -0
  135. package/dist/resources/card-type-resource.js.map +1 -1
  136. package/dist/resources/file-resource.d.ts +2 -0
  137. package/dist/resources/file-resource.js +12 -4
  138. package/dist/resources/file-resource.js.map +1 -1
  139. package/dist/resources/folder-resource.d.ts +19 -0
  140. package/dist/resources/folder-resource.js +51 -2
  141. package/dist/resources/folder-resource.js.map +1 -1
  142. package/dist/resources/graph-model-resource.js +1 -1
  143. package/dist/resources/graph-model-resource.js.map +1 -1
  144. package/dist/resources/graph-view-resource.js +1 -1
  145. package/dist/resources/graph-view-resource.js.map +1 -1
  146. package/dist/resources/report-resource.js +1 -1
  147. package/dist/resources/report-resource.js.map +1 -1
  148. package/dist/resources/resource-object.d.ts +8 -0
  149. package/dist/resources/resource-object.js +9 -0
  150. package/dist/resources/resource-object.js.map +1 -1
  151. package/dist/resources/template-resource.js +1 -1
  152. package/dist/resources/template-resource.js.map +1 -1
  153. package/dist/resources/workflow-resource.d.ts +2 -0
  154. package/dist/resources/workflow-resource.js +53 -9
  155. package/dist/resources/workflow-resource.js.map +1 -1
  156. package/dist/svg/index.d.ts +15 -0
  157. package/dist/svg/index.js +16 -0
  158. package/dist/svg/index.js.map +1 -0
  159. package/dist/svg/lib.d.ts +9 -0
  160. package/dist/svg/lib.js +26 -0
  161. package/dist/svg/lib.js.map +1 -0
  162. package/dist/svg/percentage.d.ts +25 -0
  163. package/dist/svg/percentage.js +90 -0
  164. package/dist/svg/percentage.js.map +1 -0
  165. package/dist/svg/scoreCard.d.ts +19 -0
  166. package/dist/svg/scoreCard.js +55 -0
  167. package/dist/svg/scoreCard.js.map +1 -0
  168. package/dist/types/queries.d.ts +8 -7
  169. package/dist/types/queries.js.map +1 -1
  170. package/dist/utils/card-utils.d.ts +6 -0
  171. package/dist/utils/card-utils.js +12 -0
  172. package/dist/utils/card-utils.js.map +1 -1
  173. package/dist/utils/clingo-facts.d.ts +2 -1
  174. package/dist/utils/clingo-facts.js +19 -2
  175. package/dist/utils/clingo-facts.js.map +1 -1
  176. package/dist/utils/clingo-parser.d.ts +1 -0
  177. package/dist/utils/clingo-parser.js +22 -100
  178. package/dist/utils/clingo-parser.js.map +1 -1
  179. package/dist/utils/constants.d.ts +7 -0
  180. package/dist/utils/constants.js +14 -0
  181. package/dist/utils/constants.js.map +1 -1
  182. package/dist/utils/csv.js.map +1 -1
  183. package/dist/utils/report.d.ts +17 -3
  184. package/dist/utils/report.js +38 -2
  185. package/dist/utils/report.js.map +1 -1
  186. package/dist/utils/resource-utils.d.ts +1 -0
  187. package/dist/utils/resource-utils.js +9 -0
  188. package/dist/utils/resource-utils.js.map +1 -1
  189. package/dist/utils/user-preferences.d.ts +1 -11
  190. package/dist/utils/user-preferences.js +30 -13
  191. package/dist/utils/user-preferences.js.map +1 -1
  192. package/dist/utils/validate.d.ts +2 -3
  193. package/dist/utils/validate.js +2 -2
  194. package/dist/utils/validate.js.map +1 -1
  195. package/package.json +8 -6
  196. package/src/command-handler.ts +96 -17
  197. package/src/command-manager.ts +8 -8
  198. package/src/commands/calculate.ts +11 -525
  199. package/src/commands/create.ts +53 -16
  200. package/src/commands/edit.ts +53 -11
  201. package/src/commands/export.ts +108 -34
  202. package/src/commands/import.ts +31 -2
  203. package/src/commands/move.ts +12 -15
  204. package/src/commands/remove.ts +10 -19
  205. package/src/commands/rename.ts +3 -12
  206. package/src/commands/show.ts +121 -8
  207. package/src/commands/transition.ts +3 -7
  208. package/src/commands/update.ts +6 -0
  209. package/src/commands/validate.ts +39 -47
  210. package/src/containers/card-container.ts +74 -0
  211. package/src/containers/project/calculation-engine.ts +535 -0
  212. package/src/containers/project/resource-collector.ts +45 -26
  213. package/src/containers/project.ts +66 -84
  214. package/src/containers/template.ts +16 -0
  215. package/src/exceptions/index.ts +36 -0
  216. package/src/index.ts +13 -2
  217. package/src/interfaces/macros.ts +7 -1
  218. package/src/interfaces/project-interfaces.ts +27 -0
  219. package/src/interfaces/resource-interfaces.ts +1 -0
  220. package/src/macros/base-macro.ts +89 -25
  221. package/src/macros/common.ts +22 -9
  222. package/src/macros/createCards/index.ts +1 -2
  223. package/src/macros/graph/index.ts +17 -12
  224. package/src/macros/image/index.ts +121 -0
  225. package/src/macros/image/metadata.ts +25 -0
  226. package/src/macros/include/index.ts +147 -0
  227. package/src/macros/include/metadata.ts +22 -0
  228. package/src/macros/index.ts +179 -100
  229. package/src/macros/percentage/index.ts +54 -0
  230. package/src/macros/percentage/metadata.ts +22 -0
  231. package/src/macros/report/index.ts +22 -17
  232. package/src/macros/scoreCard/index.ts +23 -23
  233. package/src/macros/vega/index.ts +55 -0
  234. package/src/macros/vega/metadata.ts +21 -0
  235. package/src/macros/vegalite/index.ts +50 -0
  236. package/src/macros/vegalite/metadata.ts +21 -0
  237. package/src/macros/xref/index.ts +73 -0
  238. package/src/macros/xref/metadata.ts +22 -0
  239. package/src/module-manager.ts +241 -69
  240. package/src/permissions/action-guard.ts +3 -3
  241. package/src/project-settings.ts +2 -11
  242. package/src/resources/card-type-resource.ts +100 -0
  243. package/src/resources/file-resource.ts +16 -4
  244. package/src/resources/folder-resource.ts +59 -2
  245. package/src/resources/graph-model-resource.ts +1 -1
  246. package/src/resources/graph-view-resource.ts +1 -1
  247. package/src/resources/report-resource.ts +1 -1
  248. package/src/resources/resource-object.ts +14 -0
  249. package/src/resources/template-resource.ts +1 -1
  250. package/src/resources/workflow-resource.ts +68 -13
  251. package/src/svg/index.ts +15 -0
  252. package/src/svg/lib.ts +31 -0
  253. package/src/svg/percentage.ts +97 -0
  254. package/src/svg/scoreCard.ts +88 -0
  255. package/src/types/queries.ts +8 -7
  256. package/src/types/string-pixel-width.d.ts +23 -0
  257. package/src/utils/card-utils.ts +13 -0
  258. package/src/utils/clingo-facts.ts +65 -3
  259. package/src/utils/clingo-parser.ts +31 -144
  260. package/src/utils/constants.ts +16 -0
  261. package/src/utils/csv.ts +1 -1
  262. package/src/utils/report.ts +45 -4
  263. package/src/utils/resource-utils.ts +9 -0
  264. package/src/utils/user-preferences.ts +32 -14
  265. package/src/utils/validate.ts +3 -3
@@ -30,6 +30,8 @@ import type {
30
30
  ProjectMetadata,
31
31
  Resource,
32
32
  CardLocation,
33
+ Context,
34
+ ResourceFolderType,
33
35
  } from '../interfaces/project-interfaces.js';
34
36
  import type {
35
37
  CardType,
@@ -38,13 +40,18 @@ import type {
38
40
  Workflow,
39
41
  } from '../interfaces/resource-interfaces.js';
40
42
  import { Project, type ResourcesFrom } from '../containers/project.js';
41
- import { resourceName } from '../utils/resource-utils.js';
43
+ import {
44
+ type ResourceName,
45
+ resourceName,
46
+ resourceNameToString,
47
+ } from '../utils/resource-utils.js';
42
48
  import { TemplateResource } from '../resources/template-resource.js';
43
49
  import { UserPreferences } from '../utils/user-preferences.js';
44
50
 
45
51
  import ReportMacro from '../macros/report/index.js';
46
52
  import TaskQueue from '../macros/task-queue.js';
47
- import type { Calculate } from './calculate.js';
53
+ import { evaluateMacros } from '../macros/index.js';
54
+ import { FolderResource } from '../resources/folder-resource.js';
48
55
 
49
56
  /**
50
57
  * Show command.
@@ -54,11 +61,9 @@ export class Show {
54
61
  string,
55
62
  (from?: ResourcesFrom) => Promise<Resource[]>
56
63
  >;
57
- constructor(
58
- private project: Project,
59
- private calculate: Calculate,
60
- ) {
64
+ constructor(private project: Project) {
61
65
  this.resourceFunction = new Map([
66
+ ['calculations', this.project.calculations.bind(this.project)],
62
67
  ['cardTypes', this.project.cardTypes.bind(this.project)],
63
68
  ['fieldTypes', this.project.fieldTypes.bind(this.project)],
64
69
  ['graphModels', this.project.graphModels.bind(this.project)],
@@ -119,6 +124,27 @@ export class Show {
119
124
  }
120
125
  }
121
126
 
127
+ /**
128
+ * Shows all template cards in a project.
129
+ * @returns all template cards in a project.
130
+ */
131
+ public async showAllTemplateCards(): Promise<
132
+ { name: string; cards: Card[] }[]
133
+ > {
134
+ return Promise.all(
135
+ (await this.project.templates()).map(async (template) => {
136
+ const templateResource = new TemplateResource(
137
+ this.project,
138
+ resourceName(template.name),
139
+ );
140
+ return {
141
+ name: template.name,
142
+ cards: await templateResource.templateObject().showTemplateCards(),
143
+ };
144
+ }),
145
+ );
146
+ }
147
+
122
148
  /**
123
149
  * Shows all attachments (either template or project attachments) from a project.
124
150
  * @returns array of card attachments
@@ -264,6 +290,15 @@ export class Show {
264
290
  return this.project.listCards(cardsFrom);
265
291
  }
266
292
 
293
+ /**
294
+ * Shows the content of a logic program.
295
+ * @param cardKey The key of the card.
296
+ * @returns the content of the logic program.
297
+ */
298
+ public async showCardLogicProgram(cardKey: string) {
299
+ return this.project.calculationEngine.cardLogicProgram(cardKey);
300
+ }
301
+
267
302
  /**
268
303
  * Shows all card types in a project.
269
304
  * @returns array of card type details
@@ -282,6 +317,57 @@ export class Show {
282
317
  return results.filter((item) => item);
283
318
  }
284
319
 
320
+ /**
321
+ * Shows the content of a file in a resource.
322
+ * @param resourceName Name of the resource.
323
+ * @param fileName Name of the file to show.
324
+ * @returns the content of the file.
325
+ */
326
+ public async showFile(
327
+ resourceName: ResourceName,
328
+ fileName: string,
329
+ ): Promise<string> {
330
+ const resourceNameStr = resourceNameToString(resourceName);
331
+ if (
332
+ !(await this.project.resourceExists(
333
+ resourceName.type as ResourceFolderType,
334
+ resourceNameStr,
335
+ ))
336
+ ) {
337
+ throw new Error(
338
+ `Resource '${resourceNameStr}' does not exist in the project`,
339
+ );
340
+ }
341
+ const resource = Project.resourceObject(this.project, resourceName);
342
+ if (!(resource instanceof FolderResource)) {
343
+ throw new Error(`Resource '${resourceNameStr}' is not a folder resource`);
344
+ }
345
+ return resource.showFile(fileName);
346
+ }
347
+
348
+ /**
349
+ * Shows all file names in a folder resource.
350
+ * @param resourceName Name of the resource.
351
+ * @returns all file names in the resource.
352
+ */
353
+ public async showFileNames(resourceName: ResourceName): Promise<string[]> {
354
+ const resourceNameStr = resourceNameToString(resourceName);
355
+ if (
356
+ !(await this.project.resourceExists(
357
+ resourceName.type as ResourceFolderType,
358
+ resourceNameStr,
359
+ ))
360
+ ) {
361
+ throw new Error(
362
+ `Resource '${resourceNameStr}' does not exist in the project`,
363
+ );
364
+ }
365
+ const resource = Project.resourceObject(this.project, resourceName);
366
+ if (!(resource instanceof FolderResource)) {
367
+ throw new Error(`Resource '${resourceNameStr}' is not a folder resource`);
368
+ }
369
+ return resource.showFileNames();
370
+ }
285
371
  /**
286
372
  * Returns all unique labels in a project
287
373
  * @returns labels in a list
@@ -297,6 +383,15 @@ export class Show {
297
383
  return Array.from(new Set(labels));
298
384
  }
299
385
 
386
+ /**
387
+ * Shows the content of a logic program.
388
+ * @param resource Name of the resource.
389
+ * @returns the content of the logic program.
390
+ */
391
+ public async showLogicProgram(resource: ResourceName) {
392
+ return this.project.calculationEngine.resourceLogicProgram(resource);
393
+ }
394
+
300
395
  /**
301
396
  * Shows details of a module.
302
397
  * @param moduleName name of a module
@@ -349,6 +444,7 @@ export class Show {
349
444
  reportName: string,
350
445
  cardKey: string,
351
446
  parameters: object,
447
+ context: Context,
352
448
  outputPath?: string,
353
449
  ): Promise<string> {
354
450
  if (
@@ -359,16 +455,25 @@ export class Show {
359
455
  throw new Error(`Report '${reportName}' does not exist`);
360
456
  }
361
457
 
362
- const reportMacro = new ReportMacro(new TaskQueue(), this.calculate);
363
- const result = await reportMacro.handleInject(
458
+ await this.project.calculationEngine.generate();
459
+ const reportMacro = new ReportMacro(new TaskQueue());
460
+ let result = await reportMacro.handleInject(
364
461
  {
365
462
  project: this.project,
366
463
  cardKey: cardKey,
367
464
  mode: 'static',
465
+ context,
368
466
  },
369
467
  { name: reportName, ...parameters },
370
468
  );
371
469
 
470
+ result = await evaluateMacros(result, {
471
+ project: this.project,
472
+ cardKey: cardKey,
473
+ mode: 'static',
474
+ context,
475
+ });
476
+
372
477
  // Show the results either in the console or write to a file.
373
478
  if (outputPath) {
374
479
  try {
@@ -393,6 +498,14 @@ export class Show {
393
498
  name: string,
394
499
  showUse: boolean = false,
395
500
  ): Promise<ResourceContent | undefined> {
501
+ // TODO: remove this workaround once calculations are implemented as a resource class
502
+ if (resourceName(name).type === 'calculations') {
503
+ return {
504
+ name,
505
+ displayName: resourceName(name).identifier,
506
+ };
507
+ }
508
+
396
509
  const strictNameCheck = true;
397
510
  const resource = Project.resourceObject(
398
511
  this.project,
@@ -12,7 +12,6 @@
12
12
  */
13
13
 
14
14
  import { ActionGuard } from '../permissions/action-guard.js';
15
- import type { Calculate } from './calculate.js';
16
15
  import type {
17
16
  CardType,
18
17
  Workflow,
@@ -22,10 +21,7 @@ import { CardMetadataUpdater } from '../card-metadata-updater.js';
22
21
  import type { Project } from '../containers/project.js';
23
22
 
24
23
  export class Transition {
25
- constructor(
26
- private project: Project,
27
- private calculateCmd: Calculate,
28
- ) {}
24
+ constructor(private project: Project) {}
29
25
 
30
26
  /**
31
27
  * Transitions a card from its current state to a new state.
@@ -93,7 +89,7 @@ export class Transition {
93
89
  );
94
90
  }
95
91
 
96
- const actionGuard = new ActionGuard(this.calculateCmd);
92
+ const actionGuard = new ActionGuard(this.project.calculationEngine);
97
93
  await actionGuard.checkPermission('transition', cardKey, transition.name);
98
94
 
99
95
  details.metadata.workflowState = found.toState;
@@ -119,7 +115,7 @@ export class Transition {
119
115
  // Wrapper to run onTransition query.
120
116
  private async transitionChangesQuery(cardKey: string, transition: string) {
121
117
  if (!cardKey || !transition) return undefined;
122
- return this.calculateCmd.runQuery('onTransition', {
118
+ return this.project.calculationEngine.runQuery('onTransition', 'localApp', {
123
119
  cardKey,
124
120
  transition,
125
121
  });
@@ -34,6 +34,7 @@ export class Update {
34
34
  * @param key Property to change in resource JSON
35
35
  * @param value Value for 'key'
36
36
  * @param optionalDetail Additional detail needed for some operations. For example, 'update' needs a new value.
37
+ * @param mappingTable Optional mapping table for workflow state transitions (only used for workflow changes)
37
38
  */
38
39
  public async updateValue<Type>(
39
40
  name: string,
@@ -41,6 +42,7 @@ export class Update {
41
42
  key: string,
42
43
  value: Type,
43
44
  optionalDetail?: Type, // todo: for 'rank' it might be reasonable to accept also 'number'
45
+ mappingTable?: { stateMapping: Record<string, string> },
44
46
  ) {
45
47
  const resource = Project.resourceObject(this.project, resourceName(name));
46
48
  const op: Operation<Type> = {
@@ -60,6 +62,10 @@ export class Update {
60
62
  (op as ChangeOperation<Type>).to = optionalDetail
61
63
  ? optionalDetail
62
64
  : (value as Type);
65
+ // Add mapping table if provided (for workflow changes)
66
+ if (mappingTable) {
67
+ (op as ChangeOperation<Type>).mappingTable = mappingTable;
68
+ }
63
69
  } else if (operation === 'rank') {
64
70
  (op as RankOperation<Type>).newIndex = optionalDetail as number;
65
71
  (op as RankOperation<Type>).target = value;
@@ -42,7 +42,7 @@ import { isTemplateCard } from '../utils/card-utils.js';
42
42
  import { pathExists } from '../utils/file-utils.js';
43
43
  import { Project } from '../containers/project.js';
44
44
  import { readJsonFile } from '../utils/json.js';
45
- import { resourceName } from '../utils/resource-utils.js';
45
+ import { type ResourceName, resourceName } from '../utils/resource-utils.js';
46
46
 
47
47
  const invalidNames = new RegExp(
48
48
  '[<>:"/\\|?*\x00-\x1F]|^(?:aux|con|clock$|nul|prn|com[1-9]|lpt[1-9])$', // eslint-disable-line no-control-regex
@@ -52,7 +52,6 @@ const SHORT_TEXT_MAX_LENGTH = 80;
52
52
 
53
53
  import * as EmailValidator from 'email-validator';
54
54
  import { evaluateMacros } from '../macros/index.js';
55
- import { Calculate } from './calculate.js';
56
55
  const baseDir = dirname(fileURLToPath(import.meta.url));
57
56
  const subFoldersToValidate = ['.cards', 'cardRoot'];
58
57
 
@@ -547,7 +546,6 @@ export class Validate {
547
546
  } else {
548
547
  const errorMsg: string[] = [];
549
548
  const project = new Project(projectPath);
550
- const calculate = new Calculate(project);
551
549
 
552
550
  // Then, validate that each 'contentSchema' children as well.
553
551
  const result = await this.readAndValidateContentFiles(
@@ -562,7 +560,15 @@ export class Validate {
562
560
  const cards = await project.cards();
563
561
  cards.push(...(await project.allTemplateCards()));
564
562
 
563
+ const cardIds = new Map<string, number>();
564
+
565
565
  for (const card of cards) {
566
+ if (cardIds.has(card.key)) {
567
+ cardIds.set(card.key, (cardIds.get(card.key) || 0) + 1);
568
+ } else {
569
+ cardIds.set(card.key, 1);
570
+ }
571
+
566
572
  if (card.metadata) {
567
573
  // validate card's workflow
568
574
  if (!isTemplateCard(card)) {
@@ -591,15 +597,12 @@ export class Validate {
591
597
 
592
598
  // Validate macros in content
593
599
  if (card.content) {
594
- await evaluateMacros(
595
- card.content,
596
- {
597
- mode: 'validate',
598
- project,
599
- cardKey: card.key,
600
- },
601
- calculate,
602
- );
600
+ await evaluateMacros(card.content, {
601
+ context: 'localApp',
602
+ mode: 'validate',
603
+ project,
604
+ cardKey: card.key,
605
+ });
603
606
  }
604
607
  }
605
608
  if (errorMsg.length) {
@@ -607,6 +610,12 @@ export class Validate {
607
610
  .filter(this.removeDuplicateEntries)
608
611
  .join('\n');
609
612
  }
613
+ // Validate that there are no duplicate card keys
614
+ for (const [key, count] of cardIds) {
615
+ if (count > 1) {
616
+ validationErrors += `Duplicate card key '${key}' found ${count} times\n`;
617
+ }
618
+ }
610
619
  }
611
620
  } catch (error) {
612
621
  validationErrors += errorFunction(error);
@@ -704,41 +713,6 @@ export class Validate {
704
713
  return contentValidated && lengthValidated;
705
714
  }
706
715
 
707
- /**
708
- * Validate schema that matches schemaId from path.
709
- * @param projectPath path to schema
710
- * @param schemaId schema's id
711
- * @returns string containing all validation errors
712
- * @todo - unused; remove?
713
- */
714
- public async validateSchema(
715
- projectPath: string,
716
- schemaId: string,
717
- ): Promise<string> {
718
- const validationErrors: string[] = [];
719
- if (!schemaId.startsWith('/')) {
720
- schemaId = '/' + schemaId;
721
- }
722
- const activeJsonSchema = this.validator.schemas[schemaId];
723
- if (activeJsonSchema === undefined) {
724
- throw new Error(`Unknown schema '${schemaId}'`);
725
- } else {
726
- let contentFile = '';
727
- try {
728
- contentFile = await readJsonFile(projectPath);
729
- } catch {
730
- throw new Error(`Path is not valid ${projectPath}`);
731
- }
732
-
733
- const result = this.validator.validate(contentFile, activeJsonSchema);
734
- for (const error of result.errors) {
735
- const msg = `Schema '${schemaId}' validation Error: ${error.message}\n`;
736
- validationErrors.push(msg);
737
- }
738
- }
739
- return validationErrors.join('\n');
740
- }
741
-
742
716
  /**
743
717
  * Validates that card's custom fields are according to schema and have correct data in them.
744
718
  * @param project currently used Project
@@ -954,6 +928,24 @@ export class Validate {
954
928
  return validationErrors.join('\n');
955
929
  }
956
930
 
931
+ /**
932
+ * Validates a single resource.
933
+ * @param resource Resource to validate
934
+ * @returns string containing all validation errors
935
+ */
936
+ public async validateResource(
937
+ resourceName: ResourceName,
938
+ project: Project,
939
+ ): Promise<string> {
940
+ try {
941
+ const resource = Project.resourceObject(project, resourceName);
942
+ await resource.validate();
943
+ return '';
944
+ } catch (error) {
945
+ return errorFunction(error);
946
+ }
947
+ }
948
+
957
949
  /**
958
950
  * Possibly creates (if no instance exists) and returns an instance of Validate command.
959
951
  * @returns instance of Validate command.
@@ -17,6 +17,8 @@ import { basename, join, sep } from 'node:path';
17
17
  import type { Dirent } from 'node:fs';
18
18
  import { readdir, readFile, writeFile } from 'node:fs/promises';
19
19
 
20
+ import { findParentPath } from '../utils/card-utils.js';
21
+ import { readJsonFile } from '../utils/json.js';
20
22
  import { writeJsonFile } from '../utils/json.js';
21
23
  import { getFilesSync } from '../utils/file-utils.js';
22
24
 
@@ -24,6 +26,7 @@ import { getFilesSync } from '../utils/file-utils.js';
24
26
  import {
25
27
  type CardAttachment,
26
28
  type Card,
29
+ type CardMetadata,
27
30
  CardNameRegEx,
28
31
  type FetchCardDetails,
29
32
  } from '../interfaces/project-interfaces.js';
@@ -375,4 +378,75 @@ export class CardContainer {
375
378
  await writeJsonFile(metadataFile, card.metadata);
376
379
  }
377
380
  }
381
+
382
+ /**
383
+ * Show cards with hierarchy structure from a given path.
384
+ * @param path The path to read cards from
385
+ * @returns an array of cards with proper parent-child relationships.
386
+ */
387
+ protected async showCards(path: string): Promise<Card[]> {
388
+ const cards: Card[] = [];
389
+ const cardPathMap = new Map<string, Card>();
390
+ const entries = await readdir(path, {
391
+ withFileTypes: true,
392
+ recursive: true,
393
+ });
394
+
395
+ // Checks if Dirent folder is a card folder
396
+ function cardFolder(
397
+ entry: Dirent,
398
+ cardPathMap: Map<string, Card>,
399
+ ): Card | undefined {
400
+ const fullPath = join(entry.parentPath, entry.name);
401
+ if (!cardPathMap.has(fullPath)) {
402
+ const newCard: Card = {
403
+ key: entry.name,
404
+ path: fullPath,
405
+ children: [],
406
+ attachments: [],
407
+ };
408
+ cardPathMap.set(fullPath, newCard);
409
+ return newCard;
410
+ }
411
+ }
412
+
413
+ // Process card directories first
414
+ entries
415
+ .filter((entry) => entry.isDirectory() && CardNameRegEx.test(entry.name))
416
+ .forEach((entry) => {
417
+ const card = cardFolder(entry, cardPathMap);
418
+ if (card) cards.push(card);
419
+ });
420
+
421
+ // Process metadata files in parallel
422
+ await Promise.all(
423
+ entries
424
+ .filter(
425
+ (entry) =>
426
+ entry.isFile() && entry.name === CardContainer.cardMetadataFile,
427
+ )
428
+ .map(async (entry) => {
429
+ const parentCard = cardPathMap.get(entry.parentPath);
430
+ if (!parentCard) return;
431
+ parentCard.metadata = (await readJsonFile(
432
+ join(entry.parentPath, entry.name),
433
+ )) as CardMetadata;
434
+ }),
435
+ );
436
+
437
+ // Finally, build the card hierarchy
438
+ Array.from(cardPathMap.entries()).map(([cardPath, card]) => {
439
+ const parentPath = findParentPath(cardPath);
440
+ if (!parentPath) return;
441
+ const parentCard = cardPathMap.get(parentPath);
442
+ if (!parentCard) return;
443
+
444
+ parentCard.children.push(card);
445
+ const index = cards.indexOf(card);
446
+ if (index > -1) {
447
+ cards.splice(index, 1);
448
+ }
449
+ });
450
+ return cards;
451
+ }
378
452
  }