@cyberismo/data-handler 0.0.11 → 0.0.13

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 (179) hide show
  1. package/dist/card-metadata-updater.js +1 -1
  2. package/dist/card-metadata-updater.js.map +1 -1
  3. package/dist/command-handler.d.ts +26 -39
  4. package/dist/command-handler.js +76 -31
  5. package/dist/command-handler.js.map +1 -1
  6. package/dist/command-manager.d.ts +2 -1
  7. package/dist/command-manager.js +4 -2
  8. package/dist/command-manager.js.map +1 -1
  9. package/dist/commands/calculate.d.ts +7 -0
  10. package/dist/commands/calculate.js +9 -0
  11. package/dist/commands/calculate.js.map +1 -1
  12. package/dist/commands/create.d.ts +5 -0
  13. package/dist/commands/create.js +15 -8
  14. package/dist/commands/create.js.map +1 -1
  15. package/dist/commands/fetch.d.ts +24 -0
  16. package/dist/commands/fetch.js +118 -0
  17. package/dist/commands/fetch.js.map +1 -0
  18. package/dist/commands/import.js +2 -2
  19. package/dist/commands/import.js.map +1 -1
  20. package/dist/commands/index.d.ts +2 -1
  21. package/dist/commands/index.js +2 -1
  22. package/dist/commands/index.js.map +1 -1
  23. package/dist/commands/remove.d.ts +1 -0
  24. package/dist/commands/remove.js +16 -12
  25. package/dist/commands/remove.js.map +1 -1
  26. package/dist/commands/rename.js +4 -6
  27. package/dist/commands/rename.js.map +1 -1
  28. package/dist/commands/show.d.ts +22 -1
  29. package/dist/commands/show.js +56 -0
  30. package/dist/commands/show.js.map +1 -1
  31. package/dist/commands/update.d.ts +11 -1
  32. package/dist/commands/update.js +14 -2
  33. package/dist/commands/update.js.map +1 -1
  34. package/dist/commands/validate.d.ts +2 -1
  35. package/dist/commands/validate.js +10 -10
  36. package/dist/commands/validate.js.map +1 -1
  37. package/dist/containers/card-container.js +1 -1
  38. package/dist/containers/card-container.js.map +1 -1
  39. package/dist/containers/project/calculation-engine.d.ts +8 -0
  40. package/dist/containers/project/calculation-engine.js +21 -10
  41. package/dist/containers/project/calculation-engine.js.map +1 -1
  42. package/dist/containers/project.d.ts +19 -8
  43. package/dist/containers/project.js +52 -34
  44. package/dist/containers/project.js.map +1 -1
  45. package/dist/containers/template.js +1 -1
  46. package/dist/containers/template.js.map +1 -1
  47. package/dist/index.d.ts +4 -2
  48. package/dist/index.js.map +1 -1
  49. package/dist/interfaces/command-options.d.ts +81 -0
  50. package/dist/interfaces/command-options.js +14 -0
  51. package/dist/interfaces/command-options.js.map +1 -0
  52. package/dist/interfaces/folder-content-interfaces.d.ts +50 -0
  53. package/dist/interfaces/folder-content-interfaces.js +45 -0
  54. package/dist/interfaces/folder-content-interfaces.js.map +1 -0
  55. package/dist/interfaces/project-interfaces.d.ts +13 -2
  56. package/dist/interfaces/project-interfaces.js.map +1 -1
  57. package/dist/interfaces/resource-interfaces.d.ts +28 -10
  58. package/dist/interfaces/resource-interfaces.js.map +1 -1
  59. package/dist/macros/base-macro.d.ts +1 -1
  60. package/dist/macros/base-macro.js +1 -1
  61. package/dist/macros/base-macro.js.map +1 -1
  62. package/dist/macros/createCards/index.d.ts +1 -1
  63. package/dist/macros/createCards/index.js +1 -1
  64. package/dist/macros/createCards/index.js.map +1 -1
  65. package/dist/macros/graph/index.d.ts +1 -1
  66. package/dist/macros/graph/index.js +21 -29
  67. package/dist/macros/graph/index.js.map +1 -1
  68. package/dist/macros/image/index.d.ts +1 -1
  69. package/dist/macros/image/index.js +1 -7
  70. package/dist/macros/image/index.js.map +1 -1
  71. package/dist/macros/include/index.d.ts +1 -1
  72. package/dist/macros/include/index.js +1 -1
  73. package/dist/macros/include/index.js.map +1 -1
  74. package/dist/macros/index.d.ts +12 -5
  75. package/dist/macros/index.js +19 -7
  76. package/dist/macros/index.js.map +1 -1
  77. package/dist/macros/percentage/index.d.ts +1 -1
  78. package/dist/macros/percentage/index.js +1 -1
  79. package/dist/macros/percentage/index.js.map +1 -1
  80. package/dist/macros/report/index.d.ts +1 -1
  81. package/dist/macros/report/index.js +5 -5
  82. package/dist/macros/report/index.js.map +1 -1
  83. package/dist/macros/scoreCard/index.d.ts +1 -1
  84. package/dist/macros/scoreCard/index.js +1 -1
  85. package/dist/macros/scoreCard/index.js.map +1 -1
  86. package/dist/macros/vega/index.d.ts +1 -1
  87. package/dist/macros/vega/index.js +1 -1
  88. package/dist/macros/vega/index.js.map +1 -1
  89. package/dist/macros/vegalite/index.d.ts +1 -1
  90. package/dist/macros/vegalite/index.js +1 -1
  91. package/dist/macros/vegalite/index.js.map +1 -1
  92. package/dist/macros/xref/index.d.ts +1 -1
  93. package/dist/macros/xref/index.js +1 -1
  94. package/dist/macros/xref/index.js.map +1 -1
  95. package/dist/project-settings.d.ts +14 -1
  96. package/dist/project-settings.js +51 -1
  97. package/dist/project-settings.js.map +1 -1
  98. package/dist/resources/card-type-resource.js +11 -5
  99. package/dist/resources/card-type-resource.js.map +1 -1
  100. package/dist/resources/field-type-resource.d.ts +5 -0
  101. package/dist/resources/field-type-resource.js +9 -4
  102. package/dist/resources/field-type-resource.js.map +1 -1
  103. package/dist/resources/folder-resource.d.ts +37 -9
  104. package/dist/resources/folder-resource.js +108 -12
  105. package/dist/resources/folder-resource.js.map +1 -1
  106. package/dist/resources/graph-model-resource.d.ts +7 -4
  107. package/dist/resources/graph-model-resource.js +12 -25
  108. package/dist/resources/graph-model-resource.js.map +1 -1
  109. package/dist/resources/graph-view-resource.d.ts +7 -4
  110. package/dist/resources/graph-view-resource.js +15 -31
  111. package/dist/resources/graph-view-resource.js.map +1 -1
  112. package/dist/resources/link-type-resource.js +1 -1
  113. package/dist/resources/link-type-resource.js.map +1 -1
  114. package/dist/resources/report-resource.d.ts +14 -10
  115. package/dist/resources/report-resource.js +41 -45
  116. package/dist/resources/report-resource.js.map +1 -1
  117. package/dist/resources/resource-object.d.ts +7 -0
  118. package/dist/resources/resource-object.js.map +1 -1
  119. package/dist/resources/template-resource.d.ts +5 -1
  120. package/dist/resources/template-resource.js +12 -7
  121. package/dist/resources/template-resource.js.map +1 -1
  122. package/dist/resources/workflow-resource.js +12 -5
  123. package/dist/resources/workflow-resource.js.map +1 -1
  124. package/dist/utils/log-utils.js +1 -1
  125. package/dist/utils/log-utils.js.map +1 -1
  126. package/dist/utils/report.js +6 -0
  127. package/dist/utils/report.js.map +1 -1
  128. package/dist/utils/resource-utils.d.ts +8 -0
  129. package/dist/utils/resource-utils.js +11 -0
  130. package/dist/utils/resource-utils.js.map +1 -1
  131. package/package.json +11 -11
  132. package/src/card-metadata-updater.ts +1 -1
  133. package/src/command-handler.ts +129 -61
  134. package/src/command-manager.ts +4 -1
  135. package/src/commands/calculate.ts +18 -0
  136. package/src/commands/create.ts +31 -19
  137. package/src/commands/fetch.ts +152 -0
  138. package/src/commands/import.ts +2 -0
  139. package/src/commands/index.ts +2 -0
  140. package/src/commands/remove.ts +18 -12
  141. package/src/commands/rename.ts +11 -11
  142. package/src/commands/show.ts +72 -0
  143. package/src/commands/update.ts +20 -2
  144. package/src/commands/validate.ts +13 -10
  145. package/src/containers/card-container.ts +1 -1
  146. package/src/containers/project/calculation-engine.ts +27 -11
  147. package/src/containers/project.ts +71 -61
  148. package/src/containers/template.ts +1 -1
  149. package/src/index.ts +36 -2
  150. package/src/interfaces/command-options.ts +144 -0
  151. package/src/interfaces/folder-content-interfaces.ts +69 -0
  152. package/src/interfaces/project-interfaces.ts +18 -0
  153. package/src/interfaces/resource-interfaces.ts +41 -12
  154. package/src/macros/base-macro.ts +5 -2
  155. package/src/macros/createCards/index.ts +1 -1
  156. package/src/macros/graph/index.ts +47 -51
  157. package/src/macros/image/index.ts +1 -7
  158. package/src/macros/include/index.ts +1 -1
  159. package/src/macros/index.ts +19 -7
  160. package/src/macros/percentage/index.ts +1 -1
  161. package/src/macros/report/index.ts +5 -5
  162. package/src/macros/scoreCard/index.ts +1 -1
  163. package/src/macros/vega/index.ts +1 -1
  164. package/src/macros/vegalite/index.ts +1 -1
  165. package/src/macros/xref/index.ts +1 -1
  166. package/src/project-settings.ts +62 -1
  167. package/src/resources/card-type-resource.ts +12 -6
  168. package/src/resources/field-type-resource.ts +9 -4
  169. package/src/resources/folder-resource.ts +149 -19
  170. package/src/resources/graph-model-resource.ts +16 -27
  171. package/src/resources/graph-view-resource.ts +23 -33
  172. package/src/resources/link-type-resource.ts +1 -1
  173. package/src/resources/report-resource.ts +60 -62
  174. package/src/resources/resource-object.ts +11 -0
  175. package/src/resources/template-resource.ts +12 -7
  176. package/src/resources/workflow-resource.ts +11 -6
  177. package/src/utils/log-utils.ts +1 -1
  178. package/src/utils/report.ts +6 -0
  179. package/src/utils/resource-utils.ts +16 -0
