@cyberismo/data-handler 0.0.15 → 0.0.17

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 (191) 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 +22 -8
  5. package/dist/command-handler.js.map +1 -1
  6. package/dist/command-manager.d.ts +24 -1
  7. package/dist/command-manager.js +31 -7
  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/fetch.d.ts +8 -0
  16. package/dist/commands/fetch.js +101 -23
  17. package/dist/commands/fetch.js.map +1 -1
  18. package/dist/commands/import.d.ts +14 -3
  19. package/dist/commands/import.js +27 -10
  20. package/dist/commands/import.js.map +1 -1
  21. package/dist/commands/move.js +0 -1
  22. package/dist/commands/move.js.map +1 -1
  23. package/dist/commands/remove.d.ts +11 -2
  24. package/dist/commands/remove.js +15 -5
  25. package/dist/commands/remove.js.map +1 -1
  26. package/dist/commands/rename.d.ts +4 -9
  27. package/dist/commands/rename.js +37 -101
  28. package/dist/commands/rename.js.map +1 -1
  29. package/dist/commands/show.d.ts +20 -12
  30. package/dist/commands/show.js +79 -57
  31. package/dist/commands/show.js.map +1 -1
  32. package/dist/commands/transition.d.ts +9 -2
  33. package/dist/commands/transition.js +25 -17
  34. package/dist/commands/transition.js.map +1 -1
  35. package/dist/commands/update.d.ts +16 -12
  36. package/dist/commands/update.js +19 -17
  37. package/dist/commands/update.js.map +1 -1
  38. package/dist/commands/validate.d.ts +17 -9
  39. package/dist/commands/validate.js +94 -35
  40. package/dist/commands/validate.js.map +1 -1
  41. package/dist/containers/card-container.d.ts +7 -5
  42. package/dist/containers/card-container.js +30 -5
  43. package/dist/containers/card-container.js.map +1 -1
  44. package/dist/containers/project/calculation-engine.d.ts +7 -4
  45. package/dist/containers/project/calculation-engine.js +61 -66
  46. package/dist/containers/project/calculation-engine.js.map +1 -1
  47. package/dist/containers/project/project-paths.d.ts +7 -4
  48. package/dist/containers/project/project-paths.js +22 -12
  49. package/dist/containers/project/project-paths.js.map +1 -1
  50. package/dist/containers/project/resource-cache.d.ts +169 -0
  51. package/dist/containers/project/resource-cache.js +509 -0
  52. package/dist/containers/project/resource-cache.js.map +1 -0
  53. package/dist/containers/project/resource-handler.d.ts +129 -0
  54. package/dist/containers/project/resource-handler.js +206 -0
  55. package/dist/containers/project/resource-handler.js.map +1 -0
  56. package/dist/containers/project.d.ts +46 -152
  57. package/dist/containers/project.js +179 -409
  58. package/dist/containers/project.js.map +1 -1
  59. package/dist/containers/template.d.ts +8 -2
  60. package/dist/containers/template.js +24 -19
  61. package/dist/containers/template.js.map +1 -1
  62. package/dist/interfaces/command-options.d.ts +3 -1
  63. package/dist/interfaces/folder-content-interfaces.d.ts +5 -3
  64. package/dist/interfaces/folder-content-interfaces.js +3 -3
  65. package/dist/interfaces/folder-content-interfaces.js.map +1 -1
  66. package/dist/interfaces/project-interfaces.d.ts +7 -9
  67. package/dist/interfaces/project-interfaces.js.map +1 -1
  68. package/dist/interfaces/resource-interfaces.d.ts +14 -1
  69. package/dist/interfaces/resource-interfaces.js.map +1 -1
  70. package/dist/macros/graph/index.js +12 -26
  71. package/dist/macros/graph/index.js.map +1 -1
  72. package/dist/macros/index.d.ts +1 -1
  73. package/dist/macros/index.js +2 -2
  74. package/dist/macros/index.js.map +1 -1
  75. package/dist/macros/report/index.js +3 -6
  76. package/dist/macros/report/index.js.map +1 -1
  77. package/dist/module-manager.d.ts +16 -3
  78. package/dist/module-manager.js +51 -19
  79. package/dist/module-manager.js.map +1 -1
  80. package/dist/project-settings.d.ts +21 -3
  81. package/dist/project-settings.js +91 -14
  82. package/dist/project-settings.js.map +1 -1
  83. package/dist/resources/calculation-resource.d.ts +4 -3
  84. package/dist/resources/calculation-resource.js +11 -5
  85. package/dist/resources/calculation-resource.js.map +1 -1
  86. package/dist/resources/card-type-resource.d.ts +6 -1
  87. package/dist/resources/card-type-resource.js +34 -23
  88. package/dist/resources/card-type-resource.js.map +1 -1
  89. package/dist/resources/create-defaults.d.ts +3 -2
  90. package/dist/resources/create-defaults.js +3 -2
  91. package/dist/resources/create-defaults.js.map +1 -1
  92. package/dist/resources/field-type-resource.d.ts +4 -1
  93. package/dist/resources/field-type-resource.js +22 -23
  94. package/dist/resources/field-type-resource.js.map +1 -1
  95. package/dist/resources/file-resource.d.ts +5 -9
  96. package/dist/resources/file-resource.js +6 -11
  97. package/dist/resources/file-resource.js.map +1 -1
  98. package/dist/resources/folder-resource.d.ts +29 -32
  99. package/dist/resources/folder-resource.js +59 -78
  100. package/dist/resources/folder-resource.js.map +1 -1
  101. package/dist/resources/graph-model-resource.d.ts +4 -1
  102. package/dist/resources/graph-model-resource.js +11 -4
  103. package/dist/resources/graph-model-resource.js.map +1 -1
  104. package/dist/resources/graph-view-resource.d.ts +5 -2
  105. package/dist/resources/graph-view-resource.js +7 -3
  106. package/dist/resources/graph-view-resource.js.map +1 -1
  107. package/dist/resources/link-type-resource.d.ts +5 -2
  108. package/dist/resources/link-type-resource.js +5 -2
  109. package/dist/resources/link-type-resource.js.map +1 -1
  110. package/dist/resources/report-resource.d.ts +6 -7
  111. package/dist/resources/report-resource.js +14 -23
  112. package/dist/resources/report-resource.js.map +1 -1
  113. package/dist/resources/resource-object.d.ts +94 -8
  114. package/dist/resources/resource-object.js +212 -109
  115. package/dist/resources/resource-object.js.map +1 -1
  116. package/dist/resources/template-resource.d.ts +7 -3
  117. package/dist/resources/template-resource.js +10 -3
  118. package/dist/resources/template-resource.js.map +1 -1
  119. package/dist/resources/workflow-resource.d.ts +5 -2
  120. package/dist/resources/workflow-resource.js +18 -22
  121. package/dist/resources/workflow-resource.js.map +1 -1
  122. package/dist/utils/card-utils.d.ts +2 -2
  123. package/dist/utils/card-utils.js +1 -1
  124. package/dist/utils/clingo-fact-builder.d.ts +25 -14
  125. package/dist/utils/clingo-fact-builder.js +27 -5
  126. package/dist/utils/clingo-fact-builder.js.map +1 -1
  127. package/dist/utils/clingo-facts.js +3 -4
  128. package/dist/utils/clingo-facts.js.map +1 -1
  129. package/dist/utils/configuration-logger.d.ts +91 -0
  130. package/dist/utils/configuration-logger.js +151 -0
  131. package/dist/utils/configuration-logger.js.map +1 -0
  132. package/dist/utils/constants.d.ts +1 -1
  133. package/dist/utils/constants.js +5 -3
  134. package/dist/utils/constants.js.map +1 -1
  135. package/dist/utils/resource-utils.d.ts +1 -0
  136. package/dist/utils/resource-utils.js +2 -1
  137. package/dist/utils/resource-utils.js.map +1 -1
  138. package/package.json +9 -9
  139. package/src/card-metadata-updater.ts +6 -2
  140. package/src/command-handler.ts +39 -12
  141. package/src/command-manager.ts +33 -21
  142. package/src/commands/create.ts +43 -78
  143. package/src/commands/export.ts +63 -52
  144. package/src/commands/fetch.ts +143 -34
  145. package/src/commands/import.ts +37 -15
  146. package/src/commands/move.ts +0 -1
  147. package/src/commands/remove.ts +20 -7
  148. package/src/commands/rename.ts +58 -149
  149. package/src/commands/show.ts +123 -80
  150. package/src/commands/transition.ts +26 -28
  151. package/src/commands/update.ts +25 -22
  152. package/src/commands/validate.ts +104 -67
  153. package/src/containers/card-container.ts +37 -5
  154. package/src/containers/project/calculation-engine.ts +61 -93
  155. package/src/containers/project/project-paths.ts +29 -13
  156. package/src/containers/project/resource-cache.ts +651 -0
  157. package/src/containers/project/resource-handler.ts +265 -0
  158. package/src/containers/project.ts +250 -527
  159. package/src/containers/template.ts +28 -23
  160. package/src/interfaces/command-options.ts +3 -1
  161. package/src/interfaces/folder-content-interfaces.ts +7 -6
  162. package/src/interfaces/project-interfaces.ts +12 -11
  163. package/src/interfaces/resource-interfaces.ts +18 -3
  164. package/src/macros/graph/index.ts +26 -47
  165. package/src/macros/index.ts +2 -2
  166. package/src/macros/report/index.ts +3 -9
  167. package/src/module-manager.ts +74 -17
  168. package/src/project-settings.ts +96 -14
  169. package/src/resources/calculation-resource.ts +18 -18
  170. package/src/resources/card-type-resource.ts +50 -50
  171. package/src/resources/create-defaults.ts +3 -2
  172. package/src/resources/field-type-resource.ts +41 -55
  173. package/src/resources/file-resource.ts +10 -36
  174. package/src/resources/folder-resource.ts +69 -120
  175. package/src/resources/graph-model-resource.ts +20 -22
  176. package/src/resources/graph-view-resource.ts +15 -17
  177. package/src/resources/link-type-resource.ts +10 -13
  178. package/src/resources/report-resource.ts +21 -43
  179. package/src/resources/resource-object.ts +263 -149
  180. package/src/resources/template-resource.ts +17 -16
  181. package/src/resources/workflow-resource.ts +25 -44
  182. package/src/utils/card-utils.ts +2 -2
  183. package/src/utils/clingo-fact-builder.ts +28 -16
  184. package/src/utils/clingo-facts.ts +3 -4
  185. package/src/utils/configuration-logger.ts +206 -0
  186. package/src/utils/constants.ts +5 -3
  187. package/src/utils/resource-utils.ts +2 -1
  188. package/dist/containers/project/resource-collector.d.ts +0 -110
  189. package/dist/containers/project/resource-collector.js +0 -344
  190. package/dist/containers/project/resource-collector.js.map +0 -1
  191. package/src/containers/project/resource-collector.ts +0 -404
