@cyberismo/data-handler 0.0.15 → 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 (173) hide show
  1. package/dist/card-metadata-updater.js +7 -1
  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 +19 -3
  5. package/dist/command-handler.js.map +1 -1
  6. package/dist/command-manager.d.ts +24 -1
  7. package/dist/command-manager.js +27 -3
  8. package/dist/command-manager.js.map +1 -1
  9. package/dist/commands/create.d.ts +1 -1
  10. package/dist/commands/create.js +34 -36
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/export.d.ts +11 -2
  13. package/dist/commands/export.js +54 -41
  14. package/dist/commands/export.js.map +1 -1
  15. package/dist/commands/import.d.ts +9 -1
  16. package/dist/commands/import.js +15 -7
  17. package/dist/commands/import.js.map +1 -1
  18. package/dist/commands/move.js +0 -1
  19. package/dist/commands/move.js.map +1 -1
  20. package/dist/commands/remove.d.ts +8 -1
  21. package/dist/commands/remove.js +8 -4
  22. package/dist/commands/remove.js.map +1 -1
  23. package/dist/commands/rename.d.ts +4 -9
  24. package/dist/commands/rename.js +32 -101
  25. package/dist/commands/rename.js.map +1 -1
  26. package/dist/commands/show.d.ts +16 -10
  27. package/dist/commands/show.js +71 -55
  28. package/dist/commands/show.js.map +1 -1
  29. package/dist/commands/transition.d.ts +9 -2
  30. package/dist/commands/transition.js +25 -17
  31. package/dist/commands/transition.js.map +1 -1
  32. package/dist/commands/update.d.ts +16 -12
  33. package/dist/commands/update.js +19 -17
  34. package/dist/commands/update.js.map +1 -1
  35. package/dist/commands/validate.d.ts +17 -9
  36. package/dist/commands/validate.js +96 -35
  37. package/dist/commands/validate.js.map +1 -1
  38. package/dist/containers/project/calculation-engine.d.ts +7 -4
  39. package/dist/containers/project/calculation-engine.js +61 -66
  40. package/dist/containers/project/calculation-engine.js.map +1 -1
  41. package/dist/containers/project/project-paths.d.ts +5 -4
  42. package/dist/containers/project/project-paths.js +16 -12
  43. package/dist/containers/project/project-paths.js.map +1 -1
  44. package/dist/containers/project/resource-cache.d.ts +169 -0
  45. package/dist/containers/project/resource-cache.js +507 -0
  46. package/dist/containers/project/resource-cache.js.map +1 -0
  47. package/dist/containers/project/resource-handler.d.ts +129 -0
  48. package/dist/containers/project/resource-handler.js +206 -0
  49. package/dist/containers/project/resource-handler.js.map +1 -0
  50. package/dist/containers/project.d.ts +38 -153
  51. package/dist/containers/project.js +129 -405
  52. package/dist/containers/project.js.map +1 -1
  53. package/dist/containers/template.d.ts +8 -2
  54. package/dist/containers/template.js +20 -15
  55. package/dist/containers/template.js.map +1 -1
  56. package/dist/interfaces/folder-content-interfaces.d.ts +5 -3
  57. package/dist/interfaces/folder-content-interfaces.js +3 -3
  58. package/dist/interfaces/folder-content-interfaces.js.map +1 -1
  59. package/dist/interfaces/project-interfaces.d.ts +2 -4
  60. package/dist/interfaces/project-interfaces.js.map +1 -1
  61. package/dist/interfaces/resource-interfaces.d.ts +14 -1
  62. package/dist/interfaces/resource-interfaces.js.map +1 -1
  63. package/dist/macros/graph/index.js +12 -26
  64. package/dist/macros/graph/index.js.map +1 -1
  65. package/dist/macros/index.d.ts +1 -1
  66. package/dist/macros/index.js +2 -2
  67. package/dist/macros/index.js.map +1 -1
  68. package/dist/macros/report/index.js +3 -6
  69. package/dist/macros/report/index.js.map +1 -1
  70. package/dist/module-manager.d.ts +16 -3
  71. package/dist/module-manager.js +51 -19
  72. package/dist/module-manager.js.map +1 -1
  73. package/dist/project-settings.d.ts +16 -3
  74. package/dist/project-settings.js +79 -14
  75. package/dist/project-settings.js.map +1 -1
  76. package/dist/resources/calculation-resource.d.ts +4 -3
  77. package/dist/resources/calculation-resource.js +11 -5
  78. package/dist/resources/calculation-resource.js.map +1 -1
  79. package/dist/resources/card-type-resource.d.ts +6 -1
  80. package/dist/resources/card-type-resource.js +34 -23
  81. package/dist/resources/card-type-resource.js.map +1 -1
  82. package/dist/resources/create-defaults.d.ts +3 -2
  83. package/dist/resources/create-defaults.js +3 -2
  84. package/dist/resources/create-defaults.js.map +1 -1
  85. package/dist/resources/field-type-resource.d.ts +4 -1
  86. package/dist/resources/field-type-resource.js +22 -23
  87. package/dist/resources/field-type-resource.js.map +1 -1
  88. package/dist/resources/file-resource.d.ts +5 -9
  89. package/dist/resources/file-resource.js +6 -11
  90. package/dist/resources/file-resource.js.map +1 -1
  91. package/dist/resources/folder-resource.d.ts +29 -32
  92. package/dist/resources/folder-resource.js +59 -78
  93. package/dist/resources/folder-resource.js.map +1 -1
  94. package/dist/resources/graph-model-resource.d.ts +4 -1
  95. package/dist/resources/graph-model-resource.js +11 -4
  96. package/dist/resources/graph-model-resource.js.map +1 -1
  97. package/dist/resources/graph-view-resource.d.ts +5 -2
  98. package/dist/resources/graph-view-resource.js +7 -3
  99. package/dist/resources/graph-view-resource.js.map +1 -1
  100. package/dist/resources/link-type-resource.d.ts +5 -2
  101. package/dist/resources/link-type-resource.js +5 -2
  102. package/dist/resources/link-type-resource.js.map +1 -1
  103. package/dist/resources/report-resource.d.ts +6 -7
  104. package/dist/resources/report-resource.js +14 -23
  105. package/dist/resources/report-resource.js.map +1 -1
  106. package/dist/resources/resource-object.d.ts +93 -8
  107. package/dist/resources/resource-object.js +162 -110
  108. package/dist/resources/resource-object.js.map +1 -1
  109. package/dist/resources/template-resource.d.ts +7 -3
  110. package/dist/resources/template-resource.js +10 -3
  111. package/dist/resources/template-resource.js.map +1 -1
  112. package/dist/resources/workflow-resource.d.ts +5 -2
  113. package/dist/resources/workflow-resource.js +18 -22
  114. package/dist/resources/workflow-resource.js.map +1 -1
  115. package/dist/utils/card-utils.d.ts +2 -2
  116. package/dist/utils/card-utils.js +1 -1
  117. package/dist/utils/clingo-fact-builder.d.ts +25 -14
  118. package/dist/utils/clingo-fact-builder.js +27 -5
  119. package/dist/utils/clingo-fact-builder.js.map +1 -1
  120. package/dist/utils/clingo-facts.js +3 -4
  121. package/dist/utils/clingo-facts.js.map +1 -1
  122. package/dist/utils/resource-utils.d.ts +1 -0
  123. package/dist/utils/resource-utils.js +2 -1
  124. package/dist/utils/resource-utils.js.map +1 -1
  125. package/package.json +8 -8
  126. package/src/card-metadata-updater.ts +6 -2
  127. package/src/command-handler.ts +24 -5
  128. package/src/command-manager.ts +29 -17
  129. package/src/commands/create.ts +43 -78
  130. package/src/commands/export.ts +63 -52
  131. package/src/commands/import.ts +24 -14
  132. package/src/commands/move.ts +0 -1
  133. package/src/commands/remove.ts +11 -7
  134. package/src/commands/rename.ts +43 -149
  135. package/src/commands/show.ts +113 -78
  136. package/src/commands/transition.ts +26 -28
  137. package/src/commands/update.ts +25 -22
  138. package/src/commands/validate.ts +108 -67
  139. package/src/containers/project/calculation-engine.ts +61 -93
  140. package/src/containers/project/project-paths.ts +21 -13
  141. package/src/containers/project/resource-cache.ts +648 -0
  142. package/src/containers/project/resource-handler.ts +265 -0
  143. package/src/containers/project.ts +178 -522
  144. package/src/containers/template.ts +24 -19
  145. package/src/interfaces/folder-content-interfaces.ts +7 -6
  146. package/src/interfaces/project-interfaces.ts +7 -6
  147. package/src/interfaces/resource-interfaces.ts +18 -3
  148. package/src/macros/graph/index.ts +26 -47
  149. package/src/macros/index.ts +2 -2
  150. package/src/macros/report/index.ts +3 -9
  151. package/src/module-manager.ts +74 -17
  152. package/src/project-settings.ts +83 -14
  153. package/src/resources/calculation-resource.ts +18 -18
  154. package/src/resources/card-type-resource.ts +50 -50
  155. package/src/resources/create-defaults.ts +3 -2
  156. package/src/resources/field-type-resource.ts +41 -55
  157. package/src/resources/file-resource.ts +10 -36
  158. package/src/resources/folder-resource.ts +69 -120
  159. package/src/resources/graph-model-resource.ts +20 -22
  160. package/src/resources/graph-view-resource.ts +15 -17
  161. package/src/resources/link-type-resource.ts +10 -13
  162. package/src/resources/report-resource.ts +21 -43
  163. package/src/resources/resource-object.ts +194 -152
  164. package/src/resources/template-resource.ts +17 -16
  165. package/src/resources/workflow-resource.ts +25 -44
  166. package/src/utils/card-utils.ts +2 -2
  167. package/src/utils/clingo-fact-builder.ts +28 -16
  168. package/src/utils/clingo-facts.ts +3 -4
  169. package/src/utils/resource-utils.ts +2 -1
  170. package/dist/containers/project/resource-collector.d.ts +0 -110
  171. package/dist/containers/project/resource-collector.js +0 -344
  172. package/dist/containers/project/resource-collector.js.map +0 -1
  173. package/src/containers/project/resource-collector.ts +0 -404
