@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.
- package/dist/card-metadata-updater.js +7 -1
- package/dist/card-metadata-updater.js.map +1 -1
- package/dist/command-handler.d.ts +4 -0
- package/dist/command-handler.js +22 -8
- package/dist/command-handler.js.map +1 -1
- package/dist/command-manager.d.ts +24 -1
- package/dist/command-manager.js +31 -7
- package/dist/command-manager.js.map +1 -1
- package/dist/commands/create.d.ts +1 -1
- package/dist/commands/create.js +34 -36
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/export.d.ts +11 -2
- package/dist/commands/export.js +54 -41
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/fetch.d.ts +8 -0
- package/dist/commands/fetch.js +101 -23
- package/dist/commands/fetch.js.map +1 -1
- package/dist/commands/import.d.ts +14 -3
- package/dist/commands/import.js +27 -10
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/move.js +0 -1
- package/dist/commands/move.js.map +1 -1
- package/dist/commands/remove.d.ts +11 -2
- package/dist/commands/remove.js +15 -5
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/rename.d.ts +4 -9
- package/dist/commands/rename.js +37 -101
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/show.d.ts +20 -12
- package/dist/commands/show.js +79 -57
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/transition.d.ts +9 -2
- package/dist/commands/transition.js +25 -17
- package/dist/commands/transition.js.map +1 -1
- package/dist/commands/update.d.ts +16 -12
- package/dist/commands/update.js +19 -17
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.d.ts +17 -9
- package/dist/commands/validate.js +94 -35
- package/dist/commands/validate.js.map +1 -1
- package/dist/containers/card-container.d.ts +7 -5
- package/dist/containers/card-container.js +30 -5
- package/dist/containers/card-container.js.map +1 -1
- package/dist/containers/project/calculation-engine.d.ts +7 -4
- package/dist/containers/project/calculation-engine.js +61 -66
- package/dist/containers/project/calculation-engine.js.map +1 -1
- package/dist/containers/project/project-paths.d.ts +7 -4
- package/dist/containers/project/project-paths.js +22 -12
- package/dist/containers/project/project-paths.js.map +1 -1
- package/dist/containers/project/resource-cache.d.ts +169 -0
- package/dist/containers/project/resource-cache.js +509 -0
- package/dist/containers/project/resource-cache.js.map +1 -0
- package/dist/containers/project/resource-handler.d.ts +129 -0
- package/dist/containers/project/resource-handler.js +206 -0
- package/dist/containers/project/resource-handler.js.map +1 -0
- package/dist/containers/project.d.ts +46 -152
- package/dist/containers/project.js +179 -409
- package/dist/containers/project.js.map +1 -1
- package/dist/containers/template.d.ts +8 -2
- package/dist/containers/template.js +24 -19
- package/dist/containers/template.js.map +1 -1
- package/dist/interfaces/command-options.d.ts +3 -1
- package/dist/interfaces/folder-content-interfaces.d.ts +5 -3
- package/dist/interfaces/folder-content-interfaces.js +3 -3
- package/dist/interfaces/folder-content-interfaces.js.map +1 -1
- package/dist/interfaces/project-interfaces.d.ts +7 -9
- package/dist/interfaces/project-interfaces.js.map +1 -1
- package/dist/interfaces/resource-interfaces.d.ts +14 -1
- package/dist/interfaces/resource-interfaces.js.map +1 -1
- package/dist/macros/graph/index.js +12 -26
- package/dist/macros/graph/index.js.map +1 -1
- package/dist/macros/index.d.ts +1 -1
- package/dist/macros/index.js +2 -2
- package/dist/macros/index.js.map +1 -1
- package/dist/macros/report/index.js +3 -6
- package/dist/macros/report/index.js.map +1 -1
- package/dist/module-manager.d.ts +16 -3
- package/dist/module-manager.js +51 -19
- package/dist/module-manager.js.map +1 -1
- package/dist/project-settings.d.ts +21 -3
- package/dist/project-settings.js +91 -14
- package/dist/project-settings.js.map +1 -1
- package/dist/resources/calculation-resource.d.ts +4 -3
- package/dist/resources/calculation-resource.js +11 -5
- package/dist/resources/calculation-resource.js.map +1 -1
- package/dist/resources/card-type-resource.d.ts +6 -1
- package/dist/resources/card-type-resource.js +34 -23
- package/dist/resources/card-type-resource.js.map +1 -1
- package/dist/resources/create-defaults.d.ts +3 -2
- package/dist/resources/create-defaults.js +3 -2
- package/dist/resources/create-defaults.js.map +1 -1
- package/dist/resources/field-type-resource.d.ts +4 -1
- package/dist/resources/field-type-resource.js +22 -23
- package/dist/resources/field-type-resource.js.map +1 -1
- package/dist/resources/file-resource.d.ts +5 -9
- package/dist/resources/file-resource.js +6 -11
- package/dist/resources/file-resource.js.map +1 -1
- package/dist/resources/folder-resource.d.ts +29 -32
- package/dist/resources/folder-resource.js +59 -78
- package/dist/resources/folder-resource.js.map +1 -1
- package/dist/resources/graph-model-resource.d.ts +4 -1
- package/dist/resources/graph-model-resource.js +11 -4
- package/dist/resources/graph-model-resource.js.map +1 -1
- package/dist/resources/graph-view-resource.d.ts +5 -2
- package/dist/resources/graph-view-resource.js +7 -3
- package/dist/resources/graph-view-resource.js.map +1 -1
- package/dist/resources/link-type-resource.d.ts +5 -2
- package/dist/resources/link-type-resource.js +5 -2
- package/dist/resources/link-type-resource.js.map +1 -1
- package/dist/resources/report-resource.d.ts +6 -7
- package/dist/resources/report-resource.js +14 -23
- package/dist/resources/report-resource.js.map +1 -1
- package/dist/resources/resource-object.d.ts +94 -8
- package/dist/resources/resource-object.js +212 -109
- package/dist/resources/resource-object.js.map +1 -1
- package/dist/resources/template-resource.d.ts +7 -3
- package/dist/resources/template-resource.js +10 -3
- package/dist/resources/template-resource.js.map +1 -1
- package/dist/resources/workflow-resource.d.ts +5 -2
- package/dist/resources/workflow-resource.js +18 -22
- package/dist/resources/workflow-resource.js.map +1 -1
- package/dist/utils/card-utils.d.ts +2 -2
- package/dist/utils/card-utils.js +1 -1
- package/dist/utils/clingo-fact-builder.d.ts +25 -14
- package/dist/utils/clingo-fact-builder.js +27 -5
- package/dist/utils/clingo-fact-builder.js.map +1 -1
- package/dist/utils/clingo-facts.js +3 -4
- package/dist/utils/clingo-facts.js.map +1 -1
- package/dist/utils/configuration-logger.d.ts +91 -0
- package/dist/utils/configuration-logger.js +151 -0
- package/dist/utils/configuration-logger.js.map +1 -0
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +5 -3
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/resource-utils.d.ts +1 -0
- package/dist/utils/resource-utils.js +2 -1
- package/dist/utils/resource-utils.js.map +1 -1
- package/package.json +9 -9
- package/src/card-metadata-updater.ts +6 -2
- package/src/command-handler.ts +39 -12
- package/src/command-manager.ts +33 -21
- package/src/commands/create.ts +43 -78
- package/src/commands/export.ts +63 -52
- package/src/commands/fetch.ts +143 -34
- package/src/commands/import.ts +37 -15
- package/src/commands/move.ts +0 -1
- package/src/commands/remove.ts +20 -7
- package/src/commands/rename.ts +58 -149
- package/src/commands/show.ts +123 -80
- package/src/commands/transition.ts +26 -28
- package/src/commands/update.ts +25 -22
- package/src/commands/validate.ts +104 -67
- package/src/containers/card-container.ts +37 -5
- package/src/containers/project/calculation-engine.ts +61 -93
- package/src/containers/project/project-paths.ts +29 -13
- package/src/containers/project/resource-cache.ts +651 -0
- package/src/containers/project/resource-handler.ts +265 -0
- package/src/containers/project.ts +250 -527
- package/src/containers/template.ts +28 -23
- package/src/interfaces/command-options.ts +3 -1
- package/src/interfaces/folder-content-interfaces.ts +7 -6
- package/src/interfaces/project-interfaces.ts +12 -11
- package/src/interfaces/resource-interfaces.ts +18 -3
- package/src/macros/graph/index.ts +26 -47
- package/src/macros/index.ts +2 -2
- package/src/macros/report/index.ts +3 -9
- package/src/module-manager.ts +74 -17
- package/src/project-settings.ts +96 -14
- package/src/resources/calculation-resource.ts +18 -18
- package/src/resources/card-type-resource.ts +50 -50
- package/src/resources/create-defaults.ts +3 -2
- package/src/resources/field-type-resource.ts +41 -55
- package/src/resources/file-resource.ts +10 -36
- package/src/resources/folder-resource.ts +69 -120
- package/src/resources/graph-model-resource.ts +20 -22
- package/src/resources/graph-view-resource.ts +15 -17
- package/src/resources/link-type-resource.ts +10 -13
- package/src/resources/report-resource.ts +21 -43
- package/src/resources/resource-object.ts +263 -149
- package/src/resources/template-resource.ts +17 -16
- package/src/resources/workflow-resource.ts +25 -44
- package/src/utils/card-utils.ts +2 -2
- package/src/utils/clingo-fact-builder.ts +28 -16
- package/src/utils/clingo-facts.ts +3 -4
- package/src/utils/configuration-logger.ts +206 -0
- package/src/utils/constants.ts +5 -3
- package/src/utils/resource-utils.ts +2 -1
- package/dist/containers/project/resource-collector.d.ts +0 -110
- package/dist/containers/project/resource-collector.js +0 -344
- package/dist/containers/project/resource-collector.js.map +0 -1
- package/src/containers/project/resource-collector.ts +0 -404
|
@@ -14,41 +14,43 @@
|
|
|
14
14
|
|
|
15
15
|
// node
|
|
16
16
|
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
17
|
-
import { basename, join
|
|
18
|
-
|
|
19
|
-
import { hasCode } from '../utils/error-utils.js';
|
|
17
|
+
import { basename, join } from 'node:path';
|
|
20
18
|
|
|
21
19
|
import { ArrayHandler } from './array-handler.js';
|
|
20
|
+
import { deleteFile, pathExists } from '../utils/file-utils.js';
|
|
21
|
+
import { getChildLogger } from '../utils/log-utils.js';
|
|
22
|
+
import {
|
|
23
|
+
readJsonFile,
|
|
24
|
+
readJsonFileSync,
|
|
25
|
+
writeJsonFile,
|
|
26
|
+
} from '../utils/json.js';
|
|
27
|
+
import {
|
|
28
|
+
resourceName,
|
|
29
|
+
resourceNameToPath,
|
|
30
|
+
resourceNameToString,
|
|
31
|
+
type ResourceName,
|
|
32
|
+
} from '../utils/resource-utils.js';
|
|
33
|
+
import { ResourcesFrom } from '../containers/project.js';
|
|
34
|
+
|
|
22
35
|
import type {
|
|
23
36
|
Card,
|
|
24
|
-
Resource,
|
|
25
37
|
ResourceFolderType,
|
|
26
38
|
} from '../interfaces/project-interfaces.js';
|
|
27
39
|
import type { Logger } from 'pino';
|
|
28
40
|
import type { Project } from '../containers/project.js';
|
|
29
|
-
import { ResourcesFrom } from '../containers/project/resource-collector.js';
|
|
30
41
|
import type {
|
|
31
42
|
ResourceBaseMetadata,
|
|
32
43
|
UpdateKey,
|
|
33
44
|
} from '../interfaces/resource-interfaces.js';
|
|
34
45
|
import type { Validate } from '../commands/validate.js';
|
|
46
|
+
|
|
35
47
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
type ResourceName,
|
|
40
|
-
} from '../utils/resource-utils.js';
|
|
41
|
-
import { getChildLogger } from '../utils/log-utils.js';
|
|
42
|
-
import { deleteFile, pathExists } from '../utils/file-utils.js';
|
|
43
|
-
import {
|
|
44
|
-
readJsonFile,
|
|
45
|
-
readJsonFileSync,
|
|
46
|
-
writeJsonFile,
|
|
47
|
-
} from '../utils/json.js';
|
|
48
|
+
ConfigurationLogger,
|
|
49
|
+
ConfigurationOperation,
|
|
50
|
+
} from '../utils/configuration-logger.js';
|
|
48
51
|
|
|
49
52
|
// Possible operations to perform when doing "update"
|
|
50
53
|
export type UpdateOperations = 'add' | 'change' | 'rank' | 'remove';
|
|
51
|
-
//| 'elementTypeChange';
|
|
52
54
|
|
|
53
55
|
// Base class for update operations.
|
|
54
56
|
type BaseOperation<T> = {
|
|
@@ -117,7 +119,7 @@ export abstract class AbstractResource<
|
|
|
117
119
|
protected abstract delete(): Promise<void>; // delete from disk
|
|
118
120
|
protected abstract read(): Promise<void>; // read content from disk (replaces existing content, if any)
|
|
119
121
|
protected abstract rename(newName: ResourceName): Promise<void>; // change name of the resource and filename; same as update('name', ...)
|
|
120
|
-
protected abstract show():
|
|
122
|
+
protected abstract show(): ShowReturnType<T, U>; // return the content as JSON
|
|
121
123
|
protected abstract update<Type, K extends string>(
|
|
122
124
|
updateKey: UpdateKey<K>,
|
|
123
125
|
operation: Operation<Type>,
|
|
@@ -136,8 +138,6 @@ export abstract class ResourceObject<
|
|
|
136
138
|
T extends ResourceBaseMetadata,
|
|
137
139
|
U,
|
|
138
140
|
> extends AbstractResource<T, U> {
|
|
139
|
-
// TODO: Remove when INTDEV-1048 is implemented, since caching is done at object level
|
|
140
|
-
private cache: Map<string, JSON>;
|
|
141
141
|
private static validateInstancePromise?: Promise<ValidateInstance>;
|
|
142
142
|
|
|
143
143
|
protected content: T;
|
|
@@ -153,6 +153,12 @@ export abstract class ResourceObject<
|
|
|
153
153
|
*/
|
|
154
154
|
public fileName: string = '';
|
|
155
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Constructs a ResourceObject instance
|
|
158
|
+
* @param project Project where this resource is
|
|
159
|
+
* @param resourceName Name for the resource
|
|
160
|
+
* @param type Type of resource
|
|
161
|
+
*/
|
|
156
162
|
constructor(
|
|
157
163
|
protected project: Project,
|
|
158
164
|
protected resourceName: ResourceName,
|
|
@@ -161,12 +167,19 @@ export abstract class ResourceObject<
|
|
|
161
167
|
super();
|
|
162
168
|
this.moduleResource =
|
|
163
169
|
this.resourceName.prefix !== this.project.projectPrefix;
|
|
164
|
-
this.cache = this.project.resourceCache;
|
|
165
170
|
this.type = type;
|
|
166
171
|
this.logger = this.getLogger(this.getType);
|
|
167
172
|
this.content = { name: '' } as T; // not found if name is empty
|
|
168
173
|
}
|
|
169
174
|
|
|
175
|
+
// Check if resource already exists. First checks the cache, then filesystem.
|
|
176
|
+
private exists(): boolean {
|
|
177
|
+
const name = resourceNameToString(this.resourceName);
|
|
178
|
+
const existsInCache = this.project.resources.exists(name);
|
|
179
|
+
return existsInCache || pathExists(this.fileName);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Gets Validate command instance.
|
|
170
183
|
private static async getValidate(): Promise<ValidateInstance> {
|
|
171
184
|
// a bit hacky solution to avoid circular dependencies
|
|
172
185
|
if (!this.validateInstancePromise) {
|
|
@@ -177,11 +190,14 @@ export abstract class ResourceObject<
|
|
|
177
190
|
return this.validateInstancePromise;
|
|
178
191
|
}
|
|
179
192
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
193
|
+
// Gets handlebar files.
|
|
194
|
+
private async reportHandlerBarFiles(from: ResourcesFrom = ResourcesFrom.all) {
|
|
195
|
+
const reports = this.project.resources.reports(from);
|
|
196
|
+
const handleBarFiles: string[] = [];
|
|
197
|
+
for (const report of reports) {
|
|
198
|
+
handleBarFiles.push(...(await report.handleBarFiles()));
|
|
199
|
+
}
|
|
200
|
+
return handleBarFiles;
|
|
185
201
|
}
|
|
186
202
|
|
|
187
203
|
// Type of resource.
|
|
@@ -189,19 +205,13 @@ export abstract class ResourceObject<
|
|
|
189
205
|
return this.type;
|
|
190
206
|
}
|
|
191
207
|
|
|
192
|
-
private toCache() {
|
|
193
|
-
this.cache.set(
|
|
194
|
-
resourceNameToString(this.resourceName),
|
|
195
|
-
this.content as unknown as JSON,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
208
|
/**
|
|
200
|
-
* Checks if resource exists
|
|
209
|
+
* Checks if resource exists.
|
|
210
|
+
* This should only throw, if someone creates resources directly; ie. not through the cache
|
|
201
211
|
* @throws if resource does not exist
|
|
202
212
|
*/
|
|
203
213
|
protected assertResourceExists() {
|
|
204
|
-
if (!
|
|
214
|
+
if (!this.exists()) {
|
|
205
215
|
const resourceType = `${this.type[0].toUpperCase()}${this.type.slice(1, this.type.length - 1)}`;
|
|
206
216
|
const name = resourceNameToString(this.resourceName);
|
|
207
217
|
throw new Error(
|
|
@@ -210,39 +220,30 @@ export abstract class ResourceObject<
|
|
|
210
220
|
}
|
|
211
221
|
}
|
|
212
222
|
|
|
223
|
+
/**
|
|
224
|
+
* Calculate; empty implementation.
|
|
225
|
+
*/
|
|
213
226
|
protected async calculate() {}
|
|
214
227
|
|
|
215
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Calculations that use this resource.
|
|
230
|
+
* @throws if accessing calculations files failed
|
|
231
|
+
*/
|
|
216
232
|
protected async calculations(): Promise<string[]> {
|
|
217
233
|
const references: string[] = [];
|
|
218
234
|
const resourceName = resourceNameToString(this.resourceName);
|
|
219
|
-
for (const calculation of
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
? calculation.name
|
|
224
|
-
: calculation.name + '.lp';
|
|
225
|
-
const filename = join(calculation.path, basename(fileNameWithExtension));
|
|
226
|
-
try {
|
|
227
|
-
const content = await readFile(filename, 'utf-8');
|
|
228
|
-
if (content.includes(resourceName)) {
|
|
229
|
-
references.push(calculation.name);
|
|
230
|
-
}
|
|
231
|
-
} catch (error) {
|
|
232
|
-
// Skip files that don't exist (they may have been renamed or deleted)
|
|
233
|
-
if (hasCode(error) && error.code === 'ENOENT') {
|
|
234
|
-
this.logger.warn(`Skipping non-existent file: ${filename}`);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
throw new Error(
|
|
238
|
-
`Failed to process file ${filename}: ${(error as Error).message}`,
|
|
239
|
-
);
|
|
235
|
+
for (const calculation of this.project.resources.calculations()) {
|
|
236
|
+
const content = calculation.contentData();
|
|
237
|
+
if (content.calculation && content.calculation.includes(resourceName)) {
|
|
238
|
+
references.push(calculation.data!.name);
|
|
240
239
|
}
|
|
241
240
|
}
|
|
242
241
|
return references;
|
|
243
242
|
}
|
|
244
243
|
|
|
245
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Cards from project.
|
|
246
|
+
*/
|
|
246
247
|
protected cards(): Card[] {
|
|
247
248
|
return [
|
|
248
249
|
...this.project.cards(undefined),
|
|
@@ -264,9 +265,15 @@ export abstract class ResourceObject<
|
|
|
264
265
|
] as unknown as JSON;
|
|
265
266
|
}
|
|
266
267
|
|
|
267
|
-
|
|
268
|
+
/**
|
|
269
|
+
* Creates resource.
|
|
270
|
+
* @param newContent Content for resource.
|
|
271
|
+
* @throws when resource already exists in the project.
|
|
272
|
+
*/
|
|
268
273
|
protected async create(newContent?: T) {
|
|
269
|
-
|
|
274
|
+
this.validateResourceIdentifier();
|
|
275
|
+
|
|
276
|
+
if (this.exists()) {
|
|
270
277
|
throw new Error(
|
|
271
278
|
`Resource '${this.resourceName.identifier}' already exists in the project`,
|
|
272
279
|
);
|
|
@@ -279,13 +286,17 @@ export abstract class ResourceObject<
|
|
|
279
286
|
this.resourceFolder = this.project.paths.resourcePath(
|
|
280
287
|
this.resourceName.type as ResourceFolderType,
|
|
281
288
|
);
|
|
289
|
+
this.fileName = join(
|
|
290
|
+
this.resourceFolder,
|
|
291
|
+
this.resourceName.identifier + '.json',
|
|
292
|
+
);
|
|
282
293
|
}
|
|
283
294
|
|
|
284
295
|
const validator = await ResourceObject.getValidate();
|
|
285
296
|
const validName = validator.validResourceName(
|
|
286
297
|
this.resourceType(),
|
|
287
298
|
resourceNameToString(this.resourceName),
|
|
288
|
-
|
|
299
|
+
this.project.projectPrefixes(),
|
|
289
300
|
);
|
|
290
301
|
|
|
291
302
|
let validContent = {} as T;
|
|
@@ -300,19 +311,27 @@ export abstract class ResourceObject<
|
|
|
300
311
|
this.content = validContent;
|
|
301
312
|
await this.write();
|
|
302
313
|
|
|
303
|
-
|
|
304
|
-
this.project.
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
);
|
|
314
|
+
const resourceString = resourceNameToString(this.resourceName);
|
|
315
|
+
this.project.resources.add(resourceString, this);
|
|
316
|
+
|
|
317
|
+
// Log resource creation to migration log
|
|
318
|
+
await this.logResourceOperation('create');
|
|
308
319
|
}
|
|
309
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Gets a logger instance.
|
|
323
|
+
* @param loggerName
|
|
324
|
+
* @returns logger instance
|
|
325
|
+
*/
|
|
310
326
|
protected getLogger(loggerName: string): Logger {
|
|
311
327
|
return getChildLogger({
|
|
312
328
|
module: loggerName,
|
|
313
329
|
});
|
|
314
330
|
}
|
|
315
331
|
|
|
332
|
+
/**
|
|
333
|
+
* Returns type of this resource.
|
|
334
|
+
*/
|
|
316
335
|
protected get getType(): string {
|
|
317
336
|
return this.type;
|
|
318
337
|
}
|
|
@@ -323,6 +342,7 @@ export abstract class ResourceObject<
|
|
|
323
342
|
* @param arrayName Name of the array, for error messages.
|
|
324
343
|
* @param array Array to be updated.
|
|
325
344
|
* @returns Changed array after the operation.
|
|
345
|
+
* @throws when operation cannot be done.
|
|
326
346
|
*/
|
|
327
347
|
protected handleArray<Type>(
|
|
328
348
|
operation: Operation<Type>,
|
|
@@ -347,6 +367,7 @@ export abstract class ResourceObject<
|
|
|
347
367
|
* Updates scalar value. The only accepted operation is 'change'
|
|
348
368
|
* @param operation Operation to perform on scalar.
|
|
349
369
|
* @returns What the scalar should be changed to.
|
|
370
|
+
* @throws when operation cannot be done
|
|
350
371
|
*/
|
|
351
372
|
protected handleScalar<Type>(operation: Operation<Type>): Type {
|
|
352
373
|
if (
|
|
@@ -359,7 +380,9 @@ export abstract class ResourceObject<
|
|
|
359
380
|
return operation.to;
|
|
360
381
|
}
|
|
361
382
|
|
|
362
|
-
|
|
383
|
+
/**
|
|
384
|
+
* Initialize the resource.
|
|
385
|
+
*/
|
|
363
386
|
protected initialize() {
|
|
364
387
|
if (this.resourceName.type === '') {
|
|
365
388
|
this.resourceName.type = this.type;
|
|
@@ -379,26 +402,77 @@ export abstract class ResourceObject<
|
|
|
379
402
|
: this.project.paths.resourcePath(this.type);
|
|
380
403
|
this.fileName = resourceNameToPath(this.project, this.resourceName);
|
|
381
404
|
}
|
|
382
|
-
//
|
|
383
|
-
if (
|
|
384
|
-
this.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
405
|
+
// Only load content from disk if resource exists in the cache registry
|
|
406
|
+
if (
|
|
407
|
+
this.project.resources.exists(resourceNameToString(this.resourceName))
|
|
408
|
+
) {
|
|
409
|
+
try {
|
|
410
|
+
this.content = readJsonFileSync(this.fileName);
|
|
411
|
+
} catch {
|
|
412
|
+
this.logger.debug(
|
|
413
|
+
`Initializing resource '${resourceNameToString(this.resourceName)}' failed: failed to read file '${this.fileName}'`,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
388
416
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Log details
|
|
420
|
+
protected async logResourceOperation<Type>(
|
|
421
|
+
operationType: 'create' | 'delete' | 'update' | 'rename',
|
|
422
|
+
op?: Operation<Type>,
|
|
423
|
+
key?: string,
|
|
424
|
+
): Promise<void> {
|
|
425
|
+
let configOperation: ConfigurationOperation;
|
|
426
|
+
const target = resourceNameToString(this.resourceName);
|
|
427
|
+
const parameters: Record<string, unknown> = { type: this.type };
|
|
428
|
+
|
|
429
|
+
switch (operationType) {
|
|
430
|
+
case 'create':
|
|
431
|
+
configOperation = ConfigurationOperation.RESOURCE_CREATE;
|
|
432
|
+
break;
|
|
433
|
+
case 'delete':
|
|
434
|
+
configOperation = ConfigurationOperation.RESOURCE_DELETE;
|
|
435
|
+
break;
|
|
436
|
+
case 'update':
|
|
437
|
+
configOperation = ConfigurationOperation.RESOURCE_UPDATE;
|
|
438
|
+
if (op) {
|
|
439
|
+
parameters.operation = op.name;
|
|
440
|
+
}
|
|
441
|
+
if (key) {
|
|
442
|
+
parameters.key = key;
|
|
443
|
+
}
|
|
444
|
+
break;
|
|
445
|
+
case 'rename':
|
|
446
|
+
configOperation = ConfigurationOperation.RESOURCE_RENAME;
|
|
447
|
+
if (op && op.name === 'change') {
|
|
448
|
+
const changeOp = op as ChangeOperation<string>;
|
|
449
|
+
parameters.oldName = changeOp.target;
|
|
450
|
+
parameters.newName = changeOp.to;
|
|
451
|
+
}
|
|
452
|
+
break;
|
|
453
|
+
default:
|
|
454
|
+
throw new Error(`Unknown operation type: ${operationType}`);
|
|
398
455
|
}
|
|
456
|
+
|
|
457
|
+
await ConfigurationLogger.log(
|
|
458
|
+
this.project.basePath,
|
|
459
|
+
configOperation,
|
|
460
|
+
target,
|
|
461
|
+
{
|
|
462
|
+
parameters,
|
|
463
|
+
},
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
this.logger.info(`Configuration: ${configOperation} - ${target}`);
|
|
399
467
|
}
|
|
400
468
|
|
|
401
|
-
|
|
469
|
+
/**
|
|
470
|
+
* Called after inherited class has finished 'update' operation.
|
|
471
|
+
* @param content New content for resource
|
|
472
|
+
* @param updateKey Which property to change
|
|
473
|
+
* @param op What kind of operation is performed to updateKey
|
|
474
|
+
* @throws if validation fails after the update
|
|
475
|
+
*/
|
|
402
476
|
protected async postUpdate<Type, K extends string>(
|
|
403
477
|
content: T,
|
|
404
478
|
updateKey: UpdateKey<K>,
|
|
@@ -433,38 +507,30 @@ export abstract class ResourceObject<
|
|
|
433
507
|
|
|
434
508
|
this.content = content;
|
|
435
509
|
await this.write();
|
|
436
|
-
}
|
|
437
510
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
key: UpdateKey<K>,
|
|
441
|
-
_op: Operation<Type>,
|
|
442
|
-
): Promise<void> {
|
|
443
|
-
const content = this.data;
|
|
444
|
-
if (!content) {
|
|
445
|
-
throw new Error(
|
|
446
|
-
`Resource '${resourceNameToString(this.resourceName)}' does not exist`,
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
if (this.moduleResource) {
|
|
450
|
-
throw new Error(`Cannot update module resources`);
|
|
451
|
-
}
|
|
452
|
-
if (key.key === '' || key === undefined) {
|
|
453
|
-
throw new Error(`Cannot update empty key`);
|
|
454
|
-
}
|
|
511
|
+
// Log resource update to migration log
|
|
512
|
+
await this.logResourceOperation('update', op, updateKey.key);
|
|
455
513
|
}
|
|
456
514
|
|
|
457
|
-
|
|
515
|
+
/**
|
|
516
|
+
* Reads content from file to memory.
|
|
517
|
+
*/
|
|
458
518
|
protected async read() {
|
|
459
519
|
this.content = await readJsonFile(this.fileName);
|
|
460
520
|
}
|
|
461
521
|
|
|
462
|
-
|
|
522
|
+
/**
|
|
523
|
+
* Renames resource.
|
|
524
|
+
* @param newName New name for the resource.
|
|
525
|
+
* @throws if trying to rename module resource, or
|
|
526
|
+
* if resource does not exist,
|
|
527
|
+
* if trying to rename so that type changes
|
|
528
|
+
*/
|
|
463
529
|
protected async rename(newName: ResourceName) {
|
|
464
530
|
if (this.moduleResource) {
|
|
465
531
|
throw new Error(`Cannot rename module resources`);
|
|
466
532
|
}
|
|
467
|
-
if (!
|
|
533
|
+
if (!this.exists()) {
|
|
468
534
|
throw new Error(
|
|
469
535
|
`Resource '${this.resourceName.identifier}' does not exist`,
|
|
470
536
|
);
|
|
@@ -479,25 +545,78 @@ export abstract class ResourceObject<
|
|
|
479
545
|
validator.validResourceName(
|
|
480
546
|
this.resourceType(),
|
|
481
547
|
resourceNameToString(newName),
|
|
482
|
-
|
|
548
|
+
this.project.projectPrefixes(),
|
|
483
549
|
);
|
|
484
550
|
const newFilename = join(
|
|
485
551
|
this.project.paths.resourcePath(newName.type as ResourceFolderType),
|
|
486
552
|
newName.identifier + '.json',
|
|
487
553
|
);
|
|
554
|
+
|
|
555
|
+
const oldName = resourceNameToString(this.resourceName);
|
|
488
556
|
await rename(this.fileName, newFilename);
|
|
489
557
|
|
|
490
|
-
this.cache.delete(resourceNameToString(this.resourceName));
|
|
491
558
|
this.fileName = newFilename;
|
|
492
559
|
this.content.name = resourceNameToString(newName);
|
|
560
|
+
const newNameString = this.content.name;
|
|
493
561
|
this.resourceName = newName;
|
|
494
|
-
|
|
562
|
+
|
|
563
|
+
this.project.resources.rename(oldName, newNameString);
|
|
564
|
+
|
|
565
|
+
// Log resource rename to migration log
|
|
566
|
+
await this.logResourceOperation('rename', {
|
|
567
|
+
name: 'change',
|
|
568
|
+
target: oldName,
|
|
569
|
+
to: newNameString,
|
|
570
|
+
} as ChangeOperation<string>);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Update resource; the base class makes some checks only.
|
|
575
|
+
* @template type Resource type
|
|
576
|
+
* @template K Resource key
|
|
577
|
+
* @throws if resource does not exist, or
|
|
578
|
+
* if trying to update module content, or
|
|
579
|
+
* if key is empty
|
|
580
|
+
*/
|
|
581
|
+
protected async update<Type, K extends string>(
|
|
582
|
+
key: UpdateKey<K>,
|
|
583
|
+
_op: Operation<Type>,
|
|
584
|
+
): Promise<void> {
|
|
585
|
+
const content = this.data;
|
|
586
|
+
if (!content) {
|
|
587
|
+
throw new Error(
|
|
588
|
+
`Resource '${resourceNameToString(this.resourceName)}' does not exist`,
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
if (this.moduleResource) {
|
|
592
|
+
throw new Error(`Cannot update module resources`);
|
|
593
|
+
}
|
|
594
|
+
if (key.key === '' || key === undefined) {
|
|
595
|
+
throw new Error(`Cannot update empty key`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/**
|
|
600
|
+
* Validates resource identifier to prevent filesystem operations with invalid names
|
|
601
|
+
* todo: To Validate?
|
|
602
|
+
*/
|
|
603
|
+
protected validateResourceIdentifier() {
|
|
604
|
+
if (!this.moduleResource && this.resourceName.identifier) {
|
|
605
|
+
const identifier = this.resourceName.identifier;
|
|
606
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(identifier)) {
|
|
607
|
+
throw new Error(
|
|
608
|
+
`Resource identifier must follow naming rules. Identifier '${identifier}' is invalid`,
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
495
612
|
}
|
|
496
613
|
|
|
497
614
|
/**
|
|
498
615
|
* Update calculation files.
|
|
499
616
|
* @param from Resource name to update
|
|
500
617
|
* @param to New name for resource
|
|
618
|
+
* @throws if 'from' or 'to' is empty string, or
|
|
619
|
+
* if there was error accessing calculation files.
|
|
501
620
|
*/
|
|
502
621
|
protected async updateCalculations(from: string, to: string) {
|
|
503
622
|
if (!from.trim() || !to.trim()) {
|
|
@@ -506,41 +625,16 @@ export abstract class ResourceObject<
|
|
|
506
625
|
);
|
|
507
626
|
}
|
|
508
627
|
|
|
509
|
-
const calculations =
|
|
628
|
+
const calculations = this.project.resources.calculations(
|
|
510
629
|
ResourcesFrom.localOnly,
|
|
511
630
|
);
|
|
512
631
|
|
|
513
632
|
await Promise.all(
|
|
514
633
|
calculations.map(async (calculation) => {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
const base = basename(calculation.name);
|
|
522
|
-
const fileNameWithExtension = base.endsWith('.lp')
|
|
523
|
-
? base
|
|
524
|
-
: base + '.lp';
|
|
525
|
-
const filename = join(calculation.path, fileNameWithExtension);
|
|
526
|
-
|
|
527
|
-
try {
|
|
528
|
-
const content = await readFile(filename, 'utf-8');
|
|
529
|
-
const updatedContent = content.replaceAll(from, to);
|
|
530
|
-
await writeFile(filename, updatedContent);
|
|
531
|
-
} catch (error) {
|
|
532
|
-
if (hasCode(error) && error.code === 'ENOENT') {
|
|
533
|
-
// Skip files that don't exist (they may have been renamed or deleted)
|
|
534
|
-
this.getLogger(this.getType).warn(
|
|
535
|
-
`Skipping non-existent file: ${filename}`,
|
|
536
|
-
);
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
if (error instanceof Error) {
|
|
540
|
-
throw new Error(
|
|
541
|
-
`Failed to process file while updating calculation ${filename}: ${error.message}`,
|
|
542
|
-
);
|
|
543
|
-
}
|
|
634
|
+
const content = calculation.contentData();
|
|
635
|
+
if (content.calculation) {
|
|
636
|
+
const updatedContent = content.calculation.replaceAll(from, to);
|
|
637
|
+
await calculation.updateFile('calculation.lp', updatedContent);
|
|
544
638
|
}
|
|
545
639
|
}),
|
|
546
640
|
);
|
|
@@ -551,6 +645,7 @@ export abstract class ResourceObject<
|
|
|
551
645
|
* @param from Resource name to update
|
|
552
646
|
* @param to New name for resource
|
|
553
647
|
* @param handleBarFiles Optional. List of handlebar files. If omitted, affects all handlebar files in the project.
|
|
648
|
+
* @throws if 'from' or 'to' is empty string
|
|
554
649
|
*/
|
|
555
650
|
protected async updateHandleBars(
|
|
556
651
|
from: string,
|
|
@@ -564,7 +659,7 @@ export abstract class ResourceObject<
|
|
|
564
659
|
}
|
|
565
660
|
|
|
566
661
|
if (!handleBarFiles) {
|
|
567
|
-
handleBarFiles = await this.
|
|
662
|
+
handleBarFiles = await this.reportHandlerBarFiles(
|
|
568
663
|
ResourcesFrom.localOnly,
|
|
569
664
|
);
|
|
570
665
|
}
|
|
@@ -579,10 +674,14 @@ export abstract class ResourceObject<
|
|
|
579
674
|
);
|
|
580
675
|
}
|
|
581
676
|
|
|
582
|
-
|
|
583
|
-
|
|
677
|
+
/**
|
|
678
|
+
* Check if there are references to the resource in the card content.
|
|
679
|
+
* @note that this needs to be async, since inherited classes need to async operations
|
|
680
|
+
* @param cards cards to check
|
|
681
|
+
* @throws if resource does not exist
|
|
682
|
+
*/
|
|
584
683
|
protected async usage(cards?: Card[]): Promise<string[]> {
|
|
585
|
-
if (!
|
|
684
|
+
if (!this.exists()) {
|
|
586
685
|
throw new Error(
|
|
587
686
|
`Resource '${this.resourceName.identifier}' does not exist in the project`,
|
|
588
687
|
);
|
|
@@ -596,17 +695,25 @@ export abstract class ResourceObject<
|
|
|
596
695
|
.map((card) => card.key);
|
|
597
696
|
}
|
|
598
697
|
|
|
698
|
+
/**
|
|
699
|
+
* Checks if resource name is valid.
|
|
700
|
+
* @param newName New name for resource.
|
|
701
|
+
* @returns valid name
|
|
702
|
+
*/
|
|
599
703
|
protected async validName(newName: ResourceName) {
|
|
600
704
|
const validator = await ResourceObject.getValidate();
|
|
601
705
|
const validName = validator.validResourceName(
|
|
602
706
|
this.resourceType(),
|
|
603
707
|
resourceNameToString(newName),
|
|
604
|
-
|
|
708
|
+
this.project.projectPrefixes(),
|
|
605
709
|
);
|
|
606
710
|
return validName;
|
|
607
711
|
}
|
|
608
712
|
|
|
609
|
-
|
|
713
|
+
/**
|
|
714
|
+
* Write the content from memory to disk.
|
|
715
|
+
* @throws if trying to write a module resource.
|
|
716
|
+
*/
|
|
610
717
|
protected async write() {
|
|
611
718
|
if (this.moduleResource) {
|
|
612
719
|
throw new Error(`Cannot change module resources`);
|
|
@@ -624,15 +731,16 @@ export abstract class ResourceObject<
|
|
|
624
731
|
// Check if "name" has changed. Changing "name" means renaming the file.
|
|
625
732
|
const nameInContent = resourceName(this.content.name).identifier + '.json';
|
|
626
733
|
const currentFileName = basename(this.fileName);
|
|
734
|
+
const resourceString = resourceNameToString(this.resourceName);
|
|
627
735
|
|
|
628
736
|
if (nameInContent !== currentFileName) {
|
|
629
737
|
const newFileName = join(this.resourceFolder, nameInContent);
|
|
630
738
|
await rename(this.fileName, newFileName);
|
|
631
739
|
this.fileName = newFileName;
|
|
740
|
+
this.resourceName = resourceName(this.content.name);
|
|
741
|
+
this.project.resources.rename(resourceString, this.content.name);
|
|
632
742
|
}
|
|
633
|
-
|
|
634
743
|
await writeJsonFile(this.fileName, this.content);
|
|
635
|
-
this.toCache();
|
|
636
744
|
}
|
|
637
745
|
|
|
638
746
|
/**
|
|
@@ -646,7 +754,9 @@ export abstract class ResourceObject<
|
|
|
646
754
|
|
|
647
755
|
/**
|
|
648
756
|
* Deletes the file and removes the resource from project.
|
|
649
|
-
* @throws if resource is a module resource or
|
|
757
|
+
* @throws if resource is a module resource, or
|
|
758
|
+
* if resource does not exist, or
|
|
759
|
+
* if resource is used by other resources.
|
|
650
760
|
*/
|
|
651
761
|
public async delete() {
|
|
652
762
|
if (this.moduleResource) {
|
|
@@ -657,7 +767,7 @@ export abstract class ResourceObject<
|
|
|
657
767
|
if (!this.fileName.endsWith('.json')) {
|
|
658
768
|
this.fileName += '.json';
|
|
659
769
|
}
|
|
660
|
-
if (!
|
|
770
|
+
if (!this.exists()) {
|
|
661
771
|
throw new Error(
|
|
662
772
|
`Resource '${this.resourceName.identifier}' does not exist in the project`,
|
|
663
773
|
);
|
|
@@ -669,13 +779,17 @@ export abstract class ResourceObject<
|
|
|
669
779
|
);
|
|
670
780
|
}
|
|
671
781
|
await deleteFile(this.fileName);
|
|
672
|
-
this.project.
|
|
782
|
+
this.project.resources.remove(resourceNameToString(this.resourceName));
|
|
673
783
|
this.fileName = '';
|
|
784
|
+
|
|
785
|
+
// Log resource deletion to migration log
|
|
786
|
+
await this.logResourceOperation('delete');
|
|
674
787
|
}
|
|
675
788
|
|
|
676
789
|
/**
|
|
677
790
|
* Validates the content of the resource.
|
|
678
791
|
* @param content Content to be validated.
|
|
792
|
+
* @throws if content is invalid.
|
|
679
793
|
*/
|
|
680
794
|
public async validate(content?: object) {
|
|
681
795
|
const validator = await ResourceObject.getValidate();
|