@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
package/src/commands/create.ts
CHANGED
|
@@ -15,31 +15,18 @@
|
|
|
15
15
|
import { join, resolve } from 'node:path';
|
|
16
16
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
17
17
|
|
|
18
|
+
import { SCHEMA_VERSION } from '@cyberismo/assets';
|
|
18
19
|
import { errorFunction } from '../utils/error-utils.js';
|
|
19
20
|
import { Project } from '../containers/project.js';
|
|
20
|
-
import { Validate } from './
|
|
21
|
+
import { Validate } from './validate.js';
|
|
21
22
|
|
|
22
23
|
import { EMPTY_RANK, sortItems } from '../utils/lexorank.js';
|
|
23
24
|
import { isModulePath } from '../utils/card-utils.js';
|
|
24
|
-
import type {
|
|
25
|
-
DataType,
|
|
26
|
-
Link,
|
|
27
|
-
LinkType,
|
|
28
|
-
} from '../interfaces/resource-interfaces.js';
|
|
25
|
+
import type { DataType } from '../interfaces/resource-interfaces.js';
|
|
29
26
|
import type { Card, ProjectFile } from '../interfaces/project-interfaces.js';
|
|
30
27
|
import { resourceName, resourceNameToString } from '../utils/resource-utils.js';
|
|
31
28
|
import { writeJsonFile } from '../utils/json.js';
|
|
32
29
|
|
|
33
|
-
import { CalculationResource } from '../resources/calculation-resource.js';
|
|
34
|
-
import { CardTypeResource } from '../resources/card-type-resource.js';
|
|
35
|
-
import { FieldTypeResource } from '../resources/field-type-resource.js';
|
|
36
|
-
import { GraphModelResource } from '../resources/graph-model-resource.js';
|
|
37
|
-
import { GraphViewResource } from '../resources/graph-view-resource.js';
|
|
38
|
-
import { LinkTypeResource } from '../resources/link-type-resource.js';
|
|
39
|
-
import { ReportResource } from '../resources/report-resource.js';
|
|
40
|
-
import { TemplateResource } from '../resources/template-resource.js';
|
|
41
|
-
import { WorkflowResource } from '../resources/workflow-resource.js';
|
|
42
|
-
|
|
43
30
|
// todo: Is there a easy to way to make JSON schema into a TypeScript interface/type?
|
|
44
31
|
// Check this out: https://www.npmjs.com/package/json-schema-to-ts
|
|
45
32
|
|
|
@@ -58,6 +45,7 @@ export class Create {
|
|
|
58
45
|
{
|
|
59
46
|
path: '.cards/local',
|
|
60
47
|
content: {
|
|
48
|
+
schemaVersion: SCHEMA_VERSION,
|
|
61
49
|
cardKeyPrefix: '$PROJECT-PREFIX',
|
|
62
50
|
name: '$PROJECT-NAME',
|
|
63
51
|
modules: [],
|
|
@@ -107,9 +95,9 @@ export class Create {
|
|
|
107
95
|
if (cardTypeName === undefined) {
|
|
108
96
|
throw new Error(`Input validation error: card type cannot be empty`);
|
|
109
97
|
}
|
|
110
|
-
const templateResource =
|
|
111
|
-
|
|
112
|
-
|
|
98
|
+
const templateResource = this.project.resources.byType(
|
|
99
|
+
templateName,
|
|
100
|
+
'templates',
|
|
113
101
|
);
|
|
114
102
|
const templateObject = templateResource.templateObject();
|
|
115
103
|
const specificCard = card ? templateObject.findCard(card) : undefined;
|
|
@@ -181,11 +169,9 @@ export class Create {
|
|
|
181
169
|
* @param calculationName name for the calculation resource
|
|
182
170
|
*/
|
|
183
171
|
public async createCalculation(calculationName: string) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
188
|
-
await calculation.create();
|
|
172
|
+
return this.project.resources
|
|
173
|
+
.byType(calculationName, 'calculations')
|
|
174
|
+
.create();
|
|
189
175
|
}
|
|
190
176
|
|
|
191
177
|
/**
|
|
@@ -198,15 +184,15 @@ export class Create {
|
|
|
198
184
|
templateName: string,
|
|
199
185
|
parentCardKey?: string,
|
|
200
186
|
): Promise<Card[]> {
|
|
201
|
-
const templateResource =
|
|
202
|
-
|
|
203
|
-
|
|
187
|
+
const templateResource = this.project.resources.byType(
|
|
188
|
+
templateName,
|
|
189
|
+
'templates',
|
|
204
190
|
);
|
|
205
191
|
|
|
206
192
|
Validate.getInstance().validResourceName(
|
|
207
193
|
'templates',
|
|
208
194
|
resourceNameToString(resourceName(templateName)),
|
|
209
|
-
|
|
195
|
+
this.project.allModulePrefixes(),
|
|
210
196
|
);
|
|
211
197
|
|
|
212
198
|
await templateResource.validate();
|
|
@@ -236,12 +222,9 @@ export class Create {
|
|
|
236
222
|
* @param workflowName workflow name to use in the card type.
|
|
237
223
|
*/
|
|
238
224
|
public async createCardType(cardTypeName: string, workflowName: string) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
await cardType.createCardType(workflowName);
|
|
225
|
+
return this.project.resources
|
|
226
|
+
.byType(cardTypeName, 'cardTypes')
|
|
227
|
+
.createCardType(workflowName);
|
|
245
228
|
}
|
|
246
229
|
|
|
247
230
|
/**
|
|
@@ -250,11 +233,9 @@ export class Create {
|
|
|
250
233
|
* @param dataType data type for the field type
|
|
251
234
|
*/
|
|
252
235
|
public async createFieldType(fieldTypeName: string, dataType: DataType) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
);
|
|
257
|
-
await fieldType.createFieldType(dataType);
|
|
236
|
+
return this.project.resources
|
|
237
|
+
.byType(fieldTypeName, 'fieldTypes')
|
|
238
|
+
.createFieldType(dataType);
|
|
258
239
|
}
|
|
259
240
|
|
|
260
241
|
/**
|
|
@@ -262,23 +243,17 @@ export class Create {
|
|
|
262
243
|
* @param graphModelName name for the graph model.
|
|
263
244
|
*/
|
|
264
245
|
public async createGraphModel(graphModelName: string) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
);
|
|
269
|
-
await graphModel.create();
|
|
246
|
+
return this.project.resources
|
|
247
|
+
.byType(graphModelName, 'graphModels')
|
|
248
|
+
.create();
|
|
270
249
|
}
|
|
271
250
|
|
|
272
251
|
/**
|
|
273
252
|
* Creates a new graph view.
|
|
274
|
-
* @param
|
|
253
|
+
* @param graphViewName name for the graph view.
|
|
275
254
|
*/
|
|
276
255
|
public async createGraphView(graphViewName: string) {
|
|
277
|
-
|
|
278
|
-
this.project,
|
|
279
|
-
resourceName(graphViewName),
|
|
280
|
-
);
|
|
281
|
-
await graphView.create();
|
|
256
|
+
return this.project.resources.byType(graphViewName, 'graphViews').create();
|
|
282
257
|
}
|
|
283
258
|
|
|
284
259
|
/**
|
|
@@ -307,11 +282,7 @@ export class Create {
|
|
|
307
282
|
* @param linkTypeName name for the link type.
|
|
308
283
|
*/
|
|
309
284
|
public async createLinkType(linkTypeName: string) {
|
|
310
|
-
|
|
311
|
-
this.project,
|
|
312
|
-
resourceName(linkTypeName),
|
|
313
|
-
);
|
|
314
|
-
await linkType.create();
|
|
285
|
+
return this.project.resources.byType(linkTypeName, 'linkTypes').create();
|
|
315
286
|
}
|
|
316
287
|
|
|
317
288
|
/**
|
|
@@ -335,10 +306,9 @@ export class Create {
|
|
|
335
306
|
const card = this.project.findCard(cardKey);
|
|
336
307
|
const destinationCard = this.project.findCard(destinationCardKey);
|
|
337
308
|
// make sure the link type exists
|
|
338
|
-
const linkTypeObject = this.project.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
}
|
|
309
|
+
const linkTypeObject = this.project.resources
|
|
310
|
+
.byType(linkType, 'linkTypes')
|
|
311
|
+
.show();
|
|
342
312
|
|
|
343
313
|
// make sure that if linkDescription is not enabled, linkDescription is not provided
|
|
344
314
|
if (
|
|
@@ -387,7 +357,7 @@ export class Create {
|
|
|
387
357
|
);
|
|
388
358
|
}
|
|
389
359
|
|
|
390
|
-
const links
|
|
360
|
+
const links = card.metadata?.links || [];
|
|
391
361
|
links.push({
|
|
392
362
|
linkType,
|
|
393
363
|
cardKey: destinationCardKey,
|
|
@@ -416,6 +386,12 @@ export class Create {
|
|
|
416
386
|
|
|
417
387
|
const projectFolders: string[] = ['.cards/local', 'cardRoot'];
|
|
418
388
|
|
|
389
|
+
if (!Validate.validateFolder(projectPath)) {
|
|
390
|
+
throw new Error(
|
|
391
|
+
`Input validation error: folder name '${projectPath}' is invalid`,
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
419
395
|
if (
|
|
420
396
|
projectPrefix === undefined ||
|
|
421
397
|
projectPrefix.length < 3 ||
|
|
@@ -486,8 +462,7 @@ export class Create {
|
|
|
486
462
|
* @param name name of the report
|
|
487
463
|
*/
|
|
488
464
|
public async createReport(name: string) {
|
|
489
|
-
|
|
490
|
-
await report.createReport();
|
|
465
|
+
return this.project.resources.byType(name, 'reports').createReport();
|
|
491
466
|
}
|
|
492
467
|
|
|
493
468
|
/**
|
|
@@ -496,14 +471,9 @@ export class Create {
|
|
|
496
471
|
* @param templateContent JSON content for the template file.
|
|
497
472
|
*/
|
|
498
473
|
public async createTemplate(templateName: string, templateContent: string) {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
);
|
|
503
|
-
|
|
504
|
-
await template.create(
|
|
505
|
-
templateContent ? JSON.parse(templateContent) : undefined,
|
|
506
|
-
);
|
|
474
|
+
return this.project.resources
|
|
475
|
+
.byType(templateName, 'templates')
|
|
476
|
+
.create(templateContent ? JSON.parse(templateContent) : undefined);
|
|
507
477
|
}
|
|
508
478
|
|
|
509
479
|
/**
|
|
@@ -512,13 +482,8 @@ export class Create {
|
|
|
512
482
|
* @param workflowContent workflow content JSON
|
|
513
483
|
*/
|
|
514
484
|
public async createWorkflow(workflowName: string, workflowContent: string) {
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
await workflow.create(
|
|
521
|
-
workflowContent ? JSON.parse(workflowContent) : undefined,
|
|
522
|
-
);
|
|
485
|
+
return this.project.resources
|
|
486
|
+
.byType(workflowName, 'workflows')
|
|
487
|
+
.create(workflowContent ? JSON.parse(workflowContent) : undefined);
|
|
523
488
|
}
|
|
524
489
|
}
|
package/src/commands/export.ts
CHANGED
|
@@ -31,12 +31,20 @@ import { generateReportContent } from '../utils/report.js';
|
|
|
31
31
|
import { getStaticDirectoryPath, pdfReport } from '@cyberismo/assets';
|
|
32
32
|
import { Project } from '../containers/project.js';
|
|
33
33
|
import type { QueryResult } from '../types/queries.js';
|
|
34
|
-
import type { Show } from './
|
|
34
|
+
import type { Show } from './show.js';
|
|
35
35
|
import { sortItems } from '../utils/lexorank.js';
|
|
36
36
|
|
|
37
37
|
const attachmentFolder: string = 'a';
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Handles all export commands.
|
|
41
|
+
*/
|
|
39
42
|
export class Export {
|
|
43
|
+
/**
|
|
44
|
+
* Creates an instance of export.
|
|
45
|
+
* @param project Project to use
|
|
46
|
+
* @param showCmd Instance of Export command to use.
|
|
47
|
+
*/
|
|
40
48
|
constructor(
|
|
41
49
|
protected project: Project,
|
|
42
50
|
protected showCmd: Show,
|
|
@@ -97,6 +105,56 @@ export class Export {
|
|
|
97
105
|
return content;
|
|
98
106
|
}
|
|
99
107
|
|
|
108
|
+
// Runs Ascii Doctor converter --> to PDF
|
|
109
|
+
private async runAsciidoctorPdf(content: string): Promise<Buffer> {
|
|
110
|
+
const staticRootDir = await getStaticDirectoryPath();
|
|
111
|
+
const proc = spawn(
|
|
112
|
+
'asciidoctor-pdf',
|
|
113
|
+
[
|
|
114
|
+
'-a',
|
|
115
|
+
'pdf-theme=cyberismo',
|
|
116
|
+
'-a',
|
|
117
|
+
`pdf-themesdir=${join(staticRootDir, 'pdf-themes')}`,
|
|
118
|
+
'-a',
|
|
119
|
+
`pdf-fontsdir=${join(staticRootDir, 'pdf-themes', 'fonts')};GEM_FONTS_DIR`,
|
|
120
|
+
'-',
|
|
121
|
+
],
|
|
122
|
+
{
|
|
123
|
+
timeout: 100000,
|
|
124
|
+
shell: process.platform === 'win32',
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
proc.stdin.end(content);
|
|
128
|
+
const result = await new Promise<Buffer>((resolve, reject) => {
|
|
129
|
+
const chunks: Buffer[] = [];
|
|
130
|
+
proc.stdout.on('data', (chunk) => {
|
|
131
|
+
chunks.push(chunk);
|
|
132
|
+
});
|
|
133
|
+
proc.stderr.on('data', (chunk) => {
|
|
134
|
+
process.stderr.write(chunk);
|
|
135
|
+
});
|
|
136
|
+
proc.on('error', (error) => {
|
|
137
|
+
if ('code' in error && error.code === 'ENOENT') {
|
|
138
|
+
reject(
|
|
139
|
+
new Error(
|
|
140
|
+
'Asciidoctor-pdf not found. Please install asciidoctor-pdf to use this feature.',
|
|
141
|
+
),
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
reject(error);
|
|
145
|
+
});
|
|
146
|
+
proc.on('close', (code) => {
|
|
147
|
+
if (code === 0) {
|
|
148
|
+
resolve(Buffer.concat(chunks));
|
|
149
|
+
} else {
|
|
150
|
+
reject(new Error(`Asciidoctor-pdf failed with code ${code}`));
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Adds cards to an ADOC file as additional content.
|
|
100
158
|
private async toAdocFileAsContent(path: string, cards: Card[]) {
|
|
101
159
|
for (const card of cards) {
|
|
102
160
|
let fileContent = '';
|
|
@@ -108,9 +166,9 @@ export class Export {
|
|
|
108
166
|
}
|
|
109
167
|
|
|
110
168
|
if (card.metadata) {
|
|
111
|
-
const cardTypeForCard =
|
|
112
|
-
card.metadata?.cardType,
|
|
113
|
-
|
|
169
|
+
const cardTypeForCard = this.project.resources
|
|
170
|
+
.byType(card.metadata?.cardType, 'cardTypes')
|
|
171
|
+
.show();
|
|
114
172
|
const metaDataContent = this.metaToAdoc(card, cardTypeForCard);
|
|
115
173
|
fileContent += metaDataContent;
|
|
116
174
|
}
|
|
@@ -177,6 +235,7 @@ export class Export {
|
|
|
177
235
|
* Convert treeQueryResult object into a Card object and add content, metadata & attachments
|
|
178
236
|
* Handles card children recursively
|
|
179
237
|
* @param treeQueryResult tree query result object
|
|
238
|
+
* @returns Tree query result as a Card.
|
|
180
239
|
*/
|
|
181
240
|
protected async treeQueryResultToCard(
|
|
182
241
|
treeQueryResult: QueryResult<'tree'>,
|
|
@@ -218,54 +277,6 @@ export class Export {
|
|
|
218
277
|
return card;
|
|
219
278
|
}
|
|
220
279
|
|
|
221
|
-
private async runAsciidoctorPdf(content: string): Promise<Buffer> {
|
|
222
|
-
const staticRootDir = await getStaticDirectoryPath();
|
|
223
|
-
const proc = spawn(
|
|
224
|
-
'asciidoctor-pdf',
|
|
225
|
-
[
|
|
226
|
-
'-a',
|
|
227
|
-
'pdf-theme=cyberismo',
|
|
228
|
-
'-a',
|
|
229
|
-
`pdf-themesdir=${join(staticRootDir, 'pdf-themes')}`,
|
|
230
|
-
'-a',
|
|
231
|
-
`pdf-fontsdir=${join(staticRootDir, 'pdf-themes', 'fonts')};GEM_FONTS_DIR`,
|
|
232
|
-
'-',
|
|
233
|
-
],
|
|
234
|
-
{
|
|
235
|
-
timeout: 100000,
|
|
236
|
-
shell: process.platform === 'win32',
|
|
237
|
-
},
|
|
238
|
-
);
|
|
239
|
-
proc.stdin.end(content);
|
|
240
|
-
const result = await new Promise<Buffer>((resolve, reject) => {
|
|
241
|
-
const chunks: Buffer[] = [];
|
|
242
|
-
proc.stdout.on('data', (chunk) => {
|
|
243
|
-
chunks.push(chunk);
|
|
244
|
-
});
|
|
245
|
-
proc.stderr.on('data', (chunk) => {
|
|
246
|
-
process.stderr.write(chunk);
|
|
247
|
-
});
|
|
248
|
-
proc.on('error', (error) => {
|
|
249
|
-
if ('code' in error && error.code === 'ENOENT') {
|
|
250
|
-
reject(
|
|
251
|
-
new Error(
|
|
252
|
-
'Asciidoctor-pdf not found. Please install asciidoctor-pdf to use this feature.',
|
|
253
|
-
),
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
reject(error);
|
|
257
|
-
});
|
|
258
|
-
proc.on('close', (code) => {
|
|
259
|
-
if (code === 0) {
|
|
260
|
-
resolve(Buffer.concat(chunks));
|
|
261
|
-
} else {
|
|
262
|
-
reject(new Error(`Asciidoctor-pdf failed with code ${code}`));
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
});
|
|
266
|
-
return result;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
280
|
/**
|
|
270
281
|
* Exports the card(s) to pdf.
|
|
271
282
|
* @param destination Path to where the resulting file(s) will be created.
|
package/src/commands/fetch.ts
CHANGED
|
@@ -13,16 +13,28 @@
|
|
|
13
13
|
|
|
14
14
|
import { mkdir } from 'node:fs/promises';
|
|
15
15
|
import { resolve, sep } from 'node:path';
|
|
16
|
-
import type { Project } from '../containers/project.js';
|
|
17
16
|
|
|
18
|
-
import { writeJsonFile } from '../utils/json.js';
|
|
19
|
-
import { validateJson } from '../utils/validate.js';
|
|
20
|
-
import { type ModuleSetting } from '../interfaces/project-interfaces.js';
|
|
21
|
-
import { errorFunction } from '../utils/error-utils.js';
|
|
22
17
|
import { getChildLogger } from '../utils/log-utils.js';
|
|
18
|
+
import { readJsonFile, writeJsonFile } from '../utils/json.js';
|
|
19
|
+
import { validateJson } from '../utils/validate.js';
|
|
20
|
+
|
|
21
|
+
import type { ModuleSetting } from '../interfaces/project-interfaces.js';
|
|
22
|
+
import type { Project } from '../containers/project.js';
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
// Hub structure
|
|
25
|
+
interface HubVersionInfo {
|
|
26
|
+
location: string;
|
|
27
|
+
version: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Structure of .temp/moduleList.json file.
|
|
31
|
+
interface ModuleListFile {
|
|
32
|
+
modules: ModuleSetting[];
|
|
33
|
+
hubs: HubVersionInfo[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const FETCH_TIMEOUT_MS = 30 * 1000; // 30s timeout for fetching a hub file.
|
|
37
|
+
const MAX_RESPONSE_SIZE_MB = 1024 * 1024; // 1MB limit for safety
|
|
26
38
|
const HUB_SCHEMA = 'hubSchema';
|
|
27
39
|
const MODULE_LIST_FILE = 'moduleList.json';
|
|
28
40
|
const TEMP_FOLDER = `.temp`;
|
|
@@ -30,7 +42,10 @@ const TEMP_FOLDER = `.temp`;
|
|
|
30
42
|
export const MODULE_LIST_FULL_PATH = `${TEMP_FOLDER}/${MODULE_LIST_FILE}`;
|
|
31
43
|
|
|
32
44
|
export class Fetch {
|
|
33
|
-
|
|
45
|
+
private moduleListPath;
|
|
46
|
+
constructor(private project: Project) {
|
|
47
|
+
this.moduleListPath = resolve(this.project.basePath, MODULE_LIST_FULL_PATH);
|
|
48
|
+
}
|
|
34
49
|
|
|
35
50
|
private get logger() {
|
|
36
51
|
return getChildLogger({
|
|
@@ -38,6 +53,38 @@ export class Fetch {
|
|
|
38
53
|
});
|
|
39
54
|
}
|
|
40
55
|
|
|
56
|
+
// Checks the version of the remote moduleList.json.
|
|
57
|
+
private async checkRemoteVersion(
|
|
58
|
+
location: string,
|
|
59
|
+
): Promise<number | undefined> {
|
|
60
|
+
try {
|
|
61
|
+
const url = new URL(`${location}/${MODULE_LIST_FILE}`);
|
|
62
|
+
if (!['http:', 'https:'].includes(url.protocol)) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const response = await fetch(url.toString(), {
|
|
67
|
+
method: 'GET',
|
|
68
|
+
headers: {
|
|
69
|
+
Accept: 'application/json',
|
|
70
|
+
'User-Agent': 'Cyberismo/1.0',
|
|
71
|
+
},
|
|
72
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const json = await response.json();
|
|
80
|
+
return json.version;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.logger.error(error, `Could not check hub version for ${location} }`);
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Fetches one hub's data as JSON.
|
|
41
88
|
private async fetchJSON(location: string, schemaId: string) {
|
|
42
89
|
try {
|
|
43
90
|
const url = new URL(`${location}/${MODULE_LIST_FILE}`);
|
|
@@ -47,14 +94,14 @@ export class Fetch {
|
|
|
47
94
|
);
|
|
48
95
|
}
|
|
49
96
|
|
|
50
|
-
this.logger.info(`Fetching module list from: ${url.toString()}`);
|
|
97
|
+
this.logger.info(`Fetching module list from hub: ${url.toString()}`);
|
|
51
98
|
const response = await fetch(url.toString(), {
|
|
52
99
|
method: 'GET',
|
|
53
100
|
headers: {
|
|
54
101
|
Accept: 'application/json',
|
|
55
102
|
'User-Agent': 'Cyberismo/1.0',
|
|
56
103
|
},
|
|
57
|
-
signal: AbortSignal.timeout(
|
|
104
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
58
105
|
});
|
|
59
106
|
|
|
60
107
|
if (!response.ok) {
|
|
@@ -65,9 +112,9 @@ export class Fetch {
|
|
|
65
112
|
|
|
66
113
|
// Check content length before downloading
|
|
67
114
|
const contentLength = response.headers.get('content-length');
|
|
68
|
-
if (contentLength && parseInt(contentLength) >
|
|
115
|
+
if (contentLength && parseInt(contentLength) > MAX_RESPONSE_SIZE_MB) {
|
|
69
116
|
throw new Error(
|
|
70
|
-
`Response too large: ${contentLength} bytes (max: ${
|
|
117
|
+
`Response too large: ${contentLength} bytes (max: ${MAX_RESPONSE_SIZE_MB})`,
|
|
71
118
|
);
|
|
72
119
|
}
|
|
73
120
|
|
|
@@ -79,14 +126,10 @@ export class Fetch {
|
|
|
79
126
|
const json = await response.json();
|
|
80
127
|
// Validate the incoming JSON before saving it into a file.
|
|
81
128
|
await validateJson(json, { schemaId: schemaId });
|
|
82
|
-
|
|
83
|
-
// Validate JSON structure and prevent prototype pollution
|
|
84
129
|
if (typeof json !== 'object' || json === null || Array.isArray(json)) {
|
|
85
130
|
throw new Error('Response must be a JSON object');
|
|
86
131
|
}
|
|
87
|
-
|
|
88
|
-
// Additional size check after JSON parsing
|
|
89
|
-
if (JSON.stringify(json).length > MAX_RESPONSE_SIZE) {
|
|
132
|
+
if (JSON.stringify(json).length > MAX_RESPONSE_SIZE_MB) {
|
|
90
133
|
throw new Error('JSON content too large after parsing');
|
|
91
134
|
}
|
|
92
135
|
|
|
@@ -94,41 +137,109 @@ export class Fetch {
|
|
|
94
137
|
} catch (error) {
|
|
95
138
|
this.logger.error(
|
|
96
139
|
error,
|
|
97
|
-
`Failed to fetch module list from ${location}
|
|
140
|
+
`Failed to fetch module list from hub ${location}`,
|
|
98
141
|
);
|
|
99
142
|
throw error;
|
|
100
143
|
}
|
|
101
144
|
}
|
|
102
145
|
|
|
146
|
+
// Checks if the local moduleList.json needs to be updated by comparing
|
|
147
|
+
// each hub's version with the stored version.
|
|
148
|
+
private async fetchModuleList(): Promise<boolean> {
|
|
149
|
+
try {
|
|
150
|
+
const configuredHubs = this.project.configuration.hubs;
|
|
151
|
+
if (configuredHubs.length === 0) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const localData = (await readJsonFile(
|
|
156
|
+
this.moduleListPath,
|
|
157
|
+
)) as ModuleListFile;
|
|
158
|
+
const localHubs = localData.hubs || [];
|
|
159
|
+
if (localHubs.length !== configuredHubs.length) {
|
|
160
|
+
this.logger.info('Hub configuration changed, fetching module list');
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Check each hub's version
|
|
165
|
+
for (const configHub of configuredHubs) {
|
|
166
|
+
const localHub = localHubs.find(
|
|
167
|
+
(hub) => hub.location === configHub.location,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (!localHub) {
|
|
171
|
+
this.logger.info(
|
|
172
|
+
`New hub detected: ${configHub.location}, fetching module list`,
|
|
173
|
+
);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const remoteVersion = await this.checkRemoteVersion(configHub.location);
|
|
178
|
+
if (remoteVersion === undefined) {
|
|
179
|
+
const hubName = configHub.displayName || configHub.location;
|
|
180
|
+
this.logger.info(`Hub ${hubName} has no version data, skipped.`);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (remoteVersion > localHub.version) {
|
|
185
|
+
this.logger.info(
|
|
186
|
+
`Hub ${configHub.location} has newer version (remote: ${remoteVersion}, local: ${localHub.version}), fetching module list`,
|
|
187
|
+
);
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.logger.info('Module list is up to date');
|
|
193
|
+
return false;
|
|
194
|
+
} catch (error) {
|
|
195
|
+
this.logger.error(
|
|
196
|
+
error,
|
|
197
|
+
`Error when checking versions for hub module list`,
|
|
198
|
+
);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Ensures the module list is up to date by fetching if needed.
|
|
205
|
+
*/
|
|
206
|
+
public async ensureModuleListUpToDate() {
|
|
207
|
+
await this.fetchHubs();
|
|
208
|
+
}
|
|
209
|
+
|
|
103
210
|
/**
|
|
104
211
|
* Fetches modules from modules hub(s) and writes them to a file.
|
|
212
|
+
* Only fetches if the remote version is newer than the local version.
|
|
105
213
|
*/
|
|
106
214
|
public async fetchHubs() {
|
|
107
|
-
const
|
|
215
|
+
const needsFetch = await this.fetchModuleList();
|
|
216
|
+
if (!needsFetch) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
108
219
|
|
|
220
|
+
const hubs = this.project.configuration.hubs;
|
|
109
221
|
const moduleMap: Map<string, ModuleSetting> = new Map([]);
|
|
222
|
+
const hubVersions: HubVersionInfo[] = [];
|
|
110
223
|
|
|
111
224
|
for (const hub of hubs) {
|
|
112
225
|
const json = await this.fetchJSON(hub.location, HUB_SCHEMA);
|
|
113
226
|
json.modules.forEach((module: ModuleSetting) => {
|
|
114
227
|
if (!moduleMap.has(module.name)) {
|
|
115
228
|
moduleMap.set(module.name, module);
|
|
116
|
-
} else {
|
|
117
|
-
this.logger.info(
|
|
118
|
-
`Skipping module '${module.name}' since it was already listed.`,
|
|
119
|
-
);
|
|
120
229
|
}
|
|
121
230
|
});
|
|
231
|
+
|
|
232
|
+
hubVersions.push({
|
|
233
|
+
location: hub.location,
|
|
234
|
+
version: json.version || 1,
|
|
235
|
+
});
|
|
122
236
|
}
|
|
123
237
|
|
|
124
238
|
try {
|
|
125
|
-
const fullPath = resolve(this.project.basePath, MODULE_LIST_FULL_PATH);
|
|
126
239
|
const normalizedBasePath = resolve(this.project.basePath);
|
|
127
|
-
|
|
128
|
-
// Ensure the file is written within the project directory (prevent path traversal)
|
|
129
240
|
if (
|
|
130
|
-
!
|
|
131
|
-
|
|
241
|
+
!this.moduleListPath.startsWith(normalizedBasePath + sep) &&
|
|
242
|
+
this.moduleListPath !== normalizedBasePath
|
|
132
243
|
) {
|
|
133
244
|
throw new Error(
|
|
134
245
|
'Invalid file path: attempting to write outside project directory',
|
|
@@ -138,15 +249,13 @@ export class Fetch {
|
|
|
138
249
|
await mkdir(resolve(this.project.basePath, TEMP_FOLDER), {
|
|
139
250
|
recursive: true,
|
|
140
251
|
});
|
|
141
|
-
await writeJsonFile(
|
|
252
|
+
await writeJsonFile(this.moduleListPath, {
|
|
142
253
|
modules: Array.from(moduleMap.values()),
|
|
254
|
+
hubs: hubVersions,
|
|
143
255
|
});
|
|
144
|
-
this.logger.info(`Module list written to: ${
|
|
256
|
+
this.logger.info(`Module list written to: ${this.moduleListPath}`);
|
|
145
257
|
} catch (error) {
|
|
146
|
-
this.logger.error(
|
|
147
|
-
error,
|
|
148
|
-
`Failed to write module list to local file: ${errorFunction(error)}`,
|
|
149
|
-
);
|
|
258
|
+
this.logger.error(error, `Failed to write module list to local file`);
|
|
150
259
|
throw error;
|
|
151
260
|
}
|
|
152
261
|
}
|