@@ -18,12 +18,13 @@ import {
18
18
  constants as fsConstants,
19
19
  copyFile,
20
20
  mkdir,
21
- readdir,
22
21
  unlink,
23
22
  writeFile,
24
23
  } from 'node:fs/promises';
24
+ import { readdirSync } from 'node:fs';
25
25
 
26
- import { CardContainer } from './card-container.js'; // base class
26
+ // base class
27
+ import { CardContainer } from './card-container.js';
27
28
 
28
29
  import { CalculationEngine } from './project/calculation-engine.js';
29
30
  import {
@@ -38,9 +39,6 @@ import {
38
39
  type ModuleSetting,
39
40
  type ProjectFetchCardDetails,
40
41
  type ProjectMetadata,
41
- type ProjectSettings,
42
- type Resource,
43
- type ResourceFolderType,
44
42
  } from '../interfaces/project-interfaces.js';
45
43
  import { pathExists } from '../utils/file-utils.js';
46
44
  import { generateRandomString } from '../utils/random.js';
@@ -52,107 +50,90 @@ import {
52
50
  import { ProjectConfiguration } from '../project-settings.js';
53
51
  import { ProjectPaths } from './project/project-paths.js';
54
52
  import { readJsonFile } from '../utils/json.js';
55
- import {
56
- pathToResourceName,
57
- resourceName,
58
- type ResourceName,
59
- resourceNameToString,
60
- } from '../utils/resource-utils.js';
61
- import {
62
- ResourcesFrom,
63
- ResourceCollector,
64
- } from './project/resource-collector.js';
65
- import type { Template } from './template.js';
53
+ import { ResourcesFrom } from './project/resource-cache.js';
54
+ import { ResourceHandler } from './project/resource-handler.js';
66
55
  import { Validate } from '../commands/validate.js';
67
-
68
- import { CalculationResource } from '../resources/calculation-resource.js';
69
- import { CardTypeResource } from '../resources/card-type-resource.js';
70
- import { FieldTypeResource } from '../resources/field-type-resource.js';
71
- import { GraphModelResource } from '../resources/graph-model-resource.js';
72
- import { GraphViewResource } from '../resources/graph-view-resource.js';
73
- import { LinkTypeResource } from '../resources/link-type-resource.js';
74
- import { ReportResource } from '../resources/report-resource.js';
75
- import { TemplateResource } from '../resources/template-resource.js';
76
- import { WorkflowResource } from '../resources/workflow-resource.js';
77
-
78
56
  import { ContentWatcher } from './project/project-content-watcher.js';
79
57
  import { getChildLogger } from '../utils/log-utils.js';
80
58
 
59
+ import type { Template } from './template.js';
60
+
81
61
  import { ROOT } from '../utils/constants.js';
82
62
 
63
+ import {
64
+ ConfigurationLogger,
65
+ ConfigurationOperation,
66
+ } from '../utils/configuration-logger.js';
67
+
83
68
  // Re-export this, so that classes that use Project do not need to have separate import.
84
69
  export { ResourcesFrom };
85
70
 
71
+ /**
72
+ * Options for Project initialization.
73
+ * autoSave - If project configuration changes are saved automatically. Default true.
74
+ * watchResourceChanges - If project refresh automatically to filesystem changes. Default false.
75
+ */
76
+ export interface ProjectOptions {
77
+ autoSave?: boolean;
78
+ watchResourceChanges?: boolean;
79
+ }
80
+
86
81
  /**
87
82
  * Represents project folder.
88
83
  */
89
84
  export class Project extends CardContainer {
90
85
  public calculationEngine: CalculationEngine;
91
- // Created resources are held in a cache.
92
- // In the cache, key is resource name, and data is resource metadata (as JSON).
93
- private createdResources = new Map<string, JSON>();
94
86
  private logger = getChildLogger({ module: 'Project' });
95
87
  private projectPaths: ProjectPaths;
96
- private resources: ResourceCollector;
88
+ private resourceHandler: ResourceHandler;
97
89
  private resourceWatcher: ContentWatcher | undefined;
98
90
  private settings: ProjectConfiguration;
99
91
  private validator: Validate;
92
+ private cachedAllModulePrefixes: string[] = [];
100
93
 
101
94
  constructor(
102
95
  path: string,
103
- private watchResourceChanges?: boolean,
96
+ private options: ProjectOptions = {
97
+ autoSave: true,
98
+ watchResourceChanges: false,
99
+ },
104
100
  ) {
105
101
  const settings = new ProjectConfiguration(
106
102
  join(path, '.cards', 'local', Project.projectConfigFileName),
103
+ options.autoSave ?? true,
107
104
  );
108
- super(path, settings.cardKeyPrefix, '');
105
+ super(path, settings.cardKeyPrefix);
109
106
  this.settings = settings;
110
107
 
111
108
  this.logger.info({ path }, 'Initializing project');
112
109
 
113
110
  this.calculationEngine = new CalculationEngine(this);
114
111
  this.projectPaths = new ProjectPaths(path);
115
- this.resources = new ResourceCollector(this);
116
-
117
- this.containerName = this.settings.name;
112
+ this.resourceHandler = new ResourceHandler(this);
118
113
  // todo: implement project validation
119
114
  this.validator = Validate.getInstance();
115
+
120
116
  this.logger.info(
121
- { resourcesFolder: this.paths.resourcesFolder },
122
- 'Collecting local resources',
123
- );
124
- this.resources.collectLocalResources();
125
- this.logger.info(
126
- { name: this.containerName },
117
+ { name: this.settings.name },
127
118
  'Project initialization complete',
128
119
  );
129
120
 
121
+ this.refreshAllModulePrefixes();
122
+
130
123
  const ignoreRenameFileChanges = true;
131
124
 
132
125
  // Watch changes in .cards if there are multiple instances of Project being
133
126
  // run concurrently.
134
- if (this.watchResourceChanges) {
127
+ if (this.options.watchResourceChanges) {
135
128
  this.resourceWatcher = new ContentWatcher(
136
129
  ignoreRenameFileChanges,
137
130
  this.paths.resourcesFolder,
138
131
  (fileName: string) => {
139
132
  void (async () => {
140
- let resource;
141
- try {
142
- resource = pathToResourceName(
143
- this,
144
- join(this.paths.resourcesFolder, fileName),
145
- );
146
- if (!resource) {
147
- return;
148
- }
149
- } catch {
150
- // it wasn't a resource that changed, so ignore the change
151
- return;
152
- }
153
- const resourceName = `${resource.prefix}/${resource.type}/${resource.identifier}`;
154
- await this.replaceCacheValue(resourceName);
155
- this.resources.collectLocalResources();
133
+ this.resources.handleFileSystemChange(
134
+ join(this.paths.resourcesFolder, fileName),
135
+ );
136
+ this.resources.changed();
156
137
  })();
157
138
  },
158
139
  );
@@ -171,10 +152,26 @@ export class Project extends CardContainer {
171
152
  }
172
153
 
173
154
  // Finds specific module.
174
- private async findModule(moduleName: string): Promise<Resource | undefined> {
175
- return (await this.resources.resources('modules')).find(
176
- (item) => item.name === moduleName && item.path,
155
+ private async findModule(
156
+ moduleName: string,
157
+ ): Promise<{ name: string; path: string } | undefined> {
158
+ const moduleExists = this.resources.moduleNames().includes(moduleName);
159
+ if (!moduleExists) {
160
+ return undefined;
161
+ }
162
+
163
+ // For modules, we need to construct the local path where the module is stored
164
+ const moduleConfig = this.configuration.modules?.find(
165
+ (module) => module.name === moduleName,
177
166
  );
167
+ if (!moduleConfig) {
168
+ return undefined;
169
+ }
170
+
171
+ return {
172
+ name: moduleName,
173
+ path: join(this.paths.modulesFolder, moduleConfig.name),
174
+ };
178
175
  }
179
176
 
180
177
  // Handles attachment changes after filesystem operations.
@@ -196,6 +193,7 @@ export class Project extends CardContainer {
196
193
  }
197
194
 
198
195
  // Determines the parent card key from a card's filesystem path.
196
+ // todo: could be moved to card-utils
199
197
  private parentFromPath(cardPath: string): string {
200
198
  return cardPathParts(this.projectPrefix, cardPath).parents.at(-1) || 'root';
201
199
  }
@@ -211,28 +209,6 @@ export class Project extends CardContainer {
211
209
  }
212
210
  }
213
211
 
214
- // Removes current version of a resource from the resource cache.
215
- // Then re-creates the resource with current data and caches the value again.
216
- // If the value wasn't in the cache before, it will be added.
217
- private async replaceCacheValue(resourceName: string) {
218
- if (this.createdResources.has(resourceName)) {
219
- // First, remove the old version from cache
220
- this.createdResources.delete(resourceName);
221
- }
222
- const resourceData = await this.resource(resourceName);
223
- if (resourceData) {
224
- this.createdResources.set(resourceName, resourceData as JSON);
225
- }
226
- }
227
-
228
- // Returns (local or all) resources of a given type.
229
- private async resourcesOfType(
230
- type: ResourceFolderType,
231
- from: ResourcesFrom = ResourcesFrom.localOnly,
232
- ): Promise<Resource[]> {
233
- return this.resources.resources(type, from);
234
- }
235
-
236
212
  // Updates children in the card cache
237
213
  private updateCachedChildren(parentKey: string, newChild: Card) {
238
214
  const parentCard = this.cardCache.getCard(parentKey);
@@ -248,35 +224,84 @@ export class Project extends CardContainer {
248
224
  }
249
225
  }
250
226
 
227
+ // Refreshes the cached list of all module prefixes.
228
+ // This includes both direct and transient module dependencies.
229
+ private refreshAllModulePrefixes(): void {
230
+ const prefixes: string[] = [this.projectPrefix];
231
+
232
+ try {
233
+ const modules = readdirSync(this.paths.modulesFolder, {
234
+ withFileTypes: true,
235
+ })
236
+ .filter((item) => item.isDirectory())
237
+ .map((item) => item.name);
238
+
239
+ prefixes.push(...modules);
240
+ } catch {
241
+ // If modules folder doesn't exist, fall back to configuration modules only
242
+ const moduleNames = this.configuration.modules.map((item) => item.name);
243
+ prefixes.push(...moduleNames);
244
+ }
245
+
246
+ this.cachedAllModulePrefixes = prefixes;
247
+ }
248
+
249
+ // Validates that card's data is valid.
250
+ private async validateCard(card: Card): Promise<string> {
251
+ const invalidCustomData = await this.validator.validateCustomFields(
252
+ this,
253
+ card,
254
+ this.allModulePrefixes(),
255
+ );
256
+ const invalidWorkFlow = await this.validator.validateWorkflowState(
257
+ this,
258
+ card,
259
+ );
260
+
261
+ const invalidLabels = this.validator.validateCardLabels(card);
262
+ if (
263
+ invalidCustomData.length === 0 &&
264
+ invalidWorkFlow.length === 0 &&
265
+ invalidLabels.length === 0
266
+ ) {
267
+ return '';
268
+ }
269
+ const errors: string[] = [];
270
+ if (invalidCustomData.length > 0) {
271
+ errors.push(invalidCustomData);
272
+ }
273
+ if (invalidWorkFlow.length > 0) {
274
+ errors.push(invalidWorkFlow);
275
+ }
276
+ if (invalidLabels.length > 0) {
277
+ errors.push(invalidLabels);
278
+ }
279
+ return errors.join('\n');
280
+ }
281
+
251
282
  /**
252
283
  * Populate template cards into the card cache.
253
284
  */
254
285
  protected async populateTemplateCards(): Promise<void> {
255
286
  try {
256
- // Gets local & module templates
257
- const templateResources = await this.templates();
258
- const prefixes = await this.projectPrefixes();
287
+ const templateResources = this.resources.templates();
288
+ const prefixes = this.allModulePrefixes();
259
289
  const loadPromises = templateResources.map(async (template) => {
260
290
  try {
261
291
  this.validator.validResourceName(
262
292
  'templates',
263
- template.name,
293
+ template.data?.name || '',
264
294
  prefixes,
265
295
  );
266
296
  } catch (error) {
267
297
  this.logger.warn(
268
- { templateName: template.name, error },
269
- `Template name '${template.name}' does not follow required format, skipping`,
298
+ { templateName: template, error },
299
+ `Template name '${template}' does not follow required format, skipping`,
270
300
  );
271
301
  return;
272
302
  }
273
303
 
274
- const templateResource = new TemplateResource(
275
- this,
276
- resourceName(template.name),
277
- );
278
-
279
- const templateObject = templateResource.templateObject();
304
+ const templateObject = template.templateObject();
280
305
  const isCreated = templateObject && templateObject.isCreated();
281
306
  if (!templateObject || !isCreated) {
282
307
  return;
@@ -308,16 +333,6 @@ export class Project extends CardContainer {
308
333
  await this.populateTemplateCards();
309
334
  }
310
335
 
311
- /**
312
- * Add a given 'resource' to the local resource arrays.
313
- * @param resource Resource to add.
314
- * @param data JSON data for the resource.
315
- */
316
- public addResource(resource: Resource, data: JSON) {
317
- this.resources.add(resource);
318
- this.createdResources.set(resource.name, data);
319
- }
320
-
321
336
  /**
322
337
  * Returns all template cards from the project. This includes all module templates' cards.
323
338
  * @returns all the template cards from the project
@@ -344,37 +359,6 @@ export class Project extends CardContainer {
344
359
  return super.attachments(path);
345
360
  }
346
361
 
347
- /**
348
- * Returns all the attachments in the template cards.
349
- * @returns all the attachments in the template cards.
350
- */
351
- public async attachmentsFromTemplates() {
352
- const templateAttachments: CardAttachment[] = [];
353
- const templates = await this.templates();
354
- for (const template of templates) {
355
- const templateResource = new TemplateResource(
356
- this,
357
- resourceName(template.name),
358
- );
359
- const templateObject = templateResource.templateObject();
360
- if (templateObject) {
361
- templateAttachments.push(...templateObject.attachments());
362
- }
363
- }
364
- return templateAttachments;
365
- }
366
-
367
- /**
368
- * Returns an array of all the calculation files (*.lp) in the project.
369
- * @param from Defines where resources are collected from.
370
- * @returns array of all calculation files in the project.
371
- */
372
- public async calculations(
373
- from: ResourcesFrom = ResourcesFrom.all,
374
- ): Promise<Resource[]> {
375
- return this.resources.resources('calculations', from);
376
- }
377
-
378
362
  /**
379
363
  * Returns path to a card's attachment folder.
380
364
  * @param cardKey card key
@@ -431,34 +415,6 @@ export class Project extends CardContainer {
431
415
  );
432
416
  }
433
417
 
434
- /**
435
- * Removes an attachment from a card.
436
- * @param cardKey The card to remove attachment from
437
- * @param fileName The name of the attachment file to remove
438
- * @throws if trying to remove module card attachment, or the attachment was not found.
439
- */
440
- public async removeCardAttachment(
441
- cardKey: string,
442
- fileName: string,
443
- ): Promise<void> {
444
- const attachmentFolder = this.cardAttachmentFolder(cardKey);
445
-
446
- // Modules cannot be modified.
447
- if (isModulePath(attachmentFolder)) {
448
- throw new Error(`Cannot modify imported module`);
449
- }
450
-
451
- const attachmentPath = join(attachmentFolder, fileName);
452
-
453
- try {
454
- await unlink(attachmentPath);
455
- } catch (error) {
456
- this.logger.error({ error }, 'Removing card attachment');
457
- throw new Error(`Attachment not found: ${fileName}`);
458
- }
459
- await this.handleAttachmentChange(cardKey, 'removed', fileName);
460
- }
461
-
462
418
  /**
463
419
  * Returns path to a card's folder.
464
420
  * @param cardKey card key
@@ -470,12 +426,9 @@ export class Project extends CardContainer {
470
426
  return found.path;
471
427
  }
472
428
 
473
- const templates = await this.templates();
429
+ const templates = this.resources.templates();
474
430
  const templatePromises = templates.map((template) => {
475
- const templateObject = new TemplateResource(
476
- this,
477
- resourceName(template.name),
478
- ).templateObject();
431
+ const templateObject = template.templateObject();
479
432
  const templateCard = templateObject
480
433
  ? templateObject.findCard(cardKey)
481
434
  : undefined;
@@ -503,15 +456,6 @@ export class Project extends CardContainer {
503
456
  return cards;
504
457
  }
505
458
 
506
- /**
507
- * Accessor for cards cache.
508
- * Used by template container (it needs to access project's cache, not their own instance).
509
- * @note Should not be used directly (other than Template).
510
- */
511
- public get cardsCache() {
512
- return this.cardCache;
513
- }
514
-
515
459
  /**
516
460
  * Returns an array of all the cards in the project.
517
461
  * @note These are project cards only, by default (unless path dictates otherwise).
@@ -527,14 +471,12 @@ export class Project extends CardContainer {
527
471
  }
528
472
 
529
473
  /**
530
- * Returns an array of all the card types in the project.
531
- * @param from Defines where resources are collected from.
532
- * @returns array of all card types in the project.
474
+ * Accessor for cards cache.
475
+ * Used by template container (it needs to access project's cache, not their own instance).
476
+ * @note Should not be used directly (other than Template).
533
477
  */
534
- public async cardTypes(
535
- from: ResourcesFrom = ResourcesFrom.all,
536
- ): Promise<Resource[]> {
537
- return this.resources.resources('cardTypes', from);
478
+ public get cardsCache() {
479
+ return this.cardCache;
538
480
  }
539
481
 
540
482
  /**
@@ -553,20 +495,6 @@ export class Project extends CardContainer {
553
495
  return cards;
554
496
  }
555
497
 
556
- /**
557
- * Updates all local resources.
558
- */
559
- public collectLocalResources() {
560
- this.resources.changed();
561
- }
562
-
563
- /**
564
- * Updates all imported module resources.
565
- */
566
- public collectModuleResources() {
567
- this.resources.moduleImported();
568
- }
569
-
570
498
  /**
571
499
  * Returns project configuration.
572
500
  * @returns project configuration.
@@ -585,7 +513,8 @@ export class Project extends CardContainer {
585
513
  return undefined;
586
514
  }
587
515
  const { template } = cardPathParts(this.projectPrefix, card.path);
588
- return new TemplateResource(this, resourceName(template)).templateObject();
516
+ const templateResource = this.resources.byType(template, 'templates');
517
+ return templateResource.templateObject();
589
518
  }
590
519
 
591
520
  /**
@@ -599,14 +528,13 @@ export class Project extends CardContainer {
599
528
  }
600
529
 
601
530
  /**
602
- * Returns an array of all the field types in the project.
603
- * @param from Defines where resources are collected from.
604
- * @returns array of all field types in the project.
531
+ * Returns specific card.
532
+ * @param cardToFind Card key to find
533
+ * @param details Defines which card details are included in the return values.
534
+ * @returns specific card details, or undefined if card is not part of the project.
605
535
  */
606
- public async fieldTypes(
607
- from: ResourcesFrom = ResourcesFrom.all,
608
- ): Promise<Resource[]> {
609
- return this.resources.resources('fieldTypes', from);
536
+ public findCard(cardToFind: string, details?: ProjectFetchCardDetails): Card {
537
+ return super.findCard(cardToFind, details);
610
538
  }
611
539
 
612
540
  /**
@@ -628,38 +556,6 @@ export class Project extends CardContainer {
628
556
  return Project.findProjectRoot(parentPath);
629
557
  }
630
558
 
631
- /**
632
- * Returns specific card.
633
- * @param cardToFind Card key to find
634
- * @param details Defines which card details are included in the return values.
635
- * @returns specific card details, or undefined if card is not part of the project.
636
- */
637
- public findCard(cardToFind: string, details?: ProjectFetchCardDetails): Card {
638
- return super.findCard(cardToFind, details);
639
- }
640
-
641
- /**
642
- * Returns an array of all the graph models in the project.
643
- * @param from Defines where resources are collected from.
644
- * @returns array of all the graph models in the project.
645
- */
646
- public async graphModels(
647
- from: ResourcesFrom = ResourcesFrom.all,
648
- ): Promise<Resource[]> {
649
- return this.resources.resources('graphModels', from);
650
- }
651
-
652
- /**
653
- * Returns an array of all the graph views in the project.
654
- * @param from Defines where resources are collected from.
655
- * @returns array of all the graph views in the project.
656
- */
657
- public async graphViews(
658
- from: ResourcesFrom = ResourcesFrom.all,
659
- ): Promise<Resource[]> {
660
- return this.resources.resources('graphViews', from);
661
- }
662
-
663
559
  /**
664
560
  * When card changes.
665
561
  * @param changedCard Card that was changed.
@@ -742,12 +638,30 @@ export class Project extends CardContainer {
742
638
  /**
743
639
  * Adds a module from project.
744
640
  * @param module Module to add
641
+ * @param skipMigrationLog If true, skip logging to migration log. Used during project creation.
745
642
  */
746
- public async importModule(module: ModuleSetting) {
643
+ public async importModule(module: ModuleSetting, skipMigrationLog = false) {
747
644
  // Add module as a dependency.
748
645
  await this.configuration.addModule(module);
749
- this.collectModuleResources();
646
+ this.resources.changedModules();
647
+ this.refreshAllModulePrefixes();
750
648
  await this.populateTemplateCards();
649
+
650
+ // Log configuration change
651
+ if (!skipMigrationLog) {
652
+ await ConfigurationLogger.log(
653
+ this.basePath,
654
+ ConfigurationOperation.MODULE_ADD,
655
+ module.name,
656
+ {
657
+ parameters: {
658
+ location: module.location,
659
+ branch: module.branch,
660
+ private: module.private,
661
+ },
662
+ },
663
+ );
664
+ }
751
665
  this.logger.info(`Imported module '${module.name}'`);
752
666
  }
753
667
 
@@ -760,17 +674,6 @@ export class Project extends CardContainer {
760
674
  return pathExists(join(path, 'cardRoot'));
761
675
  }
762
676
 
763
- /**
764
- * Returns an array of all the link types in the project.
765
- * @param from Defines where resources are collected from.
766
- * @returns array of all link types in the project.
767
- */
768
- public async linkTypes(
769
- from: ResourcesFrom = ResourcesFrom.all,
770
- ): Promise<Resource[]> {
771
- return this.resources.resources('linkTypes', from);
772
- }
773
-
774
677
  /**
775
678
  * Returns an array of cards in the project, in the templates or both.
776
679
  * Cards don't have content and nor metadata.
@@ -799,18 +702,15 @@ export class Project extends CardContainer {
799
702
  cardsFrom === CardLocation.all ||
800
703
  cardsFrom === CardLocation.templatesOnly
801
704
  ) {
802
- const templates = await this.templates();
705
+ const templates = this.resources.templates();
803
706
  for (const template of templates) {
804
- const templateObject = new TemplateResource(
805
- this,
806
- resourceName(template.name),
807
- ).templateObject();
707
+ const templateObject = template.templateObject();
808
708
  if (templateObject) {
809
709
  // todo: optimization - do all this in parallel
810
710
  const templateCards = templateObject.listCards();
811
711
  if (templateCards.length) {
812
712
  cardListContainer.push({
813
- name: template.name,
713
+ name: template.data?.name || '',
814
714
  type: 'template',
815
715
  cards: templateCards.map((item) => item.key),
816
716
  });
@@ -847,7 +747,7 @@ export class Project extends CardContainer {
847
747
  public async module(moduleName: string): Promise<ModuleContent | undefined> {
848
748
  const module = await this.findModule(moduleName);
849
749
  if (module && module.path) {
850
- const modulePath = join(module.path, module.name);
750
+ const modulePath = module.path;
851
751
  const moduleConfig = await readJsonFile(
852
752
  join(modulePath, Project.projectConfigFileName),
853
753
  );
@@ -857,73 +757,32 @@ export class Project extends CardContainer {
857
757
  hubs: moduleConfig.hubs,
858
758
  path: modulePath,
859
759
  cardKeyPrefix: moduleConfig.cardKeyPrefix,
860
- calculations: [
861
- ...(await this.resources.collectResourcesFromModules(
862
- 'calculations',
863
- moduleName,
864
- )),
865
- ],
866
- cardTypes: [
867
- ...(await this.resources.collectResourcesFromModules(
868
- 'cardTypes',
869
- moduleName,
870
- )),
871
- ],
872
- fieldTypes: [
873
- ...(await this.resources.collectResourcesFromModules(
874
- 'fieldTypes',
875
- moduleName,
876
- )),
877
- ],
878
- graphModels: [
879
- ...(await this.resources.collectResourcesFromModules(
880
- 'graphModels',
881
- moduleName,
882
- )),
883
- ],
884
- graphViews: [
885
- ...(await this.resources.collectResourcesFromModules(
886
- 'graphViews',
887
- moduleName,
888
- )),
889
- ],
890
- linkTypes: [
891
- ...(await this.resources.collectResourcesFromModules(
892
- 'linkTypes',
893
- moduleName,
894
- )),
895
- ],
896
- reports: [
897
- ...(await this.resources.collectResourcesFromModules(
898
- 'reports',
899
- moduleName,
900
- )),
901
- ],
902
- templates: [
903
- ...(await this.resources.collectResourcesFromModules(
904
- 'templates',
905
- moduleName,
906
- )),
907
- ],
908
- workflows: [
909
- ...(await this.resources.collectResourcesFromModules(
910
- 'workflows',
911
- moduleName,
912
- )),
913
- ],
760
+ calculations: this.resources.moduleResourceNames(
761
+ 'calculations',
762
+ moduleName,
763
+ ),
764
+ cardTypes: this.resources.moduleResourceNames('cardTypes', moduleName),
765
+ fieldTypes: this.resources.moduleResourceNames(
766
+ 'fieldTypes',
767
+ moduleName,
768
+ ),
769
+ graphModels: this.resources.moduleResourceNames(
770
+ 'graphModels',
771
+ moduleName,
772
+ ),
773
+ graphViews: this.resources.moduleResourceNames(
774
+ 'graphViews',
775
+ moduleName,
776
+ ),
777
+ linkTypes: this.resources.moduleResourceNames('linkTypes', moduleName),
778
+ reports: this.resources.moduleResourceNames('reports', moduleName),
779
+ templates: this.resources.moduleResourceNames('templates', moduleName),
780
+ workflows: this.resources.moduleResourceNames('workflows', moduleName),
914
781
  };
915
782
  }
916
783
  return undefined;
917
784
  }
918
785
 
919
- /**
920
- * Returns list of modules in the project.
921
- * @returns list of modules in the project.
922
- */
923
- public async modules(): Promise<Resource[]> {
924
- return this.resources.resources('modules');
925
- }
926
-
927
786
  /**
928
787
  * Returns a new unique card key with project prefix (e.g. test_x649it4x).
929
788
  * Random part of string will be always 8 characters in base-36 (0-9a-z)
@@ -996,6 +855,10 @@ export class Project extends CardContainer {
996
855
  */
997
856
  public async populateCaches() {
998
857
  if (!this.cardCache.isPopulated) {
858
+ // Only collect modules that are registered in the project configuration
859
+ if (this.configuration.modules && this.configuration.modules.length > 0) {
860
+ this.resources.changedModules();
861
+ }
999
862
  await this.populateCardsCache();
1000
863
  }
1001
864
  }
@@ -1015,185 +878,96 @@ export class Project extends CardContainer {
1015
878
  }
1016
879
 
1017
880
  /**
1018
- * Collects all prefixes used in the project (project's own plus all from modules).
881
+ * Returns all prefixes used in the project.
882
+ * This includes both direct dependencies and transient dependencies.
1019
883
  * @returns all prefixes used in the project.
1020
- * @todo - move the module prefix fetch to resource-collector.
1021
- * Make it use cached value that is only changed when module is removed/imported.
1022
884
  */
1023
- public async projectPrefixes(): Promise<string[]> {
1024
- const prefixes: string[] = [this.projectPrefix];
1025
- let files;
1026
- try {
1027
- // TODO: Could be optimized so that prefixes are stored once fetched.
1028
- files = await readdir(this.paths.modulesFolder, {
1029
- withFileTypes: true,
1030
- recursive: true,
1031
- });
1032
- const configurationFiles = files
1033
- .filter((dirent) => dirent.isFile())
1034
- .filter((dirent) => dirent.name === Project.projectConfigFileName);
1035
-
1036
- const configurationPromises = configurationFiles.map(async (file) => {
1037
- const configuration = (await readJsonFile(
1038
- join(file.parentPath, file.name),
1039
- )) as ProjectSettings;
1040
- return configuration.cardKeyPrefix;
1041
- });
1042
-
1043
- const configurationPrefixes = await Promise.all(configurationPromises);
1044
- prefixes.push(...configurationPrefixes);
1045
- } catch (error) {
1046
- this.logger.error({ error }, 'Failed to collect prefixes in use');
1047
- }
1048
-
1049
- return prefixes;
885
+ public allModulePrefixes(): string[] {
886
+ return this.cachedAllModulePrefixes;
1050
887
  }
1051
888
 
1052
889
  /**
1053
- * Removes a module from the project
1054
- * @param module Module (name) to remove.
890
+ * Returns prefixes for direct module dependencies only (from cardsConfig.json).
891
+ * @returns prefixes for direct module dependencies.
1055
892
  */
1056
- public async removeModule(moduleName: string) {
1057
- const toBeRemovedTemplates = this.resources.moduleResources.resourceArray(
1058
- 'templates',
1059
- moduleName,
1060
- );
1061
- // First, remove cards from the cache
1062
- for (const template of toBeRemovedTemplates) {
1063
- this.cardCache.deleteCardsFromTemplate(template.name);
1064
- }
1065
-
1066
- // Then, remove module from project configuration
1067
- await this.configuration.removeModule(moduleName);
1068
- this.collectModuleResources();
893
+ public projectPrefixes(): string[] {
894
+ const prefixes: string[] = [this.projectPrefix];
895
+ const moduleNames = this.configuration.modules.map((item) => item.name);
896
+ prefixes.push(...moduleNames);
1069
897
 
1070
- this.logger.info(`Removed module '${moduleName}'`);
898
+ return prefixes;
1071
899
  }
1072
900
 
1073
901
  /**
1074
- * Removes a resource from Project.
1075
- * @param resource Resource to remove.
902
+ * Removes an attachment from a card.
903
+ * @param cardKey The card to remove attachment from
904
+ * @param fileName The name of the attachment file to remove
905
+ * @throws if trying to remove module card attachment, or the attachment was not found.
1076
906
  */
1077
- public removeResource(resource: Resource) {
1078
- // Template cards must be removed from the cache when resource is removed.
1079
- if (resource.path.includes('templates')) {
1080
- const templateName = resourceNameToString(resourceName(resource.name));
1081
- this.cardCache.deleteCardsFromTemplate(templateName);
907
+ public async removeCardAttachment(
908
+ cardKey: string,
909
+ fileName: string,
910
+ ): Promise<void> {
911
+ const attachmentFolder = this.cardAttachmentFolder(cardKey);
912
+
913
+ // Modules cannot be modified.
914
+ if (isModulePath(attachmentFolder)) {
915
+ throw new Error(`Cannot modify imported module`);
1082
916
  }
1083
- this.resources.remove(resource);
1084
- this.createdResources.delete(resource.name);
1085
- }
1086
917
 
1087
- /**
1088
- * Array of reports in the project.
1089
- * @param from Defines where resources are collected from.
1090
- * @returns array of all reports in the project.
1091
- */
1092
- public async reports(
1093
- from: ResourcesFrom = ResourcesFrom.all,
1094
- ): Promise<Resource[]> {
1095
- return this.resources.resources('reports', from);
1096
- }
918
+ const attachmentPath = join(attachmentFolder, fileName);
1097
919
 
1098
- /**
1099
- * Returns handlebar files from reports.
1100
- * @param from Defines where report handlebar files are collected from.
1101
- * @returns handlebar files from reports.
1102
- */
1103
- public async reportHandlerBarFiles(from: ResourcesFrom = ResourcesFrom.all) {
1104
- const reports = await this.reports(from);
1105
- const handleBarFiles: string[] = [];
1106
- for (const reportResourceName of reports) {
1107
- const name = resourceName(reportResourceName.name);
1108
- const report = new ReportResource(this, name);
1109
- handleBarFiles.push(...(await report.handleBarFiles()));
920
+ try {
921
+ await unlink(attachmentPath);
922
+ } catch (error) {
923
+ this.logger.error({ error }, 'Removing card attachment');
924
+ throw new Error(`Attachment not found: ${fileName}`);
1110
925
  }
1111
- return handleBarFiles;
926
+ await this.handleAttachmentChange(cardKey, 'removed', fileName);
1112
927
  }
1113
928
 
1114
929
  /**
1115
- * Returns metadata from a given resource
1116
- * @param name Name of a resource
1117
- * @returns Metadata from the resource.
930
+ * Removes a module from the project cache and configuration.
931
+ * @note that ModuleManager removes the actual files.
932
+ * @param moduleName Module name to remove.
1118
933
  */
1119
- public resource<Type>(name: string): Type | undefined {
1120
- const resName = resourceName(name);
1121
- if (this.createdResources.has(resourceNameToString(resName))) {
1122
- const value = this.createdResources.get(
1123
- resourceNameToString(resName),
1124
- ) as unknown as Type;
1125
- return value;
1126
- }
1127
- let resource = undefined;
1128
- try {
1129
- resource = Project.resourceObject(this, resName);
1130
- } catch {
1131
- return undefined;
1132
- }
1133
- const data = resource?.data as Type;
1134
- if (!data) {
1135
- return undefined;
934
+ public async removeModule(moduleName: string) {
935
+ const toBeRemovedTemplates = this.resources.moduleResourceNames(
936
+ 'templates',
937
+ moduleName,
938
+ );
939
+
940
+ // First, remove template cards from the cache that are part of removed templates.
941
+ for (const templateName of toBeRemovedTemplates) {
942
+ this.cardCache.deleteCardsFromTemplate(templateName);
1136
943
  }
1137
- return data;
1138
- }
1139
944
 
1140
- /**
1141
- * Returns resource cache.
1142
- */
1143
- public get resourceCache(): Map<string, JSON> {
1144
- return this.createdResources;
1145
- }
945
+ // Then, remove all module resources from cache
946
+ this.resources.removeModule(moduleName);
1146
947
 
1147
- /**
1148
- * Checks if a given resource exists in the project already.
1149
- * @param resourceType Type of resource as a string.
1150
- * @param name Valid name of resource.
1151
- * @returns boolean, true if resource exists; false otherwise.
1152
- */
1153
- public async resourceExists(
1154
- resourceType: ResourceFolderType,
1155
- name: string,
1156
- ): Promise<boolean> {
1157
- const resources = await this.resourcesOfType(
1158
- resourceType,
1159
- ResourcesFrom.all,
948
+ // Finally, remove module from project configuration
949
+ await this.configuration.removeModule(moduleName);
950
+
951
+ // Refresh cached module prefixes after removal
952
+ this.refreshAllModulePrefixes();
953
+
954
+ // Log configuration change
955
+ await ConfigurationLogger.log(
956
+ this.basePath,
957
+ ConfigurationOperation.MODULE_REMOVE,
958
+ moduleName,
959
+ {},
1160
960
  );
1161
- const resource = resources.find((item) => item.name === name);
1162
- return resource !== undefined;
961
+
962
+ this.logger.info(`Removed module '${moduleName}'`);
1163
963
  }
1164
964
 
1165
965
  /**
1166
- * Instantiates resource object from project with a resource name.
1167
- * @note that this is memory based object only.
1168
- * To manipulate the resource (create files, delete files etc), use the resource object's API.
1169
- * @param project Project from which resources are created from.
1170
- * @param name Resource name
1171
- * @throws if called with unsupported resource type.
1172
- * @returns Created resource.
966
+ * Accessor for resource handler.
967
+ * @returns Resource handler instance.
1173
968
  */
1174
- public static resourceObject(project: Project, name: ResourceName) {
1175
- if (name.type === 'calculations') {
1176
- return new CalculationResource(project, name);
1177
- } else if (name.type === 'cardTypes') {
1178
- return new CardTypeResource(project, name);
1179
- } else if (name.type === 'fieldTypes') {
1180
- return new FieldTypeResource(project, name);
1181
- } else if (name.type === 'graphModels') {
1182
- return new GraphModelResource(project, name);
1183
- } else if (name.type === 'graphViews') {
1184
- return new GraphViewResource(project, name);
1185
- } else if (name.type === 'linkTypes') {
1186
- return new LinkTypeResource(project, name);
1187
- } else if (name.type === 'reports') {
1188
- return new ReportResource(project, name);
1189
- } else if (name.type === 'templates') {
1190
- return new TemplateResource(project, name);
1191
- } else if (name.type === 'workflows') {
1192
- return new WorkflowResource(project, name);
1193
- }
1194
- throw new Error(
1195
- `Unsupported resource type '${resourceNameToString(name)}'`,
1196
- );
969
+ public get resources(): ResourceHandler {
970
+ return this.resourceHandler;
1197
971
  }
1198
972
 
1199
973
  /**
@@ -1202,11 +976,11 @@ export class Project extends CardContainer {
1202
976
  */
1203
977
  public async show(): Promise<ProjectMetadata> {
1204
978
  return {
1205
- name: this.containerName,
979
+ name: this.settings.name,
1206
980
  path: this.basePath,
1207
981
  prefix: this.projectPrefix,
1208
982
  hubs: this.configuration.hubs,
1209
- modules: (await this.modules()).map((item) => item.name),
983
+ modules: this.resources.moduleNames(),
1210
984
  numberOfCards: (await this.listCards(CardLocation.projectOnly))[0].cards
1211
985
  .length,
1212
986
  };
@@ -1235,17 +1009,6 @@ export class Project extends CardContainer {
1235
1009
  });
1236
1010
  }
1237
1011
 
1238
- /**
1239
- * Array of templates in the project.
1240
- * @param from Defines where resources are collected from.
1241
- * @returns array of all templates in the project.
1242
- */
1243
- public async templates(
1244
- from: ResourcesFrom = ResourcesFrom.all,
1245
- ): Promise<Resource[]> {
1246
- return this.resources.resources('templates', from);
1247
- }
1248
-
1249
1012
  /**
1250
1013
  * Update a card's content.
1251
1014
  * @param cardKey card key to update.
@@ -1348,44 +1111,4 @@ export class Project extends CardContainer {
1348
1111
  await this.handleCardChanged(card);
1349
1112
  }
1350
1113
  }
1351
-
1352
- // Validates that card's data is valid.
1353
- private async validateCard(card: Card): Promise<string> {
1354
- const invalidCustomData = await this.validator.validateCustomFields(
1355
- this,
1356
- card,
1357
- );
1358
- const invalidWorkFlow = this.validator.validateWorkflowState(this, card);
1359
-
1360
- const invalidLabels = this.validator.validateCardLabels(card);
1361
- if (
1362
- invalidCustomData.length === 0 &&
1363
- invalidWorkFlow.length === 0 &&
1364
- invalidLabels.length === 0
1365
- ) {
1366
- return '';
1367
- }
1368
- const errors: string[] = [];
1369
- if (invalidCustomData.length > 0) {
1370
- errors.push(invalidCustomData);
1371
- }
1372
- if (invalidWorkFlow.length > 0) {
1373
- errors.push(invalidWorkFlow);
1374
- }
1375
- if (invalidLabels.length > 0) {
1376
- errors.push(invalidLabels);
1377
- }
1378
- return errors.join('\n');
1379
- }
1380
-
1381
- /**
1382
- * Array of workflows in the project.
1383
- * @param from Defines where resources are collected from.
1384
- * @returns array of all workflows in the project.
1385
- */
1386
- public async workflows(
1387
- from: ResourcesFrom = ResourcesFrom.all,
1388
- ): Promise<Resource[]> {
1389
- return this.resources.resources('workflows', from);
1390
- }
1391
1114
  }