@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.
- 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 +19 -3
- package/dist/command-handler.js.map +1 -1
- package/dist/command-manager.d.ts +24 -1
- package/dist/command-manager.js +27 -3
- 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/import.d.ts +9 -1
- package/dist/commands/import.js +15 -7
- 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 +8 -1
- package/dist/commands/remove.js +8 -4
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/rename.d.ts +4 -9
- package/dist/commands/rename.js +32 -101
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/show.d.ts +16 -10
- package/dist/commands/show.js +71 -55
- 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 +96 -35
- package/dist/commands/validate.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 +5 -4
- package/dist/containers/project/project-paths.js +16 -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 +507 -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 +38 -153
- package/dist/containers/project.js +129 -405
- package/dist/containers/project.js.map +1 -1
- package/dist/containers/template.d.ts +8 -2
- package/dist/containers/template.js +20 -15
- package/dist/containers/template.js.map +1 -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 +2 -4
- 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 +16 -3
- package/dist/project-settings.js +79 -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 +93 -8
- package/dist/resources/resource-object.js +162 -110
- 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/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 +8 -8
- package/src/card-metadata-updater.ts +6 -2
- package/src/command-handler.ts +24 -5
- package/src/command-manager.ts +29 -17
- package/src/commands/create.ts +43 -78
- package/src/commands/export.ts +63 -52
- package/src/commands/import.ts +24 -14
- package/src/commands/move.ts +0 -1
- package/src/commands/remove.ts +11 -7
- package/src/commands/rename.ts +43 -149
- package/src/commands/show.ts +113 -78
- package/src/commands/transition.ts +26 -28
- package/src/commands/update.ts +25 -22
- package/src/commands/validate.ts +108 -67
- package/src/containers/project/calculation-engine.ts +61 -93
- package/src/containers/project/project-paths.ts +21 -13
- package/src/containers/project/resource-cache.ts +648 -0
- package/src/containers/project/resource-handler.ts +265 -0
- package/src/containers/project.ts +178 -522
- package/src/containers/template.ts +24 -19
- package/src/interfaces/folder-content-interfaces.ts +7 -6
- package/src/interfaces/project-interfaces.ts +7 -6
- 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 +83 -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 +194 -152
- 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/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,38 @@
|
|
|
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';
|
|
35
|
-
import {
|
|
36
|
-
resourceName,
|
|
37
|
-
resourceNameToPath,
|
|
38
|
-
resourceNameToString,
|
|
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
46
|
|
|
49
47
|
// Possible operations to perform when doing "update"
|
|
50
48
|
export type UpdateOperations = 'add' | 'change' | 'rank' | 'remove';
|
|
51
|
-
//| 'elementTypeChange';
|
|
52
49
|
|
|
53
50
|
// Base class for update operations.
|
|
54
51
|
type BaseOperation<T> = {
|
|
@@ -117,7 +114,7 @@ export abstract class AbstractResource<
|
|
|
117
114
|
protected abstract delete(): Promise<void>; // delete from disk
|
|
118
115
|
protected abstract read(): Promise<void>; // read content from disk (replaces existing content, if any)
|
|
119
116
|
protected abstract rename(newName: ResourceName): Promise<void>; // change name of the resource and filename; same as update('name', ...)
|
|
120
|
-
protected abstract show():
|
|
117
|
+
protected abstract show(): ShowReturnType<T, U>; // return the content as JSON
|
|
121
118
|
protected abstract update<Type, K extends string>(
|
|
122
119
|
updateKey: UpdateKey<K>,
|
|
123
120
|
operation: Operation<Type>,
|
|
@@ -136,8 +133,6 @@ export abstract class ResourceObject<
|
|
|
136
133
|
T extends ResourceBaseMetadata,
|
|
137
134
|
U,
|
|
138
135
|
> 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
136
|
private static validateInstancePromise?: Promise<ValidateInstance>;
|
|
142
137
|
|
|
143
138
|
protected content: T;
|
|
@@ -153,6 +148,12 @@ export abstract class ResourceObject<
|
|
|
153
148
|
*/
|
|
154
149
|
public fileName: string = '';
|
|
155
150
|
|
|
151
|
+
/**
|
|
152
|
+
* Constructs a ResourceObject instance
|
|
153
|
+
* @param project Project where this resource is
|
|
154
|
+
* @param resourceName Name for the resource
|
|
155
|
+
* @param type Type of resource
|
|
156
|
+
*/
|
|
156
157
|
constructor(
|
|
157
158
|
protected project: Project,
|
|
158
159
|
protected resourceName: ResourceName,
|
|
@@ -161,12 +162,19 @@ export abstract class ResourceObject<
|
|
|
161
162
|
super();
|
|
162
163
|
this.moduleResource =
|
|
163
164
|
this.resourceName.prefix !== this.project.projectPrefix;
|
|
164
|
-
this.cache = this.project.resourceCache;
|
|
165
165
|
this.type = type;
|
|
166
166
|
this.logger = this.getLogger(this.getType);
|
|
167
167
|
this.content = { name: '' } as T; // not found if name is empty
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
// Check if resource already exists. First checks the cache, then filesystem.
|
|
171
|
+
private exists(): boolean {
|
|
172
|
+
const name = resourceNameToString(this.resourceName);
|
|
173
|
+
const existsInCache = this.project.resources.exists(name);
|
|
174
|
+
return existsInCache || pathExists(this.fileName);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Gets Validate command instance.
|
|
170
178
|
private static async getValidate(): Promise<ValidateInstance> {
|
|
171
179
|
// a bit hacky solution to avoid circular dependencies
|
|
172
180
|
if (!this.validateInstancePromise) {
|
|
@@ -177,11 +185,14 @@ export abstract class ResourceObject<
|
|
|
177
185
|
return this.validateInstancePromise;
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
// Gets handlebar files.
|
|
189
|
+
private async reportHandlerBarFiles(from: ResourcesFrom = ResourcesFrom.all) {
|
|
190
|
+
const reports = this.project.resources.reports(from);
|
|
191
|
+
const handleBarFiles: string[] = [];
|
|
192
|
+
for (const report of reports) {
|
|
193
|
+
handleBarFiles.push(...(await report.handleBarFiles()));
|
|
194
|
+
}
|
|
195
|
+
return handleBarFiles;
|
|
185
196
|
}
|
|
186
197
|
|
|
187
198
|
// Type of resource.
|
|
@@ -189,19 +200,13 @@ export abstract class ResourceObject<
|
|
|
189
200
|
return this.type;
|
|
190
201
|
}
|
|
191
202
|
|
|
192
|
-
private toCache() {
|
|
193
|
-
this.cache.set(
|
|
194
|
-
resourceNameToString(this.resourceName),
|
|
195
|
-
this.content as unknown as JSON,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
203
|
/**
|
|
200
|
-
* Checks if resource exists
|
|
204
|
+
* Checks if resource exists.
|
|
205
|
+
* This should only throw, if someone creates resources directly; ie. not through the cache
|
|
201
206
|
* @throws if resource does not exist
|
|
202
207
|
*/
|
|
203
208
|
protected assertResourceExists() {
|
|
204
|
-
if (!
|
|
209
|
+
if (!this.exists()) {
|
|
205
210
|
const resourceType = `${this.type[0].toUpperCase()}${this.type.slice(1, this.type.length - 1)}`;
|
|
206
211
|
const name = resourceNameToString(this.resourceName);
|
|
207
212
|
throw new Error(
|
|
@@ -210,39 +215,30 @@ export abstract class ResourceObject<
|
|
|
210
215
|
}
|
|
211
216
|
}
|
|
212
217
|
|
|
218
|
+
/**
|
|
219
|
+
* Calculate; empty implementation.
|
|
220
|
+
*/
|
|
213
221
|
protected async calculate() {}
|
|
214
222
|
|
|
215
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Calculations that use this resource.
|
|
225
|
+
* @throws if accessing calculations files failed
|
|
226
|
+
*/
|
|
216
227
|
protected async calculations(): Promise<string[]> {
|
|
217
228
|
const references: string[] = [];
|
|
218
229
|
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
|
-
);
|
|
230
|
+
for (const calculation of this.project.resources.calculations()) {
|
|
231
|
+
const content = calculation.contentData();
|
|
232
|
+
if (content.calculation && content.calculation.includes(resourceName)) {
|
|
233
|
+
references.push(calculation.data!.name);
|
|
240
234
|
}
|
|
241
235
|
}
|
|
242
236
|
return references;
|
|
243
237
|
}
|
|
244
238
|
|
|
245
|
-
|
|
239
|
+
/**
|
|
240
|
+
* Cards from project.
|
|
241
|
+
*/
|
|
246
242
|
protected cards(): Card[] {
|
|
247
243
|
return [
|
|
248
244
|
...this.project.cards(undefined),
|
|
@@ -264,9 +260,15 @@ export abstract class ResourceObject<
|
|
|
264
260
|
] as unknown as JSON;
|
|
265
261
|
}
|
|
266
262
|
|
|
267
|
-
|
|
263
|
+
/**
|
|
264
|
+
* Creates resource.
|
|
265
|
+
* @param newContent Content for resource.
|
|
266
|
+
* @throws when resource already exists in the project.
|
|
267
|
+
*/
|
|
268
268
|
protected async create(newContent?: T) {
|
|
269
|
-
|
|
269
|
+
this.validateResourceIdentifier();
|
|
270
|
+
|
|
271
|
+
if (this.exists()) {
|
|
270
272
|
throw new Error(
|
|
271
273
|
`Resource '${this.resourceName.identifier}' already exists in the project`,
|
|
272
274
|
);
|
|
@@ -279,13 +281,17 @@ export abstract class ResourceObject<
|
|
|
279
281
|
this.resourceFolder = this.project.paths.resourcePath(
|
|
280
282
|
this.resourceName.type as ResourceFolderType,
|
|
281
283
|
);
|
|
284
|
+
this.fileName = join(
|
|
285
|
+
this.resourceFolder,
|
|
286
|
+
this.resourceName.identifier + '.json',
|
|
287
|
+
);
|
|
282
288
|
}
|
|
283
289
|
|
|
284
290
|
const validator = await ResourceObject.getValidate();
|
|
285
291
|
const validName = validator.validResourceName(
|
|
286
292
|
this.resourceType(),
|
|
287
293
|
resourceNameToString(this.resourceName),
|
|
288
|
-
|
|
294
|
+
this.project.projectPrefixes(),
|
|
289
295
|
);
|
|
290
296
|
|
|
291
297
|
let validContent = {} as T;
|
|
@@ -300,19 +306,24 @@ export abstract class ResourceObject<
|
|
|
300
306
|
this.content = validContent;
|
|
301
307
|
await this.write();
|
|
302
308
|
|
|
303
|
-
|
|
304
|
-
this.project.
|
|
305
|
-
this.resourceObjectToResource(),
|
|
306
|
-
this.content as unknown as JSON,
|
|
307
|
-
);
|
|
309
|
+
const resourceString = resourceNameToString(this.resourceName);
|
|
310
|
+
this.project.resources.add(resourceString, this);
|
|
308
311
|
}
|
|
309
312
|
|
|
313
|
+
/**
|
|
314
|
+
* Gets a logger instance.
|
|
315
|
+
* @param loggerName
|
|
316
|
+
* @returns logger instance
|
|
317
|
+
*/
|
|
310
318
|
protected getLogger(loggerName: string): Logger {
|
|
311
319
|
return getChildLogger({
|
|
312
320
|
module: loggerName,
|
|
313
321
|
});
|
|
314
322
|
}
|
|
315
323
|
|
|
324
|
+
/**
|
|
325
|
+
* Returns type of this resource.
|
|
326
|
+
*/
|
|
316
327
|
protected get getType(): string {
|
|
317
328
|
return this.type;
|
|
318
329
|
}
|
|
@@ -323,6 +334,7 @@ export abstract class ResourceObject<
|
|
|
323
334
|
* @param arrayName Name of the array, for error messages.
|
|
324
335
|
* @param array Array to be updated.
|
|
325
336
|
* @returns Changed array after the operation.
|
|
337
|
+
* @throws when operation cannot be done.
|
|
326
338
|
*/
|
|
327
339
|
protected handleArray<Type>(
|
|
328
340
|
operation: Operation<Type>,
|
|
@@ -347,6 +359,7 @@ export abstract class ResourceObject<
|
|
|
347
359
|
* Updates scalar value. The only accepted operation is 'change'
|
|
348
360
|
* @param operation Operation to perform on scalar.
|
|
349
361
|
* @returns What the scalar should be changed to.
|
|
362
|
+
* @throws when operation cannot be done
|
|
350
363
|
*/
|
|
351
364
|
protected handleScalar<Type>(operation: Operation<Type>): Type {
|
|
352
365
|
if (
|
|
@@ -359,7 +372,9 @@ export abstract class ResourceObject<
|
|
|
359
372
|
return operation.to;
|
|
360
373
|
}
|
|
361
374
|
|
|
362
|
-
|
|
375
|
+
/**
|
|
376
|
+
* Initialize the resource.
|
|
377
|
+
*/
|
|
363
378
|
protected initialize() {
|
|
364
379
|
if (this.resourceName.type === '') {
|
|
365
380
|
this.resourceName.type = this.type;
|
|
@@ -379,26 +394,27 @@ export abstract class ResourceObject<
|
|
|
379
394
|
: this.project.paths.resourcePath(this.type);
|
|
380
395
|
this.fileName = resourceNameToPath(this.project, this.resourceName);
|
|
381
396
|
}
|
|
382
|
-
//
|
|
383
|
-
if (
|
|
384
|
-
this.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
} catch {
|
|
394
|
-
// do nothing, it is possible that file has not been created yet.
|
|
395
|
-
this.logger.info(
|
|
396
|
-
`Initializing resource '${resourceNameToString(this.resourceName)}' failed: failed to read file '${this.fileName}'`,
|
|
397
|
-
);
|
|
397
|
+
// Only load content from disk if resource exists in the cache registry
|
|
398
|
+
if (
|
|
399
|
+
this.project.resources.exists(resourceNameToString(this.resourceName))
|
|
400
|
+
) {
|
|
401
|
+
try {
|
|
402
|
+
this.content = readJsonFileSync(this.fileName);
|
|
403
|
+
} catch {
|
|
404
|
+
this.logger.debug(
|
|
405
|
+
`Initializing resource '${resourceNameToString(this.resourceName)}' failed: failed to read file '${this.fileName}'`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
398
408
|
}
|
|
399
409
|
}
|
|
400
410
|
|
|
401
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Called after inherited class has finished 'update' operation.
|
|
413
|
+
* @param content New content for resource
|
|
414
|
+
* @param updateKey Which property to change
|
|
415
|
+
* @param op What kind of operation is performed to updateKey
|
|
416
|
+
* @throws if validation fails after the update
|
|
417
|
+
*/
|
|
402
418
|
protected async postUpdate<Type, K extends string>(
|
|
403
419
|
content: T,
|
|
404
420
|
updateKey: UpdateKey<K>,
|
|
@@ -435,36 +451,25 @@ export abstract class ResourceObject<
|
|
|
435
451
|
await this.write();
|
|
436
452
|
}
|
|
437
453
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
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
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
// Reads content from file to memory.
|
|
454
|
+
/**
|
|
455
|
+
* Reads content from file to memory.
|
|
456
|
+
*/
|
|
458
457
|
protected async read() {
|
|
459
458
|
this.content = await readJsonFile(this.fileName);
|
|
460
459
|
}
|
|
461
460
|
|
|
462
|
-
|
|
461
|
+
/**
|
|
462
|
+
* Renames resource.
|
|
463
|
+
* @param newName New name for the resource.
|
|
464
|
+
* @throws if trying to rename module resource, or
|
|
465
|
+
* if resource does not exist,
|
|
466
|
+
* if trying to rename so that type changes
|
|
467
|
+
*/
|
|
463
468
|
protected async rename(newName: ResourceName) {
|
|
464
469
|
if (this.moduleResource) {
|
|
465
470
|
throw new Error(`Cannot rename module resources`);
|
|
466
471
|
}
|
|
467
|
-
if (!
|
|
472
|
+
if (!this.exists()) {
|
|
468
473
|
throw new Error(
|
|
469
474
|
`Resource '${this.resourceName.identifier}' does not exist`,
|
|
470
475
|
);
|
|
@@ -479,25 +484,70 @@ export abstract class ResourceObject<
|
|
|
479
484
|
validator.validResourceName(
|
|
480
485
|
this.resourceType(),
|
|
481
486
|
resourceNameToString(newName),
|
|
482
|
-
|
|
487
|
+
this.project.projectPrefixes(),
|
|
483
488
|
);
|
|
484
489
|
const newFilename = join(
|
|
485
490
|
this.project.paths.resourcePath(newName.type as ResourceFolderType),
|
|
486
491
|
newName.identifier + '.json',
|
|
487
492
|
);
|
|
493
|
+
|
|
494
|
+
const oldName = resourceNameToString(this.resourceName);
|
|
488
495
|
await rename(this.fileName, newFilename);
|
|
489
496
|
|
|
490
|
-
this.cache.delete(resourceNameToString(this.resourceName));
|
|
491
497
|
this.fileName = newFilename;
|
|
492
498
|
this.content.name = resourceNameToString(newName);
|
|
493
499
|
this.resourceName = newName;
|
|
494
|
-
|
|
500
|
+
|
|
501
|
+
this.project.resources.rename(oldName, this.content.name);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Update resource; the base class makes some checks only.
|
|
506
|
+
* @template type Resource type
|
|
507
|
+
* @template K Resource key
|
|
508
|
+
* @throws if resource does not exist, or
|
|
509
|
+
* if trying to update module content, or
|
|
510
|
+
* if key is empty
|
|
511
|
+
*/
|
|
512
|
+
protected async update<Type, K extends string>(
|
|
513
|
+
key: UpdateKey<K>,
|
|
514
|
+
_op: Operation<Type>,
|
|
515
|
+
): Promise<void> {
|
|
516
|
+
const content = this.data;
|
|
517
|
+
if (!content) {
|
|
518
|
+
throw new Error(
|
|
519
|
+
`Resource '${resourceNameToString(this.resourceName)}' does not exist`,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
if (this.moduleResource) {
|
|
523
|
+
throw new Error(`Cannot update module resources`);
|
|
524
|
+
}
|
|
525
|
+
if (key.key === '' || key === undefined) {
|
|
526
|
+
throw new Error(`Cannot update empty key`);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Validates resource identifier to prevent filesystem operations with invalid names
|
|
532
|
+
* todo: To Validate?
|
|
533
|
+
*/
|
|
534
|
+
protected validateResourceIdentifier() {
|
|
535
|
+
if (!this.moduleResource && this.resourceName.identifier) {
|
|
536
|
+
const identifier = this.resourceName.identifier;
|
|
537
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(identifier)) {
|
|
538
|
+
throw new Error(
|
|
539
|
+
`Resource identifier must follow naming rules. Identifier '${identifier}' is invalid`,
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
}
|
|
495
543
|
}
|
|
496
544
|
|
|
497
545
|
/**
|
|
498
546
|
* Update calculation files.
|
|
499
547
|
* @param from Resource name to update
|
|
500
548
|
* @param to New name for resource
|
|
549
|
+
* @throws if 'from' or 'to' is empty string, or
|
|
550
|
+
* if there was error accessing calculation files.
|
|
501
551
|
*/
|
|
502
552
|
protected async updateCalculations(from: string, to: string) {
|
|
503
553
|
if (!from.trim() || !to.trim()) {
|
|
@@ -506,41 +556,16 @@ export abstract class ResourceObject<
|
|
|
506
556
|
);
|
|
507
557
|
}
|
|
508
558
|
|
|
509
|
-
const calculations =
|
|
559
|
+
const calculations = this.project.resources.calculations(
|
|
510
560
|
ResourcesFrom.localOnly,
|
|
511
561
|
);
|
|
512
562
|
|
|
513
563
|
await Promise.all(
|
|
514
564
|
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
|
-
}
|
|
565
|
+
const content = calculation.contentData();
|
|
566
|
+
if (content.calculation) {
|
|
567
|
+
const updatedContent = content.calculation.replaceAll(from, to);
|
|
568
|
+
await calculation.updateFile('calculation.lp', updatedContent);
|
|
544
569
|
}
|
|
545
570
|
}),
|
|
546
571
|
);
|
|
@@ -551,6 +576,7 @@ export abstract class ResourceObject<
|
|
|
551
576
|
* @param from Resource name to update
|
|
552
577
|
* @param to New name for resource
|
|
553
578
|
* @param handleBarFiles Optional. List of handlebar files. If omitted, affects all handlebar files in the project.
|
|
579
|
+
* @throws if 'from' or 'to' is empty string
|
|
554
580
|
*/
|
|
555
581
|
protected async updateHandleBars(
|
|
556
582
|
from: string,
|
|
@@ -564,7 +590,7 @@ export abstract class ResourceObject<
|
|
|
564
590
|
}
|
|
565
591
|
|
|
566
592
|
if (!handleBarFiles) {
|
|
567
|
-
handleBarFiles = await this.
|
|
593
|
+
handleBarFiles = await this.reportHandlerBarFiles(
|
|
568
594
|
ResourcesFrom.localOnly,
|
|
569
595
|
);
|
|
570
596
|
}
|
|
@@ -579,10 +605,14 @@ export abstract class ResourceObject<
|
|
|
579
605
|
);
|
|
580
606
|
}
|
|
581
607
|
|
|
582
|
-
|
|
583
|
-
|
|
608
|
+
/**
|
|
609
|
+
* Check if there are references to the resource in the card content.
|
|
610
|
+
* @note that this needs to be async, since inherited classes need to async operations
|
|
611
|
+
* @param cards cards to check
|
|
612
|
+
* @throws if resource does not exist
|
|
613
|
+
*/
|
|
584
614
|
protected async usage(cards?: Card[]): Promise<string[]> {
|
|
585
|
-
if (!
|
|
615
|
+
if (!this.exists()) {
|
|
586
616
|
throw new Error(
|
|
587
617
|
`Resource '${this.resourceName.identifier}' does not exist in the project`,
|
|
588
618
|
);
|
|
@@ -596,17 +626,25 @@ export abstract class ResourceObject<
|
|
|
596
626
|
.map((card) => card.key);
|
|
597
627
|
}
|
|
598
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Checks if resource name is valid.
|
|
631
|
+
* @param newName New name for resource.
|
|
632
|
+
* @returns valid name
|
|
633
|
+
*/
|
|
599
634
|
protected async validName(newName: ResourceName) {
|
|
600
635
|
const validator = await ResourceObject.getValidate();
|
|
601
636
|
const validName = validator.validResourceName(
|
|
602
637
|
this.resourceType(),
|
|
603
638
|
resourceNameToString(newName),
|
|
604
|
-
|
|
639
|
+
this.project.projectPrefixes(),
|
|
605
640
|
);
|
|
606
641
|
return validName;
|
|
607
642
|
}
|
|
608
643
|
|
|
609
|
-
|
|
644
|
+
/**
|
|
645
|
+
* Write the content from memory to disk.
|
|
646
|
+
* @throws if trying to write a module resource.
|
|
647
|
+
*/
|
|
610
648
|
protected async write() {
|
|
611
649
|
if (this.moduleResource) {
|
|
612
650
|
throw new Error(`Cannot change module resources`);
|
|
@@ -624,15 +662,16 @@ export abstract class ResourceObject<
|
|
|
624
662
|
// Check if "name" has changed. Changing "name" means renaming the file.
|
|
625
663
|
const nameInContent = resourceName(this.content.name).identifier + '.json';
|
|
626
664
|
const currentFileName = basename(this.fileName);
|
|
665
|
+
const resourceString = resourceNameToString(this.resourceName);
|
|
627
666
|
|
|
628
667
|
if (nameInContent !== currentFileName) {
|
|
629
668
|
const newFileName = join(this.resourceFolder, nameInContent);
|
|
630
669
|
await rename(this.fileName, newFileName);
|
|
631
670
|
this.fileName = newFileName;
|
|
671
|
+
this.resourceName = resourceName(this.content.name);
|
|
672
|
+
this.project.resources.rename(resourceString, this.content.name);
|
|
632
673
|
}
|
|
633
|
-
|
|
634
674
|
await writeJsonFile(this.fileName, this.content);
|
|
635
|
-
this.toCache();
|
|
636
675
|
}
|
|
637
676
|
|
|
638
677
|
/**
|
|
@@ -646,7 +685,9 @@ export abstract class ResourceObject<
|
|
|
646
685
|
|
|
647
686
|
/**
|
|
648
687
|
* Deletes the file and removes the resource from project.
|
|
649
|
-
* @throws if resource is a module resource or
|
|
688
|
+
* @throws if resource is a module resource, or
|
|
689
|
+
* if resource does not exist, or
|
|
690
|
+
* if resource is used by other resources.
|
|
650
691
|
*/
|
|
651
692
|
public async delete() {
|
|
652
693
|
if (this.moduleResource) {
|
|
@@ -657,7 +698,7 @@ export abstract class ResourceObject<
|
|
|
657
698
|
if (!this.fileName.endsWith('.json')) {
|
|
658
699
|
this.fileName += '.json';
|
|
659
700
|
}
|
|
660
|
-
if (!
|
|
701
|
+
if (!this.exists()) {
|
|
661
702
|
throw new Error(
|
|
662
703
|
`Resource '${this.resourceName.identifier}' does not exist in the project`,
|
|
663
704
|
);
|
|
@@ -669,13 +710,14 @@ export abstract class ResourceObject<
|
|
|
669
710
|
);
|
|
670
711
|
}
|
|
671
712
|
await deleteFile(this.fileName);
|
|
672
|
-
this.project.
|
|
713
|
+
this.project.resources.remove(resourceNameToString(this.resourceName));
|
|
673
714
|
this.fileName = '';
|
|
674
715
|
}
|
|
675
716
|
|
|
676
717
|
/**
|
|
677
718
|
* Validates the content of the resource.
|
|
678
719
|
* @param content Content to be validated.
|
|
720
|
+
* @throws if content is invalid.
|
|
679
721
|
*/
|
|
680
722
|
public async validate(content?: object) {
|
|
681
723
|
const validator = await ResourceObject.getValidate();
|
|
@@ -14,25 +14,22 @@
|
|
|
14
14
|
import { dirname, join } from 'node:path';
|
|
15
15
|
import { mkdir } from 'node:fs/promises';
|
|
16
16
|
|
|
17
|
-
import
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from '
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} from './folder-resource.js';
|
|
17
|
+
import { DefaultContent } from './create-defaults.js';
|
|
18
|
+
import { FolderResource } from './folder-resource.js';
|
|
19
|
+
import { resourceNameToString } from '../utils/resource-utils.js';
|
|
20
|
+
import { sortCards } from '../utils/card-utils.js';
|
|
21
|
+
import { Template } from '../containers/template.js';
|
|
22
|
+
import { writeJsonFile } from '../utils/json.js';
|
|
23
|
+
|
|
24
|
+
import type { Card } from '../interfaces/project-interfaces.js';
|
|
25
|
+
import type { Operation } from './resource-object.js';
|
|
26
|
+
import type { Project } from '../containers/project.js';
|
|
27
|
+
import type { ResourceName } from '../utils/resource-utils.js';
|
|
29
28
|
import type {
|
|
30
29
|
TemplateConfiguration,
|
|
31
30
|
TemplateMetadata,
|
|
32
31
|
UpdateKey,
|
|
33
32
|
} from '../interfaces/resource-interfaces.js';
|
|
34
|
-
import { Template } from '../containers/template.js';
|
|
35
|
-
import { writeJsonFile } from '../utils/json.js';
|
|
36
33
|
|
|
37
34
|
/**
|
|
38
35
|
* Template resource class.
|
|
@@ -51,6 +48,7 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
51
48
|
this.cardsFolder = join(this.internalFolder, 'c');
|
|
52
49
|
|
|
53
50
|
// Each template resource contains a template card container (with template cards).
|
|
51
|
+
// todo: Fix Template constructor not to use Resource, but just this filename with path
|
|
54
52
|
this.cardContainer = new Template(this.project, {
|
|
55
53
|
name: resourceNameToString(this.resourceName),
|
|
56
54
|
path: dirname(this.fileName),
|
|
@@ -88,8 +86,11 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
88
86
|
|
|
89
87
|
/**
|
|
90
88
|
* Deletes file and folder that this resource is based on.
|
|
89
|
+
* Also removes template cards from the project's card cache.
|
|
91
90
|
*/
|
|
92
91
|
public async delete() {
|
|
92
|
+
const templateName = resourceNameToString(this.resourceName);
|
|
93
|
+
this.project.cardsCache.deleteCardsFromTemplate(templateName);
|
|
93
94
|
return super.delete();
|
|
94
95
|
}
|
|
95
96
|
|
|
@@ -107,8 +108,8 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
107
108
|
* Shows metadata of the resource.
|
|
108
109
|
* @returns template metadata.
|
|
109
110
|
*/
|
|
110
|
-
public
|
|
111
|
-
const templateMetadata =
|
|
111
|
+
public show(): TemplateConfiguration {
|
|
112
|
+
const templateMetadata = super.show();
|
|
112
113
|
const container = this.templateObject();
|
|
113
114
|
|
|
114
115
|
return {
|