@cyberismo/data-handler 0.0.14 → 0.0.15

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 (240) hide show
  1. package/dist/card-metadata-updater.js +1 -3
  2. package/dist/card-metadata-updater.js.map +1 -1
  3. package/dist/command-handler.js +10 -16
  4. package/dist/command-handler.js.map +1 -1
  5. package/dist/command-manager.d.ts +1 -1
  6. package/dist/command-manager.js +4 -3
  7. package/dist/command-manager.js.map +1 -1
  8. package/dist/commands/create.js +13 -59
  9. package/dist/commands/create.js.map +1 -1
  10. package/dist/commands/edit.d.ts +1 -15
  11. package/dist/commands/edit.js +15 -89
  12. package/dist/commands/edit.js.map +1 -1
  13. package/dist/commands/export.js +4 -17
  14. package/dist/commands/export.js.map +1 -1
  15. package/dist/commands/import.js +3 -5
  16. package/dist/commands/import.js.map +1 -1
  17. package/dist/commands/move.d.ts +1 -2
  18. package/dist/commands/move.js +108 -146
  19. package/dist/commands/move.js.map +1 -1
  20. package/dist/commands/remove.js +9 -44
  21. package/dist/commands/remove.js.map +1 -1
  22. package/dist/commands/rename.js +2 -7
  23. package/dist/commands/rename.js.map +1 -1
  24. package/dist/commands/show.d.ts +7 -25
  25. package/dist/commands/show.js +38 -102
  26. package/dist/commands/show.js.map +1 -1
  27. package/dist/commands/transition.js +27 -30
  28. package/dist/commands/transition.js.map +1 -1
  29. package/dist/commands/update.d.ts +5 -3
  30. package/dist/commands/update.js +19 -5
  31. package/dist/commands/update.js.map +1 -1
  32. package/dist/commands/validate.d.ts +3 -3
  33. package/dist/commands/validate.js +19 -26
  34. package/dist/commands/validate.js.map +1 -1
  35. package/dist/containers/card-container.d.ts +87 -24
  36. package/dist/containers/card-container.js +183 -279
  37. package/dist/containers/card-container.js.map +1 -1
  38. package/dist/containers/project/calculation-engine.d.ts +6 -0
  39. package/dist/containers/project/calculation-engine.js +19 -12
  40. package/dist/containers/project/calculation-engine.js.map +1 -1
  41. package/dist/containers/project/card-cache.d.ts +146 -0
  42. package/dist/containers/project/card-cache.js +411 -0
  43. package/dist/containers/project/card-cache.js.map +1 -0
  44. package/dist/containers/project/resource-collector.d.ts +24 -1
  45. package/dist/containers/project/resource-collector.js +8 -1
  46. package/dist/containers/project/resource-collector.js.map +1 -1
  47. package/dist/containers/project.d.ts +117 -83
  48. package/dist/containers/project.js +418 -252
  49. package/dist/containers/project.js.map +1 -1
  50. package/dist/containers/template.d.ts +15 -31
  51. package/dist/containers/template.js +97 -104
  52. package/dist/containers/template.js.map +1 -1
  53. package/dist/index.d.ts +1 -0
  54. package/dist/index.js +1 -0
  55. package/dist/index.js.map +1 -1
  56. package/dist/interfaces/folder-content-interfaces.d.ts +2 -1
  57. package/dist/interfaces/folder-content-interfaces.js.map +1 -1
  58. package/dist/interfaces/macros.d.ts +1 -0
  59. package/dist/interfaces/macros.js +1 -1
  60. package/dist/interfaces/macros.js.map +1 -1
  61. package/dist/interfaces/project-interfaces.d.ts +5 -1
  62. package/dist/interfaces/project-interfaces.js.map +1 -1
  63. package/dist/interfaces/resource-interfaces.d.ts +11 -21
  64. package/dist/interfaces/resource-interfaces.js +3 -0
  65. package/dist/interfaces/resource-interfaces.js.map +1 -1
  66. package/dist/macros/common.d.ts +10 -10
  67. package/dist/macros/createCards/index.d.ts +0 -13
  68. package/dist/macros/createCards/index.js.map +1 -1
  69. package/dist/macros/createCards/types.d.ts +44 -0
  70. package/dist/macros/createCards/types.js +15 -0
  71. package/dist/macros/createCards/types.js.map +1 -0
  72. package/dist/macros/graph/index.d.ts +2 -6
  73. package/dist/macros/graph/index.js +2 -2
  74. package/dist/macros/graph/index.js.map +1 -1
  75. package/dist/macros/graph/types.d.ts +23 -0
  76. package/dist/macros/graph/types.js +15 -0
  77. package/dist/macros/graph/types.js.map +1 -0
  78. package/dist/macros/image/index.d.ts +8 -16
  79. package/dist/macros/image/index.js +36 -33
  80. package/dist/macros/image/index.js.map +1 -1
  81. package/dist/macros/image/types.d.ts +38 -0
  82. package/dist/macros/image/types.js +15 -0
  83. package/dist/macros/image/types.js.map +1 -0
  84. package/dist/macros/include/index.d.ts +1 -6
  85. package/dist/macros/include/index.js +4 -7
  86. package/dist/macros/include/index.js.map +1 -1
  87. package/dist/macros/include/types.d.ts +31 -0
  88. package/dist/macros/include/types.js +15 -0
  89. package/dist/macros/include/types.js.map +1 -0
  90. package/dist/macros/percentage/index.d.ts +0 -6
  91. package/dist/macros/percentage/index.js.map +1 -1
  92. package/dist/macros/percentage/types.d.ts +31 -0
  93. package/dist/macros/percentage/types.js +15 -0
  94. package/dist/macros/percentage/types.js.map +1 -0
  95. package/dist/macros/report/index.d.ts +0 -3
  96. package/dist/macros/report/index.js.map +1 -1
  97. package/dist/macros/report/types.d.ts +19 -0
  98. package/dist/macros/report/types.js +15 -0
  99. package/dist/macros/report/types.js.map +1 -0
  100. package/dist/macros/scoreCard/index.d.ts +0 -6
  101. package/dist/macros/scoreCard/index.js.map +1 -1
  102. package/dist/macros/scoreCard/types.d.ts +31 -0
  103. package/dist/macros/scoreCard/types.js +15 -0
  104. package/dist/macros/scoreCard/types.js.map +1 -0
  105. package/dist/macros/types.d.ts +25 -0
  106. package/dist/macros/types.js +2 -0
  107. package/dist/macros/types.js.map +1 -0
  108. package/dist/macros/vega/index.d.ts +0 -4
  109. package/dist/macros/vega/index.js.map +1 -1
  110. package/dist/macros/vega/types.d.ts +20 -0
  111. package/dist/macros/vega/types.js +2 -0
  112. package/dist/macros/vega/types.js.map +1 -0
  113. package/dist/macros/vegalite/index.d.ts +0 -4
  114. package/dist/macros/vegalite/index.js.map +1 -1
  115. package/dist/macros/vegalite/types.d.ts +20 -0
  116. package/dist/macros/vegalite/types.js +15 -0
  117. package/dist/macros/vegalite/types.js.map +1 -0
  118. package/dist/macros/xref/index.d.ts +0 -3
  119. package/dist/macros/xref/index.js +5 -14
  120. package/dist/macros/xref/index.js.map +1 -1
  121. package/dist/macros/xref/types.d.ts +19 -0
  122. package/dist/macros/xref/types.js +15 -0
  123. package/dist/macros/xref/types.js.map +1 -0
  124. package/dist/module-manager.js +4 -4
  125. package/dist/module-manager.js.map +1 -1
  126. package/dist/project-settings.js.map +1 -1
  127. package/dist/resources/calculation-resource.d.ts +4 -32
  128. package/dist/resources/calculation-resource.js +0 -55
  129. package/dist/resources/calculation-resource.js.map +1 -1
  130. package/dist/resources/card-type-resource.d.ts +4 -21
  131. package/dist/resources/card-type-resource.js +13 -44
  132. package/dist/resources/card-type-resource.js.map +1 -1
  133. package/dist/resources/field-type-resource.d.ts +4 -21
  134. package/dist/resources/field-type-resource.js +14 -38
  135. package/dist/resources/field-type-resource.js.map +1 -1
  136. package/dist/resources/file-resource.d.ts +12 -29
  137. package/dist/resources/file-resource.js +19 -293
  138. package/dist/resources/file-resource.js.map +1 -1
  139. package/dist/resources/folder-resource.d.ts +31 -50
  140. package/dist/resources/folder-resource.js +68 -96
  141. package/dist/resources/folder-resource.js.map +1 -1
  142. package/dist/resources/graph-model-resource.d.ts +5 -33
  143. package/dist/resources/graph-model-resource.js +8 -61
  144. package/dist/resources/graph-model-resource.js.map +1 -1
  145. package/dist/resources/graph-view-resource.d.ts +5 -28
  146. package/dist/resources/graph-view-resource.js +6 -45
  147. package/dist/resources/graph-view-resource.js.map +1 -1
  148. package/dist/resources/link-type-resource.d.ts +4 -21
  149. package/dist/resources/link-type-resource.js +6 -31
  150. package/dist/resources/link-type-resource.js.map +1 -1
  151. package/dist/resources/report-resource.d.ts +5 -17
  152. package/dist/resources/report-resource.js +6 -44
  153. package/dist/resources/report-resource.js.map +1 -1
  154. package/dist/resources/resource-object.d.ts +58 -23
  155. package/dist/resources/resource-object.js +293 -24
  156. package/dist/resources/resource-object.js.map +1 -1
  157. package/dist/resources/template-resource.d.ts +4 -15
  158. package/dist/resources/template-resource.js +10 -25
  159. package/dist/resources/template-resource.js.map +1 -1
  160. package/dist/resources/workflow-resource.d.ts +4 -23
  161. package/dist/resources/workflow-resource.js +12 -38
  162. package/dist/resources/workflow-resource.js.map +1 -1
  163. package/dist/utils/card-utils.d.ts +69 -19
  164. package/dist/utils/card-utils.js +179 -30
  165. package/dist/utils/card-utils.js.map +1 -1
  166. package/dist/utils/clingo-facts.js +11 -3
  167. package/dist/utils/clingo-facts.js.map +1 -1
  168. package/dist/utils/clingo-parser.js +1 -1
  169. package/dist/utils/clingo-parser.js.map +1 -1
  170. package/dist/utils/constants.d.ts +2 -0
  171. package/dist/utils/constants.js +4 -0
  172. package/dist/utils/constants.js.map +1 -1
  173. package/dist/utils/csv.js +1 -1
  174. package/dist/utils/csv.js.map +1 -1
  175. package/package.json +5 -5
  176. package/src/card-metadata-updater.ts +3 -5
  177. package/src/command-handler.ts +11 -18
  178. package/src/command-manager.ts +4 -3
  179. package/src/commands/create.ts +17 -83
  180. package/src/commands/edit.ts +16 -132
  181. package/src/commands/export.ts +8 -29
  182. package/src/commands/import.ts +4 -6
  183. package/src/commands/move.ts +144 -179
  184. package/src/commands/remove.ts +9 -52
  185. package/src/commands/rename.ts +2 -7
  186. package/src/commands/show.ts +50 -143
  187. package/src/commands/transition.ts +30 -33
  188. package/src/commands/update.ts +27 -9
  189. package/src/commands/validate.ts +21 -36
  190. package/src/containers/card-container.ts +200 -360
  191. package/src/containers/project/calculation-engine.ts +21 -13
  192. package/src/containers/project/card-cache.ts +497 -0
  193. package/src/containers/project/resource-collector.ts +9 -1
  194. package/src/containers/project.ts +529 -327
  195. package/src/containers/template.ts +109 -127
  196. package/src/index.ts +1 -0
  197. package/src/interfaces/folder-content-interfaces.ts +7 -1
  198. package/src/interfaces/macros.ts +2 -0
  199. package/src/interfaces/project-interfaces.ts +7 -1
  200. package/src/interfaces/resource-interfaces.ts +12 -24
  201. package/src/macros/createCards/index.ts +1 -12
  202. package/src/macros/createCards/types.ts +46 -0
  203. package/src/macros/graph/index.ts +3 -7
  204. package/src/macros/graph/types.ts +24 -0
  205. package/src/macros/image/index.ts +50 -61
  206. package/src/macros/image/types.ts +39 -0
  207. package/src/macros/include/index.ts +6 -15
  208. package/src/macros/include/types.ts +32 -0
  209. package/src/macros/percentage/index.ts +1 -7
  210. package/src/macros/percentage/types.ts +32 -0
  211. package/src/macros/report/index.ts +1 -4
  212. package/src/macros/report/types.ts +20 -0
  213. package/src/macros/scoreCard/index.ts +1 -7
  214. package/src/macros/scoreCard/types.ts +32 -0
  215. package/src/macros/types.ts +48 -0
  216. package/src/macros/vega/index.ts +1 -4
  217. package/src/macros/vega/types.ts +21 -0
  218. package/src/macros/vegalite/index.ts +1 -4
  219. package/src/macros/vegalite/types.ts +22 -0
  220. package/src/macros/xref/index.ts +6 -20
  221. package/src/macros/xref/types.ts +20 -0
  222. package/src/module-manager.ts +5 -5
  223. package/src/project-settings.ts +1 -1
  224. package/src/resources/calculation-resource.ts +6 -76
  225. package/src/resources/card-type-resource.ts +24 -59
  226. package/src/resources/field-type-resource.ts +22 -51
  227. package/src/resources/file-resource.ts +27 -409
  228. package/src/resources/folder-resource.ts +98 -124
  229. package/src/resources/graph-model-resource.ts +17 -74
  230. package/src/resources/graph-view-resource.ts +14 -54
  231. package/src/resources/link-type-resource.ts +13 -40
  232. package/src/resources/report-resource.ts +17 -57
  233. package/src/resources/resource-object.ts +435 -32
  234. package/src/resources/template-resource.ts +16 -29
  235. package/src/resources/workflow-resource.ts +26 -50
  236. package/src/utils/card-utils.ts +217 -31
  237. package/src/utils/clingo-facts.ts +13 -3
  238. package/src/utils/clingo-parser.ts +1 -1
  239. package/src/utils/constants.ts +6 -0
  240. package/src/utils/csv.ts +1 -1
