@cyberismo/data-handler 0.0.2
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/LICENSE +702 -0
- package/dist/card-metadata-updater.d.ts +33 -0
- package/dist/card-metadata-updater.js +121 -0
- package/dist/card-metadata-updater.js.map +1 -0
- package/dist/command-handler.d.ts +96 -0
- package/dist/command-handler.js +557 -0
- package/dist/command-handler.js.map +1 -0
- package/dist/command-manager.d.ts +43 -0
- package/dist/command-manager.js +73 -0
- package/dist/command-manager.js.map +1 -0
- package/dist/commands/calculate.d.ts +86 -0
- package/dist/commands/calculate.js +444 -0
- package/dist/commands/calculate.js.map +1 -0
- package/dist/commands/create.d.ts +114 -0
- package/dist/commands/create.js +389 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/edit.d.ts +37 -0
- package/dist/commands/edit.js +99 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/export-site.d.ts +45 -0
- package/dist/commands/export-site.js +301 -0
- package/dist/commands/export-site.js.map +1 -0
- package/dist/commands/export.d.ts +53 -0
- package/dist/commands/export.js +251 -0
- package/dist/commands/export.js.map +1 -0
- package/dist/commands/import.d.ts +53 -0
- package/dist/commands/import.js +133 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/index.d.ts +26 -0
- package/dist/commands/index.js +27 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/move.d.ts +55 -0
- package/dist/commands/move.js +341 -0
- package/dist/commands/move.js.map +1 -0
- package/dist/commands/remove.d.ts +38 -0
- package/dist/commands/remove.js +192 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/rename.d.ts +46 -0
- package/dist/commands/rename.js +289 -0
- package/dist/commands/rename.js.map +1 -0
- package/dist/commands/show.d.ts +124 -0
- package/dist/commands/show.js +345 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/transition.d.ts +27 -0
- package/dist/commands/transition.js +92 -0
- package/dist/commands/transition.js.map +1 -0
- package/dist/commands/update.d.ts +29 -0
- package/dist/commands/update.js +64 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +143 -0
- package/dist/commands/validate.js +689 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/containers/card-container.d.ts +44 -0
- package/dist/containers/card-container.js +282 -0
- package/dist/containers/card-container.js.map +1 -0
- package/dist/containers/project/project-paths.d.ts +46 -0
- package/dist/containers/project/project-paths.js +105 -0
- package/dist/containers/project/project-paths.js.map +1 -0
- package/dist/containers/project/resource-collector.d.ts +86 -0
- package/dist/containers/project/resource-collector.js +331 -0
- package/dist/containers/project/resource-collector.js.map +1 -0
- package/dist/containers/project.d.ts +351 -0
- package/dist/containers/project.js +896 -0
- package/dist/containers/project.js.map +1 -0
- package/dist/containers/template.d.ts +108 -0
- package/dist/containers/template.js +433 -0
- package/dist/containers/template.js.map +1 -0
- package/dist/exceptions/index.d.ts +19 -0
- package/dist/exceptions/index.js +26 -0
- package/dist/exceptions/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/adoc.d.ts +12 -0
- package/dist/interfaces/adoc.js +13 -0
- package/dist/interfaces/adoc.js.map +1 -0
- package/dist/interfaces/macros.d.ts +45 -0
- package/dist/interfaces/macros.js +13 -0
- package/dist/interfaces/macros.js.map +1 -0
- package/dist/interfaces/project-interfaces.d.ts +121 -0
- package/dist/interfaces/project-interfaces.js +21 -0
- package/dist/interfaces/project-interfaces.js.map +1 -0
- package/dist/interfaces/request-status-interfaces.d.ts +28 -0
- package/dist/interfaces/request-status-interfaces.js +20 -0
- package/dist/interfaces/request-status-interfaces.js.map +1 -0
- package/dist/interfaces/resource-interfaces.d.ts +117 -0
- package/dist/interfaces/resource-interfaces.js +20 -0
- package/dist/interfaces/resource-interfaces.js.map +1 -0
- package/dist/macros/base-macro.d.ts +31 -0
- package/dist/macros/base-macro.js +126 -0
- package/dist/macros/base-macro.js.map +1 -0
- package/dist/macros/common.d.ts +17 -0
- package/dist/macros/common.js +23 -0
- package/dist/macros/common.js.map +1 -0
- package/dist/macros/createCards/index.d.ts +36 -0
- package/dist/macros/createCards/index.js +35 -0
- package/dist/macros/createCards/index.js.map +1 -0
- package/dist/macros/createCards/metadata.d.ts +14 -0
- package/dist/macros/createCards/metadata.js +18 -0
- package/dist/macros/createCards/metadata.js.map +1 -0
- package/dist/macros/graph/index.d.ts +29 -0
- package/dist/macros/graph/index.js +91 -0
- package/dist/macros/graph/index.js.map +1 -0
- package/dist/macros/graph/metadata.d.ts +14 -0
- package/dist/macros/graph/metadata.js +18 -0
- package/dist/macros/graph/metadata.js.map +1 -0
- package/dist/macros/index.d.ts +93 -0
- package/dist/macros/index.js +237 -0
- package/dist/macros/index.js.map +1 -0
- package/dist/macros/report/index.d.ts +26 -0
- package/dist/macros/report/index.js +70 -0
- package/dist/macros/report/index.js.map +1 -0
- package/dist/macros/report/metadata.d.ts +14 -0
- package/dist/macros/report/metadata.js +18 -0
- package/dist/macros/report/metadata.js.map +1 -0
- package/dist/macros/scoreCard/index.d.ts +30 -0
- package/dist/macros/scoreCard/index.js +38 -0
- package/dist/macros/scoreCard/index.js.map +1 -0
- package/dist/macros/scoreCard/metadata.d.ts +14 -0
- package/dist/macros/scoreCard/metadata.js +18 -0
- package/dist/macros/scoreCard/metadata.js.map +1 -0
- package/dist/macros/task-queue.d.ts +46 -0
- package/dist/macros/task-queue.js +69 -0
- package/dist/macros/task-queue.js.map +1 -0
- package/dist/module-manager.d.ts +62 -0
- package/dist/module-manager.js +350 -0
- package/dist/module-manager.js.map +1 -0
- package/dist/permissions/action-guard.d.ts +28 -0
- package/dist/permissions/action-guard.js +61 -0
- package/dist/permissions/action-guard.js.map +1 -0
- package/dist/project-settings.d.ts +42 -0
- package/dist/project-settings.js +120 -0
- package/dist/project-settings.js.map +1 -0
- package/dist/resources/array-handler.d.ts +28 -0
- package/dist/resources/array-handler.js +116 -0
- package/dist/resources/array-handler.js.map +1 -0
- package/dist/resources/card-type-resource.d.ts +72 -0
- package/dist/resources/card-type-resource.js +334 -0
- package/dist/resources/card-type-resource.js.map +1 -0
- package/dist/resources/create-defaults.d.ts +81 -0
- package/dist/resources/create-defaults.js +184 -0
- package/dist/resources/create-defaults.js.map +1 -0
- package/dist/resources/field-type-resource.d.ts +88 -0
- package/dist/resources/field-type-resource.js +411 -0
- package/dist/resources/field-type-resource.js.map +1 -0
- package/dist/resources/file-resource.d.ts +50 -0
- package/dist/resources/file-resource.js +301 -0
- package/dist/resources/file-resource.js.map +1 -0
- package/dist/resources/folder-resource.d.ts +66 -0
- package/dist/resources/folder-resource.js +100 -0
- package/dist/resources/folder-resource.js.map +1 -0
- package/dist/resources/graph-model-resource.d.ts +78 -0
- package/dist/resources/graph-model-resource.js +164 -0
- package/dist/resources/graph-model-resource.js.map +1 -0
- package/dist/resources/graph-view-resource.d.ts +78 -0
- package/dist/resources/graph-view-resource.js +163 -0
- package/dist/resources/graph-view-resource.js.map +1 -0
- package/dist/resources/link-type-resource.d.ts +62 -0
- package/dist/resources/link-type-resource.js +150 -0
- package/dist/resources/link-type-resource.js.map +1 -0
- package/dist/resources/report-resource.d.ts +77 -0
- package/dist/resources/report-resource.js +171 -0
- package/dist/resources/report-resource.js.map +1 -0
- package/dist/resources/resource-object.d.ts +108 -0
- package/dist/resources/resource-object.js +147 -0
- package/dist/resources/resource-object.js.map +1 -0
- package/dist/resources/template-resource.d.ts +82 -0
- package/dist/resources/template-resource.js +173 -0
- package/dist/resources/template-resource.js.map +1 -0
- package/dist/resources/workflow-resource.d.ts +67 -0
- package/dist/resources/workflow-resource.js +156 -0
- package/dist/resources/workflow-resource.js.map +1 -0
- package/dist/types/queries.d.ts +142 -0
- package/dist/types/queries.js +16 -0
- package/dist/types/queries.js.map +1 -0
- package/dist/utils/card-utils.d.ts +34 -0
- package/dist/utils/card-utils.js +78 -0
- package/dist/utils/card-utils.js.map +1 -0
- package/dist/utils/clingo-fact-builder.d.ts +58 -0
- package/dist/utils/clingo-fact-builder.js +126 -0
- package/dist/utils/clingo-fact-builder.js.map +1 -0
- package/dist/utils/clingo-facts.d.ts +97 -0
- package/dist/utils/clingo-facts.js +352 -0
- package/dist/utils/clingo-facts.js.map +1 -0
- package/dist/utils/clingo-parser.d.ts +59 -0
- package/dist/utils/clingo-parser.js +403 -0
- package/dist/utils/clingo-parser.js.map +1 -0
- package/dist/utils/clingo-program-builder.d.ts +39 -0
- package/dist/utils/clingo-program-builder.js +57 -0
- package/dist/utils/clingo-program-builder.js.map +1 -0
- package/dist/utils/common-utils.d.ts +24 -0
- package/dist/utils/common-utils.js +47 -0
- package/dist/utils/common-utils.js.map +1 -0
- package/dist/utils/constants.d.ts +18 -0
- package/dist/utils/constants.js +27 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/csv.d.ts +18 -0
- package/dist/utils/csv.js +45 -0
- package/dist/utils/csv.js.map +1 -0
- package/dist/utils/file-utils.d.ts +69 -0
- package/dist/utils/file-utils.js +158 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/json.d.ts +61 -0
- package/dist/utils/json.js +108 -0
- package/dist/utils/json.js.map +1 -0
- package/dist/utils/lexorank.d.ts +59 -0
- package/dist/utils/lexorank.js +159 -0
- package/dist/utils/lexorank.js.map +1 -0
- package/dist/utils/log-utils.d.ts +40 -0
- package/dist/utils/log-utils.js +109 -0
- package/dist/utils/log-utils.js.map +1 -0
- package/dist/utils/random.d.ts +19 -0
- package/dist/utils/random.js +34 -0
- package/dist/utils/random.js.map +1 -0
- package/dist/utils/resource-utils.d.ts +45 -0
- package/dist/utils/resource-utils.js +137 -0
- package/dist/utils/resource-utils.js.map +1 -0
- package/dist/utils/sanitize-svg.d.ts +18 -0
- package/dist/utils/sanitize-svg.js +38 -0
- package/dist/utils/sanitize-svg.js.map +1 -0
- package/dist/utils/user-preferences.d.ts +64 -0
- package/dist/utils/user-preferences.js +106 -0
- package/dist/utils/user-preferences.js.map +1 -0
- package/dist/utils/validate.d.ts +26 -0
- package/dist/utils/validate.js +53 -0
- package/dist/utils/validate.js.map +1 -0
- package/dist/utils/value-utils.d.ts +58 -0
- package/dist/utils/value-utils.js +181 -0
- package/dist/utils/value-utils.js.map +1 -0
- package/package.json +67 -0
- package/src/card-metadata-updater.ts +182 -0
- package/src/command-handler.ts +686 -0
- package/src/command-manager.ts +99 -0
- package/src/commands/calculate.ts +591 -0
- package/src/commands/create.ts +559 -0
- package/src/commands/edit.ts +123 -0
- package/src/commands/export-site.ts +356 -0
- package/src/commands/export.ts +315 -0
- package/src/commands/import.ts +169 -0
- package/src/commands/index.ts +42 -0
- package/src/commands/move.ts +451 -0
- package/src/commands/remove.ts +244 -0
- package/src/commands/rename.ts +378 -0
- package/src/commands/show.ts +442 -0
- package/src/commands/transition.ts +127 -0
- package/src/commands/update.ts +76 -0
- package/src/commands/validate.ts +962 -0
- package/src/containers/card-container.ts +378 -0
- package/src/containers/project/project-paths.ts +127 -0
- package/src/containers/project/resource-collector.ts +379 -0
- package/src/containers/project.ts +1135 -0
- package/src/containers/template.ts +573 -0
- package/src/exceptions/index.ts +29 -0
- package/src/index.ts +33 -0
- package/src/interfaces/adoc.ts +18 -0
- package/src/interfaces/macros.ts +54 -0
- package/src/interfaces/project-interfaces.ts +208 -0
- package/src/interfaces/request-status-interfaces.ts +30 -0
- package/src/interfaces/resource-interfaces.ts +179 -0
- package/src/macros/base-macro.ts +176 -0
- package/src/macros/common.ts +24 -0
- package/src/macros/createCards/index.ts +57 -0
- package/src/macros/createCards/metadata.ts +21 -0
- package/src/macros/graph/index.ts +130 -0
- package/src/macros/graph/metadata.ts +21 -0
- package/src/macros/index.ts +321 -0
- package/src/macros/report/index.ts +88 -0
- package/src/macros/report/metadata.ts +21 -0
- package/src/macros/scoreCard/index.ts +55 -0
- package/src/macros/scoreCard/metadata.ts +21 -0
- package/src/macros/task-queue.ts +79 -0
- package/src/module-manager.ts +443 -0
- package/src/permissions/action-guard.ts +77 -0
- package/src/project-settings.ts +140 -0
- package/src/resources/array-handler.ts +141 -0
- package/src/resources/card-type-resource.ts +455 -0
- package/src/resources/create-defaults.ts +216 -0
- package/src/resources/field-type-resource.ts +533 -0
- package/src/resources/file-resource.ts +433 -0
- package/src/resources/folder-resource.ts +140 -0
- package/src/resources/graph-model-resource.ts +205 -0
- package/src/resources/graph-view-resource.ts +199 -0
- package/src/resources/link-type-resource.ts +191 -0
- package/src/resources/report-resource.ts +224 -0
- package/src/resources/resource-object.ts +246 -0
- package/src/resources/template-resource.ts +210 -0
- package/src/resources/workflow-resource.ts +205 -0
- package/src/types/queries.ts +149 -0
- package/src/utils/card-utils.ts +83 -0
- package/src/utils/clingo-fact-builder.ts +167 -0
- package/src/utils/clingo-facts.ts +550 -0
- package/src/utils/clingo-parser.ts +519 -0
- package/src/utils/clingo-program-builder.ts +71 -0
- package/src/utils/common-utils.ts +54 -0
- package/src/utils/constants.ts +32 -0
- package/src/utils/csv.ts +53 -0
- package/src/utils/file-utils.ts +182 -0
- package/src/utils/json.ts +118 -0
- package/src/utils/lexorank.ts +180 -0
- package/src/utils/log-utils.ts +127 -0
- package/src/utils/random.ts +37 -0
- package/src/utils/resource-utils.ts +180 -0
- package/src/utils/sanitize-svg.ts +46 -0
- package/src/utils/user-preferences.ts +126 -0
- package/src/utils/validate.ts +66 -0
- package/src/utils/value-utils.ts +189 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Cyberismo
|
|
3
|
+
Copyright © Cyberismo Ltd and contributors 2024
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
6
|
+
|
|
7
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU Affero General Public
|
|
10
|
+
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { MacroTaskState } from '../interfaces/macros.js';
|
|
14
|
+
|
|
15
|
+
export default class TaskQueue {
|
|
16
|
+
private tasks: MacroTaskState[] = [];
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pushes a task to the task queue
|
|
20
|
+
* @param task The task to push
|
|
21
|
+
*/
|
|
22
|
+
public push(task: MacroTaskState) {
|
|
23
|
+
this.tasks.push(task);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Finds an existing task based on its id
|
|
28
|
+
* @param globalId unique id across both macro classes and instances
|
|
29
|
+
* @param localId Id within the instance
|
|
30
|
+
* @returns task if found else undefined
|
|
31
|
+
*/
|
|
32
|
+
public find(globalId: string, localId: number) {
|
|
33
|
+
return this.tasks.find(
|
|
34
|
+
(task) => task.globalId === globalId && task.localId === localId,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Waits for all tasks to be done
|
|
40
|
+
*/
|
|
41
|
+
public async waitAll() {
|
|
42
|
+
for (const task of this.tasks) {
|
|
43
|
+
await task.promise;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Waits for a single task to be done
|
|
49
|
+
* @param task task to wait
|
|
50
|
+
*/
|
|
51
|
+
public async waitTask(task: MacroTaskState) {
|
|
52
|
+
await task.promise;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Removes all tasks. If they are running, they continue to run because they are promises
|
|
57
|
+
*/
|
|
58
|
+
public async reset() {
|
|
59
|
+
this.tasks = [];
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* When iterating over task queue, it'll return each task
|
|
64
|
+
*/
|
|
65
|
+
public [Symbol.iterator]() {
|
|
66
|
+
let index = 0;
|
|
67
|
+
const tasks = this.tasks;
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
next(): IteratorResult<MacroTaskState> {
|
|
71
|
+
if (index < tasks.length) {
|
|
72
|
+
return { value: tasks[index++], done: false };
|
|
73
|
+
} else {
|
|
74
|
+
return { value: undefined, done: true };
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Cyberismo
|
|
3
|
+
Copyright © Cyberismo Ltd and contributors 2025
|
|
4
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
5
|
+
the terms of the GNU Affero General Public License version 3 as published by
|
|
6
|
+
the Free Software Foundation. This program is distributed in the hope that it
|
|
7
|
+
will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
8
|
+
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
See the GNU Affero General Public License for more details.
|
|
10
|
+
You should have received a copy of the GNU Affero General Public
|
|
11
|
+
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { mkdir, readdir, rm } from 'node:fs/promises';
|
|
17
|
+
|
|
18
|
+
import git from 'isomorphic-git';
|
|
19
|
+
import http from 'isomorphic-git/http/node/index.js';
|
|
20
|
+
|
|
21
|
+
import { copyDir, deleteDir, pathExists } from './utils/file-utils.js';
|
|
22
|
+
import type { Import } from './commands/index.js';
|
|
23
|
+
import type {
|
|
24
|
+
ModuleSetting,
|
|
25
|
+
ModuleSettingOptions,
|
|
26
|
+
} from './interfaces/project-interfaces.js';
|
|
27
|
+
import { Project } from './containers/project.js';
|
|
28
|
+
import type { ProjectConfiguration } from './project-settings.js';
|
|
29
|
+
import { ProjectPaths } from './containers/project/project-paths.js';
|
|
30
|
+
import { readJsonFile } from './utils/json.js';
|
|
31
|
+
import { Validate } from './commands/index.js';
|
|
32
|
+
|
|
33
|
+
const FILE_PROTOCOL = 'file:';
|
|
34
|
+
// todo: add support for git's default branch.
|
|
35
|
+
const MAIN_BRANCH = 'main';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Class that handles module updates and imports.
|
|
39
|
+
*/
|
|
40
|
+
export class ModuleManager {
|
|
41
|
+
private modules: ModuleSetting[] = [];
|
|
42
|
+
private tempModulesDir: string = '';
|
|
43
|
+
constructor(
|
|
44
|
+
private project: Project,
|
|
45
|
+
private importCmd: Import,
|
|
46
|
+
) {
|
|
47
|
+
this.tempModulesDir = join(this.project.paths.tempFolder, 'modules');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Copies module files into project directories.
|
|
51
|
+
private async addFileContents(sourcePath: string, destinationPath: string) {
|
|
52
|
+
// Copy files.
|
|
53
|
+
await copyDir(sourcePath, destinationPath);
|
|
54
|
+
|
|
55
|
+
// Update the resources.
|
|
56
|
+
await this.project.collectModuleResources();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handles a branch of a repository.
|
|
60
|
+
private async branch(module: ModuleSetting) {
|
|
61
|
+
if (module.branch === MAIN_BRANCH || module.branch === '' || !module.branch)
|
|
62
|
+
return;
|
|
63
|
+
|
|
64
|
+
await git.checkout({
|
|
65
|
+
fs,
|
|
66
|
+
dir: join(this.tempModulesDir, module.name),
|
|
67
|
+
ref: module.branch,
|
|
68
|
+
});
|
|
69
|
+
console.error(
|
|
70
|
+
`... Switched to '${module.branch}' branch for module '${module.name}'`,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Handles cloning of a repository.
|
|
75
|
+
private async clone(
|
|
76
|
+
module: ModuleSetting,
|
|
77
|
+
verbose: boolean = true,
|
|
78
|
+
): Promise<string> {
|
|
79
|
+
if (!module.name || module.name === '') {
|
|
80
|
+
module.name = this.repositoryName(module.location);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
let repoUrl: URL;
|
|
84
|
+
try {
|
|
85
|
+
repoUrl = new URL(module.location);
|
|
86
|
+
} catch {
|
|
87
|
+
throw new Error(`Invalid repository URL: ${module.location}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (
|
|
91
|
+
process.env.CYBERISMO_GIT_USER &&
|
|
92
|
+
process.env.CYBERISMO_GIT_TOKEN &&
|
|
93
|
+
module.private
|
|
94
|
+
) {
|
|
95
|
+
if (verbose) {
|
|
96
|
+
console.log(
|
|
97
|
+
`... Using credentials '${process.env.CYBERISMO_GIT_USER}' for cloning '${module.name}'`,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
repoUrl.username = process.env.CYBERISMO_GIT_USER;
|
|
101
|
+
repoUrl.password = process.env.CYBERISMO_GIT_TOKEN;
|
|
102
|
+
}
|
|
103
|
+
await git.clone({
|
|
104
|
+
fs,
|
|
105
|
+
http,
|
|
106
|
+
dir: join(this.tempModulesDir, module.name),
|
|
107
|
+
url: repoUrl.toString(),
|
|
108
|
+
depth: 1,
|
|
109
|
+
onAuth: () => {
|
|
110
|
+
// Turn credentials 'off' when they are not available
|
|
111
|
+
if (
|
|
112
|
+
!process.env.CYBERISMO_GIT_USER ||
|
|
113
|
+
!process.env.CYBERISMO_GIT_TOKEN
|
|
114
|
+
) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
// Turn credentials 'off' for public repos
|
|
118
|
+
if (!module.private) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
username: process.env.CYBERISMO_GIT_USER,
|
|
123
|
+
password: process.env.CYBERISMO_GIT_TOKEN,
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (verbose) {
|
|
129
|
+
console.log(`... Cloned '${module.name}' to a temporary folder`);
|
|
130
|
+
}
|
|
131
|
+
return module.name;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Collects all module prefixes from module hierarchy into 'this.modules'.
|
|
135
|
+
// Note that collected result can contain duplicates.
|
|
136
|
+
private async collectModulePrefixes(modules: ModuleSetting[]) {
|
|
137
|
+
if (modules) {
|
|
138
|
+
for (const module of modules) {
|
|
139
|
+
await this.doCollectModulePrefix(module);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Read project configuration JSON file from 'path'.
|
|
145
|
+
private async configuration(path: string): Promise<ProjectConfiguration> {
|
|
146
|
+
try {
|
|
147
|
+
const paths = new ProjectPaths(path);
|
|
148
|
+
return readJsonFile(paths.configurationFile);
|
|
149
|
+
} catch {
|
|
150
|
+
throw new Error(`Module not found from '${path}'`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Collects one module's dependency prefixes to 'this.modules'.
|
|
155
|
+
// Note that there can be duplicate entries.
|
|
156
|
+
private async doCollectModulePrefix(module: ModuleSetting) {
|
|
157
|
+
let moduleRoot = '';
|
|
158
|
+
if (this.isFileModule(module)) {
|
|
159
|
+
const urlStart = FILE_PROTOCOL.length;
|
|
160
|
+
// Remove 'file:' from location
|
|
161
|
+
moduleRoot = module.location.substring(urlStart, module.location.length);
|
|
162
|
+
} else {
|
|
163
|
+
await this.clone(module, false);
|
|
164
|
+
moduleRoot = join(this.tempModulesDir, module.name);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.modules.push(module);
|
|
168
|
+
|
|
169
|
+
const configuration = await this.configuration(moduleRoot);
|
|
170
|
+
await this.collectModulePrefixes(configuration.modules);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Updates one module that is read from local file system.
|
|
174
|
+
private async handleFileModule(module: ModuleSetting) {
|
|
175
|
+
this.removeProtocolFromLocation(module);
|
|
176
|
+
await this.remove(module);
|
|
177
|
+
await this.importFromFolder(module);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Updates one module that is received from Git.
|
|
181
|
+
private async handleGitModule(module: ModuleSetting) {
|
|
182
|
+
await this.clone(module);
|
|
183
|
+
await this.branch(module);
|
|
184
|
+
await this.remove(module);
|
|
185
|
+
await this.importFromTemp(module);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Updates one module.
|
|
189
|
+
private async handleModule(module: ModuleSetting) {
|
|
190
|
+
return this.isFileModule(module)
|
|
191
|
+
? this.handleFileModule(module)
|
|
192
|
+
: this.handleGitModule(module);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Handles importing a module from module settings 'location'
|
|
196
|
+
private async importFromFolder(module: ModuleSetting) {
|
|
197
|
+
await this.importCmd.updateExistingModule(module.location);
|
|
198
|
+
console.log(
|
|
199
|
+
`... Imported module '${module.name}' to '${this.project.configuration.name}'`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Handles importing a module from '.temp' folder
|
|
204
|
+
private async importFromTemp(module: ModuleSetting) {
|
|
205
|
+
await this.importCmd.updateExistingModule(
|
|
206
|
+
join(this.tempModulesDir, module.name),
|
|
207
|
+
);
|
|
208
|
+
console.log(
|
|
209
|
+
`... Imported module '${module.name}' to '${this.project.configuration.name}'`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Returns true if module is imported from file-system.
|
|
214
|
+
private isFileModule(module: ModuleSetting): boolean {
|
|
215
|
+
if (!module.location) return false;
|
|
216
|
+
return module.location.startsWith('file:');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Prepares '.temp/modules' for cloning
|
|
220
|
+
private async prepare() {
|
|
221
|
+
await mkdir(this.tempModulesDir, { recursive: true });
|
|
222
|
+
for (const file of await readdir(this.tempModulesDir)) {
|
|
223
|
+
await rm(join(this.tempModulesDir, file), {
|
|
224
|
+
force: true,
|
|
225
|
+
recursive: true,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Returns whether to use git or file system for handling the module.
|
|
231
|
+
private protocol(module: ModuleSetting) {
|
|
232
|
+
return this.isFileModule(module) ? 'file' : 'git';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Handles removing an imported module.
|
|
236
|
+
private async remove(module: ModuleSetting) {
|
|
237
|
+
try {
|
|
238
|
+
await this.removeModuleFiles(module.name);
|
|
239
|
+
console.log(`... Removed imported module '${module.name}'`);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error instanceof Error)
|
|
242
|
+
console.error(
|
|
243
|
+
`... New imported module '${module.name}', skipping remove`,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Remove module files.
|
|
249
|
+
private async removeModuleFiles(moduleName: string) {
|
|
250
|
+
const module = await this.project.module(moduleName);
|
|
251
|
+
if (!module) {
|
|
252
|
+
throw new Error(`Module '${moduleName}' not found`);
|
|
253
|
+
}
|
|
254
|
+
await deleteDir(module.path);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Updates module's 'location' not to have 'protocol:' in the beginning (only for "file:" needed).
|
|
258
|
+
private removeProtocolFromLocation(module: ModuleSetting) {
|
|
259
|
+
const protocol = this.protocol(module);
|
|
260
|
+
module.location = module.location.substring(
|
|
261
|
+
protocol.length + 1,
|
|
262
|
+
module.location.length,
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Checks for duplicate ModuleSetting entries and throws an error if modules
|
|
267
|
+
// with the same name have different branches or locations.
|
|
268
|
+
// Treats undefined branch, empty string branch, and "main" branch as equivalent.
|
|
269
|
+
// Returns an array with duplicate entries removed
|
|
270
|
+
private removeDuplicates(modules: ModuleSetting[]): ModuleSetting[] {
|
|
271
|
+
const moduleMap = new Map<string, ModuleSetting>();
|
|
272
|
+
|
|
273
|
+
// Assume that empty, or missing branch means 'main'
|
|
274
|
+
const normalizeBranch = (branch: string | undefined): string => {
|
|
275
|
+
if (!branch || branch === '' || branch === MAIN_BRANCH) {
|
|
276
|
+
return MAIN_BRANCH;
|
|
277
|
+
}
|
|
278
|
+
return branch;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
for (const module of modules) {
|
|
282
|
+
const existingModule = moduleMap.get(module.name);
|
|
283
|
+
if (existingModule) {
|
|
284
|
+
if (existingModule.private !== module.private) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`Module conflict: '${module.name}' has different access:\n` +
|
|
287
|
+
` - ${existingModule.private || 'undefined'}\n` +
|
|
288
|
+
` - ${module.private || 'undefined'}`,
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
if (existingModule.location !== module.location) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
`Module conflict: '${module.name}' has different locations:\n` +
|
|
294
|
+
` - ${existingModule.location}\n` +
|
|
295
|
+
` - ${module.location}`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
const existingBranch = normalizeBranch(existingModule.branch);
|
|
299
|
+
const newBranch = normalizeBranch(module.branch);
|
|
300
|
+
|
|
301
|
+
if (existingBranch !== newBranch) {
|
|
302
|
+
throw new Error(
|
|
303
|
+
`Module conflict: '${module.name}' has different branches:\n` +
|
|
304
|
+
` - ${existingModule.branch || 'undefined'}\n` +
|
|
305
|
+
` - ${module.branch || 'undefined'}`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
} else {
|
|
309
|
+
moduleMap.set(module.name, module);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return Array.from(moduleMap.values());
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Gets repository name from gitUrl
|
|
316
|
+
private repositoryName(gitUrl: string): string {
|
|
317
|
+
const last = gitUrl.lastIndexOf('/');
|
|
318
|
+
const repoName = gitUrl.substring(last + 1, gitUrl.length - 4); //remove trailing ".git"
|
|
319
|
+
return repoName;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Checks that module prefix is not in use in the project
|
|
323
|
+
private async validatePrefix(modulePrefix: string) {
|
|
324
|
+
// Do not allow modules with same prefixes.
|
|
325
|
+
const currentlyUsedPrefixes = await this.project.projectPrefixes();
|
|
326
|
+
if (currentlyUsedPrefixes.includes(modulePrefix)) {
|
|
327
|
+
throw new Error(
|
|
328
|
+
`Imported project has a prefix '${modulePrefix}' that is already used in the project. Cannot import from module.`,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Imports module from local file path.
|
|
335
|
+
* @param source Path to import from.
|
|
336
|
+
* @param destination is this really needed???
|
|
337
|
+
*/
|
|
338
|
+
public async importFileModule(source: string, destination?: string) {
|
|
339
|
+
if (!Validate.validateFolder(source)) {
|
|
340
|
+
throw new Error(
|
|
341
|
+
`Input validation error: folder name is invalid '${source}'`,
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
if (!pathExists(source)) {
|
|
345
|
+
throw new Error(
|
|
346
|
+
`Input validation error: cannot find project '${source}'`,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
if (destination && !pathExists(destination)) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`Input validation error: destination does not exist '${destination}'`,
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
const sourceProject = new Project(source);
|
|
355
|
+
const modulePrefix = sourceProject.projectPrefix;
|
|
356
|
+
const destinationPath = join(
|
|
357
|
+
this.project.paths.modulesFolder,
|
|
358
|
+
modulePrefix,
|
|
359
|
+
);
|
|
360
|
+
const sourcePath = sourceProject.paths.resourcesFolder;
|
|
361
|
+
|
|
362
|
+
await this.validatePrefix(modulePrefix);
|
|
363
|
+
|
|
364
|
+
// Copy files.
|
|
365
|
+
await this.addFileContents(sourcePath, destinationPath);
|
|
366
|
+
return modulePrefix;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Imports module from gitUrl.
|
|
371
|
+
* @param source Git URL to import from.
|
|
372
|
+
* @param options Modules setting options.
|
|
373
|
+
* @returns module prefix as defined in its CardsConfig.json
|
|
374
|
+
*/
|
|
375
|
+
public async importGitModule(source: string, options?: ModuleSettingOptions) {
|
|
376
|
+
const repoName = await this.clone({
|
|
377
|
+
name: '',
|
|
378
|
+
location: source,
|
|
379
|
+
...options,
|
|
380
|
+
});
|
|
381
|
+
await this.branch({ name: repoName, location: source, ...options });
|
|
382
|
+
const clonePath = join(this.project.paths.tempFolder, 'modules', repoName);
|
|
383
|
+
const modulePrefix = (await this.configuration(clonePath)).cardKeyPrefix;
|
|
384
|
+
await this.validatePrefix(modulePrefix);
|
|
385
|
+
|
|
386
|
+
const sourcePath = new ProjectPaths(clonePath).resourcesFolder;
|
|
387
|
+
const destinationPath = join(
|
|
388
|
+
this.project.paths.modulesFolder,
|
|
389
|
+
modulePrefix,
|
|
390
|
+
);
|
|
391
|
+
await this.addFileContents(sourcePath, destinationPath);
|
|
392
|
+
return modulePrefix;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Updates all imported modules.
|
|
397
|
+
*/
|
|
398
|
+
public async update() {
|
|
399
|
+
// Prints dots every half second so that user knows that something is ongoing
|
|
400
|
+
function start() {
|
|
401
|
+
console.log('... Collecting unique modules. This takes a moment.');
|
|
402
|
+
return setInterval(() => process.stdout.write(`.`), 500);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Stops the above, and shows results
|
|
406
|
+
function finished(interval: NodeJS.Timeout, modules: string[]) {
|
|
407
|
+
clearInterval(interval);
|
|
408
|
+
console.log(`\n... Found modules: ${modules.join(', ')}`);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
await this.prepare();
|
|
412
|
+
|
|
413
|
+
const modules = this.project.configuration.modules;
|
|
414
|
+
if (modules.length === 0) {
|
|
415
|
+
throw new Error(`No modules in the project!`);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const dotInterval = start();
|
|
419
|
+
|
|
420
|
+
// Collect prefixes from project's dependency modules.
|
|
421
|
+
await this.collectModulePrefixes(modules);
|
|
422
|
+
|
|
423
|
+
let uniqueModules: ModuleSetting[] = [];
|
|
424
|
+
try {
|
|
425
|
+
uniqueModules = this.removeDuplicates(this.modules);
|
|
426
|
+
} finally {
|
|
427
|
+
finished(
|
|
428
|
+
dotInterval,
|
|
429
|
+
uniqueModules.map((item) => item.name),
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
// Update modules parallel.
|
|
433
|
+
const promises: Promise<void>[] = [];
|
|
434
|
+
uniqueModules.forEach((module) =>
|
|
435
|
+
promises.push(this.handleModule(module)),
|
|
436
|
+
);
|
|
437
|
+
await Promise.all(promises);
|
|
438
|
+
|
|
439
|
+
await deleteDir(this.tempModulesDir);
|
|
440
|
+
await this.project.collectModuleResources();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Cyberismo
|
|
3
|
+
Copyright © Cyberismo Ltd and contributors 2024
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
|
|
6
|
+
|
|
7
|
+
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
|
8
|
+
|
|
9
|
+
You should have received a copy of the GNU Affero General Public
|
|
10
|
+
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { Calculate } from '../commands/index.js';
|
|
14
|
+
import type { DeniedOperationCollection } from '../types/queries.js';
|
|
15
|
+
|
|
16
|
+
export type Action = keyof DeniedOperationCollection;
|
|
17
|
+
|
|
18
|
+
function checkOperation<T extends { errorMessage: string }>(data: Array<T>) {
|
|
19
|
+
if (data.length > 0) {
|
|
20
|
+
throw new Error(data.map((value) => value.errorMessage).join('; '));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* This class is used to guard actions from being used without permissions
|
|
26
|
+
*/
|
|
27
|
+
export class ActionGuard {
|
|
28
|
+
constructor(private calculate: Calculate) {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Checks whether an action can be done
|
|
32
|
+
* @param action Action that will be done
|
|
33
|
+
* @param cardKey Key of the card being targeted
|
|
34
|
+
* @param param Required or not used param depending on the action
|
|
35
|
+
*/
|
|
36
|
+
public async checkPermission(
|
|
37
|
+
action: Action,
|
|
38
|
+
cardKey: string,
|
|
39
|
+
param?: string,
|
|
40
|
+
) {
|
|
41
|
+
await this.calculate.generate();
|
|
42
|
+
const cards = await this.calculate.runQuery('card', {
|
|
43
|
+
cardKey,
|
|
44
|
+
});
|
|
45
|
+
if (cards.length === 0) {
|
|
46
|
+
throw new Error("Card query didn't return results");
|
|
47
|
+
}
|
|
48
|
+
if (cards.length !== 1) {
|
|
49
|
+
throw new Error('Card query returned multiple cards');
|
|
50
|
+
}
|
|
51
|
+
const res = cards[0];
|
|
52
|
+
if (action === 'editContent') {
|
|
53
|
+
return checkOperation(res.deniedOperations.editContent);
|
|
54
|
+
}
|
|
55
|
+
if (action === 'transition') {
|
|
56
|
+
return checkOperation(
|
|
57
|
+
res.deniedOperations.transition.filter(
|
|
58
|
+
(value) => value.transitionName === param,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
if (action === 'delete') {
|
|
63
|
+
return checkOperation(res.deniedOperations.delete);
|
|
64
|
+
}
|
|
65
|
+
if (action === 'editField') {
|
|
66
|
+
return checkOperation(
|
|
67
|
+
res.deniedOperations.editField.filter(
|
|
68
|
+
(value) => value.fieldName === param,
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
if (action === 'move') {
|
|
73
|
+
return checkOperation(res.deniedOperations.move);
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`Action: ${action} does not support checking permissions`);
|
|
76
|
+
}
|
|
77
|
+
}
|