@@ -13,8 +13,9 @@
13
13
  */
14
14
  // node
15
15
  import { basename, join, resolve } from 'node:path';
16
- import { constants as fsConstants, copyFile, mkdir, readdir, unlink, writeFile, } from 'node:fs/promises';
17
- import { CardContainer } from './card-container.js'; // base class
16
+ import { constants as fsConstants, copyFile, mkdir, unlink, writeFile, } from 'node:fs/promises';
17
+ // base class
18
+ import { CardContainer } from './card-container.js';
18
19
  import { CalculationEngine } from './project/calculation-engine.js';
19
20
  import { CardLocation, } from '../interfaces/project-interfaces.js';
20
21
  import { pathExists } from '../utils/file-utils.js';
@@ -23,18 +24,9 @@ import { cardPathParts, isModulePath, isTemplateCard, } from '../utils/card-util
23
24
  import { ProjectConfiguration } from '../project-settings.js';
24
25
  import { ProjectPaths } from './project/project-paths.js';
25
26
  import { readJsonFile } from '../utils/json.js';
26
- import { pathToResourceName, resourceName, resourceNameToString, } from '../utils/resource-utils.js';
27
- import { ResourcesFrom, ResourceCollector, } from './project/resource-collector.js';
27
+ import { ResourcesFrom } from './project/resource-cache.js';
28
+ import { ResourceHandler } from './project/resource-handler.js';
28
29
  import { Validate } from '../commands/validate.js';