@@ -16,13 +16,12 @@ import { basename, dirname, join, normalize } from 'node:path';
16
16
  import { mkdir, readdir, readFile, rename, rm } from 'node:fs/promises';
17
17
 
18
18
  import type { Card, Operation, ResourceName } from './file-resource.js';
19
- import type {
20
- ContentUpdateKey,
21
- ResourceContent,
22
- UpdateKey,
19
+ import type { ResourceBaseMetadata } from '../interfaces/resource-interfaces.js';
20
+ import {
21
+ isContentKey,
22
+ type UpdateKey,
23
23
  } from '../interfaces/resource-interfaces.js';
24
24
  import type { ResourceFolderType } from '../interfaces/project-interfaces.js';
25
- import type { Schema } from 'jsonschema';
26
25
 
27
26
  import {
28
27
  DefaultContent,
@@ -32,13 +31,16 @@ import {
32
31
  resourceNameToString,
33
32
  sortCards,
34
33
  } from './file-resource.js';
34
+ import type { FolderResourceContent } from '../interfaces/folder-content-interfaces.js';
35
35
  import {
36
36
  filename,
37
37
  propertyName,
38
38
  } from '../interfaces/folder-content-interfaces.js';
39
- import { readJsonFile } from '../utils/json.js';
39
+ import { formatJson, readJsonFile } from '../utils/json.js';
40
40
  import { VALID_FOLDER_RESOURCE_FILES } from '../utils/constants.js';
41
41
  import { writeFileSafe } from '../utils/file-utils.js';
42
+ import type { ShowReturnType } from './resource-object.js';
43
+ import { ResourceObject } from './resource-object.js';
42
44
 
43
45
  export {
44
46
  type Card,
@@ -54,7 +56,10 @@ export {
54
56
  /**
55
57
  * Folder type resource class. These are resources that have their own folders for content.
56
58
  */
57
- export class FolderResource extends FileResource {
59
+ export abstract class FolderResource<
60
+ T extends ResourceBaseMetadata,
61
+ U extends FolderResourceContent,
62
+ > extends ResourceObject<T, U> {
58
63
  protected internalFolder: string = '';
59
64
 
60
65
  // Cache for content files to avoid repeated filesystem operations. Content is stored as string.
@@ -62,6 +67,7 @@ export class FolderResource extends FileResource {
62
67
 
63
68
  constructor(project: Project, name: ResourceName, type: ResourceFolderType) {
64
69
  super(project, name, type);
70
+ this.initialize();
65
71
  }
66
72
 
67
73
  // Clears the content files cache.
@@ -69,65 +75,15 @@ export class FolderResource extends FileResource {
69
75
  this.contentFilesCache.clear();
70
76
  }
71
77
 
72
- // Type guard to check if a key is a ContentUpdateKey
73
- private isContentUpdateKey(key: UpdateKey): key is ContentUpdateKey {
74
- return typeof key === 'object' && key.key === 'content' && 'subKey' in key;
75
- }
76
-
77
78
  /**
78
79
  * Creates a new folder type object. Base class writes the object to disk automatically.
79
80
  * @param newContent Content for the type.
80
81
  */
81
- protected async create(newContent?: ResourceContent) {
82
+ protected async create(newContent?: T) {
82
83
  await super.create(newContent);
83
84
  await mkdir(this.internalFolder, { recursive: true });
84
85
  }
85
86
 
86
- /**
87
- * Gets content of all files to properties.
88
- * @returns object with property names as keys and file contents as values.
89
- */
90
- public async contentData(): Promise<Record<string, string | Schema>> {
91
- const fileNames = await this.showFileNames();
92
- const content: Record<string, string | Schema> = {};
93
-
94
- for (const fileName of fileNames) {
95
- const name = propertyName(fileName);
96
- if (name) {
97
- const JSONFile = name === 'schema';
98
- content[name] = await this.showFile(fileName, JSONFile);
99
- }
100
- }
101
-
102
- return content;
103
- }
104
-
105
- /**
106
- * Returns content data.
107
- */
108
- public get data() {
109
- return super.data;
110
- }
111
-
112
- /**
113
- * Deletes file(s) from disk and clears out the memory resident object.
114
- */
115
- protected async delete() {
116
- await super.delete();
117
- await rm(this.internalFolder, { recursive: true, force: true });
118
- this.clearContentCache();
119
- }
120
-
121
- // Get (resource folder) type name
122
- protected get getType() {
123
- return super.getType;
124
- }
125
-
126
- // Get logger instance
127
- protected get logger() {
128
- return super.getLogger(this.getType);
129
- }
130
-
131
87
  /**
132
88
  * Initialize the resource item.
133
89
  */
@@ -140,6 +96,12 @@ export class FolderResource extends FileResource {
140
96
  );
141
97
  }
142
98
 
99
+ /**
100
+ * For handling name changes.
101
+ * @param previousName The previous name before the change
102
+ */
103
+ protected abstract onNameChange?(previousName: string): Promise<void>;
104
+
143
105
  /**
144
106
  * Renames resource metadata file and renames memory resident object 'name'.
145
107
  * @param newName New name for the resource.
@@ -149,21 +111,12 @@ export class FolderResource extends FileResource {
149
111
  }
150
112
 
151
113
  /**
152
- * Shows metadata of the resource.
153
- * @returns resource type's metadata.
154
- */
155
- protected async show(): Promise<ResourceContent> {
156
- return super.show();
157
- }
158
-
159
- /**
160
- * TODO: to be made protected - no direct access to files
161
114
  * Shows the content of a file in the resource.
162
115
  * @param fileName Name of the file to show.
163
116
  * @param json Content is JSON file.
164
117
  * @returns the content of the file.
165
118
  */
166
- public async showFile(
119
+ protected async showFile(
167
120
  fileName: string,
168
121
  json: boolean = false,
169
122
  ): Promise<string> {
@@ -181,18 +134,17 @@ export class FolderResource extends FileResource {
181
134
 
182
135
  // Update cache
183
136
  const contentStr =
184
- typeof content === 'string' ? content : JSON.stringify(content, null, 2);
137
+ typeof content === 'string' ? content : formatJson(content);
185
138
  this.contentFilesCache.set(fileName, contentStr);
186
139
 
187
140
  return json ? content : contentStr;
188
141
  }
189
142
 
190
143
  /**
191
- * TODO: to be made protected - no direct access to files
192
144
  * Shows all file names in the resource.
193
145
  * @returns all file names in the resource.
194
146
  */
195
- public async showFileNames(): Promise<string[]> {
147
+ protected async showFileNames(): Promise<string[]> {
196
148
  // Always first check cache...
197
149
  if (this.contentFilesCache.size > 0) {
198
150
  return Array.from(this.contentFilesCache.keys());
@@ -212,16 +164,6 @@ export class FolderResource extends FileResource {
212
164
  return validFiles;
213
165
  }
214
166
 
215
- /**
216
- * Updates content files from a content object.
217
- * @param contentFiles Object with file names as keys and file contents as values.
218
- */
219
- protected async updateContentFiles(contentFiles: Record<string, string>) {
220
- for (const [fileName, fileContent] of Object.entries(contentFiles)) {
221
- await this.updateFile(fileName, fileContent);
222
- }
223
- }
224
-
225
167
  /**
226
168
  * Updates a file in the resource.
227
169
  * @param fileName The name of the file to update.
@@ -243,7 +185,7 @@ export class FolderResource extends FileResource {
243
185
  }
244
186
  // check if the file is allow-listed
245
187
  if (!VALID_FOLDER_RESOURCE_FILES.includes(fileName)) {
246
- throw new Error(`File '${fileName}' is not allowed`);
188
+ throw new Error(`File '${fileName}' is not allowed to be updated`);
247
189
  }
248
190
 
249
191
  await writeFileSafe(filePath, changedContent, { flag: 'w' });
@@ -252,23 +194,80 @@ export class FolderResource extends FileResource {
252
194
  this.contentFilesCache.set(fileName, changedContent);
253
195
  }
254
196
 
197
+ /**
198
+ * Writes resource content to disk.
199
+ */
200
+ protected async write() {
201
+ const folderName = basename(this.internalFolder);
202
+
203
+ // Check if "name" has changed. Changing "name" means renaming the file.
204
+ const nameInContent = resourceName(this.content.name).identifier;
205
+ if (folderName !== nameInContent) {
206
+ const newFolderName = join(this.resourceFolder, nameInContent);
207
+ await rename(this.internalFolder, newFolderName);
208
+ this.internalFolder = newFolderName;
209
+ }
210
+ return super.write();
211
+ }
212
+
213
+ /**
214
+ * Gets content of all files to properties.
215
+ * @returns object with property names as keys and file contents as values.
216
+ */
217
+ public async contentData(): Promise<U> {
218
+ const fileNames = await this.showFileNames();
219
+ const content = {} as Record<string, unknown>;
220
+
221
+ for (const fileName of fileNames) {
222
+ const name = propertyName(fileName);
223
+ if (name) {
224
+ const JSONFile = name === 'schema';
225
+ content[name] = await this.showFile(fileName, JSONFile);
226
+ }
227
+ }
228
+
229
+ // TODO: Instead of casting, validate that content matches U
230
+ // This requires a runtime schema for U to be defined(via an abstract variable)
231
+
232
+ return content as U;
233
+ }
234
+
235
+ /**
236
+ * Deletes file and content folder from disk and clears out the memory resident object.
237
+ * @throws if resource is a module resource or does not exist or is used by other resources.
238
+ */
239
+ public async delete() {
240
+ await super.delete();
241
+ await rm(this.internalFolder, { recursive: true, force: true });
242
+ this.clearContentCache();
243
+ }
244
+
255
245
  /**
256
246
  * Updates resource.
257
- * @param key Key to modify
247
+ * @param updateKey Key to modify
258
248
  * @param op Operation to perform on 'key'
259
249
  * @throws if key is unknown.
260
250
  */
261
- protected async update<Type>(key: UpdateKey, op: Operation<Type>) {
262
- if (this.isContentUpdateKey(key)) {
263
- const fileName = filename(key.subKey)!;
264
- const fileContent = super.handleScalar(op) as string;
265
- await this.updateFile(fileName, fileContent);
251
+ public async update<Type, K extends string>(
252
+ updateKey: UpdateKey<K>,
253
+ op: Operation<Type>,
254
+ ) {
255
+ const { key } = updateKey;
256
+ if (isContentKey(updateKey)) {
257
+ const fileName = filename(updateKey.subKey)!;
258
+ const fileContent = super.handleScalar(op);
259
+ const fileContentString =
260
+ typeof fileContent === 'string'
261
+ ? fileContent
262
+ : formatJson(fileContent as object); // TODO: Fix operation types. In practice, content files are either strings or objects
263
+
264
+ await this.updateFile(fileName, fileContentString);
266
265
  return;
267
266
  }
268
267
 
269
268
  const nameChange = key === 'name';
270
269
  const existingName = this.content.name;
271
- await super.update(key, op);
270
+ await super.update(updateKey, op);
272
271
  const content = structuredClone(this.content);
273
272
 
274
273
  if (key === 'name') {
@@ -281,7 +280,7 @@ export class FolderResource extends FileResource {
281
280
  throw new Error(`Unknown property '${key}' for folder resource`);
282
281
  }
283
282
 
284
- await super.postUpdate(content, key, op);
283
+ await super.postUpdate(content, updateKey, op);
285
284
 
286
285
  if (nameChange) {
287
286
  await this.onNameChange?.(existingName);
@@ -289,40 +288,15 @@ export class FolderResource extends FileResource {
289
288
  }
290
289
 
291
290
  /**
292
- * For handling name changes.
293
- * @param previousName The previous name before the change
294
- */
295
- protected async onNameChange?(previousName: string): Promise<void>;
296
-
297
- /**
298
- * Returns an array of card keys, and/or resource names where this resource is used.
299
- * @param cards Optional. If defined, only these cards are checked.
300
- * @returns an array of card keys, and/or resource names where this resource is used.
301
- */
302
- protected async usage(cards?: Card[]): Promise<string[]> {
303
- return super.usage(cards);
304
- }
305
-
306
- /**
307
- * Writes resource content to disk.
308
- */
309
- protected async write() {
310
- const folderName = basename(this.internalFolder);
311
-
312
- // Check if "name" has changed. Changing "name" means renaming the file.
313
- const nameInContent = resourceName(this.content.name).identifier;
314
- if (folderName !== nameInContent) {
315
- const newFolderName = join(this.resourceFolder, nameInContent);
316
- await rename(this.internalFolder, newFolderName);
317
- this.internalFolder = newFolderName;
318
- }
319
- return super.write();
320
- }
321
-
322
- /**
323
- * Validates the resource. If object is invalid, throws.
291
+ * Shows metadata of the resource and content of the resource.
292
+ * @returns resource type's metadata and content.
293
+ * @throws if resource does not exist.
324
294
  */
325
- protected async validate(content?: object) {
326
- return super.validate(content);
295
+ public async show(): Promise<ShowReturnType<T, U>> {
296
+ this.assertResourceExists();
297
+ return {
298
+ ...this.content,
299
+ content: await this.contentData(),
300
+ };
327
301
  }
328
302
  }
@@ -12,8 +12,7 @@
12
12
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
13
13
  */
14
14
 
15
- import { readdir } from 'node:fs/promises';
16
- import { extname, join } from 'node:path';
15
+ import { join } from 'node:path';
17
16
 
18
17
  import type {
19
18
  Card,
@@ -28,9 +27,8 @@ import {
28
27
  sortCards,
29
28
  } from './folder-resource.js';
30
29
  import type {
31
- GraphModel,
32
30
  GraphModelMetadata,
33
- GraphModelUpdateKey,
31
+ UpdateKey,
34
32
  } from '../interfaces/resource-interfaces.js';
35
33
  import type { GraphModelContent } from '../interfaces/folder-content-interfaces.js';
36
34
  import { writeFileSafe } from '../utils/file-utils.js';
@@ -38,14 +36,15 @@ import { writeFileSafe } from '../utils/file-utils.js';
38
36
  /**
39
37
  * Graph model resource class.
40
38
  */
41
- export class GraphModelResource extends FolderResource {
39
+ export class GraphModelResource extends FolderResource<
40
+ GraphModelMetadata,
41
+ GraphModelContent
42
+ > {
42
43
  constructor(project: Project, name: ResourceName) {
43
44
  super(project, name, 'graphModels');
44
45
 
45
46
  this.contentSchemaId = 'graphModelSchema';
46
47
  this.contentSchema = super.contentSchemaContent(this.contentSchemaId);
47
-
48
- this.initialize();
49
48
  }
50
49
 
51
50
  /**
@@ -55,7 +54,7 @@ export class GraphModelResource extends FolderResource {
55
54
  protected async onNameChange(existingName: string): Promise<void> {
56
55
  await Promise.all([
57
56
  super.updateHandleBars(existingName, this.content.name, [
58
- await this.calculationFile(),
57
+ join(this.internalFolder, 'model.lp'),
59
58
  ]),
60
59
  super.updateCalculations(existingName, this.content.name),
61
60
  ]);
@@ -90,36 +89,6 @@ export class GraphModelResource extends FolderResource {
90
89
  );
91
90
  }
92
91
 
93
- /**
94
- * Returns resource content.
95
- */
96
- public get data(): GraphModel {
97
- return super.data as GraphModel;
98
- }
99
-
100
- /**
101
- * Deletes file and folder that this resource is based on.
102
- */
103
- public async delete() {
104
- return super.delete();
105
- }
106
-
107
- /**
108
- * Returns calculation file that this graph model has.
109
- * @returns calculation file name that this graph model has.
110
- */
111
- public async calculationFile(nameOnly: boolean = false): Promise<string> {
112
- return (
113
- await readdir(this.internalFolder, {
114
- withFileTypes: true,
115
- recursive: true,
116
- })
117
- )
118
- .filter((dirent) => dirent.isFile() && extname(dirent.name) === '.lp')
119
- .map((item) => (nameOnly ? item.name : join(item.parentPath, item.name)))
120
- .at(0)!;
121
- }
122
-
123
92
  /**
124
93
  * Renames the object and the file.
125
94
  * @param newName New name for the resource.
@@ -130,33 +99,24 @@ export class GraphModelResource extends FolderResource {
130
99
  return this.onNameChange(existingName);
131
100
  }
132
101
 
133
- /**
134
- * Shows metadata of the resource.
135
- * @returns graph model metadata.
136
- */
137
- public async show(): Promise<GraphModel> {
138
- const baseData = (await super.show()) as GraphModelMetadata;
139
- return {
140
- ...baseData,
141
- content: (await super.contentData()) as GraphModelContent,
142
- };
143
- }
144
-
145
102
  /**
146
103
  * Updates graph model resource.
147
- * @param key Key to modify
104
+ * @param updateKey Key to modify
148
105
  * @param op Operation to perform on 'key'
149
106
  */
150
- public async update<Type>(key: GraphModelUpdateKey, op: Operation<Type>) {
151
- if (key === 'category') {
152
- const content = structuredClone(this.content) as GraphModelMetadata;
107
+ public async update<Type, K extends string>(
108
+ updateKey: UpdateKey<K>,
109
+ op: Operation<Type>,
110
+ ) {
111
+ if (updateKey.key === 'category') {
112
+ const content = structuredClone(this.content);
153
113
  content.category = super.handleScalar(op) as string;
154
114
 
155
- await super.postUpdate(content, key, op);
115
+ await super.postUpdate(content, updateKey, op);
156
116
  return;
157
117
  }
158
118
 
159
- await super.update(key, op);
119
+ await super.update(updateKey, op);
160
120
  }
161
121
 
162
122
  /**
@@ -167,28 +127,11 @@ export class GraphModelResource extends FolderResource {
167
127
  * @returns array of card keys and calculation filenames that refer this resource.
168
128
  */
169
129
  public async usage(cards?: Card[]): Promise<string[]> {
170
- const allCards = cards ?? (await super.cards());
130
+ const allCards = cards ?? super.cards();
171
131
  const [relevantCards, calculations] = await Promise.all([
172
132
  super.usage(allCards),
173
133
  super.calculations(),
174
134
  ]);
175
135
  return [...relevantCards.sort(sortCards), ...calculations];
176
136
  }
177
-
178
- /**
179
- * Validates graphModel.
180
- * @throws when there are validation errors.
181
- * @param content Content to be validated.
182
- * @note If content is not provided, base class validation will use resource's current content.
183
- */
184
- public async validate(content?: object) {
185
- return super.validate(content);
186
- }
187
-
188
- /**
189
- * Create the graph model's folder and calculation file.
190
- */
191
- public async write() {
192
- await super.write();
193
- }
194
137
  }
@@ -28,9 +28,8 @@ import {
28
28
  sortCards,
29
29
  } from './folder-resource.js';
30
30
  import type {
31
- GraphView,
32
31
  GraphViewMetadata,
33
- GraphViewUpdateKey,
32
+ UpdateKey,
34
33
  } from '../interfaces/resource-interfaces.js';
35
34
  import type { GraphViewContent } from '../interfaces/folder-content-interfaces.js';
36
35
 
@@ -40,14 +39,15 @@ import { copyDir } from '../utils/file-utils.js';
40
39
  /**
41
40
  * Graph view resource class.
42
41
  */
43
- export class GraphViewResource extends FolderResource {
42
+ export class GraphViewResource extends FolderResource<
43
+ GraphViewMetadata,
44
+ GraphViewContent
45
+ > {
44
46
  constructor(project: Project, name: ResourceName) {
45
47
  super(project, name, 'graphViews');
46
48
 
47
49
  this.contentSchemaId = 'graphViewSchema';
48
50
  this.contentSchema = super.contentSchemaContent(this.contentSchemaId);
49
-
50
- this.initialize();
51
51
  }
52
52
 
53
53
  /**
@@ -85,20 +85,6 @@ export class GraphViewResource extends FolderResource {
85
85
  );
86
86
  }
87
87
 
88
- /**
89
- * Returns resource content.
90
- */
91
- public get data(): GraphView {
92
- return super.data as GraphView;
93
- }
94
-
95
- /**
96
- * Deletes file and folder that this resource is based on.
97
- */
98
- public async delete() {
99
- return super.delete();
100
- }
101
-
102
88
  /**
103
89
  * Returns handlebar filename that this graph view has.
104
90
  * @returns handlebar filename that this graph view has.
@@ -125,33 +111,24 @@ export class GraphViewResource extends FolderResource {
125
111
  return this.onNameChange(existingName);
126
112
  }
127
113
 
128
- /**
129
- * Shows metadata of the resource.
130
- * @returns graph view metadata.
131
- */
132
- public async show(): Promise<GraphView> {
133
- const baseData = (await super.show()) as GraphViewMetadata;
134
- return {
135
- ...baseData,
136
- content: (await super.contentData()) as GraphViewContent,
137
- };
138
- }
139
-
140
114
  /**
141
115
  * Updates graph view resource.
142
- * @param key Key to modify
116
+ * @param updateKey Key to modify
143
117
  * @param op Operation to perform on 'key'
144
118
  */
145
- public async update<Type>(key: GraphViewUpdateKey, op: Operation<Type>) {
146
- if (key === 'category') {
119
+ public async update<Type, K extends string>(
120
+ updateKey: UpdateKey<K>,
121
+ op: Operation<Type>,
122
+ ) {
123
+ if (updateKey.key === 'category') {
147
124
  const content = structuredClone(this.content) as GraphViewMetadata;
148
125
  content.category = super.handleScalar(op) as string;
149
126
 
150
- await super.postUpdate(content, key, op);
127
+ await super.postUpdate(content, updateKey, op);
151
128
  return;
152
129
  }
153
130
 
154
- await super.update(key, op);
131
+ await super.update(updateKey, op);
155
132
  }
156
133
 
157
134
  /**
@@ -162,28 +139,11 @@ export class GraphViewResource extends FolderResource {
162
139
  * @returns array of card keys and calculation filenames that refer this resource.
163
140
  */
164
141
  public async usage(cards?: Card[]): Promise<string[]> {
165
- const allCards = cards ?? (await super.cards());
142
+ const allCards = cards ?? super.cards();
166
143
  const [relevantCards, calculations] = await Promise.all([
167
144
  super.usage(allCards),
168
145
  super.calculations(),
169
146
  ]);
170
147
  return [...relevantCards.sort(sortCards), ...calculations];
171
148
  }
172
-
173
- /**
174
- * Validates graph view.
175
- * @throws when there are validation errors.
176
- * @param content Content to be validated.
177
- * @note If content is not provided, base class validation will use resource's current content.
178
- */
179
- public async validate(content?: object) {
180
- return super.validate(content);
181
- }
182
-
183
- /**
184
- * Create the graph view's folder and handlebar file.
185
- */
186
- public async write() {
187
- await super.write();
188
- }
189
149
  }