@cyberismo/data-handler 0.0.18 → 0.0.19
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/command-handler.d.ts +2 -0
- package/dist/command-handler.js +26 -2
- package/dist/command-handler.js.map +1 -1
- package/dist/command-manager.d.ts +2 -0
- package/dist/command-manager.js +3 -0
- package/dist/command-manager.js.map +1 -1
- package/dist/commands/create.d.ts +3 -1
- package/dist/commands/create.js +10 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/migrate.d.ts +33 -0
- package/dist/commands/migrate.js +66 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/containers/project/card-cache.js +13 -1
- package/dist/containers/project/card-cache.js.map +1 -1
- package/dist/containers/project/project-paths.d.ts +1 -0
- package/dist/containers/project/project-paths.js +5 -2
- package/dist/containers/project/project-paths.js.map +1 -1
- package/dist/containers/project.d.ts +10 -0
- package/dist/containers/project.js +39 -2
- package/dist/containers/project.js.map +1 -1
- package/dist/containers/template.js +2 -0
- package/dist/containers/template.js.map +1 -1
- package/dist/interfaces/command-options.d.ts +6 -1
- package/dist/interfaces/project-interfaces.d.ts +4 -0
- package/dist/interfaces/project-interfaces.js.map +1 -1
- package/dist/migrations/index.d.ts +14 -0
- package/dist/migrations/index.js +14 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/migration-executor.d.ts +79 -0
- package/dist/migrations/migration-executor.js +312 -0
- package/dist/migrations/migration-executor.js.map +1 -0
- package/dist/migrations/migration-worker.d.ts +13 -0
- package/dist/migrations/migration-worker.js +156 -0
- package/dist/migrations/migration-worker.js.map +1 -0
- package/dist/migrations/worker-executor.d.ts +24 -0
- package/dist/migrations/worker-executor.js +157 -0
- package/dist/migrations/worker-executor.js.map +1 -0
- package/dist/project-settings.d.ts +2 -0
- package/dist/project-settings.js +7 -0
- package/dist/project-settings.js.map +1 -1
- package/dist/resources/calculation-resource.d.ts +9 -0
- package/dist/resources/calculation-resource.js +13 -2
- package/dist/resources/calculation-resource.js.map +1 -1
- package/dist/resources/card-type-resource.d.ts +7 -2
- package/dist/resources/card-type-resource.js +13 -13
- package/dist/resources/card-type-resource.js.map +1 -1
- package/dist/resources/field-type-resource.d.ts +5 -0
- package/dist/resources/field-type-resource.js +13 -7
- package/dist/resources/field-type-resource.js.map +1 -1
- package/dist/resources/file-resource.d.ts +13 -1
- package/dist/resources/file-resource.js +17 -8
- package/dist/resources/file-resource.js.map +1 -1
- package/dist/resources/graph-model-resource.d.ts +5 -0
- package/dist/resources/graph-model-resource.js +6 -0
- package/dist/resources/graph-model-resource.js.map +1 -1
- package/dist/resources/graph-view-resource.d.ts +5 -0
- package/dist/resources/graph-view-resource.js +6 -0
- package/dist/resources/graph-view-resource.js.map +1 -1
- package/dist/resources/link-type-resource.d.ts +6 -0
- package/dist/resources/link-type-resource.js +26 -0
- package/dist/resources/link-type-resource.js.map +1 -1
- package/dist/resources/report-resource.d.ts +6 -1
- package/dist/resources/report-resource.js +7 -1
- package/dist/resources/report-resource.js.map +1 -1
- package/dist/resources/resource-object.d.ts +22 -7
- package/dist/resources/resource-object.js +44 -15
- package/dist/resources/resource-object.js.map +1 -1
- package/dist/resources/template-resource.d.ts +5 -1
- package/dist/resources/template-resource.js +6 -1
- package/dist/resources/template-resource.js.map +1 -1
- package/dist/resources/workflow-resource.d.ts +6 -2
- package/dist/resources/workflow-resource.js +11 -6
- package/dist/resources/workflow-resource.js.map +1 -1
- package/dist/utils/card-utils.d.ts +1 -1
- package/dist/utils/common-utils.d.ts +8 -0
- package/dist/utils/common-utils.js +14 -0
- package/dist/utils/common-utils.js.map +1 -1
- package/dist/utils/file-utils.d.ts +15 -3
- package/dist/utils/file-utils.js +48 -9
- package/dist/utils/file-utils.js.map +1 -1
- package/dist/utils/json.js +2 -2
- package/dist/utils/json.js.map +1 -1
- package/package.json +5 -3
- package/src/command-handler.ts +38 -1
- package/src/command-manager.ts +3 -0
- package/src/commands/create.ts +11 -0
- package/src/commands/migrate.ts +88 -0
- package/src/containers/project/card-cache.ts +18 -1
- package/src/containers/project/project-paths.ts +6 -2
- package/src/containers/project.ts +66 -1
- package/src/containers/template.ts +5 -0
- package/src/interfaces/command-options.ts +8 -0
- package/src/interfaces/project-interfaces.ts +4 -0
- package/src/migrations/index.ts +20 -0
- package/src/migrations/migration-executor.ts +478 -0
- package/src/migrations/migration-worker.ts +190 -0
- package/src/migrations/worker-executor.ts +185 -0
- package/src/project-settings.ts +7 -0
- package/src/resources/calculation-resource.ts +13 -2
- package/src/resources/card-type-resource.ts +19 -14
- package/src/resources/field-type-resource.ts +18 -7
- package/src/resources/file-resource.ts +25 -8
- package/src/resources/graph-model-resource.ts +6 -0
- package/src/resources/graph-view-resource.ts +6 -0
- package/src/resources/link-type-resource.ts +34 -0
- package/src/resources/report-resource.ts +7 -1
- package/src/resources/resource-object.ts +57 -18
- package/src/resources/template-resource.ts +6 -1
- package/src/resources/workflow-resource.ts +17 -7
- package/src/utils/common-utils.ts +15 -0
- package/src/utils/file-utils.ts +56 -12
- package/src/utils/json.ts +2 -6
|
@@ -25,6 +25,11 @@ import type { ResourceName } from '../utils/resource-utils.js';
|
|
|
25
25
|
* Link Type resource class.
|
|
26
26
|
*/
|
|
27
27
|
export class LinkTypeResource extends FileResource<LinkType> {
|
|
28
|
+
/**
|
|
29
|
+
* Creates instance of LinkTypeResource
|
|
30
|
+
* @param project Project to use
|
|
31
|
+
* @param name Resource name
|
|
32
|
+
*/
|
|
28
33
|
constructor(project: Project, name: ResourceName) {
|
|
29
34
|
super(project, name, 'linkTypes');
|
|
30
35
|
|
|
@@ -32,6 +37,33 @@ export class LinkTypeResource extends FileResource<LinkType> {
|
|
|
32
37
|
this.contentSchema = super.contentSchemaContent(this.contentSchemaId);
|
|
33
38
|
}
|
|
34
39
|
|
|
40
|
+
// Update card metadata links when link type is renamed
|
|
41
|
+
private async updateCardLinks(from: string, to: string) {
|
|
42
|
+
const cards = await this.collectCards(
|
|
43
|
+
from,
|
|
44
|
+
(card, linkTypeName) =>
|
|
45
|
+
card.metadata?.links?.some((link) => link.linkType === linkTypeName) ??
|
|
46
|
+
false,
|
|
47
|
+
);
|
|
48
|
+
if (cards.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await Promise.all(
|
|
53
|
+
cards.map(async (card) => {
|
|
54
|
+
if (card.metadata?.links) {
|
|
55
|
+
card.metadata.links = card.metadata.links.map((link) => {
|
|
56
|
+
if (link.linkType === from) {
|
|
57
|
+
return { ...link, linkType: to };
|
|
58
|
+
}
|
|
59
|
+
return link;
|
|
60
|
+
});
|
|
61
|
+
await this.project.updateCardMetadata(card, card.metadata);
|
|
62
|
+
}
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
35
67
|
/**
|
|
36
68
|
* When resource name changes.
|
|
37
69
|
* @param existingName Current resource name.
|
|
@@ -52,6 +84,8 @@ export class LinkTypeResource extends FileResource<LinkType> {
|
|
|
52
84
|
await Promise.all([
|
|
53
85
|
super.updateHandleBars(existingName, this.content.name),
|
|
54
86
|
super.updateCalculations(existingName, this.content.name),
|
|
87
|
+
super.updateCardContentReferences(existingName, this.content.name),
|
|
88
|
+
this.updateCardLinks(existingName, this.content.name),
|
|
55
89
|
]);
|
|
56
90
|
// Finally, write updated content.
|
|
57
91
|
await this.write();
|
|
@@ -42,6 +42,11 @@ export class ReportResource extends FolderResource<
|
|
|
42
42
|
ReportMetadata,
|
|
43
43
|
ReportContent
|
|
44
44
|
> {
|
|
45
|
+
/**
|
|
46
|
+
* Creates instance of ReportResource
|
|
47
|
+
* @param project Project to use
|
|
48
|
+
* @param name Resource name
|
|
49
|
+
*/
|
|
45
50
|
constructor(project: Project, name: ResourceName) {
|
|
46
51
|
super(project, name, 'reports');
|
|
47
52
|
|
|
@@ -68,6 +73,7 @@ export class ReportResource extends FolderResource<
|
|
|
68
73
|
await this.handleBarFiles(),
|
|
69
74
|
),
|
|
70
75
|
super.updateCalculations(existingName, this.content.name),
|
|
76
|
+
super.updateCardContentReferences(existingName, this.content.name),
|
|
71
77
|
]);
|
|
72
78
|
// Finally, write updated content.
|
|
73
79
|
await this.write();
|
|
@@ -152,9 +158,9 @@ export class ReportResource extends FolderResource<
|
|
|
152
158
|
|
|
153
159
|
/**
|
|
154
160
|
* Validates report.
|
|
155
|
-
* @throws when there are validation errors.
|
|
156
161
|
* @param content Content to be validated.
|
|
157
162
|
* @note If content is not provided, base class validation will use resource's current content.
|
|
163
|
+
* @throws when there are validation errors.
|
|
158
164
|
*/
|
|
159
165
|
public async validate(content?: object) {
|
|
160
166
|
const resourceContent = this.contentData();
|
|
@@ -416,7 +416,13 @@ export abstract class ResourceObject<
|
|
|
416
416
|
}
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
|
|
419
|
+
/**
|
|
420
|
+
* Log to migration log resource change
|
|
421
|
+
* @param operationType Operation type
|
|
422
|
+
* @param op Details of operation
|
|
423
|
+
* @param key Which property has been changed
|
|
424
|
+
* @throws when operation type is unknown
|
|
425
|
+
*/
|
|
420
426
|
protected async logResourceOperation<Type>(
|
|
421
427
|
operationType: 'create' | 'delete' | 'update' | 'rename',
|
|
422
428
|
op?: Operation<Type>,
|
|
@@ -596,27 +602,11 @@ export abstract class ResourceObject<
|
|
|
596
602
|
}
|
|
597
603
|
}
|
|
598
604
|
|
|
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
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
605
|
/**
|
|
615
606
|
* Update calculation files.
|
|
616
607
|
* @param from Resource name to update
|
|
617
608
|
* @param to New name for resource
|
|
618
|
-
* @throws if 'from' or 'to' is empty string
|
|
619
|
-
* if there was error accessing calculation files.
|
|
609
|
+
* @throws if 'from' or 'to' is empty string
|
|
620
610
|
*/
|
|
621
611
|
protected async updateCalculations(from: string, to: string) {
|
|
622
612
|
if (!from.trim() || !to.trim()) {
|
|
@@ -674,6 +664,39 @@ export abstract class ResourceObject<
|
|
|
674
664
|
);
|
|
675
665
|
}
|
|
676
666
|
|
|
667
|
+
/**
|
|
668
|
+
* Update references in card content.
|
|
669
|
+
* Searches through all card content in the cache and replaces references to the old resource name.
|
|
670
|
+
* @param from Resource name to update
|
|
671
|
+
* @param to New name for resource
|
|
672
|
+
* @throws if 'from' or 'to' is empty string
|
|
673
|
+
*/
|
|
674
|
+
protected async updateCardContentReferences(from: string, to: string) {
|
|
675
|
+
if (!from.trim() || !to.trim()) {
|
|
676
|
+
throw new Error(
|
|
677
|
+
'updateCardContentReferences: "from" and "to" parameters must not be empty',
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const allCards = this.cards();
|
|
682
|
+
const cardsToUpdate = allCards.filter(
|
|
683
|
+
(card) => card.content && card.content.includes(from),
|
|
684
|
+
);
|
|
685
|
+
|
|
686
|
+
if (cardsToUpdate.length === 0) {
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
await Promise.all(
|
|
691
|
+
cardsToUpdate.map(async (card) => {
|
|
692
|
+
if (card.content) {
|
|
693
|
+
const updatedContent = card.content.replaceAll(from, to);
|
|
694
|
+
await this.project.updateCardContent(card.key, updatedContent);
|
|
695
|
+
}
|
|
696
|
+
}),
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
|
|
677
700
|
/**
|
|
678
701
|
* Check if there are references to the resource in the card content.
|
|
679
702
|
* @note that this needs to be async, since inherited classes need to async operations
|
|
@@ -695,6 +718,22 @@ export abstract class ResourceObject<
|
|
|
695
718
|
.map((card) => card.key);
|
|
696
719
|
}
|
|
697
720
|
|
|
721
|
+
/**
|
|
722
|
+
* Validates resource identifier to prevent filesystem operations with invalid names
|
|
723
|
+
* todo: move to Validate?
|
|
724
|
+
* @throws if identifier is incorrect
|
|
725
|
+
*/
|
|
726
|
+
protected validateResourceIdentifier() {
|
|
727
|
+
if (!this.moduleResource && this.resourceName.identifier) {
|
|
728
|
+
const identifier = this.resourceName.identifier;
|
|
729
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(identifier)) {
|
|
730
|
+
throw new Error(
|
|
731
|
+
`Resource identifier must follow naming rules. Identifier '${identifier}' is invalid`,
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
698
737
|
/**
|
|
699
738
|
* Checks if resource name is valid.
|
|
700
739
|
* @param newName New name for resource.
|
|
@@ -39,6 +39,11 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
39
39
|
private cardsFolder = '';
|
|
40
40
|
private cardsSchema = super.contentSchemaContent('cardBaseSchema');
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Creates an instance of TemplateResource
|
|
44
|
+
* @param project Project to use
|
|
45
|
+
* @param name Resource name
|
|
46
|
+
*/
|
|
42
47
|
constructor(project: Project, name: ResourceName) {
|
|
43
48
|
super(project, name, 'templates');
|
|
44
49
|
|
|
@@ -63,6 +68,7 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
63
68
|
await Promise.all([
|
|
64
69
|
super.updateHandleBars(existingName, this.content.name),
|
|
65
70
|
super.updateCalculations(existingName, this.content.name),
|
|
71
|
+
super.updateCardContentReferences(existingName, this.content.name),
|
|
66
72
|
]);
|
|
67
73
|
await this.write();
|
|
68
74
|
}
|
|
@@ -70,7 +76,6 @@ export class TemplateResource extends FolderResource<TemplateMetadata, never> {
|
|
|
70
76
|
/**
|
|
71
77
|
* Sets new metadata into the template object.
|
|
72
78
|
* @param newContent metadata content for the template.
|
|
73
|
-
* @throws if 'newContent' is not valid.
|
|
74
79
|
*/
|
|
75
80
|
public async create(newContent?: TemplateMetadata) {
|
|
76
81
|
if (!newContent) {
|
|
@@ -36,6 +36,11 @@ import type { ResourceName } from '../utils/resource-utils.js';
|
|
|
36
36
|
* Workflow resource class.
|
|
37
37
|
*/
|
|
38
38
|
export class WorkflowResource extends FileResource<Workflow> {
|
|
39
|
+
/**
|
|
40
|
+
* Creates an instance of WorkflowResource
|
|
41
|
+
* @param project Project to use
|
|
42
|
+
* @param name Resource name
|
|
43
|
+
*/
|
|
39
44
|
constructor(project: Project, name: ResourceName) {
|
|
40
45
|
super(project, name, 'workflows');
|
|
41
46
|
|
|
@@ -49,7 +54,12 @@ export class WorkflowResource extends FileResource<Workflow> {
|
|
|
49
54
|
const promises: Promise<Card[]>[] = [];
|
|
50
55
|
for (const cardType of cardTypes) {
|
|
51
56
|
if (cardType.data?.workflow === resourceNameToString(this.resourceName)) {
|
|
52
|
-
promises.push(
|
|
57
|
+
promises.push(
|
|
58
|
+
this.collectCards(
|
|
59
|
+
cardType.data.name,
|
|
60
|
+
(card, cardTypeName) => card.metadata?.cardType === cardTypeName,
|
|
61
|
+
),
|
|
62
|
+
);
|
|
53
63
|
}
|
|
54
64
|
}
|
|
55
65
|
return (await Promise.all(promises)).flat();
|
|
@@ -60,6 +70,7 @@ export class WorkflowResource extends FileResource<Workflow> {
|
|
|
60
70
|
await Promise.all([
|
|
61
71
|
super.updateHandleBars(existingName, this.content.name),
|
|
62
72
|
super.updateCalculations(existingName, this.content.name),
|
|
73
|
+
super.updateCardContentReferences(existingName, this.content.name),
|
|
63
74
|
this.updateCardTypes(existingName),
|
|
64
75
|
]);
|
|
65
76
|
// Finally, write updated content.
|
|
@@ -132,6 +143,11 @@ export class WorkflowResource extends FileResource<Workflow> {
|
|
|
132
143
|
}
|
|
133
144
|
}
|
|
134
145
|
|
|
146
|
+
// Check if operation is a string operation.
|
|
147
|
+
private isStringOperation(op: Operation<unknown>): op is Operation<string> {
|
|
148
|
+
return typeof op.target === 'string';
|
|
149
|
+
}
|
|
150
|
+
|
|
135
151
|
// Returns target name irregardless of the type
|
|
136
152
|
private targetName(op: Operation<WorkflowState | WorkflowTransition>) {
|
|
137
153
|
const name = op.target.name ? op.target.name : op.target;
|
|
@@ -168,11 +184,6 @@ export class WorkflowResource extends FileResource<Workflow> {
|
|
|
168
184
|
return op.to;
|
|
169
185
|
}
|
|
170
186
|
|
|
171
|
-
// Check if operation is a string operation.
|
|
172
|
-
private isStringOperation(op: Operation<unknown>): op is Operation<string> {
|
|
173
|
-
return typeof op.target === 'string';
|
|
174
|
-
}
|
|
175
|
-
|
|
176
187
|
// Update card states when state is changed
|
|
177
188
|
private async updateCardStates(oldState: string, newState: string) {
|
|
178
189
|
const cards = await this.collectCardsUsingWorkflow();
|
|
@@ -209,7 +220,6 @@ export class WorkflowResource extends FileResource<Workflow> {
|
|
|
209
220
|
/**
|
|
210
221
|
* Sets new metadata into the workflow object.
|
|
211
222
|
* @param newContent metadata content for the workflow.
|
|
212
|
-
* @throws if 'newContent' is not valid.
|
|
213
223
|
*/
|
|
214
224
|
public async create(newContent?: Workflow) {
|
|
215
225
|
if (!newContent) {
|
|
@@ -52,3 +52,18 @@ export function isBigInt(value: string): boolean {
|
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Removes the first occurrence of a value from an array.
|
|
58
|
+
* Modifies the array in place.
|
|
59
|
+
* @param array The array to modify
|
|
60
|
+
* @param value The value to remove
|
|
61
|
+
* @returns The modified array (same reference as input)
|
|
62
|
+
*/
|
|
63
|
+
export function removeValue<T>(array: T[], value: T): T[] {
|
|
64
|
+
const index = array.findIndex((element) => element === value);
|
|
65
|
+
if (index !== -1) {
|
|
66
|
+
array.splice(index, 1);
|
|
67
|
+
}
|
|
68
|
+
return array;
|
|
69
|
+
}
|
package/src/utils/file-utils.ts
CHANGED
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
mkdir,
|
|
18
18
|
readdir,
|
|
19
19
|
rm,
|
|
20
|
+
stat,
|
|
21
|
+
statfs,
|
|
20
22
|
unlink,
|
|
21
23
|
writeFile,
|
|
22
24
|
} from 'node:fs/promises';
|
|
@@ -25,19 +27,17 @@ import { dirname, join, sep } from 'node:path';
|
|
|
25
27
|
import { homedir } from 'node:os';
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
+
* Get available disk space for a given path.
|
|
31
|
+
* @param path Path to check
|
|
32
|
+
* @returns Available space in bytes
|
|
30
33
|
*/
|
|
31
|
-
export async function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
recursive: true,
|
|
39
|
-
});
|
|
40
|
-
return writeFile(filePath, data, options);
|
|
34
|
+
export async function availableSpace(path: string): Promise<number> {
|
|
35
|
+
try {
|
|
36
|
+
const stats = await statfs(path);
|
|
37
|
+
return stats.bavail * stats.bsize;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
throw new Error(`Failed to check available disk space: ${error}`);
|
|
40
|
+
}
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -87,6 +87,34 @@ export async function deleteFile(path: string): Promise<boolean> {
|
|
|
87
87
|
return true;
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Calculate the total size of a directory recursively.
|
|
92
|
+
* @param dirPath Path to directory
|
|
93
|
+
* @returns Size in bytes
|
|
94
|
+
*/
|
|
95
|
+
export async function folderSize(dirPath: string): Promise<number> {
|
|
96
|
+
let size = 0;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
100
|
+
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
const fullPath = join(dirPath, entry.name);
|
|
103
|
+
|
|
104
|
+
if (entry.isDirectory()) {
|
|
105
|
+
size += await folderSize(fullPath);
|
|
106
|
+
} else if (entry.isFile()) {
|
|
107
|
+
const stats = await stat(fullPath);
|
|
108
|
+
size += stats.size;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} catch {
|
|
112
|
+
// Ignore permission errors or missing directories
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return size;
|
|
116
|
+
}
|
|
117
|
+
|
|
90
118
|
/**
|
|
91
119
|
* Removes extension from filename.
|
|
92
120
|
* @param filename Filename
|
|
@@ -180,3 +208,19 @@ export function resolveTilde(filePath: string): string {
|
|
|
180
208
|
* Path separator RE.
|
|
181
209
|
*/
|
|
182
210
|
export const sepRegex = /[/\\]/;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Works like the writeFile method, but ensures that the directory exists
|
|
214
|
+
* There is only one difference: This method only supports a string as the filePath
|
|
215
|
+
*/
|
|
216
|
+
export async function writeFileSafe(
|
|
217
|
+
filePath: string,
|
|
218
|
+
data: Parameters<typeof writeFile>[1],
|
|
219
|
+
options?: Parameters<typeof writeFile>[2],
|
|
220
|
+
) {
|
|
221
|
+
const dir = dirname(filePath);
|
|
222
|
+
await mkdir(dir, {
|
|
223
|
+
recursive: true,
|
|
224
|
+
});
|
|
225
|
+
return writeFile(filePath, data, options);
|
|
226
|
+
}
|
package/src/utils/json.ts
CHANGED
|
@@ -28,9 +28,7 @@ export function readJsonFileSync(file: string) {
|
|
|
28
28
|
return returnValue;
|
|
29
29
|
} catch (error) {
|
|
30
30
|
if (error instanceof Error) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`Error while handling JSON file '${file}' : ${error.message}`,
|
|
33
|
-
);
|
|
31
|
+
throw new Error(`Invalid JSON in file '${file}': ${error.message}`);
|
|
34
32
|
}
|
|
35
33
|
}
|
|
36
34
|
}
|
|
@@ -47,9 +45,7 @@ export async function readJsonFile(file: string) {
|
|
|
47
45
|
return JSON.parse(raw);
|
|
48
46
|
} catch (error) {
|
|
49
47
|
if (error instanceof Error) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`Error while handling JSON file '${file}' : ${error.message}`,
|
|
52
|
-
);
|
|
48
|
+
throw new Error(`Invalid JSON in file '${file}': ${error.message}`);
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
}
|