29
- import { CalculationResource } from '../resources/calculation-resource.js';
30
- import { CardTypeResource } from '../resources/card-type-resource.js';
31
- import { FieldTypeResource } from '../resources/field-type-resource.js';
32
- import { GraphModelResource } from '../resources/graph-model-resource.js';
33
- import { GraphViewResource } from '../resources/graph-view-resource.js';
34
- import { LinkTypeResource } from '../resources/link-type-resource.js';
35
- import { ReportResource } from '../resources/report-resource.js';
36
- import { TemplateResource } from '../resources/template-resource.js';
37
- import { WorkflowResource } from '../resources/workflow-resource.js';
38
30
  import { ContentWatcher } from './project/project-content-watcher.js';
39
31
  import { getChildLogger } from '../utils/log-utils.js';
40
32
  import { ROOT } from '../utils/constants.js';
@@ -44,52 +36,38 @@ export { ResourcesFrom };
44
36
  * Represents project folder.
45
37
  */
46
38
  export class Project extends CardContainer {
47
- watchResourceChanges;
39
+ options;
48
40
  calculationEngine;
49
- // Created resources are held in a cache.
50
- // In the cache, key is resource name, and data is resource metadata (as JSON).
51
- createdResources = new Map();
52
41
  logger = getChildLogger({ module: 'Project' });
53
42
  projectPaths;
54
- resources;
43
+ resourceHandler;
55
44
  resourceWatcher;
56
45
  settings;
57
46
  validator;
58
- constructor(path, watchResourceChanges) {
59
- const settings = new ProjectConfiguration(join(path, '.cards', 'local', Project.projectConfigFileName));
47
+ constructor(path, options = {
48
+ autoSave: true,
49
+ watchResourceChanges: false,
50
+ }) {
51
+ const settings = new ProjectConfiguration(join(path, '.cards', 'local', Project.projectConfigFileName), options.autoSave ?? true);
60
52
  super(path, settings.cardKeyPrefix, '');
61
- this.watchResourceChanges = watchResourceChanges;
53
+ this.options = options;
62
54
  this.settings = settings;
63
55
  this.logger.info({ path }, 'Initializing project');
64
56
  this.calculationEngine = new CalculationEngine(this);
65
57
  this.projectPaths = new ProjectPaths(path);
66
- this.resources = new ResourceCollector(this);
58
+ this.resourceHandler = new ResourceHandler(this);
67
59
  this.containerName = this.settings.name;
68
60
  // todo: implement project validation
69
61
  this.validator = Validate.getInstance();
70
- this.logger.info({ resourcesFolder: this.paths.resourcesFolder }, 'Collecting local resources');
71
- this.resources.collectLocalResources();
72
62
  this.logger.info({ name: this.containerName }, 'Project initialization complete');
73
63
  const ignoreRenameFileChanges = true;
74
64
  // Watch changes in .cards if there are multiple instances of Project being
75
65
  // run concurrently.
76
- if (this.watchResourceChanges) {
66
+ if (this.options.watchResourceChanges) {
77
67
  this.resourceWatcher = new ContentWatcher(ignoreRenameFileChanges, this.paths.resourcesFolder, (fileName) => {
78
68
  void (async () => {
79
- let resource;
80
- try {
81
- resource = pathToResourceName(this, join(this.paths.resourcesFolder, fileName));
82
- if (!resource) {
83
- return;
84
- }
85
- }
86
- catch {
87
- // it wasn't a resource that changed, so ignore the change
88
- return;
89
- }
90
- const resourceName = `${resource.prefix}/${resource.type}/${resource.identifier}`;
91
- await this.replaceCacheValue(resourceName);
92
- this.resources.collectLocalResources();
69
+ this.resources.handleFileSystemChange(join(this.paths.resourcesFolder, fileName));
70
+ this.resources.changed();
93
71
  })();
94
72
  });
95
73
  }
@@ -106,7 +84,19 @@ export class Project extends CardContainer {
106
84
  }
107
85
  // Finds specific module.
108
86
  async findModule(moduleName) {
109
- return (await this.resources.resources('modules')).find((item) => item.name === moduleName && item.path);
87
+ const moduleExists = this.resources.moduleNames().includes(moduleName);
88
+ if (!moduleExists) {
89
+ return undefined;
90
+ }
91
+ // For modules, we need to construct the local path where the module is stored
92
+ const moduleConfig = this.configuration.modules?.find((module) => module.name === moduleName);
93
+ if (!moduleConfig) {
94
+ return undefined;
95
+ }
96
+ return {
97
+ name: moduleName,
98
+ path: join(this.paths.modulesFolder, moduleConfig.name),
99
+ };
110
100
  }
111
101
  // Handles attachment changes after filesystem operations.
112
102
  async handleAttachmentChange(cardKey, operation, fileName) {
@@ -124,6 +114,7 @@ export class Project extends CardContainer {
124
114
  }
125
115
  }
126
116
  // Determines the parent card key from a card's filesystem path.
117
+ // todo: could be moved to card-utils
127
118
  parentFromPath(cardPath) {
128
119
  return cardPathParts(this.projectPrefix, cardPath).parents.at(-1) || 'root';
129
120
  }
@@ -135,23 +126,6 @@ export class Project extends CardContainer {
135
126
  this.cardCache.updateCard(parentCard.key, parentCard);
136
127
  }
137
128
  }
138
- // Removes current version of a resource from the resource cache.
139
- // Then re-creates the resource with current data and caches the value again.
140
- // If the value wasn't in the cache before, it will be added.
141
- async replaceCacheValue(resourceName) {
142
- if (this.createdResources.has(resourceName)) {
143
- // First, remove the old version from cache
144
- this.createdResources.delete(resourceName);
145
- }
146
- const resourceData = await this.resource(resourceName);
147
- if (resourceData) {
148
- this.createdResources.set(resourceName, resourceData);
149
- }
150
- }
151
- // Returns (local or all) resources of a given type.
152
- async resourcesOfType(type, from = ResourcesFrom.localOnly) {
153
- return this.resources.resources(type, from);
154
- }
155
129
  // Updates children in the card cache
156
130
  updateCachedChildren(parentKey, newChild) {
157
131
  const parentCard = this.cardCache.getCard(parentKey);
@@ -164,24 +138,44 @@ export class Project extends CardContainer {
164
138
  this.cardCache.updateCard(parentCard.key, parentCard);
165
139
  }
166
140
  }
141
+ // Validates that card's data is valid.
142
+ async validateCard(card) {
143
+ const invalidCustomData = await this.validator.validateCustomFields(this, card, this.projectPrefixes());
144
+ const invalidWorkFlow = await this.validator.validateWorkflowState(this, card);
145
+ const invalidLabels = this.validator.validateCardLabels(card);
146
+ if (invalidCustomData.length === 0 &&
147
+ invalidWorkFlow.length === 0 &&
148
+ invalidLabels.length === 0) {
149
+ return '';
150
+ }
151
+ const errors = [];
152
+ if (invalidCustomData.length > 0) {
153
+ errors.push(invalidCustomData);
154
+ }
155
+ if (invalidWorkFlow.length > 0) {
156
+ errors.push(invalidWorkFlow);
157
+ }
158
+ if (invalidLabels.length > 0) {
159
+ errors.push(invalidLabels);
160
+ }
161
+ return errors.join('\n');
162
+ }
167
163
  /**
168
164
  * Populate template cards into the card cache.
169
165
  */
170
166
  async populateTemplateCards() {
171
167
  try {
172
- // Gets local & module templates
173
- const templateResources = await this.templates();
174
- const prefixes = await this.projectPrefixes();
168
+ const templateResources = this.resources.templates();
169
+ const prefixes = this.projectPrefixes();
175
170
  const loadPromises = templateResources.map(async (template) => {
176
171
  try {
177
- this.validator.validResourceName('templates', template.name, prefixes);
172
+ this.validator.validResourceName('templates', template.data?.name || '', prefixes);
178
173
  }
179
174
  catch (error) {
180
- this.logger.warn({ templateName: template.name, error }, `Template name '${template.name}' does not follow required format, skipping`);
175
+ this.logger.warn({ templateName: template, error }, `Template name '${template}' does not follow required format, skipping`);
181
176
  return;
182
177
  }
183
- const templateResource = new TemplateResource(this, resourceName(template.name));
184
- const templateObject = templateResource.templateObject();
178
+ const templateObject = template.templateObject();
185
179
  const isCreated = templateObject && templateObject.isCreated();
186
180
  if (!templateObject || !isCreated) {
187
181
  return;
@@ -203,15 +197,6 @@ export class Project extends CardContainer {
203
197
  await this.cardCache.populateFromPath(this.paths.cardRootFolder);
204
198
  await this.populateTemplateCards();
205
199
  }
206
- /**
207
- * Add a given 'resource' to the local resource arrays.
208
- * @param resource Resource to add.
209
- * @param data JSON data for the resource.
210
- */
211
- addResource(resource, data) {
212
- this.resources.add(resource);
213
- this.createdResources.set(resource.name, data);
214
- }
215
200
  /**
216
201
  * Returns all template cards from the project. This includes all module templates' cards.
217
202
  * @returns all the template cards from the project
@@ -235,30 +220,6 @@ export class Project extends CardContainer {
235
220
  attachmentsByPath(path) {
236
221
  return super.attachments(path);
237
222
  }
238
- /**
239
- * Returns all the attachments in the template cards.
240
- * @returns all the attachments in the template cards.
241
- */
242
- async attachmentsFromTemplates() {
243
- const templateAttachments = [];
244
- const templates = await this.templates();
245
- for (const template of templates) {
246
- const templateResource = new TemplateResource(this, resourceName(template.name));
247
- const templateObject = templateResource.templateObject();
248
- if (templateObject) {
249
- templateAttachments.push(...templateObject.attachments());
250
- }
251
- }
252
- return templateAttachments;
253
- }
254
- /**
255
- * Returns an array of all the calculation files (*.lp) in the project.
256
- * @param from Defines where resources are collected from.
257
- * @returns array of all calculation files in the project.
258
- */
259
- async calculations(from = ResourcesFrom.all) {
260
- return this.resources.resources('calculations', from);
261
- }
262
223
  /**
263
224
  * Returns path to a card's attachment folder.
264
225
  * @param cardKey card key
@@ -298,28 +259,6 @@ export class Project extends CardContainer {
298
259
  // Update cache
299
260
  await this.handleAttachmentChange(cardKey, 'added', basename(attachmentName));
300
261
  }
301
- /**
302
- * Removes an attachment from a card.
303
- * @param cardKey The card to remove attachment from
304
- * @param fileName The name of the attachment file to remove
305
- * @throws if trying to remove module card attachment, or the attachment was not found.
306
- */
307
- async removeCardAttachment(cardKey, fileName) {
308
- const attachmentFolder = this.cardAttachmentFolder(cardKey);
309
- // Modules cannot be modified.
310
- if (isModulePath(attachmentFolder)) {
311
- throw new Error(`Cannot modify imported module`);
312
- }
313
- const attachmentPath = join(attachmentFolder, fileName);
314
- try {
315
- await unlink(attachmentPath);
316
- }
317
- catch (error) {
318
- this.logger.error({ error }, 'Removing card attachment');
319
- throw new Error(`Attachment not found: ${fileName}`);
320
- }
321
- await this.handleAttachmentChange(cardKey, 'removed', fileName);
322
- }
323
262
  /**
324
263
  * Returns path to a card's folder.
325
264
  * @param cardKey card key
@@ -330,9 +269,9 @@ export class Project extends CardContainer {
330
269
  if (found) {
331
270
  return found.path;
332
271
  }
333
- const templates = await this.templates();
272
+ const templates = this.resources.templates();
334
273
  const templatePromises = templates.map((template) => {
335
- const templateObject = new TemplateResource(this, resourceName(template.name)).templateObject();
274
+ const templateObject = template.templateObject();
336
275
  const templateCard = templateObject
337
276
  ? templateObject.findCard(cardKey)
338
277
  : undefined;
@@ -357,14 +296,6 @@ export class Project extends CardContainer {
357
296
  }
358
297
  return cards;
359
298
  }
360
- /**
361
- * Accessor for cards cache.
362
- * Used by template container (it needs to access project's cache, not their own instance).
363
- * @note Should not be used directly (other than Template).
364
- */
365
- get cardsCache() {
366
- return this.cardCache;
367
- }
368
299
  /**
369
300
  * Returns an array of all the cards in the project.
370
301
  * @note These are project cards only, by default (unless path dictates otherwise).
@@ -376,12 +307,12 @@ export class Project extends CardContainer {
376
307
  return super.cards(path, details);
377
308
  }
378
309
  /**
379
- * Returns an array of all the card types in the project.
380
- * @param from Defines where resources are collected from.
381
- * @returns array of all card types in the project.
310
+ * Accessor for cards cache.
311
+ * Used by template container (it needs to access project's cache, not their own instance).
312
+ * @note Should not be used directly (other than Template).
382
313
  */
383
- async cardTypes(from = ResourcesFrom.all) {
384
- return this.resources.resources('cardTypes', from);
314
+ get cardsCache() {
315
+ return this.cardCache;
385
316
  }
386
317
  /**
387
318
  * Returns children of a given card; as Card array
@@ -398,18 +329,6 @@ export class Project extends CardContainer {
398
329
  }
399
330
  return cards;
400
331
  }
401
- /**
402
- * Updates all local resources.
403
- */
404
- collectLocalResources() {
405
- this.resources.changed();
406
- }
407
- /**
408
- * Updates all imported module resources.
409
- */
410
- collectModuleResources() {
411
- this.resources.moduleImported();
412
- }
413
332
  /**
414
333
  * Returns project configuration.
415
334
  * @returns project configuration.
@@ -427,7 +346,8 @@ export class Project extends CardContainer {
427
346
  return undefined;
428
347
  }
429
348
  const { template } = cardPathParts(this.projectPrefix, card.path);
430
- return new TemplateResource(this, resourceName(template)).templateObject();
349
+ const templateResource = this.resources.byType(template, 'templates');
350
+ return templateResource.templateObject();
431
351
  }
432
352
  /**
433
353
  * Cleanups project when it is being closed.
@@ -439,12 +359,13 @@ export class Project extends CardContainer {
439
359
  }
440
360
  }
441
361
  /**
442
- * Returns an array of all the field types in the project.
443
- * @param from Defines where resources are collected from.
444
- * @returns array of all field types in the project.
362
+ * Returns specific card.
363
+ * @param cardToFind Card key to find
364
+ * @param details Defines which card details are included in the return values.
365
+ * @returns specific card details, or undefined if card is not part of the project.
445
366
  */
446
- async fieldTypes(from = ResourcesFrom.all) {
447
- return this.resources.resources('fieldTypes', from);
367
+ findCard(cardToFind, details) {
368
+ return super.findCard(cardToFind, details);
448
369
  }
449
370
  /**
450
371
  * Finds root of a project
@@ -462,31 +383,6 @@ export class Project extends CardContainer {
462
383
  }
463
384
  return Project.findProjectRoot(parentPath);
464
385
  }
465
- /**
466
- * Returns specific card.
467
- * @param cardToFind Card key to find
468
- * @param details Defines which card details are included in the return values.
469
- * @returns specific card details, or undefined if card is not part of the project.
470
- */
471
- findCard(cardToFind, details) {
472
- return super.findCard(cardToFind, details);
473
- }
474
- /**
475
- * Returns an array of all the graph models in the project.
476
- * @param from Defines where resources are collected from.
477
- * @returns array of all the graph models in the project.
478
- */
479
- async graphModels(from = ResourcesFrom.all) {
480
- return this.resources.resources('graphModels', from);
481
- }
482
- /**
483
- * Returns an array of all the graph views in the project.
484
- * @param from Defines where resources are collected from.
485
- * @returns array of all the graph views in the project.
486
- */
487
- async graphViews(from = ResourcesFrom.all) {
488
- return this.resources.resources('graphViews', from);
489
- }
490
386
  /**
491
387
  * When card changes.
492
388
  * @param changedCard Card that was changed.
@@ -561,7 +457,7 @@ export class Project extends CardContainer {
561
457
  async importModule(module) {
562
458
  // Add module as a dependency.
563
459
  await this.configuration.addModule(module);
564
- this.collectModuleResources();
460
+ this.resources.changedModules();
565
461
  await this.populateTemplateCards();
566
462
  this.logger.info(`Imported module '${module.name}'`);
567
463
  }
@@ -573,14 +469,6 @@ export class Project extends CardContainer {
573
469
  static isCreated(path) {
574
470
  return pathExists(join(path, 'cardRoot'));
575
471
  }
576
- /**
577
- * Returns an array of all the link types in the project.
578
- * @param from Defines where resources are collected from.
579
- * @returns array of all link types in the project.
580
- */
581
- async linkTypes(from = ResourcesFrom.all) {
582
- return this.resources.resources('linkTypes', from);
583
- }
584
472
  /**
585
473
  * Returns an array of cards in the project, in the templates or both.
586
474
  * Cards don't have content and nor metadata.
@@ -602,15 +490,15 @@ export class Project extends CardContainer {
602
490
  }
603
491
  if (cardsFrom === CardLocation.all ||
604
492
  cardsFrom === CardLocation.templatesOnly) {
605
- const templates = await this.templates();
493
+ const templates = this.resources.templates();
606
494
  for (const template of templates) {
607
- const templateObject = new TemplateResource(this, resourceName(template.name)).templateObject();
495
+ const templateObject = template.templateObject();
608
496
  if (templateObject) {
609
497
  // todo: optimization - do all this in parallel
610
498
  const templateCards = templateObject.listCards();
611
499
  if (templateCards.length) {
612
500
  cardListContainer.push({
613
- name: template.name,
501
+ name: template.data?.name || '',
614
502
  type: 'template',
615
503
  cards: templateCards.map((item) => item.key),
616
504
  });
@@ -643,7 +531,7 @@ export class Project extends CardContainer {
643
531
  async module(moduleName) {
644
532
  const module = await this.findModule(moduleName);
645
533
  if (module && module.path) {
646
- const modulePath = join(module.path, module.name);
534
+ const modulePath = module.path;
647
535
  const moduleConfig = await readJsonFile(join(modulePath, Project.projectConfigFileName));
648
536
  return {
649
537
  name: moduleConfig.name,
@@ -651,44 +539,19 @@ export class Project extends CardContainer {
651
539
  hubs: moduleConfig.hubs,
652
540
  path: modulePath,
653
541
  cardKeyPrefix: moduleConfig.cardKeyPrefix,
654
- calculations: [
655
- ...(await this.resources.collectResourcesFromModules('calculations', moduleName)),
656
- ],
657
- cardTypes: [
658
- ...(await this.resources.collectResourcesFromModules('cardTypes', moduleName)),
659
- ],
660
- fieldTypes: [
661
- ...(await this.resources.collectResourcesFromModules('fieldTypes', moduleName)),
662
- ],
663
- graphModels: [
664
- ...(await this.resources.collectResourcesFromModules('graphModels', moduleName)),
665
- ],
666
- graphViews: [
667
- ...(await this.resources.collectResourcesFromModules('graphViews', moduleName)),
668
- ],
669
- linkTypes: [
670
- ...(await this.resources.collectResourcesFromModules('linkTypes', moduleName)),
671
- ],
672
- reports: [
673
- ...(await this.resources.collectResourcesFromModules('reports', moduleName)),
674
- ],
675
- templates: [
676
- ...(await this.resources.collectResourcesFromModules('templates', moduleName)),
677
- ],
678
- workflows: [
679
- ...(await this.resources.collectResourcesFromModules('workflows', moduleName)),
680
- ],
542
+ calculations: this.resources.moduleResourceNames('calculations', moduleName),
543
+ cardTypes: this.resources.moduleResourceNames('cardTypes', moduleName),
544
+ fieldTypes: this.resources.moduleResourceNames('fieldTypes', moduleName),
545
+ graphModels: this.resources.moduleResourceNames('graphModels', moduleName),
546
+ graphViews: this.resources.moduleResourceNames('graphViews', moduleName),
547
+ linkTypes: this.resources.moduleResourceNames('linkTypes', moduleName),
548
+ reports: this.resources.moduleResourceNames('reports', moduleName),
549
+ templates: this.resources.moduleResourceNames('templates', moduleName),
550
+ workflows: this.resources.moduleResourceNames('workflows', moduleName),
681
551
  };
682
552
  }
683
553
  return undefined;
684
554
  }
685
- /**
686
- * Returns list of modules in the project.
687
- * @returns list of modules in the project.
688
- */
689
- async modules() {
690
- return this.resources.resources('modules');
691
- }
692
555
  /**
693
556
  * Returns a new unique card key with project prefix (e.g. test_x649it4x).
694
557
  * Random part of string will be always 8 characters in base-36 (0-9a-z)
@@ -759,6 +622,10 @@ export class Project extends CardContainer {
759
622
  */
760
623
  async populateCaches() {
761
624
  if (!this.cardCache.isPopulated) {
625
+ // Only collect modules that are registered in the project configuration
626
+ if (this.configuration.modules && this.configuration.modules.length > 0) {
627
+ this.resources.changedModules();
628
+ }
762
629
  await this.populateCardsCache();
763
630
  }
764
631
  }
@@ -775,165 +642,60 @@ export class Project extends CardContainer {
775
642
  return this.settings.cardKeyPrefix;
776
643
  }
777
644
  /**
778
- * Collects all prefixes used in the project (project's own plus all from modules).
645
+ * Returns all prefixes used in the project (project's own plus all from imported modules).
779
646
  * @returns all prefixes used in the project.
780
- * @todo - move the module prefix fetch to resource-collector.
781
- * Make it use cached value that is only changed when module is removed/imported.
782
647
  */
783
- async projectPrefixes() {
648
+ projectPrefixes() {
784
649
  const prefixes = [this.projectPrefix];
785
- let files;
786
- try {
787
- // TODO: Could be optimized so that prefixes are stored once fetched.
788
- files = await readdir(this.paths.modulesFolder, {
789
- withFileTypes: true,
790
- recursive: true,
791
- });
792
- const configurationFiles = files
793
- .filter((dirent) => dirent.isFile())
794
- .filter((dirent) => dirent.name === Project.projectConfigFileName);
795
- const configurationPromises = configurationFiles.map(async (file) => {
796
- const configuration = (await readJsonFile(join(file.parentPath, file.name)));
797
- return configuration.cardKeyPrefix;
798
- });
799
- const configurationPrefixes = await Promise.all(configurationPromises);
800
- prefixes.push(...configurationPrefixes);
801
- }
802
- catch (error) {
803
- this.logger.error({ error }, 'Failed to collect prefixes in use');
804
- }
650
+ const moduleNames = this.configuration.modules.map((item) => item.name);
651
+ prefixes.push(...moduleNames);
805
652
  return prefixes;
806
653
  }
807
654
  /**
808
- * Removes a module from the project
809
- * @param module Module (name) to remove.
810
- */
811
- async removeModule(moduleName) {
812
- const toBeRemovedTemplates = this.resources.moduleResources.resourceArray('templates', moduleName);
813
- // First, remove cards from the cache
814
- for (const template of toBeRemovedTemplates) {
815
- this.cardCache.deleteCardsFromTemplate(template.name);
816
- }
817
- // Then, remove module from project configuration
818
- await this.configuration.removeModule(moduleName);
819
- this.collectModuleResources();
820
- this.logger.info(`Removed module '${moduleName}'`);
821
- }
822
- /**
823
- * Removes a resource from Project.
824
- * @param resource Resource to remove.
825
- */
826
- removeResource(resource) {
827
- // Template cards must be removed from the cache when resource is removed.
828
- if (resource.path.includes('templates')) {
829
- const templateName = resourceNameToString(resourceName(resource.name));
830
- this.cardCache.deleteCardsFromTemplate(templateName);
831
- }
832
- this.resources.remove(resource);
833
- this.createdResources.delete(resource.name);
834
- }
835
- /**
836
- * Array of reports in the project.
837
- * @param from Defines where resources are collected from.
838
- * @returns array of all reports in the project.
839
- */
840
- async reports(from = ResourcesFrom.all) {
841
- return this.resources.resources('reports', from);
842
- }
843
- /**
844
- * Returns handlebar files from reports.
845
- * @param from Defines where report handlebar files are collected from.
846
- * @returns handlebar files from reports.
847
- */
848
- async reportHandlerBarFiles(from = ResourcesFrom.all) {
849
- const reports = await this.reports(from);
850
- const handleBarFiles = [];
851
- for (const reportResourceName of reports) {
852
- const name = resourceName(reportResourceName.name);
853
- const report = new ReportResource(this, name);
854
- handleBarFiles.push(...(await report.handleBarFiles()));
855
- }
856
- return handleBarFiles;
857
- }
858
- /**
859
- * Returns metadata from a given resource
860
- * @param name Name of a resource
861
- * @returns Metadata from the resource.
655
+ * Removes an attachment from a card.
656
+ * @param cardKey The card to remove attachment from
657
+ * @param fileName The name of the attachment file to remove
658
+ * @throws if trying to remove module card attachment, or the attachment was not found.
862
659
  */
863
- resource(name) {
864
- const resName = resourceName(name);
865
- if (this.createdResources.has(resourceNameToString(resName))) {
866
- const value = this.createdResources.get(resourceNameToString(resName));
867
- return value;
660
+ async removeCardAttachment(cardKey, fileName) {
661
+ const attachmentFolder = this.cardAttachmentFolder(cardKey);
662
+ // Modules cannot be modified.
663
+ if (isModulePath(attachmentFolder)) {
664
+ throw new Error(`Cannot modify imported module`);
868
665
  }
869
- let resource = undefined;
666
+ const attachmentPath = join(attachmentFolder, fileName);
870
667
  try {
871
- resource = Project.resourceObject(this, resName);
872
- }
873
- catch {
874
- return undefined;
668
+ await unlink(attachmentPath);
875
669
  }
876
- const data = resource?.data;
877
- if (!data) {
878
- return undefined;
670
+ catch (error) {
671
+ this.logger.error({ error }, 'Removing card attachment');
672
+ throw new Error(`Attachment not found: ${fileName}`);
879
673
  }
880
- return data;
881
- }
882
- /**
883
- * Returns resource cache.
884
- */
885
- get resourceCache() {
886
- return this.createdResources;
674
+ await this.handleAttachmentChange(cardKey, 'removed', fileName);
887
675
  }
888
676
  /**
889
- * Checks if a given resource exists in the project already.
890
- * @param resourceType Type of resource as a string.
891
- * @param name Valid name of resource.
892
- * @returns boolean, true if resource exists; false otherwise.
677
+ * Removes a module from the project cache and configuration.
678
+ * @note that ModuleManager removes the actual files.
679
+ * @param moduleName Module name to remove.
893
680
  */
894
- async resourceExists(resourceType, name) {
895
- const resources = await this.resourcesOfType(resourceType, ResourcesFrom.all);
896
- const resource = resources.find((item) => item.name === name);
897
- return resource !== undefined;
681
+ async removeModule(moduleName) {
682
+ const toBeRemovedTemplates = this.resources.moduleResourceNames('templates', moduleName);
683
+ // First, remove template cards from the cache that are part of removed templates.
684
+ for (const templateName of toBeRemovedTemplates) {
685
+ this.cardCache.deleteCardsFromTemplate(templateName);
686
+ }
687
+ // Then, remove all module resources from cache
688
+ this.resources.removeModule(moduleName);
689
+ // Finally, remove module from project configuration
690
+ await this.configuration.removeModule(moduleName);
691
+ this.logger.info(`Removed module '${moduleName}'`);
898
692
  }
899
693
  /**
900
- * Instantiates resource object from project with a resource name.
901
- * @note that this is memory based object only.
902
- * To manipulate the resource (create files, delete files etc), use the resource object's API.
903
- * @param project Project from which resources are created from.
904
- * @param name Resource name
905
- * @throws if called with unsupported resource type.
906
- * @returns Created resource.
694
+ * Accessor for resource handler.
695
+ * @returns Resource handler instance.
907
696
  */
908
- static resourceObject(project, name) {
909
- if (name.type === 'calculations') {
910
- return new CalculationResource(project, name);
911
- }
912
- else if (name.type === 'cardTypes') {
913
- return new CardTypeResource(project, name);
914
- }
915
- else if (name.type === 'fieldTypes') {
916
- return new FieldTypeResource(project, name);
917
- }
918
- else if (name.type === 'graphModels') {
919
- return new GraphModelResource(project, name);
920
- }
921
- else if (name.type === 'graphViews') {
922
- return new GraphViewResource(project, name);
923
- }
924
- else if (name.type === 'linkTypes') {
925
- return new LinkTypeResource(project, name);
926
- }
927
- else if (name.type === 'reports') {
928
- return new ReportResource(project, name);
929
- }
930
- else if (name.type === 'templates') {
931
- return new TemplateResource(project, name);
932
- }
933
- else if (name.type === 'workflows') {
934
- return new WorkflowResource(project, name);
935
- }
936
- throw new Error(`Unsupported resource type '${resourceNameToString(name)}'`);
697
+ get resources() {
698
+ return this.resourceHandler;
937
699
  }
938
700
  /**
939
701
  * Shows details of a project.
@@ -945,7 +707,7 @@ export class Project extends CardContainer {
945
707
  path: this.basePath,
946
708
  prefix: this.projectPrefix,
947
709
  hubs: this.configuration.hubs,
948
- modules: (await this.modules()).map((item) => item.name),
710
+ modules: this.resources.moduleNames(),
949
711
  numberOfCards: (await this.listCards(CardLocation.projectOnly))[0].cards
950
712
  .length,
951
713
  };
@@ -971,14 +733,6 @@ export class Project extends CardContainer {
971
733
  return cachedCard.location === templateName;
972
734
  });
973
735
  }
974
- /**
975
- * Array of templates in the project.
976
- * @param from Defines where resources are collected from.
977
- * @returns array of all templates in the project.
978
- */
979
- async templates(from = ResourcesFrom.all) {
980
- return this.resources.resources('templates', from);
981
- }
982
736
  /**
983
737
  * Update a card's content.
984
738
  * @param cardKey card key to update.
@@ -1063,35 +817,5 @@ export class Project extends CardContainer {
1063
817
  await this.handleCardChanged(card);
1064
818
  }
1065
819
  }
1066
- // Validates that card's data is valid.
1067
- async validateCard(card) {
1068
- const invalidCustomData = await this.validator.validateCustomFields(this, card);
1069
- const invalidWorkFlow = this.validator.validateWorkflowState(this, card);
1070
- const invalidLabels = this.validator.validateCardLabels(card);
1071
- if (invalidCustomData.length === 0 &&
1072
- invalidWorkFlow.length === 0 &&
1073
- invalidLabels.length === 0) {
1074
- return '';
1075
- }
1076
- const errors = [];
1077
- if (invalidCustomData.length > 0) {
1078
- errors.push(invalidCustomData);
1079
- }
1080
- if (invalidWorkFlow.length > 0) {
1081
- errors.push(invalidWorkFlow);
1082
- }
1083
- if (invalidLabels.length > 0) {
1084
- errors.push(invalidLabels);
1085
- }
1086
- return errors.join('\n');
1087
- }
1088
- /**
1089
- * Array of workflows in the project.
1090
- * @param from Defines where resources are collected from.
1091
- * @returns array of all workflows in the project.
1092
- */
1093
- async workflows(from = ResourcesFrom.all) {
1094
- return this.resources.resources('workflows', from);
1095
- }
1096
820
  }
1097
821
  //# sourceMappingURL=project.js.map