@cyberismo/data-handler 0.0.14 → 0.0.16

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 (280) hide show
  1. package/dist/card-metadata-updater.js +8 -4
  2. package/dist/card-metadata-updater.js.map +1 -1
  3. package/dist/command-handler.d.ts +4 -0
  4. package/dist/command-handler.js +29 -19
  5. package/dist/command-handler.js.map +1 -1
  6. package/dist/command-manager.d.ts +25 -2
  7. package/dist/command-manager.js +30 -5
  8. package/dist/command-manager.js.map +1 -1
  9. package/dist/commands/create.d.ts +1 -1
  10. package/dist/commands/create.js +45 -93
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/edit.d.ts +1 -15
  13. package/dist/commands/edit.js +15 -89
  14. package/dist/commands/edit.js.map +1 -1
  15. package/dist/commands/export.d.ts +11 -2
  16. package/dist/commands/export.js +58 -58
  17. package/dist/commands/export.js.map +1 -1
  18. package/dist/commands/import.d.ts +9 -1
  19. package/dist/commands/import.js +17 -11
  20. package/dist/commands/import.js.map +1 -1
  21. package/dist/commands/move.d.ts +1 -2
  22. package/dist/commands/move.js +107 -146
  23. package/dist/commands/move.js.map +1 -1
  24. package/dist/commands/remove.d.ts +8 -1
  25. package/dist/commands/remove.js +17 -48
  26. package/dist/commands/remove.js.map +1 -1
  27. package/dist/commands/rename.d.ts +4 -9
  28. package/dist/commands/rename.js +34 -108
  29. package/dist/commands/rename.js.map +1 -1
  30. package/dist/commands/show.d.ts +22 -34
  31. package/dist/commands/show.js +103 -151
  32. package/dist/commands/show.js.map +1 -1
  33. package/dist/commands/transition.d.ts +9 -2
  34. package/dist/commands/transition.js +49 -44
  35. package/dist/commands/transition.js.map +1 -1
  36. package/dist/commands/update.d.ts +18 -12
  37. package/dist/commands/update.js +34 -18
  38. package/dist/commands/update.js.map +1 -1
  39. package/dist/commands/validate.d.ts +18 -10
  40. package/dist/commands/validate.js +101 -47
  41. package/dist/commands/validate.js.map +1 -1
  42. package/dist/containers/card-container.d.ts +87 -24
  43. package/dist/containers/card-container.js +183 -279
  44. package/dist/containers/card-container.js.map +1 -1
  45. package/dist/containers/project/calculation-engine.d.ts +13 -4
  46. package/dist/containers/project/calculation-engine.js +79 -77
  47. package/dist/containers/project/calculation-engine.js.map +1 -1
  48. package/dist/containers/project/card-cache.d.ts +146 -0
  49. package/dist/containers/project/card-cache.js +411 -0
  50. package/dist/containers/project/card-cache.js.map +1 -0
  51. package/dist/containers/project/project-paths.d.ts +5 -4
  52. package/dist/containers/project/project-paths.js +16 -12
  53. package/dist/containers/project/project-paths.js.map +1 -1
  54. package/dist/containers/project/resource-cache.d.ts +169 -0
  55. package/dist/containers/project/resource-cache.js +507 -0
  56. package/dist/containers/project/resource-cache.js.map +1 -0
  57. package/dist/containers/project/resource-handler.d.ts +129 -0
  58. package/dist/containers/project/resource-handler.js +206 -0
  59. package/dist/containers/project/resource-handler.js.map +1 -0
  60. package/dist/containers/project.d.ts +114 -195
  61. package/dist/containers/project.js +425 -535
  62. package/dist/containers/project.js.map +1 -1
  63. package/dist/containers/template.d.ts +22 -32
  64. package/dist/containers/template.js +113 -115
  65. package/dist/containers/template.js.map +1 -1
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +1 -0
  68. package/dist/index.js.map +1 -1
  69. package/dist/interfaces/folder-content-interfaces.d.ts +7 -4
  70. package/dist/interfaces/folder-content-interfaces.js +3 -3
  71. package/dist/interfaces/folder-content-interfaces.js.map +1 -1
  72. package/dist/interfaces/macros.d.ts +1 -0
  73. package/dist/interfaces/macros.js +1 -1
  74. package/dist/interfaces/macros.js.map +1 -1
  75. package/dist/interfaces/project-interfaces.d.ts +7 -5
  76. package/dist/interfaces/project-interfaces.js.map +1 -1
  77. package/dist/interfaces/resource-interfaces.d.ts +25 -22
  78. package/dist/interfaces/resource-interfaces.js +3 -0
  79. package/dist/interfaces/resource-interfaces.js.map +1 -1
  80. package/dist/macros/common.d.ts +10 -10
  81. package/dist/macros/createCards/index.d.ts +0 -13
  82. package/dist/macros/createCards/index.js.map +1 -1
  83. package/dist/macros/createCards/types.d.ts +44 -0
  84. package/dist/macros/createCards/types.js +15 -0
  85. package/dist/macros/createCards/types.js.map +1 -0
  86. package/dist/macros/graph/index.d.ts +2 -6
  87. package/dist/macros/graph/index.js +14 -28
  88. package/dist/macros/graph/index.js.map +1 -1
  89. package/dist/macros/graph/types.d.ts +23 -0
  90. package/dist/macros/graph/types.js +15 -0
  91. package/dist/macros/graph/types.js.map +1 -0
  92. package/dist/macros/image/index.d.ts +8 -16
  93. package/dist/macros/image/index.js +36 -33
  94. package/dist/macros/image/index.js.map +1 -1
  95. package/dist/macros/image/types.d.ts +38 -0
  96. package/dist/macros/image/types.js +15 -0
  97. package/dist/macros/image/types.js.map +1 -0
  98. package/dist/macros/include/index.d.ts +1 -6
  99. package/dist/macros/include/index.js +4 -7
  100. package/dist/macros/include/index.js.map +1 -1
  101. package/dist/macros/include/types.d.ts +31 -0
  102. package/dist/macros/include/types.js +15 -0
  103. package/dist/macros/include/types.js.map +1 -0
  104. package/dist/macros/index.d.ts +1 -1
  105. package/dist/macros/index.js +2 -2
  106. package/dist/macros/index.js.map +1 -1
  107. package/dist/macros/percentage/index.d.ts +0 -6
  108. package/dist/macros/percentage/index.js.map +1 -1
  109. package/dist/macros/percentage/types.d.ts +31 -0
  110. package/dist/macros/percentage/types.js +15 -0
  111. package/dist/macros/percentage/types.js.map +1 -0
  112. package/dist/macros/report/index.d.ts +0 -3
  113. package/dist/macros/report/index.js +3 -6
  114. package/dist/macros/report/index.js.map +1 -1
  115. package/dist/macros/report/types.d.ts +19 -0
  116. package/dist/macros/report/types.js +15 -0
  117. package/dist/macros/report/types.js.map +1 -0
  118. package/dist/macros/scoreCard/index.d.ts +0 -6
  119. package/dist/macros/scoreCard/index.js.map +1 -1
  120. package/dist/macros/scoreCard/types.d.ts +31 -0
  121. package/dist/macros/scoreCard/types.js +15 -0
  122. package/dist/macros/scoreCard/types.js.map +1 -0
  123. package/dist/macros/types.d.ts +25 -0
  124. package/dist/macros/types.js +2 -0
  125. package/dist/macros/types.js.map +1 -0
  126. package/dist/macros/vega/index.d.ts +0 -4
  127. package/dist/macros/vega/index.js.map +1 -1
  128. package/dist/macros/vega/types.d.ts +20 -0
  129. package/dist/macros/vega/types.js +2 -0
  130. package/dist/macros/vega/types.js.map +1 -0
  131. package/dist/macros/vegalite/index.d.ts +0 -4
  132. package/dist/macros/vegalite/index.js.map +1 -1
  133. package/dist/macros/vegalite/types.d.ts +20 -0
  134. package/dist/macros/vegalite/types.js +15 -0
  135. package/dist/macros/vegalite/types.js.map +1 -0
  136. package/dist/macros/xref/index.d.ts +0 -3
  137. package/dist/macros/xref/index.js +5 -14
  138. package/dist/macros/xref/index.js.map +1 -1
  139. package/dist/macros/xref/types.d.ts +19 -0
  140. package/dist/macros/xref/types.js +15 -0
  141. package/dist/macros/xref/types.js.map +1 -0
  142. package/dist/module-manager.d.ts +16 -3
  143. package/dist/module-manager.js +55 -23
  144. package/dist/module-manager.js.map +1 -1
  145. package/dist/project-settings.d.ts +16 -3
  146. package/dist/project-settings.js +79 -14
  147. package/dist/project-settings.js.map +1 -1
  148. package/dist/resources/calculation-resource.d.ts +6 -33
  149. package/dist/resources/calculation-resource.js +11 -60
  150. package/dist/resources/calculation-resource.js.map +1 -1
  151. package/dist/resources/card-type-resource.d.ts +10 -22
  152. package/dist/resources/card-type-resource.js +46 -66
  153. package/dist/resources/card-type-resource.js.map +1 -1
  154. package/dist/resources/create-defaults.d.ts +3 -2
  155. package/dist/resources/create-defaults.js +3 -2
  156. package/dist/resources/create-defaults.js.map +1 -1
  157. package/dist/resources/field-type-resource.d.ts +8 -22
  158. package/dist/resources/field-type-resource.js +35 -60
  159. package/dist/resources/field-type-resource.js.map +1 -1
  160. package/dist/resources/file-resource.d.ts +14 -35
  161. package/dist/resources/file-resource.js +22 -301
  162. package/dist/resources/file-resource.js.map +1 -1
  163. package/dist/resources/folder-resource.d.ts +44 -66
  164. package/dist/resources/folder-resource.js +102 -149
  165. package/dist/resources/folder-resource.js.map +1 -1
  166. package/dist/resources/graph-model-resource.d.ts +9 -34
  167. package/dist/resources/graph-model-resource.js +18 -64
  168. package/dist/resources/graph-model-resource.js.map +1 -1
  169. package/dist/resources/graph-view-resource.d.ts +9 -29
  170. package/dist/resources/graph-view-resource.js +13 -48
  171. package/dist/resources/graph-view-resource.js.map +1 -1
  172. package/dist/resources/link-type-resource.d.ts +9 -23
  173. package/dist/resources/link-type-resource.js +11 -33
  174. package/dist/resources/link-type-resource.js.map +1 -1
  175. package/dist/resources/report-resource.d.ts +10 -23
  176. package/dist/resources/report-resource.js +20 -67
  177. package/dist/resources/report-resource.js.map +1 -1
  178. package/dist/resources/resource-object.d.ts +143 -23
  179. package/dist/resources/resource-object.js +369 -48
  180. package/dist/resources/resource-object.js.map +1 -1
  181. package/dist/resources/template-resource.d.ts +10 -17
  182. package/dist/resources/template-resource.js +19 -27
  183. package/dist/resources/template-resource.js.map +1 -1
  184. package/dist/resources/workflow-resource.d.ts +9 -25
  185. package/dist/resources/workflow-resource.js +25 -55
  186. package/dist/resources/workflow-resource.js.map +1 -1
  187. package/dist/utils/card-utils.d.ts +69 -19
  188. package/dist/utils/card-utils.js +179 -30
  189. package/dist/utils/card-utils.js.map +1 -1
  190. package/dist/utils/clingo-fact-builder.d.ts +25 -14
  191. package/dist/utils/clingo-fact-builder.js +27 -5
  192. package/dist/utils/clingo-fact-builder.js.map +1 -1
  193. package/dist/utils/clingo-facts.js +14 -7
  194. package/dist/utils/clingo-facts.js.map +1 -1
  195. package/dist/utils/clingo-parser.js +1 -1
  196. package/dist/utils/clingo-parser.js.map +1 -1
  197. package/dist/utils/constants.d.ts +2 -0
  198. package/dist/utils/constants.js +4 -0
  199. package/dist/utils/constants.js.map +1 -1
  200. package/dist/utils/csv.js +1 -1
  201. package/dist/utils/csv.js.map +1 -1
  202. package/dist/utils/resource-utils.d.ts +1 -0
  203. package/dist/utils/resource-utils.js +2 -1
  204. package/dist/utils/resource-utils.js.map +1 -1
  205. package/package.json +11 -11
  206. package/src/card-metadata-updater.ts +9 -7
  207. package/src/command-handler.ts +35 -23
  208. package/src/command-manager.ts +32 -19
  209. package/src/commands/create.ts +59 -160
  210. package/src/commands/edit.ts +16 -132
  211. package/src/commands/export.ts +71 -81
  212. package/src/commands/import.ts +26 -18
  213. package/src/commands/move.ts +143 -179
  214. package/src/commands/remove.ts +20 -59
  215. package/src/commands/rename.ts +45 -156
  216. package/src/commands/show.ts +153 -211
  217. package/src/commands/transition.ts +53 -58
  218. package/src/commands/update.ts +44 -23
  219. package/src/commands/validate.ts +108 -82
  220. package/src/containers/card-container.ts +200 -360
  221. package/src/containers/project/calculation-engine.ts +81 -105
  222. package/src/containers/project/card-cache.ts +497 -0
  223. package/src/containers/project/project-paths.ts +21 -13
  224. package/src/containers/project/resource-cache.ts +648 -0
  225. package/src/containers/project/resource-handler.ts +265 -0
  226. package/src/containers/project.ts +551 -693
  227. package/src/containers/template.ts +129 -142
  228. package/src/index.ts +1 -0
  229. package/src/interfaces/folder-content-interfaces.ts +14 -7
  230. package/src/interfaces/macros.ts +2 -0
  231. package/src/interfaces/project-interfaces.ts +14 -7
  232. package/src/interfaces/resource-interfaces.ts +30 -27
  233. package/src/macros/createCards/index.ts +1 -12
  234. package/src/macros/createCards/types.ts +46 -0
  235. package/src/macros/graph/index.ts +27 -52
  236. package/src/macros/graph/types.ts +24 -0
  237. package/src/macros/image/index.ts +50 -61
  238. package/src/macros/image/types.ts +39 -0
  239. package/src/macros/include/index.ts +6 -15
  240. package/src/macros/include/types.ts +32 -0
  241. package/src/macros/index.ts +2 -2
  242. package/src/macros/percentage/index.ts +1 -7
  243. package/src/macros/percentage/types.ts +32 -0
  244. package/src/macros/report/index.ts +4 -13
  245. package/src/macros/report/types.ts +20 -0
  246. package/src/macros/scoreCard/index.ts +1 -7
  247. package/src/macros/scoreCard/types.ts +32 -0
  248. package/src/macros/types.ts +48 -0
  249. package/src/macros/vega/index.ts +1 -4
  250. package/src/macros/vega/types.ts +21 -0
  251. package/src/macros/vegalite/index.ts +1 -4
  252. package/src/macros/vegalite/types.ts +22 -0
  253. package/src/macros/xref/index.ts +6 -20
  254. package/src/macros/xref/types.ts +20 -0
  255. package/src/module-manager.ts +79 -22
  256. package/src/project-settings.ts +84 -15
  257. package/src/resources/calculation-resource.ts +21 -91
  258. package/src/resources/card-type-resource.ts +74 -109
  259. package/src/resources/create-defaults.ts +3 -2
  260. package/src/resources/field-type-resource.ts +61 -104
  261. package/src/resources/file-resource.ts +33 -441
  262. package/src/resources/folder-resource.ts +130 -207
  263. package/src/resources/graph-model-resource.ts +36 -95
  264. package/src/resources/graph-view-resource.ts +28 -70
  265. package/src/resources/link-type-resource.ts +23 -53
  266. package/src/resources/report-resource.ts +34 -96
  267. package/src/resources/resource-object.ts +511 -66
  268. package/src/resources/template-resource.ts +32 -44
  269. package/src/resources/workflow-resource.ts +42 -85
  270. package/src/utils/card-utils.ts +217 -31
  271. package/src/utils/clingo-fact-builder.ts +28 -16
  272. package/src/utils/clingo-facts.ts +16 -7
  273. package/src/utils/clingo-parser.ts +1 -1
  274. package/src/utils/constants.ts +6 -0
  275. package/src/utils/csv.ts +1 -1
  276. package/src/utils/resource-utils.ts +2 -1
  277. package/dist/containers/project/resource-collector.d.ts +0 -87
  278. package/dist/containers/project/resource-collector.js +0 -337
  279. package/dist/containers/project/resource-collector.js.map +0 -1
  280. package/src/containers/project/resource-collector.ts +0 -396
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import { writeJsonFile as atomicWrite } from 'write-json-file';
15
+ import { writeFileSync } from 'node:fs';
15
16
 
