@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,180 @@
1
+ /**
2
+ Cyberismo
3
+ Copyright © Cyberismo Ltd and contributors 2024
4
+ 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.
5
+ 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.
6
+ You should have received a copy of the GNU Affero General Public
7
+ License along with this program. If not, see <https://www.gnu.org/licenses/>.
8
+ */
9
+
10
+ // node
11
+ import { join, parse, sep } from 'node:path';
12
+
13
+ import type { Project } from '../containers/project.js';
14
+ import { stripExtension } from './file-utils.js';
15
+
16
+ // Resource name parts are:
17
+ // - prefix; name of the project this resource is part of
18
+ // - type; type of resource; in plural
19
+ // - identifier; unique name (within a project/module) for the resource
20
+ export interface ResourceName {
21
+ prefix: string;
22
+ type: string; // todo: should be a ResourceFolderType
23
+ identifier: string;
24
+ }
25
+
26
+ // Indexes of resource name parts
27
+ const PREFIX_INDEX = 0;
28
+ const TYPE_INDEX = 1;
29
+ const IDENTIFIER_INDEX = 2;
30
+ // Valid resource name has three parts
31
+ const RESOURCE_NAME_PARTS = 3;
32
+
33
+ // Checks if name is valid (3 parts, separated by '/').
34
+ export function isResourceName(name: string): boolean {
35
+ const partsCount = name.split('/').length;
36
+ return partsCount === RESOURCE_NAME_PARTS;
37
+ }
38
+
39
+ /**
40
+ * Returns resource name parts (project prefix, type in plural, name of the resource).
41
+ * @param resourceName Name of the resource (e.g. <prefix>/<type>/<name>)
42
+ * @param strict If true, does not allow names without 'prefix' and 'type'.
43
+ * @throws if 'resourceName' is not valid resource name.
44
+ * @returns resource name parts: project or module prefix, resource type (plural) and actual name of the resource.
45
+ * @todo: In the future, switch the default value of 'strict' to true. Only in certain cases should we accept names with just 'identifier'.
46
+ */
47
+ export function resourceName(
48
+ resourceName: string,
49
+ strict: boolean = false,
50
+ ): ResourceName {
51
+ const parts = resourceName.split('/');
52
+ // just resource identifier - type and prefix are unknown
53
+ if (parts.length === 1 && parts.at(0) !== '') {
54
+ if (strict) {
55
+ throw new Error(`Name '${resourceName}' is not valid resource name`);
56
+ }
57
+ return {
58
+ prefix: '',
59
+ type: '',
60
+ identifier: resourceName,
61
+ };
62
+ }
63
+ // resource name
64
+ if (parts.length === RESOURCE_NAME_PARTS) {
65
+ return {
66
+ prefix: parts[PREFIX_INDEX],
67
+ type: parts[TYPE_INDEX],
68
+ identifier: parse(parts[IDENTIFIER_INDEX]).name,
69
+ };
70
+ }
71
+ // other formats are not accepted
72
+ if (resourceName === '') {
73
+ throw new Error('Must define resource name to query its details');
74
+ }
75
+ throw new Error(`Name '${resourceName}' is not valid resource name`);
76
+ }
77
+
78
+ /**
79
+ * Converts resource name to path.
80
+ * @param project Project
81
+ * @param resourceName Name of the resource (e.g. <prefix>/<type>/<name>)
82
+ * @returns path to resource metadata file
83
+ */
84
+ export function resourceNameToPath(
85
+ project: Project,
86
+ resourceName: ResourceName,
87
+ ): string {
88
+ if (project.projectPrefix === resourceName.prefix) {
89
+ return join(
90
+ project.paths.resourcesFolder,
91
+ resourceName.type,
92
+ resourceName.identifier + '.json',
93
+ );
94
+ } else if (resourceName.prefix !== '') {
95
+ return join(
96
+ project.paths.modulesFolder,
97
+ resourceName.prefix,
98
+ resourceName.type,
99
+ resourceName.identifier + '.json',
100
+ );
101
+ }
102
+ throw new Error('resourceName does not contain prefix');
103
+ }
104
+
105
+ /**
106
+ * Resource metadata file path to resource name (e.g. <prefix>/<type>/<name>)
107
+ * @param project Project where resource is in
108
+ * @param path Path to resource metadata file
109
+ * @returns Resource name (<prefix>/<type>/<name>)
110
+ */
111
+ export function pathToResourceName(
112
+ project: Project,
113
+ path: string,
114
+ ): ResourceName {
115
+ const parts = path.split(sep);
116
+ const modulesIndex = parts.lastIndexOf('modules');
117
+ const localIndex = parts.lastIndexOf('local');
118
+ // Check that either 'local' or 'modules' is included in path (but not both).
119
+ // And after that there is required amount of parts.
120
+ if (
121
+ (modulesIndex === -1 && localIndex === -1) ||
122
+ (modulesIndex !== -1 && localIndex !== -1) ||
123
+ (modulesIndex !== -1 &&
124
+ localIndex === 1 &&
125
+ parts.length === modulesIndex + 3) ||
126
+ (modulesIndex === -1 &&
127
+ localIndex !== -1 &&
128
+ parts.length === localIndex + 2)
129
+ ) {
130
+ throw new Error(`invalid path: ${path}`);
131
+ }
132
+ // Finally check that all relevant parts are defined.
133
+ const prefix =
134
+ modulesIndex !== -1 ? parts.at(modulesIndex + 1) : project.projectPrefix;
135
+ const typeIndex = modulesIndex !== -1 ? modulesIndex + 2 : localIndex + 1;
136
+ const identifierIndex =
137
+ modulesIndex !== -1 ? modulesIndex + 3 : localIndex + 2;
138
+ const type = parts.at(typeIndex);
139
+ const identifier = stripExtension(parts.at(identifierIndex)!);
140
+ if (!identifier || !type || !prefix) {
141
+ throw new Error(`invalid path: ${path}`);
142
+ }
143
+ return {
144
+ prefix: prefix,
145
+ type: type,
146
+ identifier: identifier,
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Returns ResourceName as a single string.
152
+ * @param resourceName Resource name to convert.
153
+ * @returns resource name as a single string.
154
+ * @note that valid resource names are: empty string, identifier alone and prefix/type/identifier combination.
155
+ */
156
+ export function resourceNameToString(resourceName: ResourceName): string {
157
+ if (!resourceName.prefix && !resourceName.type && !resourceName.identifier) {
158
+ return '';
159
+ }
160
+ if (resourceName.identifier === '') {
161
+ throw new Error(`Not a valid resource name. Identifier is missing.`);
162
+ }
163
+ if (
164
+ resourceName.prefix &&
165
+ resourceName.identifier &&
166
+ resourceName.type === ''
167
+ ) {
168
+ throw new Error(`Not a valid resource name. Type is missing.`);
169
+ }
170
+ if (
171
+ resourceName.prefix === '' &&
172
+ resourceName.identifier &&
173
+ resourceName.type
174
+ ) {
175
+ throw new Error(`Not a valid resource name. Prefix is missing.`);
176
+ }
177
+ return resourceName.prefix && resourceName.type && resourceName.prefix
178
+ ? `${resourceName.prefix}/${resourceName.type}/${resourceName.identifier}`
179
+ : `${resourceName.identifier}`;
180
+ }
@@ -0,0 +1,46 @@
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 createDOMPurify, { type WindowLike } from 'dompurify';
14
+ import { Buffer } from 'buffer';
15
+ import { JSDOM } from 'jsdom';
16
+
17
+ const window = new JSDOM('').window as unknown as Window;
18
+
19
+ // Remove SVG size to make it scale in the application properly
20
+ const removeSvgWidthAndHeight = (node: Element) => {
21
+ if (node.nodeName === 'svg') {
22
+ node.removeAttribute('width');
23
+ node.removeAttribute('height');
24
+ }
25
+ };
26
+
27
+ /**
28
+ * Sanitize an SVG Buffer and return a base64-encoded string
29
+ * @param buffer - SVG content as a Buffer
30
+ * @returns base64-encoded sanitized SVG string
31
+ */
32
+ export function sanitizeSvgBase64(buffer: Buffer): string {
33
+ const DOMPurify = createDOMPurify(window as unknown as WindowLike);
34
+
35
+ const dirty = buffer.toString('utf-8');
36
+
37
+ DOMPurify.setConfig({ USE_PROFILES: { svg: true } });
38
+ DOMPurify.addHook('afterSanitizeAttributes', removeSvgWidthAndHeight);
39
+
40
+ let cleaned = DOMPurify.sanitize(dirty);
41
+
42
+ // Remove link titles, quick fix for Clingraph/Graphviz generated titles for links that are quite strange
43
+ cleaned = cleaned.replace(/\s*xlink:title=(["']).*?\1/g, '');
44
+
45
+ return Buffer.from(cleaned, 'utf-8').toString('base64');
46
+ }
@@ -0,0 +1,126 @@
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 { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
14
+ import { formatJson } from './json.js';
15
+ import { dirname } from 'path';
16
+
17
+ export interface UserPreferencesObject {
18
+ editCommand: {
19
+ [platform: string]: {
20
+ command: string;
21
+ args: string[];
22
+ };
23
+ };
24
+ attachmentEditors: {
25
+ [platform: string]: {
26
+ mimeType: string;
27
+ command: string;
28
+ }[];
29
+ };
30
+ }
31
+ /**
32
+ * The class checks if the preferences file exists when instantiated, and if not, creates it with a default JSON object.
33
+ * The getPreferences() method simply reads and parses the file to return the preferences object.
34
+ */
35
+ export class UserPreferences {
36
+ // If preferences do not exist, they are initialised
37
+ // with these defaults.
38
+ static defaults = {
39
+ editCommand: {
40
+ darwin: {
41
+ command: 'code',
42
+ args: ['{{cardContentPath}}', '{{cardJsonPath}}'],
43
+ },
44
+ linux: {
45
+ command: 'vi',
46
+ args: ['{{cardContentPath}}', '{{cardJsonPath}}'],
47
+ },
48
+ win32: {
49
+ command: 'notepad.exe',
50
+ args: ['{{cardContentPath}}', '{{cardJsonPath}}'],
51
+ },
52
+ },
53
+ attachmentEditors: {
54
+ darwin: [
55
+ {
56
+ mimeType: 'image/png',
57
+ command: "open -a draw.io '{{attachmentPath}}'",
58
+ },
59
+ {
60
+ mimeType: 'image/svg+xml',
61
+ command: "open -a draw.io '{{attachmentPath}}'",
62
+ },
63
+ {
64
+ mimeType: 'application/pdf',
65
+ command: 'open -a Preview "{{attachmentPath}}"',
66
+ },
67
+ ],
68
+ linux: [
69
+ {
70
+ mimeType: 'image/png',
71
+ command: 'drawio {{attachmentPath}}',
72
+ },
73
+ {
74
+ mimeType: 'image/svg+xml',
75
+ command: 'drawio {{attachmentPath}}',
76
+ },
77
+ ],
78
+ win32: [
79
+ {
80
+ mimeType: 'text/plain',
81
+ command: 'notepad.exe {{attachmentPath}}',
82
+ },
83
+ {
84
+ mimeType: 'image/png',
85
+ command:
86
+ '"C:\\Program Files\\draw.io\\draw.io.exe" "{{attachmentPath}}"',
87
+ },
88
+ {
89
+ mimeType: 'image/svg+xml',
90
+ command:
91
+ '"C:\\Program Files\\draw.io\\draw.io.exe" "{{attachmentPath}}"',
92
+ },
93
+ ],
94
+ },
95
+ };
96
+
97
+ constructor(private prefsFilePath: string) {
98
+ if (!existsSync(this.prefsFilePath)) {
99
+ // Create the preferences directory based on prefsFilePath dirname
100
+ const prefsDir = dirname(this.prefsFilePath);
101
+
102
+ try {
103
+ if (!existsSync(prefsDir)) {
104
+ mkdirSync(prefsDir, { recursive: true });
105
+ }
106
+ // File does not exist, create it with default content
107
+ writeFileSync(this.prefsFilePath, formatJson(UserPreferences.defaults));
108
+ } catch (error) {
109
+ throw new Error(
110
+ `Error creating preferences file '${this.prefsFilePath}': ${error}`,
111
+ );
112
+ }
113
+ }
114
+ }
115
+
116
+ public getPreferences(): UserPreferencesObject {
117
+ // Read and parse the preferences file
118
+ try {
119
+ return JSON.parse(readFileSync(this.prefsFilePath, 'utf8'));
120
+ } catch (error) {
121
+ throw new Error(
122
+ `Error reading preferences file '${this.prefsFilePath}': ${error}`,
123
+ );
124
+ }
125
+ }
126
+ }
@@ -0,0 +1,66 @@
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
+ import { type Schema, Validator } from 'jsonschema';
13
+ import { DHValidationError, SchemaNotFound } from '../exceptions/index.js';
14
+ import { schemas } from '@cyberismo/resources';
15
+
16
+ /**
17
+ * Validates a JSON object against a schema
18
+ * @param object The object to validate
19
+ * @param schemaId The id of the schema to validate against
20
+ * @param validator An optional validator to use. If validator is not provided or does not contain any schemas, project schemas will be used
21
+ * @returns The object casted to the type T if it is valid
22
+ * @throws DHValidationError if the object is not valid
23
+ * @throws SchemaNotFound if the schema with the given id is not found
24
+ */
25
+ export function validateJson<T>(
26
+ object: unknown,
27
+ options: {
28
+ schemaId?: string;
29
+ schema?: Schema;
30
+ validator?: Validator;
31
+ },
32
+ ): T {
33
+ const { schemaId, schema } = options;
34
+ let validator = options.validator;
35
+
36
+ if (!schema && !schemaId) {
37
+ throw new Error('Must either specify schema or schemaId');
38
+ }
39
+
40
+ if (!validator) {
41
+ validator = new Validator();
42
+ for (const schema of schemas) {
43
+ validator.addSchema(schema, schema.$id);
44
+ }
45
+ }
46
+
47
+ let jsonSchema: Schema | undefined;
48
+
49
+ if (schema) {
50
+ jsonSchema = schema;
51
+ } else {
52
+ jsonSchema = Object.values(validator.schemas).find(
53
+ (s) => s.$id === schemaId,
54
+ );
55
+ }
56
+
57
+ if (!jsonSchema) {
58
+ throw new SchemaNotFound(`Schema with id ${schemaId} not found`);
59
+ }
60
+ const result = validator.validate(object, jsonSchema);
61
+ if (!result.valid) {
62
+ throw new DHValidationError('Validation failed', result.errors);
63
+ }
64
+ // we know that the object is valid, so we can safely cast it to T
65
+ return object as T;
66
+ }
@@ -0,0 +1,189 @@
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.
7
+ This program is distributed in the hope that it will be useful, but WITHOUT
8
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9
+ FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
10
+ details. 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 type { DataType } from '../interfaces/resource-interfaces.js';
15
+ import { isBigInt } from '../utils/common-utils.js';
16
+ import * as EmailValidator from 'email-validator';
17
+
18
+ const SHORT_TEXT_MAX_LENGTH = 80;
19
+
20
+ /**
21
+ * Checks if conversion 'from' 'to' can be done.
22
+ * @param from Data type to convert from
23
+ * @param to Data type to convert to
24
+ * @returns true if conversion can be done, false otherwise.
25
+ */
26
+ export function allowed(from: DataType, to: DataType) {
27
+ // Converting from strings is fine, except to enum.
28
+ if (from === 'longText' || from === 'shortText') {
29
+ switch (to) {
30
+ case 'boolean':
31
+ case 'date':
32
+ case 'dateTime':
33
+ case 'integer':
34
+ case 'list':
35
+ case 'longText':
36
+ case 'number':
37
+ case 'person':
38
+ case 'shortText':
39
+ return true;
40
+ default:
41
+ return false;
42
+ }
43
+ }
44
+ // Converting from<->to number formats is fine
45
+ if (
46
+ (from === 'number' && to === 'integer') ||
47
+ (from === 'integer' && to === 'number')
48
+ ) {
49
+ return true;
50
+ }
51
+
52
+ // Converting to strings is fine
53
+ if (to === 'shortText' || to === 'longText') {
54
+ return true;
55
+ }
56
+
57
+ // Converting from<->to date formats is fine
58
+ if (
59
+ (from === 'dateTime' && to === 'date') ||
60
+ (from === 'date' && to === 'dateTime')
61
+ ) {
62
+ return true;
63
+ }
64
+ // Everything else is forbidden.
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * Converts number value to other data types.
70
+ * @param value Value to convert
71
+ * @param to Date type to which value is converted to
72
+ * @returns converted value, or null if cannot convert
73
+ * Allowed conversions are
74
+ * date -> dateTime
75
+ * dateTime -> date
76
+ * date/dateTime -> shortText/longText
77
+ */
78
+ export function fromDate<T>(value: T, to: DataType) {
79
+ if (to === 'date') {
80
+ const tempDate = new Date(value as Date);
81
+ return new Date(tempDate).toISOString().slice(0, 10);
82
+ }
83
+ if (to === 'dateTime') {
84
+ const tempDate = new Date(value as Date);
85
+ return new Date(tempDate).toISOString();
86
+ }
87
+ if (to === 'longText' || to === 'shortText') {
88
+ return String(value);
89
+ }
90
+ return null;
91
+ }
92
+
93
+ /**
94
+ * Converts number value to other data types.
95
+ * @param value Value to convert
96
+ * @param to Date type to which value is converted to
97
+ * @returns converted value, or null if cannot convert
98
+ * Allowed conversions are
99
+ * integer -> number
100
+ * number -> integer
101
+ * number/integer -> shortText
102
+ * number/integer -> longText
103
+ */
104
+ export function fromNumber<T>(value: T, to: DataType) {
105
+ if (to === 'integer') {
106
+ return Math.trunc(value as number);
107
+ }
108
+ if (to === 'longText') {
109
+ return String(value);
110
+ }
111
+ if (to === 'number') {
112
+ return Number(value);
113
+ }
114
+ if (to === 'shortText') {
115
+ const tempString = String(value);
116
+ return tempString.length > SHORT_TEXT_MAX_LENGTH ? null : tempString;
117
+ }
118
+ return null;
119
+ }
120
+
121
+ /**
122
+ * Converts string value to other data types.
123
+ * @param value Value to convert
124
+ * @param to Date type to which value is converted to
125
+ * @returns converted value, or null if cannot convert
126
+ * Allowed conversions are
127
+ * longText -> shortText
128
+ * shortText -> longText
129
+ * longText/shortText -> integer
130
+ * longText/shortText -> number
131
+ * longText/shortText -> list
132
+ * longText/shortText -> date/dateTime
133
+ * longText/shortText -> boolean
134
+ */
135
+ export function fromString<T>(value: T, to: DataType) {
136
+ switch (to) {
137
+ case 'boolean': {
138
+ if (value === 'true') return true;
139
+ if (value === 'false') return false;
140
+ return null;
141
+ }
142
+ case 'date': {
143
+ try {
144
+ const tempDate = new Date((value as string) + 'Z').toUTCString();
145
+ return new Date(tempDate).toISOString().slice(0, 10);
146
+ } catch {
147
+ return null;
148
+ }
149
+ }
150
+ case 'dateTime': {
151
+ try {
152
+ const tempDate = new Date((value as string) + 'Z').toUTCString();
153
+ return new Date(tempDate).toISOString();
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+ case 'integer': {
159
+ if (isBigInt(value as string)) {
160
+ return BigInt(value as string);
161
+ }
162
+ const tempInt = parseInt(value as string);
163
+ return isNaN(tempInt) ? null : tempInt;
164
+ }
165
+ case 'list': {
166
+ return (value as string).split(',');
167
+ }
168
+ case 'longText': {
169
+ return value;
170
+ }
171
+ case 'number': {
172
+ if (isBigInt(value as string)) {
173
+ return BigInt(value as string);
174
+ }
175
+ const tempNumber = parseFloat(value as string);
176
+ return isNaN(tempNumber) ? null : tempNumber;
177
+ }
178
+ case 'person': {
179
+ if (EmailValidator.validate(value as string)) {
180
+ return String(value);
181
+ }
182
+ return null;
183
+ }
184
+ case 'shortText': {
185
+ return (value as string).length > SHORT_TEXT_MAX_LENGTH ? null : value;
186
+ }
187
+ }
188
+ return null;
189
+ }