@@ -150,13 +150,13 @@ export class FieldTypeResource extends FileResource {
150
150
  const allCards = [...projectCards, ...templateCards];
151
151
 
152
152
  // Finally, convert values and update the cards.
153
- allCards.forEach(async (card) => {
153
+ for (const card of allCards) {
154
154
  const metadata = card.metadata!;
155
155
  const fieldName = resourceNameToString(this.resourceName);
156
156
  try {
157
157
  metadata[fieldName] = this.convertValue(metadata[fieldName]);
158
158
  // Either value was already null, or couldn't convert.
159
- if (metadata[fieldName] === null) return;
159
+ if (metadata[fieldName] === null) continue;
160
160
 
161
161
  await this.project.updateCardMetadata(card, metadata);
162
162
  } catch (error) {
@@ -164,7 +164,7 @@ export class FieldTypeResource extends FileResource {
164
164
  `In card '${card.key}': ${error instanceof Error ? error.message : String(error)}`,
165
165
  );
166
166
  }
167
- });
167
+ }
168
168
  }
169
169
 
170
170
  // Checks that enum with 'enumValue' exists.
@@ -305,6 +305,7 @@ export class FieldTypeResource extends FileResource {
305
305
  /**
306
306
  * Creates a new field type object. Base class writes the object to disk automatically.
307
307
  * @param dataType Type for the new field type.
308
+ * @throws if called with unknown data type
308
309
  */
309
310
  public async createFieldType(dataType: DataType) {
310
311
  if (!FieldTypeResource.fieldDataTypes().includes(dataType)) {
@@ -418,6 +419,10 @@ export class FieldTypeResource extends FileResource {
418
419
  * Updates field type resource.
419
420
  * @param key Key to modify
420
421
  * @param op Operation to perform on 'key'
422
+ * @throws
423
+ * - when called with unknown data type
424
+ * - when called with data type conversion that cannot be done
425
+ * - when called with unknown property to update
421
426
  */
422
427
  public async update<Type>(key: string, op: Operation<Type>) {
423
428
  const nameChange = key === 'name';
@@ -428,7 +433,7 @@ export class FieldTypeResource extends FileResource {
428
433
 
429
434
  await super.update(key, op);
430
435
 
431
- const content = this.content as FieldType;
436
+ const content = structuredClone(this.content) as FieldType;
432
437
  if (key === 'name') {
433
438
  content.name = super.handleScalar(op) as string;
434
439
  } else if (key === 'dataType') {
@@ -1,35 +1,44 @@
1
1
  /**
2
2
  Cyberismo
3
3
  Copyright © Cyberismo Ltd and contributors 2024
4
+
4
5
  This program is free software: you can redistribute it and/or modify it under
5
6
  the terms of the GNU Affero General Public License version 3 as published by
6
- the Free Software Foundation.
7
- This program is distributed in the hope that it will be useful, but WITHOUT
8
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
- details. You should have received a copy of the GNU Affero General Public
7
+ the Free Software Foundation. This program is distributed in the hope that it
8
+ will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9
+ of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
+ See the GNU Affero General Public License for more details.
11
+ You should have received a copy of the GNU Affero General Public
11
12
  License along with this program. If not, see <https://www.gnu.org/licenses/>.
12
13
  */
13
14
 
14
15
  import { basename, dirname, join, normalize } from 'node:path';
15
16
  import { mkdir, readdir, readFile, rename, rm } from 'node:fs/promises';
16
17
 
17
- import { writeFileSafe } from '../utils/file-utils.js';
18
-
18
+ import type { Card, Operation, ResourceName } from './file-resource.js';
19
+ import type {
20
+ ContentUpdateKey,
21
+ ResourceContent,
22
+ UpdateKey,
23
+ } from '../interfaces/resource-interfaces.js';
19
24
  import type { ResourceFolderType } from '../interfaces/project-interfaces.js';
25
+ import type { Schema } from 'jsonschema';
26
+
20
27
  import {
21
- type Card,
22
28
  DefaultContent,
23
29
  FileResource,
24
- type Operation,
25
30
  Project,
26
31
  resourceName,
27
- type ResourceName,
28
32
  resourceNameToString,
29
33
  sortCards,
30
34
  } from './file-resource.js';
31
- import type { ResourceContent } from '../interfaces/resource-interfaces.js';
35
+ import {
36
+ filename,
37
+ propertyName,
38
+ } from '../interfaces/folder-content-interfaces.js';
39
+ import { readJsonFile } from '../utils/json.js';
32
40
  import { VALID_FOLDER_RESOURCE_FILES } from '../utils/constants.js';
41
+ import { writeFileSafe } from '../utils/file-utils.js';
33
42
 
34
43
  export {
35
44
  type Card,
@@ -48,10 +57,23 @@ export {
48
57
  export class FolderResource extends FileResource {
49
58
  protected internalFolder: string = '';
50
59
 
60
+ // Cache for content files to avoid repeated filesystem operations. Content is stored as string.
61
+ private contentFilesCache = new Map<string, string>();
62
+
51
63
  constructor(project: Project, name: ResourceName, type: ResourceFolderType) {
52
64
  super(project, name, type);
53
65
  }
54
66
 
67
+ // Clears the content files cache.
68
+ private clearContentCache() {
69
+ this.contentFilesCache.clear();
70
+ }
71
+
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
+
55
77
  /**
56
78
  * Creates a new folder type object. Base class writes the object to disk automatically.
57
79
  * @param newContent Content for the type.
@@ -61,6 +83,25 @@ export class FolderResource extends FileResource {
61
83
  await mkdir(this.internalFolder, { recursive: true });
62
84
  }
63
85
 
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
+
64
105
  /**
65
106
  * Returns content data.
66
107
  */
@@ -74,6 +115,7 @@ export class FolderResource extends FileResource {
74
115
  protected async delete() {
75
116
  await super.delete();
76
117
  await rm(this.internalFolder, { recursive: true, force: true });
118
+ this.clearContentCache();
77
119
  }
78
120
 
79
121
  // Get (resource folder) type name
@@ -81,11 +123,15 @@ export class FolderResource extends FileResource {
81
123
  return super.getType;
82
124
  }
83
125
 
126
+ // Get logger instance
84
127
  protected get logger() {
85
128
  return super.getLogger(this.getType);
86
129
  }
87
130
 
88
- protected initialize(): void {
131
+ /**
132
+ * Initialize the resource item.
133
+ */
134
+ protected initialize() {
89
135
  super.initialize();
90
136
 
91
137
  this.internalFolder = join(
@@ -111,22 +157,69 @@ export class FolderResource extends FileResource {
111
157
  }
112
158
 
113
159
  /**
160
+ * TODO: to be made protected - no direct access to files
114
161
  * Shows the content of a file in the resource.
115
162
  * @param fileName Name of the file to show.
163
+ * @param json Content is JSON file.
116
164
  * @returns the content of the file.
117
165
  */
118
- public async showFile(fileName: string): Promise<string> {
166
+ public async showFile(
167
+ fileName: string,
168
+ json: boolean = false,
169
+ ): Promise<string> {
170
+ // Always first check cache...
171
+ if (this.contentFilesCache.has(fileName)) {
172
+ const cached = this.contentFilesCache.get(fileName)!;
173
+ return json ? JSON.parse(cached) : cached;
174
+ }
175
+
176
+ // ...cache miss, read from filesystem
119
177
  const filePath = join(this.internalFolder, fileName);
120
- return readFile(filePath, 'utf8');
178
+ const content = json
179
+ ? await readJsonFile(filePath)
180
+ : await readFile(filePath, 'utf8');
181
+
182
+ // Update cache
183
+ const contentStr =
184
+ typeof content === 'string' ? content : JSON.stringify(content, null, 2);
185
+ this.contentFilesCache.set(fileName, contentStr);
186
+
187
+ return json ? content : contentStr;
121
188
  }
122
189
 
123
190
  /**
191
+ * TODO: to be made protected - no direct access to files
124
192
  * Shows all file names in the resource.
125
193
  * @returns all file names in the resource.
126
194
  */
127
195
  public async showFileNames(): Promise<string[]> {
196
+ // Always first check cache...
197
+ if (this.contentFilesCache.size > 0) {
198
+ return Array.from(this.contentFilesCache.keys());
199
+ }
200
+
201
+ // ...cache miss, read from filesystem and populate cache
128
202
  const files = await readdir(this.internalFolder);
129
- return files.filter((file) => VALID_FOLDER_RESOURCE_FILES.includes(file));
203
+ const validFiles = files.filter((file) =>
204
+ VALID_FOLDER_RESOURCE_FILES.includes(file),
205
+ );
206
+
207
+ // Update cache by reading all files. Each method call updates specific cache item.
208
+ for (const fileName of validFiles) {
209
+ await this.showFile(fileName);
210
+ }
211
+
212
+ return validFiles;
213
+ }
214
+
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
+ public async updateContentFiles(contentFiles: Record<string, string>) {
220
+ for (const [fileName, fileContent] of Object.entries(contentFiles)) {
221
+ await this.updateFile(fileName, fileContent);
222
+ }
130
223
  }
131
224
 
132
225
  /**
@@ -148,22 +241,59 @@ export class FolderResource extends FileResource {
148
241
  if (basename(normalizedFilePath) !== fileName) {
149
242
  throw new Error(`File '${fileName}' is not in the resource`);
150
243
  }
151
- // check if the file is whitelisted
244
+ // check if the file is allow-listed
152
245
  if (!VALID_FOLDER_RESOURCE_FILES.includes(fileName)) {
153
- throw new Error(`File '${fileName}' is not whitelisted`);
246
+ throw new Error(`File '${fileName}' is not allowed`);
154
247
  }
155
248
 
156
249
  await writeFileSafe(filePath, changedContent, { flag: 'w' });
250
+
251
+ // Update cache with new content
252
+ this.contentFilesCache.set(fileName, changedContent);
157
253
  }
254
+
158
255
  /**
159
256
  * Updates resource.
160
257
  * @param key Key to modify
161
258
  * @param op Operation to perform on 'key'
259
+ * @throws if key is unknown.
162
260
  */
163
- protected async update<Type>(key: string, op: Operation<Type>) {
164
- return super.update(key, op);
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);
266
+ return;
267
+ }
268
+
269
+ const nameChange = key === 'name';
270
+ const existingName = this.content.name;
271
+ await super.update(key, op);
272
+ const content = structuredClone(this.content);
273
+
274
+ if (key === 'name') {
275
+ content.name = super.handleScalar(op) as string;
276
+ } else if (key === 'displayName') {
277
+ content.displayName = super.handleScalar(op) as string;
278
+ } else if (key === 'description') {
279
+ content.description = super.handleScalar(op) as string;
280
+ } else {
281
+ throw new Error(`Unknown property '${key}' for folder resource`);
282
+ }
283
+
284
+ await super.postUpdate(content, key, op);
285
+
286
+ if (nameChange) {
287
+ await this.onNameChange?.(existingName);
288
+ }
165
289
  }
166
290
 
291
+ /**
292
+ * For handling name changes.
293
+ * @param previousName The previous name before the change
294
+ */
295
+ protected async onNameChange?(previousName: string): Promise<void>;
296
+
167
297
  /**
168
298
  * Returns an array of card keys, and/or resource names where this resource is used.
169
299
  * @param cards Optional. If defined, only these cards are checked.
@@ -30,7 +30,9 @@ import {
30
30
  import type {
31
31
  GraphModel,
32
32
  GraphModelMetadata,
33
+ GraphModelUpdateKey,
33
34
  } from '../interfaces/resource-interfaces.js';
35
+ import type { GraphModelContent } from '../interfaces/folder-content-interfaces.js';
34
36
  import { writeFileSafe } from '../utils/file-utils.js';
35
37
 
36
38
  /**
@@ -46,8 +48,11 @@ export class GraphModelResource extends FolderResource {
46
48
  this.initialize();
47
49
  }
48
50
 
49
- // When resource name changes.
50
- private async handleNameChange(existingName: string) {
51
+ /**
52
+ * Handle name changes for graph models
53
+ * @param existingName The previous name before the change
54
+ */
55
+ protected async onNameChange(existingName: string): Promise<void> {
51
56
  await Promise.all([
52
57
  super.updateHandleBars(existingName, this.content.name, [
53
58
  await this.calculationFile(),
@@ -122,7 +127,7 @@ export class GraphModelResource extends FolderResource {
122
127
  public async rename(newName: ResourceName) {
123
128
  const existingName = this.content.name;
124
129
  await super.rename(newName);
125
- return this.handleNameChange(existingName);
130
+ return this.onNameChange(existingName);
126
131
  }
127
132
 
128
133
  /**
@@ -130,11 +135,10 @@ export class GraphModelResource extends FolderResource {
130
135
  * @returns graph model metadata.
131
136
  */
132
137
  public async show(): Promise<GraphModel> {
133
- const showOnlyFileName = true;
134
138
  const baseData = (await super.show()) as GraphModelMetadata;
135
139
  return {
136
140
  ...baseData,
137
- calculationFile: await this.calculationFile(showOnlyFileName),
141
+ content: (await super.contentData()) as GraphModelContent,
138
142
  };
139
143
  }
140
144
 
@@ -142,32 +146,17 @@ export class GraphModelResource extends FolderResource {
142
146
  * Updates graph model resource.
143
147
  * @param key Key to modify
144
148
  * @param op Operation to perform on 'key'
145
- * @throws if key is unknown.
146
149
  */
147
- public async update<Type>(key: string, op: Operation<Type>) {
148
- const nameChange = key === 'name';
149
- const existingName = this.content.name;
150
-
151
- await super.update(key, op);
152
-
153
- const content = structuredClone(this.content) as GraphModel;
154
-
155
- if (key === 'name') {
156
- content.name = super.handleScalar(op) as string;
157
- } else if (key === 'displayName') {
158
- content.displayName = super.handleScalar(op) as string;
159
- } else if (key === 'description') {
160
- content.description = super.handleScalar(op) as string;
161
- } else if (key === 'category') {
150
+ public async update<Type>(key: GraphModelUpdateKey, op: Operation<Type>) {
151
+ if (key === 'category') {
152
+ const content = structuredClone(this.content) as GraphModelMetadata;
162
153
  content.category = super.handleScalar(op) as string;
163
- }
164
-
165
- await super.postUpdate(content, key, op);
166
154
 
167
- // Renaming this graph model causes that references to its name must be updated.
168
- if (nameChange) {
169
- await this.handleNameChange(existingName);
155
+ await super.postUpdate(content, key, op);
156
+ return;
170
157
  }
158
+
159
+ await super.update(key, op);
171
160
  }
172
161
 
173
162
  /**
@@ -30,8 +30,12 @@ import {
30
30
  import type {
31
31
  GraphView,
32
32
  GraphViewMetadata,
33
+ GraphViewUpdateKey,
33
34
  } from '../interfaces/resource-interfaces.js';
34
- import { writeFileSafe } from '../utils/file-utils.js';
35
+ import type { GraphViewContent } from '../interfaces/folder-content-interfaces.js';
36
+
37
+ import { getStaticDirectoryPath } from '@cyberismo/assets';
38
+ import { copyDir } from '../utils/file-utils.js';
35
39
 
36
40
  /**
37
41
  * Graph view resource class.
@@ -46,15 +50,17 @@ export class GraphViewResource extends FolderResource {
46
50
  this.initialize();
47
51
  }
48
52
 
49
- // When resource name changes.
50
- private async handleNameChange(existingName: string) {
53
+ /**
54
+ * Handle name changes for graph views
55
+ * @param existingName The previous name before the change
56
+ */
57
+ protected async onNameChange(existingName: string): Promise<void> {
51
58
  await Promise.all([
52
59
  super.updateHandleBars(existingName, this.content.name, [
53
60
  await this.handleBarFile(),
54
61
  ]),
55
62
  super.updateCalculations(existingName, this.content.name),
56
63
  ]);
57
- // Finally, write updated content.
58
64
  await this.write();
59
65
  }
60
66
 
@@ -73,10 +79,10 @@ export class GraphViewResource extends FolderResource {
73
79
  }
74
80
 
75
81
  await super.create(newContent);
76
- const handleBarFile = join(this.internalFolder, 'view.lp.hbs');
77
- await writeFileSafe(handleBarFile, '', {
78
- flag: 'wx',
79
- });
82
+ await copyDir(
83
+ join(await getStaticDirectoryPath(), 'defaultGraphView'),
84
+ this.internalFolder,
85
+ );
80
86
  }
81
87
 
82
88
  /**
@@ -116,7 +122,7 @@ export class GraphViewResource extends FolderResource {
116
122
  public async rename(newName: ResourceName) {
117
123
  const existingName = this.content.name;
118
124
  await super.rename(newName);
119
- return this.handleNameChange(existingName);
125
+ return this.onNameChange(existingName);
120
126
  }
121
127
 
122
128
  /**
@@ -124,11 +130,10 @@ export class GraphViewResource extends FolderResource {
124
130
  * @returns graph view metadata.
125
131
  */
126
132
  public async show(): Promise<GraphView> {
127
- const showOnlyFileName = true;
128
133
  const baseData = (await super.show()) as GraphViewMetadata;
129
134
  return {
130
135
  ...baseData,
131
- handleBarFile: await this.handleBarFile(showOnlyFileName),
136
+ content: (await super.contentData()) as GraphViewContent,
132
137
  };
133
138
  }
134
139
 
@@ -136,32 +141,17 @@ export class GraphViewResource extends FolderResource {
136
141
  * Updates graph view resource.
137
142
  * @param key Key to modify
138
143
  * @param op Operation to perform on 'key'
139
- * @throws if key is unknown.
140
144
  */
141
- public async update<Type>(key: string, op: Operation<Type>) {
142
- const nameChange = key === 'name';
143
- const existingName = this.content.name;
144
-
145
- await super.update(key, op);
146
-
147
- const content = structuredClone(this.content) as GraphView;
148
-
149
- if (key === 'name') {
150
- content.name = super.handleScalar(op) as string;
151
- } else if (key === 'displayName') {
152
- content.displayName = super.handleScalar(op) as string;
153
- } else if (key === 'description') {
154
- content.description = super.handleScalar(op) as string;
155
- } else if (key === 'category') {
145
+ public async update<Type>(key: GraphViewUpdateKey, op: Operation<Type>) {
146
+ if (key === 'category') {
147
+ const content = structuredClone(this.content) as GraphViewMetadata;
156
148
  content.category = super.handleScalar(op) as string;
157
- }
158
149
 
159
- await super.postUpdate(content, key, op);
160
-
161
- // Renaming this graph view causes that references to its name must be updated.
162
- if (nameChange) {
163
- await this.handleNameChange(existingName);
150
+ await super.postUpdate(content, key, op);
151
+ return;
164
152
  }
153
+
154
+ await super.update(key, op);
165
155
  }
166
156
 
167
157
  /**
@@ -117,7 +117,7 @@ export class LinkTypeResource extends FileResource {
117
117
 
118
118
  await super.update(key, op);
119
119
 
120
- const content = this.content as LinkType;
120
+ const content = structuredClone(this.content) as LinkType;
121
121
  if (key === 'name') {
122
122
  content.name = super.handleScalar(op) as string;
123
123
  } else if (key === 'destinationCardTypes') {