16
17
  import { resolve } from 'node:path';
17
18
  import { URL } from 'node:url';
@@ -21,47 +22,51 @@ import type {
21
22
  ModuleSetting,
22
23
  ProjectSettings,
23
24
  } from './interfaces/project-interfaces.js';
25
+ import { formatJson } from './utils/json.js';
26
+ import { getChildLogger } from './utils/log-utils.js';
24
27
  import { readJsonFileSync } from './utils/json.js';
25
- import { Validate } from './commands/index.js';
28
+ import { Validate } from './commands/validate.js';
29
+ import { SCHEMA_VERSION } from '@cyberismo/assets';
26
30
 
27
31
  /**
28
32
  * Represents Project's cardsConfig.json file.
29
33
  */
30
34
  export class ProjectConfiguration implements ProjectSettings {
31
- private static instance: ProjectConfiguration;
32
-
35
+ schemaVersion?: number;
33
36
  name: string;
34
37
  cardKeyPrefix: string;
35
38
  modules: ModuleSetting[];
36
39
  hubs: HubSetting[];
40
+ private logger = getChildLogger({ module: 'Project' });
37
41
  private settingPath: string;
42
+ private autoSave: boolean = false;
38
43
 
39
- constructor(path: string) {
44
+ constructor(path: string, autoSave: boolean = true) {
40
45
  this.name = '';
41
46
  this.settingPath = path;
42
47
  this.cardKeyPrefix = '';
43
48
  this.modules = [];
44
49
  this.hubs = [];
50
+ this.autoSave = autoSave;
45
51
  this.readSettings();
52
+ this.ensureSchemaVersionAndSave();
46
53
  }
47
54
 
48
- // Persists configuration file to disk.
49
- public async save() {
50
- if (this.cardKeyPrefix === '') {
51
- throw new Error('wrong configuration');
52
- }
53
- try {
54
- await atomicWrite(this.settingPath, this.toJSON(), { indent: 4 });
55
- } catch (error) {
56
- if (error instanceof Error) {
57
- console.error(error.message);
55
+ // Ensures that schemaVersion is set in the project configuration.
56
+ // If missing, sets it to the current SCHEMA_VERSION and marks for auto-save.
57
+ private ensureSchemaVersionAndSave() {
58
+ if (this.schemaVersion === undefined) {
59
+ this.schemaVersion = SCHEMA_VERSION;
60
+ // Auto-saves the configuration, if schema version was updated.
61
+ if (this.autoSave) {
62
+ this.saveSync();
58
63
  }
59
64
  }
60
65
  }
61
66
 
62
67
  // Sets configuration values from file.
63
68
  private readSettings() {
64
- const settings = readJsonFileSync(this.settingPath) as ProjectConfiguration;
69
+ const settings = readJsonFileSync(this.settingPath);
65
70
  if (!settings) {
66
71
  throw new Error(`File at '${this.settingPath}' is not a valid JSON file`);
67
72
  }
@@ -71,6 +76,7 @@ export class ProjectConfiguration implements ProjectSettings {
71
76
  Object.prototype.hasOwnProperty.call(settings, 'name');
72
77
 
73
78
  if (valid) {
79
+ this.schemaVersion = settings.schemaVersion;
74
80
  this.cardKeyPrefix = settings.cardKeyPrefix;
75
81
  this.name = settings.name;
76
82
  this.modules = settings.modules || [];
@@ -80,9 +86,24 @@ export class ProjectConfiguration implements ProjectSettings {
80
86
  }
81
87
  }
82
88
 
89
+ // Synchronously persists configuration file to disk.
90
+ private saveSync() {
91
+ if (this.cardKeyPrefix === '') {
92
+ throw new Error('wrong configuration');
93
+ }
94
+ try {
95
+ writeFileSync(this.settingPath, formatJson(this.toJSON()), 'utf-8');
96
+ } catch (error) {
97
+ if (error instanceof Error) {
98
+ this.logger.error({ error }, 'Cannot write project configuration');
99
+ }
100
+ }
101
+ }
102
+
83
103
  // Return the configuration as object
84
104
  private toJSON(): ProjectSettings {
85
105
  return {
106
+ schemaVersion: this.schemaVersion,
86
107
  cardKeyPrefix: this.cardKeyPrefix,
87
108
  name: this.name,
88
109
  modules: this.modules,
@@ -152,6 +173,39 @@ export class ProjectConfiguration implements ProjectSettings {
152
173
  return this.save();
153
174
  }
154
175
 
176
+ /**
177
+ * Checks schema version compatibility.
178
+ * @returns Compatibility state (true - compatible; false - not) and optional message related to it.
179
+ */
180
+ public checkSchemaVersion(): { isCompatible: boolean; message: string } {
181
+ if (this.schemaVersion === undefined) {
182
+ return {
183
+ isCompatible: true,
184
+ message: '',
185
+ };
186
+ }
187
+
188
+ if (this.schemaVersion < SCHEMA_VERSION) {
189
+ return {
190
+ isCompatible: false,
191
+ message: `Schema version mismatch: Project schema version (${this.schemaVersion}) is older than the application schema version (${SCHEMA_VERSION}). A migration is needed.`,
192
+ };
193
+ }
194
+
195
+ if (this.schemaVersion > SCHEMA_VERSION) {
196
+ return {
197
+ isCompatible: false,
198
+ message: `Schema version mismatch: Project schema version (${this.schemaVersion}) is newer than the application schema version (${SCHEMA_VERSION}). Please update the application.`,
199
+ };
200
+ }
201
+
202
+ // Schema versions are equal
203
+ return {
204
+ isCompatible: true,
205
+ message: '',
206
+ };
207
+ }
208
+
155
209
  /**
156
210
  * Removes a hub.
157
211
  * @param hubName Name of the hub to remove.
@@ -169,6 +223,7 @@ export class ProjectConfiguration implements ProjectSettings {
169
223
  /**
170
224
  * Removes module from imported modules property.
171
225
  * @param moduleName Name of the module to remove.
226
+ * @throws If Module name is empty, or not imported to the project.
172
227
  */
173
228
  public async removeModule(moduleName: string) {
174
229
  if (!moduleName) {
@@ -182,6 +237,20 @@ export class ProjectConfiguration implements ProjectSettings {
182
237
  return this.save();
183
238
  }
184
239
 
240
+ // Persists configuration file to disk.
241
+ public async save() {
242
+ if (this.cardKeyPrefix === '') {
243
+ throw new Error('wrong configuration');
244
+ }
245
+ try {
246
+ await atomicWrite(this.settingPath, this.toJSON(), { indent: 4 });
247
+ } catch (error) {
248
+ if (error instanceof Error) {
249
+ this.logger.error({ error }, 'Could not write project configuration');
250
+ }
251
+ }
252
+ }
253
+
185
254
  /**
186
255
  * Changes project prefix.
187
256
  * @param newPrefix New prefix to use in the project
@@ -14,39 +14,31 @@
14
14
 
15
15
  import { join } from 'node:path';
16
16
 
17
- import {
18
- DefaultContent,
19
- FolderResource,
20
- resourceNameToString,
21
- sortCards,
22
- } from './folder-resource.js';
17
+ import { CONTENT_FILES } from '../interfaces/folder-content-interfaces.js';
18
+ import { DefaultContent } from '../resources/create-defaults.js';
19
+ import { FolderResource } from './folder-resource.js';
20
+ import { resourceNameToString } from '../utils/resource-utils.js';
21
+ import { sortCards } from '../utils/card-utils.js';
23
22
  import { writeFileSafe } from '../utils/file-utils.js';
24
23
 
25
- import type {
26
- Calculation,
27
- CalculationMetadata,
28
- CalculationUpdateKey,
29
- } from '../interfaces/resource-interfaces.js';
30
24
  import type { CalculationContent } from '../interfaces/folder-content-interfaces.js';
31
- import type {
32
- Card,
33
- Operation,
34
- Project,
35
- ResourceName,
36
- } from './file-resource.js';
25
+ import type { CalculationMetadata } from '../interfaces/resource-interfaces.js';
26
+ import type { Card } from '../interfaces/project-interfaces.js';
27
+ import type { Project } from '../containers/project.js';
28
+ import type { ResourceName } from '../utils/resource-utils.js';
37
29
 
38
30
  /**
39
31
  * Calculation resource class.
40
32
  */
41
- export class CalculationResource extends FolderResource {
42
- private calculationsFile = 'calculation.lp';
33
+ export class CalculationResource extends FolderResource<
34
+ CalculationMetadata,
35
+ CalculationContent
36
+ > {
43
37
  constructor(project: Project, name: ResourceName) {
44
38
  super(project, name, 'calculations');
45
39
 
46
40
  this.contentSchemaId = 'calculationSchema';
47
41
  this.contentSchema = super.contentSchemaContent(this.contentSchemaId);
48
-
49
- this.initialize();
50
42
  }
51
43
 
52
44
  // When resource name changes
@@ -69,30 +61,15 @@ export class CalculationResource extends FolderResource {
69
61
  }
70
62
  await super.create(newContent);
71
63
 
72
- const calculationsFile = join(this.internalFolder, this.calculationsFile);
73
- await writeFileSafe(
74
- calculationsFile,
75
- `% add your calculations here for '${this.resourceName.identifier}'`,
76
- {
77
- flag: 'wx',
78
- },
79
- );
80
- }
81
-
82
- /**
83
- * Returns content data.
84
- */
85
- public get data(): CalculationMetadata {
86
- return super.data as CalculationMetadata;
87
- }
64
+ const calculationContent = `% add your calculations here for '${this.resourceName.identifier}'`;
65
+ const calculationFile = CONTENT_FILES.calculation;
66
+ const calculationsFile = join(this.internalFolder, calculationFile);
67
+ await writeFileSafe(calculationsFile, calculationContent, {
68
+ flag: 'wx',
69
+ });
88
70
 
89
- /**
90
- * Deletes files from disk and clears out the memory resident object.
91
- */
92
- public async delete() {
93
- await super.delete();
71
+ await this.loadContentFiles();
94
72
  }
95
-
96
73
  /**
97
74
  * Renames resource metadata file and renames memory resident object 'name'.
98
75
  * @param newName New name for the resource.
@@ -103,45 +80,6 @@ export class CalculationResource extends FolderResource {
103
80
  return this.onNameChange(existingName);
104
81
  }
105
82
 
106
- /**
107
- * Shows metadata of the resource.
108
- * @returns calculation metadata.
109
- */
110
- public async show(): Promise<Calculation> {
111
- const baseData = (await super.show()) as CalculationMetadata;
112
- const fileContents = await super.contentData();
113
- const content: CalculationContent = {
114
- calculation: fileContents.calculation as string,
115
- };
116
- return {
117
- ...baseData,
118
- content: content,
119
- };
120
- }
121
-
122
- /**
123
- * Updates calculation resource.
124
- * @template Type The type of the operation being operated on for the given key.
125
- * @param key Key to modify
126
- * @param op Operation to perform on 'key'
127
- * @example
128
- * // Update the description
129
- * await calculation.update('description', { name: 'change', to: 'New description' });
130
- * await calculation.update({ key: 'content', subKey: 'calculation' }, { name: 'change', to: 'new content' });
131
- */
132
- public async update<Type>(key: CalculationUpdateKey, op: Operation<Type>) {
133
- if (
134
- typeof key === 'object' &&
135
- key.key === 'content' &&
136
- key.subKey === 'calculation'
137
- ) {
138
- const calculationContent = super.handleScalar(op) as string;
139
- await this.updateFile(this.calculationsFile, calculationContent);
140
- return;
141
- }
142
- await super.update(key, op);
143
- }
144
-
145
83
  /**
146
84
  * List where calculation resource is used in cards, or other calculation resources.
147
85
  * Always returns card key references first, then calculation references.
@@ -150,7 +88,7 @@ export class CalculationResource extends FolderResource {
150
88
  * @returns array of card keys and calculation filenames that refer this resource.
151
89
  */
152
90
  public async usage(cards?: Card[]): Promise<string[]> {
153
- const allCards = cards || (await super.cards());
91
+ const allCards = cards || super.cards();
154
92
 
155
93
  const [cardContentReferences, calculations] = await Promise.all([
156
94
  super.usage(allCards),
@@ -160,12 +98,4 @@ export class CalculationResource extends FolderResource {
160
98
  const cardReferences = cardContentReferences.sort(sortCards);
161
99
  return [...new Set([...cardReferences, ...calculations])];
162
100
  }
163
-
164
- /**
165
- * Validates the resource. If object is invalid, throws.
166
- * @param content Content to validate
167
- */
168
- public async validate(content?: object) {
169
- return super.validate(content);
170
- }
171
101
  }
@@ -12,47 +12,44 @@
12
12
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
13
13
  */
14
14
 
15
+ import { DefaultContent } from './create-defaults.js';
16
+ import { FileResource } from './file-resource.js';
17
+ import { resourceName, resourceNameToString } from '../utils/resource-utils.js';
18
+ import { ResourcesFrom } from '../containers/project.js';
19
+ import { sortCards } from '../utils/card-utils.js';
20
+ import { Validate } from '../commands/validate.js';
21
+
22
+ import type {
23
+ AddOperation,
24
+ ChangeOperation,
25
+ Operation,
26
+ RemoveOperation,
27
+ } from './resource-object.js';
28
+ import type { Card } from '../interfaces/project-interfaces.js';
15
29
  import type {
16
30
  CardType,
17
31
  CustomField,
18
32
  LinkType,
19
- Workflow,
33
+ UpdateKey,
20
34
  } from '../interfaces/resource-interfaces.js';
21
- import { FieldTypeResource } from './field-type-resource.js';
22
- import {
23
- type AddOperation,
24
- type Card,
25
- type ChangeOperation,
26
- DefaultContent,
27
- FileResource,
28
- type Operation,
29
- type Project,
30
- type RemoveOperation,
31
- ResourcesFrom,
32
- type ResourceName,
33
- resourceName,
34
- resourceNameToString,
35
- sortCards,
36
- } from './file-resource.js';
37
- import { LinkTypeResource } from './link-type-resource.js';
38
- import { Validate } from '../commands/index.js';
35
+ import type { Project } from '../containers/project.js';
36
+ import type { ResourceName } from '../utils/resource-utils.js';
39
37
 
40
38
  /**
41
39
  * Card type resource class.
42
40
  */
43
- export class CardTypeResource extends FileResource {
41
+ export class CardTypeResource extends FileResource<CardType> {
44
42
  constructor(project: Project, name: ResourceName) {
45
43
  super(project, name, 'cardTypes');
46
44
 
47
45
  this.contentSchemaId = 'cardTypeSchema';
48
46
  this.contentSchema = super.contentSchemaContent(this.contentSchemaId);
49
47
 
50
- this.initialize();
51
48
  this.setContainerValues();
52
49
  }
53
50
 
54
51
  // Returns cards that have this card type.
55
- private async cardsWithCardType(cards: Card[]): Promise<string[]> {
52
+ private cardsWithCardType(cards: Card[]): string[] {
56
53
  const resourceName = resourceNameToString(this.resourceName);
57
54
  return cards
58
55
  .filter((card) => card.metadata?.cardType === resourceName)
@@ -62,7 +59,7 @@ export class CardTypeResource extends FileResource {
62
59
  // Checks if field type exists in the project.
63
60
  private async fieldTypeExists(field: Partial<CustomField>) {
64
61
  return field && field.name
65
- ? this.project.resourceExists('fieldTypes', field.name)
62
+ ? this.project.resources.exists(field.name)
66
63
  : false;
67
64
  }
68
65
 
@@ -72,13 +69,7 @@ export class CardTypeResource extends FileResource {
72
69
  if (op && op.name === 'rank') return;
73
70
 
74
71
  // Collect both project cards and template cards.
75
- const cards = await this.collectCards(
76
- {
77
- metadata: true,
78
- content: true,
79
- },
80
- this.content.name,
81
- );
72
+ const cards = await this.collectCards(this.content.name);
82
73
 
83
74
  if (op && op.name === 'change') {
84
75
  const from = (op as ChangeOperation<string>).target;
@@ -113,8 +104,8 @@ export class CardTypeResource extends FileResource {
113
104
 
114
105
  // When resource name changes.
115
106
  private async handleNameChange(existingName: string) {
116
- const current = this.content as CardType;
117
- const prefixes = await this.project.projectPrefixes();
107
+ const current = this.content;
108
+ const prefixes = this.project.projectPrefixes();
118
109
  if (current.customFields) {
119
110
  current.customFields.map(
120
111
  (field) =>
@@ -160,20 +151,14 @@ export class CardTypeResource extends FileResource {
160
151
  op: ChangeOperation<Type>,
161
152
  ) {
162
153
  await this.verifyStateMapping(stateMapping, op);
163
- const cards = await this.collectCards(
164
- {
165
- metadata: true,
166
- content: true,
167
- },
168
- this.content.name,
169
- );
154
+ const cards = await this.collectCards(this.content.name);
170
155
 
171
156
  const unmappedStates: string[] = [];
172
157
 
173
158
  // Update each card's workflowState if it has a mapping
174
159
  const updatePromises = cards.map(async (card) => {
175
160
  if (card.metadata && card.metadata.workflowState) {
176
- const currentState = card.metadata.workflowState as string;
161
+ const currentState = card.metadata.workflowState;
177
162
  const newState = stateMapping[currentState];
178
163
 
179
164
  if (newState && newState !== currentState) {
@@ -198,8 +183,10 @@ export class CardTypeResource extends FileResource {
198
183
  }
199
184
 
200
185
  // Checks if field type exists in this card type.
201
- private async hasFieldType(field: Partial<CustomField>): Promise<boolean> {
202
- return this.data.customFields.some((item) => item.name === field.name);
186
+ private hasFieldType(field: Partial<CustomField>): boolean {
187
+ return (
188
+ this.data?.customFields.some((item) => item.name === field.name) || false
189
+ );
203
190
  }
204
191
 
205
192
  // Remove value from array.
@@ -212,24 +199,25 @@ export class CardTypeResource extends FileResource {
212
199
  }
213
200
 
214
201
  // Return link types that use this card type.
215
- private async relevantLinkTypes(): Promise<string[]> {
202
+ private relevantLinkTypes(): string[] {
216
203
  const resourceName = resourceNameToString(this.resourceName);
217
- const allLinkTypes = await this.project.linkTypes(ResourcesFrom.all);
204
+ const allLinkTypes = this.project.resources.linkTypes();
205
+ const references: string[] = [];
218
206
 
219
- const linkTypeNames = await Promise.all(
220
- allLinkTypes.map(async (linkType) => {
221
- const metadata = await this.project.resource<LinkType>(linkType.name);
222
- if (!metadata) return null;
207
+ for (const linkType of allLinkTypes) {
208
+ const metadata = linkType.data;
209
+ if (!metadata) continue;
223
210
 
224
- const isRelevant =
225
- metadata.destinationCardTypes.includes(resourceName) ||
226
- metadata.sourceCardTypes.includes(resourceName);
211
+ const isRelevant =
212
+ metadata.destinationCardTypes.includes(resourceName) ||
213
+ metadata.sourceCardTypes.includes(resourceName);
227
214
 
228
- return isRelevant ? linkType.name : null;
229
- }),
230
- );
215
+ if (isRelevant) {
216
+ references.push(metadata.name);
217
+ }
218
+ }
231
219
 
232
- return linkTypeNames.filter((name): name is string => name !== null);
220
+ return references;
233
221
  }
234
222
 
235
223
  // If value from 'customFields' is removed, remove it also from 'optionallyVisible' and 'alwaysVisible' arrays.
@@ -251,7 +239,7 @@ export class CardTypeResource extends FileResource {
251
239
 
252
240
  // Sets content container values to be either '[]' or with proper values.
253
241
  private setContainerValues() {
254
- const content = this.content as CardType;
242
+ const content = this.content;
255
243
  if (content.customFields) {
256
244
  for (const item of content.customFields) {
257
245
  // Set "isCalculated" if it is missing; default = false
@@ -260,9 +248,9 @@ export class CardTypeResource extends FileResource {
260
248
  }
261
249
  // Fetch "displayName" from field type if it is missing.
262
250
  if (item.name && item.displayName === undefined) {
263
- const fieldType = new FieldTypeResource(
264
- this.project,
265
- resourceName(item.name),
251
+ const fieldType = this.project.resources.byType(
252
+ item.name,
253
+ 'fieldTypes',
266
254
  );
267
255
  const fieldTypeContent = fieldType.data;
268
256
  if (fieldTypeContent) {
@@ -289,14 +277,9 @@ export class CardTypeResource extends FileResource {
289
277
 
290
278
  // Updates dependent link types.
291
279
  private async updateLinkTypes(oldName: string): Promise<void> {
292
- const linkTypes = await this.project.linkTypes(ResourcesFrom.localOnly);
293
-
294
- const updatePromises = linkTypes.map(async (linkType) => {
295
- const object = new LinkTypeResource(
296
- this.project,
297
- resourceName(linkType.name),
298
- );
280
+ const linkTypes = this.project.resources.linkTypes(ResourcesFrom.localOnly);
299
281
 
282
+ const updatePromises = linkTypes.map(async (object) => {
300
283
  const data = object.data;
301
284
  const updates: Promise<void>[] = [];
302
285
 
@@ -311,7 +294,7 @@ export class CardTypeResource extends FileResource {
311
294
  target: oldName,
312
295
  to: this.content.name,
313
296
  } as ChangeOperation<string>;
314
- updates.push(object.update(field, op));
297
+ updates.push(object.update({ key: field }, op));
315
298
  }
316
299
  }
317
300
 
@@ -353,7 +336,7 @@ export class CardTypeResource extends FileResource {
353
336
  }
354
337
  // Check that field type is defined in card type.
355
338
  if (key === 'alwaysVisibleFields' || key === 'optionallyVisibleFields') {
356
- const hasField = await this.hasFieldType(field);
339
+ const hasField = this.hasFieldType(field);
357
340
  if (!hasField) {
358
341
  throw new Error(
359
342
  `Field type '${field.name}' is not defined in card type '${this.content.name}'`,
@@ -370,15 +353,19 @@ export class CardTypeResource extends FileResource {
370
353
  op: ChangeOperation<Type>,
371
354
  ) {
372
355
  const currentWorkflowName = op.target as string;
373
- const currentWorkflow =
374
- await this.project.resource<Workflow>(currentWorkflowName);
356
+ const currentWorkflow = this.project.resources
357
+ .byType(currentWorkflowName, 'workflows')
358
+ .show();
375
359
  if (!currentWorkflow) {
376
360
  throw new Error(
377
361
  `Workflow '${currentWorkflowName}' does not exist in the project`,
378
362
  );
379
363
  }
380
364
 
381
- const newWorkflow = await this.project.resource<Workflow>(op.to as string);
365
+ const newWorkflow = this.project.resources
366
+ .byType(op.to as string, 'workflows')
367
+ .show();
368
+
382
369
  if (!newWorkflow) {
383
370
  throw new Error(`Workflow '${op.to}' does not exist in the project`);
384
371
  }
@@ -416,6 +403,7 @@ export class CardTypeResource extends FileResource {
416
403
  /**
417
404
  * Creates a new card type object. Base class writes the object to disk automatically.
418
405
  * @param workflowName Workflow name that this card type uses.
406
+ * @throws when workflow is empty, or does not exist in the project.
419
407
  */
420
408
  public async createCardType(workflowName: string) {
421
409
  if (!workflowName) {
@@ -423,12 +411,14 @@ export class CardTypeResource extends FileResource {
423
411
  `Cannot create cardType without providing workflow for it`,
424
412
  );
425
413
  }
426
- const validWorkflowName = await Validate.getInstance().validResourceName(
414
+ const validWorkflowName = Validate.getInstance().validResourceName(
427
415
  'workflows',
428
416
  resourceNameToString(resourceName(workflowName)),
429
- await this.project.projectPrefixes(),
417
+ this.project.projectPrefixes(),
430
418
  );
431
- const workflow = await this.project.resource<Workflow>(workflowName);
419
+ const workflow = this.project.resources
420
+ .byType(workflowName, 'workflows')
421
+ .show();
432
422
  if (!workflow) {
433
423
  throw new Error(
434
424
  `Workflow '${workflowName}' does not exist in the project`,
@@ -441,20 +431,6 @@ export class CardTypeResource extends FileResource {
441
431
  return super.create(content);
442
432
  }
443
433
 
444
- /**
445
- * Returns content data.
446
- */
447
- public get data(): CardType {
448
- return super.data as CardType;
449
- }
450
-
451
- /**
452
- * Deletes file(s) from disk and clears out the memory resident object.
453
- */
454
- public async delete() {
455
- return super.delete();
456
- }
457
-
458
434
  /**
459
435
  * Renames resource metadata file and renames memory resident object 'name'.
460
436
  * @param newName New name for the resource.
@@ -465,26 +441,22 @@ export class CardTypeResource extends FileResource {
465
441
  return this.handleNameChange(existingName);
466
442
  }
467
443
 
468
- /**
469
- * Shows metadata of the resource.
470
- * @returns card type metadata.
471
- */
472
- public async show(): Promise<CardType> {
473
- return super.show() as Promise<CardType>;
474
- }
475
-
476
444
  /**
477
445
  * Updates card type resource.
478
- * @param key Key to modify
446
+ * @param updateKey Key to modify
479
447
  * @param op Operation to perform on 'key'
480
448
  */
481
- public async update<Type>(key: string, op: Operation<Type>) {
449
+ public async update<Type, K extends string>(
450
+ updateKey: UpdateKey<K>,
451
+ op: Operation<Type>,
452
+ ) {
453
+ const { key } = updateKey;
482
454
  const nameChange = key === 'name';
483
455
  const customFieldsChange = key === 'customFields';
484
456
  const existingName = this.content.name;
485
- await super.update(key, op);
457
+ await super.update(updateKey, op);
486
458
 
487
- const content = structuredClone(this.content) as CardType;
459
+ const content = structuredClone(this.content);
488
460
  if (key === 'name') {
489
461
  content.name = super.handleScalar(op) as string;
490
462
  } else if (key === 'alwaysVisibleFields') {
@@ -525,7 +497,7 @@ export class CardTypeResource extends FileResource {
525
497
  } else {
526
498
  throw new Error(`Unknown property '${key}' for CardType`);
527
499
  }
528
- await super.postUpdate(content, key, op);
500
+ await super.postUpdate(content, updateKey, op);
529
501
 
530
502
  // Renaming this card type causes that references to its name must be updated.
531
503
  if (nameChange) {
@@ -544,7 +516,7 @@ export class CardTypeResource extends FileResource {
544
516
  * @returns array of card keys, resource names and calculation filenames that refer this resource.
545
517
  */
546
518
  public async usage(cards?: Card[]): Promise<string[]> {
547
- const allCards = cards ?? (await super.cards());
519
+ const allCards = cards ?? super.cards();
548
520
  const [
549
521
  cardsWithCardType,
550
522
  cardContentReferences,
@@ -566,11 +538,4 @@ export class CardTypeResource extends FileResource {
566
538
  ...new Set([...cardReferences, ...relevantLinkTypes, ...calculations]),
567
539
  ];
568
540
  }
569
-
570
- /**
571
- * Validates the resource. If object is invalid, throws.
572
- */
573
- public async validate(content?: object) {
574
- return super.validate(content);
575
- }
576
541
  }