@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.
Files changed (306) hide show
  1. package/LICENSE +702 -0
  2. package/dist/card-metadata-updater.d.ts +33 -0
  3. package/dist/card-metadata-updater.js +121 -0
  4. package/dist/card-metadata-updater.js.map +1 -0
  5. package/dist/command-handler.d.ts +96 -0
  6. package/dist/command-handler.js +557 -0
  7. package/dist/command-handler.js.map +1 -0
  8. package/dist/command-manager.d.ts +43 -0
  9. package/dist/command-manager.js +73 -0
  10. package/dist/command-manager.js.map +1 -0
  11. package/dist/commands/calculate.d.ts +86 -0
  12. package/dist/commands/calculate.js +444 -0
  13. package/dist/commands/calculate.js.map +1 -0
  14. package/dist/commands/create.d.ts +114 -0
  15. package/dist/commands/create.js +389 -0
  16. package/dist/commands/create.js.map +1 -0
  17. package/dist/commands/edit.d.ts +37 -0
  18. package/dist/commands/edit.js +99 -0
  19. package/dist/commands/edit.js.map +1 -0
  20. package/dist/commands/export-site.d.ts +45 -0
  21. package/dist/commands/export-site.js +301 -0
  22. package/dist/commands/export-site.js.map +1 -0
  23. package/dist/commands/export.d.ts +53 -0
  24. package/dist/commands/export.js +251 -0
  25. package/dist/commands/export.js.map +1 -0
  26. package/dist/commands/import.d.ts +53 -0
  27. package/dist/commands/import.js +133 -0
  28. package/dist/commands/import.js.map +1 -0
  29. package/dist/commands/index.d.ts +26 -0
  30. package/dist/commands/index.js +27 -0
  31. package/dist/commands/index.js.map +1 -0
  32. package/dist/commands/move.d.ts +55 -0
  33. package/dist/commands/move.js +341 -0
  34. package/dist/commands/move.js.map +1 -0
  35. package/dist/commands/remove.d.ts +38 -0
  36. package/dist/commands/remove.js +192 -0
  37. package/dist/commands/remove.js.map +1 -0
  38. package/dist/commands/rename.d.ts +46 -0
  39. package/dist/commands/rename.js +289 -0
  40. package/dist/commands/rename.js.map +1 -0
  41. package/dist/commands/show.d.ts +124 -0
  42. package/dist/commands/show.js +345 -0
  43. package/dist/commands/show.js.map +1 -0
  44. package/dist/commands/transition.d.ts +27 -0
  45. package/dist/commands/transition.js +92 -0
  46. package/dist/commands/transition.js.map +1 -0
  47. package/dist/commands/update.d.ts +29 -0
  48. package/dist/commands/update.js +64 -0
  49. package/dist/commands/update.js.map +1 -0
  50. package/dist/commands/validate.d.ts +143 -0
  51. package/dist/commands/validate.js +689 -0
  52. package/dist/commands/validate.js.map +1 -0
  53. package/dist/containers/card-container.d.ts +44 -0
  54. package/dist/containers/card-container.js +282 -0
  55. package/dist/containers/card-container.js.map +1 -0
  56. package/dist/containers/project/project-paths.d.ts +46 -0
  57. package/dist/containers/project/project-paths.js +105 -0
  58. package/dist/containers/project/project-paths.js.map +1 -0
  59. package/dist/containers/project/resource-collector.d.ts +86 -0
  60. package/dist/containers/project/resource-collector.js +331 -0
  61. package/dist/containers/project/resource-collector.js.map +1 -0
  62. package/dist/containers/project.d.ts +351 -0
  63. package/dist/containers/project.js +896 -0
  64. package/dist/containers/project.js.map +1 -0
  65. package/dist/containers/template.d.ts +108 -0
  66. package/dist/containers/template.js +433 -0
  67. package/dist/containers/template.js.map +1 -0
  68. package/dist/exceptions/index.d.ts +19 -0
  69. package/dist/exceptions/index.js +26 -0
  70. package/dist/exceptions/index.js.map +1 -0
  71. package/dist/index.d.ts +16 -0
  72. package/dist/index.js +15 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/interfaces/adoc.d.ts +12 -0
  75. package/dist/interfaces/adoc.js +13 -0
  76. package/dist/interfaces/adoc.js.map +1 -0
  77. package/dist/interfaces/macros.d.ts +45 -0
  78. package/dist/interfaces/macros.js +13 -0
  79. package/dist/interfaces/macros.js.map +1 -0
  80. package/dist/interfaces/project-interfaces.d.ts +121 -0
  81. package/dist/interfaces/project-interfaces.js +21 -0
  82. package/dist/interfaces/project-interfaces.js.map +1 -0
  83. package/dist/interfaces/request-status-interfaces.d.ts +28 -0
  84. package/dist/interfaces/request-status-interfaces.js +20 -0
  85. package/dist/interfaces/request-status-interfaces.js.map +1 -0
  86. package/dist/interfaces/resource-interfaces.d.ts +117 -0
  87. package/dist/interfaces/resource-interfaces.js +20 -0
  88. package/dist/interfaces/resource-interfaces.js.map +1 -0
  89. package/dist/macros/base-macro.d.ts +31 -0
  90. package/dist/macros/base-macro.js +126 -0
  91. package/dist/macros/base-macro.js.map +1 -0
  92. package/dist/macros/common.d.ts +17 -0
  93. package/dist/macros/common.js +23 -0
  94. package/dist/macros/common.js.map +1 -0
  95. package/dist/macros/createCards/index.d.ts +36 -0
  96. package/dist/macros/createCards/index.js +35 -0
  97. package/dist/macros/createCards/index.js.map +1 -0
  98. package/dist/macros/createCards/metadata.d.ts +14 -0
  99. package/dist/macros/createCards/metadata.js +18 -0
  100. package/dist/macros/createCards/metadata.js.map +1 -0
  101. package/dist/macros/graph/index.d.ts +29 -0
  102. package/dist/macros/graph/index.js +91 -0
  103. package/dist/macros/graph/index.js.map +1 -0
  104. package/dist/macros/graph/metadata.d.ts +14 -0
  105. package/dist/macros/graph/metadata.js +18 -0
  106. package/dist/macros/graph/metadata.js.map +1 -0
  107. package/dist/macros/index.d.ts +93 -0
  108. package/dist/macros/index.js +237 -0
  109. package/dist/macros/index.js.map +1 -0
  110. package/dist/macros/report/index.d.ts +26 -0
  111. package/dist/macros/report/index.js +70 -0
  112. package/dist/macros/report/index.js.map +1 -0
  113. package/dist/macros/report/metadata.d.ts +14 -0
  114. package/dist/macros/report/metadata.js +18 -0
  115. package/dist/macros/report/metadata.js.map +1 -0
  116. package/dist/macros/scoreCard/index.d.ts +30 -0
  117. package/dist/macros/scoreCard/index.js +38 -0
  118. package/dist/macros/scoreCard/index.js.map +1 -0
  119. package/dist/macros/scoreCard/metadata.d.ts +14 -0
  120. package/dist/macros/scoreCard/metadata.js +18 -0
  121. package/dist/macros/scoreCard/metadata.js.map +1 -0
  122. package/dist/macros/task-queue.d.ts +46 -0
  123. package/dist/macros/task-queue.js +69 -0
  124. package/dist/macros/task-queue.js.map +1 -0
  125. package/dist/module-manager.d.ts +62 -0
  126. package/dist/module-manager.js +350 -0
  127. package/dist/module-manager.js.map +1 -0
  128. package/dist/permissions/action-guard.d.ts +28 -0
  129. package/dist/permissions/action-guard.js +61 -0
  130. package/dist/permissions/action-guard.js.map +1 -0
  131. package/dist/project-settings.d.ts +42 -0
  132. package/dist/project-settings.js +120 -0
  133. package/dist/project-settings.js.map +1 -0
  134. package/dist/resources/array-handler.d.ts +28 -0
  135. package/dist/resources/array-handler.js +116 -0
  136. package/dist/resources/array-handler.js.map +1 -0
  137. package/dist/resources/card-type-resource.d.ts +72 -0
  138. package/dist/resources/card-type-resource.js +334 -0
  139. package/dist/resources/card-type-resource.js.map +1 -0
  140. package/dist/resources/create-defaults.d.ts +81 -0
  141. package/dist/resources/create-defaults.js +184 -0
  142. package/dist/resources/create-defaults.js.map +1 -0
  143. package/dist/resources/field-type-resource.d.ts +88 -0
  144. package/dist/resources/field-type-resource.js +411 -0
  145. package/dist/resources/field-type-resource.js.map +1 -0
  146. package/dist/resources/file-resource.d.ts +50 -0
  147. package/dist/resources/file-resource.js +301 -0
  148. package/dist/resources/file-resource.js.map +1 -0
  149. package/dist/resources/folder-resource.d.ts +66 -0
  150. package/dist/resources/folder-resource.js +100 -0
  151. package/dist/resources/folder-resource.js.map +1 -0
  152. package/dist/resources/graph-model-resource.d.ts +78 -0
  153. package/dist/resources/graph-model-resource.js +164 -0
  154. package/dist/resources/graph-model-resource.js.map +1 -0
  155. package/dist/resources/graph-view-resource.d.ts +78 -0
  156. package/dist/resources/graph-view-resource.js +163 -0
  157. package/dist/resources/graph-view-resource.js.map +1 -0
  158. package/dist/resources/link-type-resource.d.ts +62 -0
  159. package/dist/resources/link-type-resource.js +150 -0
  160. package/dist/resources/link-type-resource.js.map +1 -0
  161. package/dist/resources/report-resource.d.ts +77 -0
  162. package/dist/resources/report-resource.js +171 -0
  163. package/dist/resources/report-resource.js.map +1 -0
  164. package/dist/resources/resource-object.d.ts +108 -0
  165. package/dist/resources/resource-object.js +147 -0
  166. package/dist/resources/resource-object.js.map +1 -0
  167. package/dist/resources/template-resource.d.ts +82 -0
  168. package/dist/resources/template-resource.js +173 -0
  169. package/dist/resources/template-resource.js.map +1 -0
  170. package/dist/resources/workflow-resource.d.ts +67 -0
  171. package/dist/resources/workflow-resource.js +156 -0
  172. package/dist/resources/workflow-resource.js.map +1 -0
  173. package/dist/types/queries.d.ts +142 -0
  174. package/dist/types/queries.js +16 -0
  175. package/dist/types/queries.js.map +1 -0
  176. package/dist/utils/card-utils.d.ts +34 -0
  177. package/dist/utils/card-utils.js +78 -0
  178. package/dist/utils/card-utils.js.map +1 -0
  179. package/dist/utils/clingo-fact-builder.d.ts +58 -0
  180. package/dist/utils/clingo-fact-builder.js +126 -0
  181. package/dist/utils/clingo-fact-builder.js.map +1 -0
  182. package/dist/utils/clingo-facts.d.ts +97 -0
  183. package/dist/utils/clingo-facts.js +352 -0
  184. package/dist/utils/clingo-facts.js.map +1 -0
  185. package/dist/utils/clingo-parser.d.ts +59 -0
  186. package/dist/utils/clingo-parser.js +403 -0
  187. package/dist/utils/clingo-parser.js.map +1 -0
  188. package/dist/utils/clingo-program-builder.d.ts +39 -0
  189. package/dist/utils/clingo-program-builder.js +57 -0
  190. package/dist/utils/clingo-program-builder.js.map +1 -0
  191. package/dist/utils/common-utils.d.ts +24 -0
  192. package/dist/utils/common-utils.js +47 -0
  193. package/dist/utils/common-utils.js.map +1 -0
  194. package/dist/utils/constants.d.ts +18 -0
  195. package/dist/utils/constants.js +27 -0
  196. package/dist/utils/constants.js.map +1 -0
  197. package/dist/utils/csv.d.ts +18 -0
  198. package/dist/utils/csv.js +45 -0
  199. package/dist/utils/csv.js.map +1 -0
  200. package/dist/utils/file-utils.d.ts +69 -0
  201. package/dist/utils/file-utils.js +158 -0
  202. package/dist/utils/file-utils.js.map +1 -0
  203. package/dist/utils/json.d.ts +61 -0
  204. package/dist/utils/json.js +108 -0
  205. package/dist/utils/json.js.map +1 -0
  206. package/dist/utils/lexorank.d.ts +59 -0
  207. package/dist/utils/lexorank.js +159 -0
  208. package/dist/utils/lexorank.js.map +1 -0
  209. package/dist/utils/log-utils.d.ts +40 -0
  210. package/dist/utils/log-utils.js +109 -0
  211. package/dist/utils/log-utils.js.map +1 -0
  212. package/dist/utils/random.d.ts +19 -0
  213. package/dist/utils/random.js +34 -0
  214. package/dist/utils/random.js.map +1 -0
  215. package/dist/utils/resource-utils.d.ts +45 -0
  216. package/dist/utils/resource-utils.js +137 -0
  217. package/dist/utils/resource-utils.js.map +1 -0
  218. package/dist/utils/sanitize-svg.d.ts +18 -0
  219. package/dist/utils/sanitize-svg.js +38 -0
  220. package/dist/utils/sanitize-svg.js.map +1 -0
  221. package/dist/utils/user-preferences.d.ts +64 -0
  222. package/dist/utils/user-preferences.js +106 -0
  223. package/dist/utils/user-preferences.js.map +1 -0
  224. package/dist/utils/validate.d.ts +26 -0
  225. package/dist/utils/validate.js +53 -0
  226. package/dist/utils/validate.js.map +1 -0
  227. package/dist/utils/value-utils.d.ts +58 -0
  228. package/dist/utils/value-utils.js +181 -0
  229. package/dist/utils/value-utils.js.map +1 -0
  230. package/package.json +67 -0
  231. package/src/card-metadata-updater.ts +182 -0
  232. package/src/command-handler.ts +686 -0
  233. package/src/command-manager.ts +99 -0
  234. package/src/commands/calculate.ts +591 -0
  235. package/src/commands/create.ts +559 -0
  236. package/src/commands/edit.ts +123 -0
  237. package/src/commands/export-site.ts +356 -0
  238. package/src/commands/export.ts +315 -0
  239. package/src/commands/import.ts +169 -0
  240. package/src/commands/index.ts +42 -0
  241. package/src/commands/move.ts +451 -0
  242. package/src/commands/remove.ts +244 -0
  243. package/src/commands/rename.ts +378 -0
  244. package/src/commands/show.ts +442 -0
  245. package/src/commands/transition.ts +127 -0
  246. package/src/commands/update.ts +76 -0
  247. package/src/commands/validate.ts +962 -0
  248. package/src/containers/card-container.ts +378 -0
  249. package/src/containers/project/project-paths.ts +127 -0
  250. package/src/containers/project/resource-collector.ts +379 -0
  251. package/src/containers/project.ts +1135 -0
  252. package/src/containers/template.ts +573 -0
  253. package/src/exceptions/index.ts +29 -0
  254. package/src/index.ts +33 -0
  255. package/src/interfaces/adoc.ts +18 -0
  256. package/src/interfaces/macros.ts +54 -0
  257. package/src/interfaces/project-interfaces.ts +208 -0
  258. package/src/interfaces/request-status-interfaces.ts +30 -0
  259. package/src/interfaces/resource-interfaces.ts +179 -0
  260. package/src/macros/base-macro.ts +176 -0
  261. package/src/macros/common.ts +24 -0
  262. package/src/macros/createCards/index.ts +57 -0
  263. package/src/macros/createCards/metadata.ts +21 -0
  264. package/src/macros/graph/index.ts +130 -0
  265. package/src/macros/graph/metadata.ts +21 -0
  266. package/src/macros/index.ts +321 -0
  267. package/src/macros/report/index.ts +88 -0
  268. package/src/macros/report/metadata.ts +21 -0
  269. package/src/macros/scoreCard/index.ts +55 -0
  270. package/src/macros/scoreCard/metadata.ts +21 -0
  271. package/src/macros/task-queue.ts +79 -0
  272. package/src/module-manager.ts +443 -0
  273. package/src/permissions/action-guard.ts +77 -0
  274. package/src/project-settings.ts +140 -0
  275. package/src/resources/array-handler.ts +141 -0
  276. package/src/resources/card-type-resource.ts +455 -0
  277. package/src/resources/create-defaults.ts +216 -0
  278. package/src/resources/field-type-resource.ts +533 -0
  279. package/src/resources/file-resource.ts +433 -0
  280. package/src/resources/folder-resource.ts +140 -0
  281. package/src/resources/graph-model-resource.ts +205 -0
  282. package/src/resources/graph-view-resource.ts +199 -0
  283. package/src/resources/link-type-resource.ts +191 -0
  284. package/src/resources/report-resource.ts +224 -0
  285. package/src/resources/resource-object.ts +246 -0
  286. package/src/resources/template-resource.ts +210 -0
  287. package/src/resources/workflow-resource.ts +205 -0
  288. package/src/types/queries.ts +149 -0
  289. package/src/utils/card-utils.ts +83 -0
  290. package/src/utils/clingo-fact-builder.ts +167 -0
  291. package/src/utils/clingo-facts.ts +550 -0
  292. package/src/utils/clingo-parser.ts +519 -0
  293. package/src/utils/clingo-program-builder.ts +71 -0
  294. package/src/utils/common-utils.ts +54 -0
  295. package/src/utils/constants.ts +32 -0
  296. package/src/utils/csv.ts +53 -0
  297. package/src/utils/file-utils.ts +182 -0
  298. package/src/utils/json.ts +118 -0
  299. package/src/utils/lexorank.ts +180 -0
  300. package/src/utils/log-utils.ts +127 -0
  301. package/src/utils/random.ts +37 -0
  302. package/src/utils/resource-utils.ts +180 -0
  303. package/src/utils/sanitize-svg.ts +46 -0
  304. package/src/utils/user-preferences.ts +126 -0
  305. package/src/utils/validate.ts +66 -0
  306. 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
+ }