@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,519 @@
|
|
|
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 { DataType } from '../interfaces/resource-interfaces.js';
|
|
14
|
+
import type {
|
|
15
|
+
BaseResult,
|
|
16
|
+
LinkDirection,
|
|
17
|
+
ParseResult,
|
|
18
|
+
} from '../types/queries.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This function reverses the encoding made by the "encodeClingoValue" function
|
|
22
|
+
*/
|
|
23
|
+
export function decodeClingoValue(value: string) {
|
|
24
|
+
return value.replace(/\\([n\\"])/g, (_, char) => {
|
|
25
|
+
if (char === 'n') {
|
|
26
|
+
return '\n';
|
|
27
|
+
}
|
|
28
|
+
return char;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class ClingoParser {
|
|
33
|
+
private keywords = [
|
|
34
|
+
'queryError',
|
|
35
|
+
'result',
|
|
36
|
+
'childResult',
|
|
37
|
+
'field',
|
|
38
|
+
'enumField',
|
|
39
|
+
'listField',
|
|
40
|
+
'label',
|
|
41
|
+
'link',
|
|
42
|
+
'transitionDenied',
|
|
43
|
+
'movingCardDenied',
|
|
44
|
+
'deletingCardDenied',
|
|
45
|
+
'editingFieldDenied',
|
|
46
|
+
'editingContentDenied',
|
|
47
|
+
'notification',
|
|
48
|
+
'policyCheckFailure',
|
|
49
|
+
'policyCheckSuccess',
|
|
50
|
+
'order',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
private result: ParseResult<BaseResult> = {
|
|
54
|
+
results: [],
|
|
55
|
+
error: null,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// The queue now stores the parameters instead of functions
|
|
59
|
+
private resultQueue: { key: string }[] = [];
|
|
60
|
+
private childResultQueue: {
|
|
61
|
+
parentKey: string;
|
|
62
|
+
childKey: string;
|
|
63
|
+
collection: string;
|
|
64
|
+
}[] = [];
|
|
65
|
+
private tempResults: { [key: string]: BaseResult } = {};
|
|
66
|
+
private orderQueue: {
|
|
67
|
+
level: number;
|
|
68
|
+
collection: string;
|
|
69
|
+
fieldIndex: number;
|
|
70
|
+
field: string;
|
|
71
|
+
direction: 'ASC' | 'DESC';
|
|
72
|
+
}[] = [];
|
|
73
|
+
private collections: Set<string> = new Set();
|
|
74
|
+
private reset() {
|
|
75
|
+
this.result = {
|
|
76
|
+
results: [],
|
|
77
|
+
error: null,
|
|
78
|
+
};
|
|
79
|
+
this.resultQueue = [];
|
|
80
|
+
this.childResultQueue = [];
|
|
81
|
+
this.tempResults = {};
|
|
82
|
+
this.orderQueue = [];
|
|
83
|
+
this.collections = new Set();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Command handlers for each possible keyword
|
|
88
|
+
* All of them will get parameters as strings
|
|
89
|
+
* You can trust that clingo will always provide the correct number of parameters / types
|
|
90
|
+
*/
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
|
92
|
+
private commandHandlers: Record<string, Function> = {
|
|
93
|
+
queryError: (message: string, ...params: string[]) => {
|
|
94
|
+
this.result.error = `${message}${params.length > 1 ? ` ${params.join(', ')}` : ''}`;
|
|
95
|
+
},
|
|
96
|
+
result: (key: string) => {
|
|
97
|
+
this.resultQueue.push({ key });
|
|
98
|
+
},
|
|
99
|
+
childResult: (parentKey: string, childKey: string, collection: string) => {
|
|
100
|
+
this.childResultQueue.push({ parentKey, childKey, collection });
|
|
101
|
+
this.collections.add(collection);
|
|
102
|
+
},
|
|
103
|
+
enumField: async (
|
|
104
|
+
key: string,
|
|
105
|
+
fieldName: string,
|
|
106
|
+
fieldValue: string,
|
|
107
|
+
index: string,
|
|
108
|
+
displayValue: string,
|
|
109
|
+
) => {
|
|
110
|
+
const res = this.getOrInitResult(key);
|
|
111
|
+
const decoded = decodeClingoValue(fieldValue);
|
|
112
|
+
const parsedIndex = parseInt(index, 10);
|
|
113
|
+
res[fieldName] = {
|
|
114
|
+
value: decoded,
|
|
115
|
+
index: parsedIndex,
|
|
116
|
+
displayValue,
|
|
117
|
+
};
|
|
118
|
+
},
|
|
119
|
+
// NOTE: Must be tested in INTDEV-623
|
|
120
|
+
listField: async (
|
|
121
|
+
key: string,
|
|
122
|
+
fieldName: string,
|
|
123
|
+
fieldValue: string,
|
|
124
|
+
index: string,
|
|
125
|
+
displayValue: string,
|
|
126
|
+
) => {
|
|
127
|
+
const res = this.getOrInitResult(key);
|
|
128
|
+
const decoded = decodeClingoValue(fieldValue);
|
|
129
|
+
if (!res[fieldName] || !Array.isArray(res[fieldName])) {
|
|
130
|
+
res[fieldName] = [];
|
|
131
|
+
}
|
|
132
|
+
const parsedIndex = parseInt(index, 10);
|
|
133
|
+
(res[fieldName] as unknown[]).push({
|
|
134
|
+
value: decoded,
|
|
135
|
+
index: parsedIndex,
|
|
136
|
+
displayValue,
|
|
137
|
+
});
|
|
138
|
+
},
|
|
139
|
+
field: async (
|
|
140
|
+
key: string,
|
|
141
|
+
fieldName: string,
|
|
142
|
+
fieldValue: string,
|
|
143
|
+
dataType: DataType,
|
|
144
|
+
) => {
|
|
145
|
+
const res = this.getOrInitResult(key);
|
|
146
|
+
const decoded = decodeClingoValue(fieldValue);
|
|
147
|
+
switch (dataType) {
|
|
148
|
+
case 'shortText':
|
|
149
|
+
case 'longText':
|
|
150
|
+
case 'person':
|
|
151
|
+
case 'date':
|
|
152
|
+
case 'dateTime':
|
|
153
|
+
res[fieldName] = decoded;
|
|
154
|
+
break;
|
|
155
|
+
case 'number':
|
|
156
|
+
res[fieldName] = parseFloat(decoded);
|
|
157
|
+
break;
|
|
158
|
+
case 'integer':
|
|
159
|
+
res[fieldName] = parseInt(decoded, 10);
|
|
160
|
+
break;
|
|
161
|
+
case 'boolean':
|
|
162
|
+
res[fieldName] = fieldValue === 'true';
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
label: (key: string, label: string) => {
|
|
167
|
+
const res = this.getOrInitResult(key);
|
|
168
|
+
res.labels.push(label);
|
|
169
|
+
},
|
|
170
|
+
link: (
|
|
171
|
+
key: string, // key is the card itself
|
|
172
|
+
cardKey: string, // cardKey is otherCard this is being linked to
|
|
173
|
+
title: string,
|
|
174
|
+
linkType: string,
|
|
175
|
+
displayName: string,
|
|
176
|
+
direction: LinkDirection,
|
|
177
|
+
linkSource: 'user' | 'calculated',
|
|
178
|
+
linkDescription?: string,
|
|
179
|
+
) => {
|
|
180
|
+
const res = this.getOrInitResult(key);
|
|
181
|
+
res.links.push({
|
|
182
|
+
key: cardKey,
|
|
183
|
+
linkType,
|
|
184
|
+
displayName,
|
|
185
|
+
linkDescription,
|
|
186
|
+
direction,
|
|
187
|
+
linkSource,
|
|
188
|
+
title,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
transitionDenied: (
|
|
192
|
+
key: string,
|
|
193
|
+
transitionName: string,
|
|
194
|
+
errorMessage: string,
|
|
195
|
+
) => {
|
|
196
|
+
const res = this.getOrInitResult(key);
|
|
197
|
+
res.deniedOperations.transition.push({ transitionName, errorMessage });
|
|
198
|
+
},
|
|
199
|
+
movingCardDenied: (key: string, errorMessage: string) => {
|
|
200
|
+
const res = this.getOrInitResult(key);
|
|
201
|
+
res.deniedOperations.move.push({ errorMessage });
|
|
202
|
+
},
|
|
203
|
+
deletingCardDenied: (key: string, errorMessage: string) => {
|
|
204
|
+
const res = this.getOrInitResult(key);
|
|
205
|
+
res.deniedOperations.delete.push({ errorMessage });
|
|
206
|
+
},
|
|
207
|
+
editingFieldDenied: (
|
|
208
|
+
key: string,
|
|
209
|
+
fieldName: string,
|
|
210
|
+
errorMessage: string,
|
|
211
|
+
) => {
|
|
212
|
+
const res = this.getOrInitResult(key);
|
|
213
|
+
res.deniedOperations.editField.push({ fieldName, errorMessage });
|
|
214
|
+
},
|
|
215
|
+
editingContentDenied: (key: string, errorMessage: string) => {
|
|
216
|
+
const res = this.getOrInitResult(key);
|
|
217
|
+
res.deniedOperations.editContent.push({ errorMessage });
|
|
218
|
+
},
|
|
219
|
+
notification: (
|
|
220
|
+
key: string,
|
|
221
|
+
category: string,
|
|
222
|
+
title: string,
|
|
223
|
+
message: string,
|
|
224
|
+
) => {
|
|
225
|
+
const res = this.getOrInitResult(key);
|
|
226
|
+
res.notifications.push({ key, category, title, message });
|
|
227
|
+
},
|
|
228
|
+
policyCheckFailure: (
|
|
229
|
+
key: string,
|
|
230
|
+
category: string,
|
|
231
|
+
title: string,
|
|
232
|
+
errorMessage: string,
|
|
233
|
+
fieldName?: string,
|
|
234
|
+
) => {
|
|
235
|
+
const res = this.getOrInitResult(key);
|
|
236
|
+
res.policyChecks.failures.push({
|
|
237
|
+
category,
|
|
238
|
+
title,
|
|
239
|
+
errorMessage,
|
|
240
|
+
fieldName,
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
policyCheckSuccess: (key: string, category: string, title: string) => {
|
|
244
|
+
const res = this.getOrInitResult(key);
|
|
245
|
+
res.policyChecks.successes.push({ category, title });
|
|
246
|
+
},
|
|
247
|
+
order: (
|
|
248
|
+
level: string,
|
|
249
|
+
collection: string,
|
|
250
|
+
fieldIndex: string,
|
|
251
|
+
field: string,
|
|
252
|
+
direction: 'ASC' | 'DESC',
|
|
253
|
+
) => {
|
|
254
|
+
const parsedLevel = parseInt(level, 10);
|
|
255
|
+
const parsedFieldIndex = parseInt(fieldIndex, 10);
|
|
256
|
+
this.orderQueue.push({
|
|
257
|
+
level: parsedLevel,
|
|
258
|
+
collection,
|
|
259
|
+
fieldIndex: parsedFieldIndex,
|
|
260
|
+
field,
|
|
261
|
+
direction,
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
private getOrInitResult(key: string): BaseResult {
|
|
267
|
+
if (!this.tempResults[key]) {
|
|
268
|
+
this.tempResults[key] = {
|
|
269
|
+
key,
|
|
270
|
+
labels: [],
|
|
271
|
+
links: [],
|
|
272
|
+
notifications: [],
|
|
273
|
+
policyChecks: { successes: [], failures: [] },
|
|
274
|
+
deniedOperations: {
|
|
275
|
+
transition: [],
|
|
276
|
+
move: [],
|
|
277
|
+
delete: [],
|
|
278
|
+
editField: [],
|
|
279
|
+
editContent: [],
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
return this.tempResults[key];
|
|
284
|
+
}
|
|
285
|
+
private sortByLevel(
|
|
286
|
+
results: BaseResult[],
|
|
287
|
+
level: number = 1,
|
|
288
|
+
currentCollection?: string,
|
|
289
|
+
) {
|
|
290
|
+
const levelOrders = this.orderQueue
|
|
291
|
+
.filter(
|
|
292
|
+
(order) =>
|
|
293
|
+
order.level === level &&
|
|
294
|
+
(currentCollection ? order.collection === currentCollection : true), // if no collection specified at top-level, take all
|
|
295
|
+
)
|
|
296
|
+
.sort((a, b) => a.fieldIndex - b.fieldIndex);
|
|
297
|
+
|
|
298
|
+
// Apply sorting instructions for this level/collection if any
|
|
299
|
+
if (levelOrders.length > 0) {
|
|
300
|
+
results.sort((a, b) => {
|
|
301
|
+
for (const { field, direction } of levelOrders) {
|
|
302
|
+
const sortOrder = direction === 'ASC' ? -1 : 1;
|
|
303
|
+
|
|
304
|
+
const firstValue = this.getComparableValue(a[field]);
|
|
305
|
+
const secondValue = this.getComparableValue(b[field]);
|
|
306
|
+
|
|
307
|
+
if (firstValue == null && secondValue == null) {
|
|
308
|
+
continue; // both are null, move on to next field
|
|
309
|
+
} else if (firstValue == null) {
|
|
310
|
+
return sortOrder; // first is considered less
|
|
311
|
+
} else if (secondValue == null) {
|
|
312
|
+
return -sortOrder; // second is considered less
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// Regular comparison
|
|
316
|
+
if (firstValue < secondValue) return sortOrder;
|
|
317
|
+
if (firstValue > secondValue) return -sortOrder;
|
|
318
|
+
// if equal, try next field
|
|
319
|
+
}
|
|
320
|
+
// if all fields equal
|
|
321
|
+
return 0;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Recursively sort all known child collections
|
|
326
|
+
for (const result of results) {
|
|
327
|
+
for (const childCollection of this.collections) {
|
|
328
|
+
const childResults = result[childCollection];
|
|
329
|
+
if (Array.isArray(childResults)) {
|
|
330
|
+
this.sortByLevel(childResults, level + 1, childCollection);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private getComparableValue(value: unknown) {
|
|
337
|
+
if (value == null) {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
if (
|
|
341
|
+
typeof value === 'object' &&
|
|
342
|
+
'index' in value &&
|
|
343
|
+
typeof value.index === 'number'
|
|
344
|
+
) {
|
|
345
|
+
return value.index;
|
|
346
|
+
}
|
|
347
|
+
if (Array.isArray(value)) {
|
|
348
|
+
const indeces: number[] = [];
|
|
349
|
+
for (const item of value) {
|
|
350
|
+
if (
|
|
351
|
+
item != null &&
|
|
352
|
+
typeof item === 'object' &&
|
|
353
|
+
'index' in item &&
|
|
354
|
+
typeof item.index === 'number'
|
|
355
|
+
) {
|
|
356
|
+
indeces.push(item.index);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return Math.min(...indeces);
|
|
360
|
+
}
|
|
361
|
+
return value;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
private applyResultProcessing() {
|
|
365
|
+
// Process results and parent-child relationships
|
|
366
|
+
this.resultQueue.forEach(({ key }) => {
|
|
367
|
+
const res = this.getOrInitResult(key);
|
|
368
|
+
this.result.results.push(res); // Here we assume the query is correct and returns the data specified by the query
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
this.childResultQueue.forEach(({ parentKey, childKey, collection }) => {
|
|
372
|
+
const parent = this.getOrInitResult(parentKey);
|
|
373
|
+
const child = this.getOrInitResult(childKey);
|
|
374
|
+
|
|
375
|
+
if (!parent[collection] || !Array.isArray(parent[collection])) {
|
|
376
|
+
parent[collection] = [];
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
(parent[collection] as unknown[]).push(child);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
this.sortByLevel(this.result.results);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* This methods is responsible for converting clingo output to a parsed object
|
|
387
|
+
* @param input clingo input to parse
|
|
388
|
+
* @returns
|
|
389
|
+
*/
|
|
390
|
+
public async parseInput(input: string): Promise<ParseResult<BaseResult>> {
|
|
391
|
+
let position = 0;
|
|
392
|
+
|
|
393
|
+
while (position < input.length) {
|
|
394
|
+
const keywordMatch = this.findKeyword(input, position);
|
|
395
|
+
|
|
396
|
+
if (!keywordMatch) {
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const { keyword, endIndex } = keywordMatch;
|
|
401
|
+
position = endIndex;
|
|
402
|
+
|
|
403
|
+
const parsed = this.parseArguments(input, position);
|
|
404
|
+
if (parsed) {
|
|
405
|
+
// Apply the command handler with sanitized arguments
|
|
406
|
+
await this.commandHandlers[keyword](...parsed.args);
|
|
407
|
+
position = parsed.endPosition; // move position after the argument closing parenthesis
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
this.applyResultProcessing();
|
|
412
|
+
const result = this.result;
|
|
413
|
+
|
|
414
|
+
// Reset the parser state
|
|
415
|
+
this.reset();
|
|
416
|
+
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* This method finds the next keyword in a string after a specified point
|
|
422
|
+
* @param input The string which it being searched
|
|
423
|
+
* @param start The position from which to start the search from
|
|
424
|
+
* @returns
|
|
425
|
+
*/
|
|
426
|
+
private findKeyword(
|
|
427
|
+
input: string,
|
|
428
|
+
start: number,
|
|
429
|
+
): { keyword: string; startIndex: number; endIndex: number } | null {
|
|
430
|
+
// Create a regex dynamically from the keywords list
|
|
431
|
+
const regex = new RegExp(`(${this.keywords.join('|')})\\(`, 'g');
|
|
432
|
+
|
|
433
|
+
// Apply the regex starting from the current position
|
|
434
|
+
regex.lastIndex = start;
|
|
435
|
+
const match = regex.exec(input);
|
|
436
|
+
|
|
437
|
+
if (match) {
|
|
438
|
+
return {
|
|
439
|
+
keyword: match[1], // The matched keyword (first capture group)
|
|
440
|
+
startIndex: match.index, // Position of the matched keyword
|
|
441
|
+
endIndex: match.index + match[0].length, // Position after the keyword and opening parenthesis
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* This method is a custom parser, which takes in the whole clingo output and parses the arguments.
|
|
450
|
+
* Note: Do not decode in this function. It will be handled on a higher level.
|
|
451
|
+
* As long as this function returns valid clingo, it has done it's responsibility
|
|
452
|
+
* @param input Clingo output
|
|
453
|
+
* @param position Position of the command being parsed inside the string
|
|
454
|
+
* @returns
|
|
455
|
+
*/
|
|
456
|
+
private parseArguments(
|
|
457
|
+
input: string,
|
|
458
|
+
position: number,
|
|
459
|
+
): { args: string[]; endPosition: number } | null {
|
|
460
|
+
let currentArg = '';
|
|
461
|
+
const args: string[] = [];
|
|
462
|
+
let insideQuote = false;
|
|
463
|
+
|
|
464
|
+
// calculates how deep into parenthesis we are
|
|
465
|
+
let insideParanthesis = 0;
|
|
466
|
+
|
|
467
|
+
for (let i = position; i < input.length; i++) {
|
|
468
|
+
const char = input[i];
|
|
469
|
+
|
|
470
|
+
if (char === '"') {
|
|
471
|
+
if (i !== 0 && input[i - 1] === '\\') {
|
|
472
|
+
currentArg += '"';
|
|
473
|
+
continue;
|
|
474
|
+
}
|
|
475
|
+
if (!insideQuote && insideParanthesis === 0) {
|
|
476
|
+
// We can ignore the chars, which are before a quoted string
|
|
477
|
+
currentArg = '';
|
|
478
|
+
}
|
|
479
|
+
insideQuote = !insideQuote; // Toggle inside/outside quotes
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (char === ',' && !insideQuote) {
|
|
484
|
+
if (insideParanthesis > 0) {
|
|
485
|
+
currentArg += char;
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
args.push(currentArg);
|
|
489
|
+
currentArg = '';
|
|
490
|
+
insideParanthesis = 0;
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
if (char === '(' && !insideQuote) {
|
|
494
|
+
if (insideParanthesis === 0) {
|
|
495
|
+
currentArg = '';
|
|
496
|
+
}
|
|
497
|
+
insideParanthesis++;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (char === ')' && !insideQuote) {
|
|
501
|
+
if (insideParanthesis-- !== 0) {
|
|
502
|
+
currentArg += char;
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
args.push(currentArg);
|
|
506
|
+
return {
|
|
507
|
+
args,
|
|
508
|
+
endPosition: i + 1,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
currentArg += char;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return null; // No valid arguments found
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export default ClingoParser;
|
|
@@ -0,0 +1,71 @@
|
|
|
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 {
|
|
13
|
+
type ClingoArgument,
|
|
14
|
+
ClingoFactBuilder,
|
|
15
|
+
} from './clingo-fact-builder.js';
|
|
16
|
+
|
|
17
|
+
interface IBuilder {
|
|
18
|
+
build(): string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class ClingoProgramBuilder {
|
|
22
|
+
private rows: IBuilder[] = [];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Adds a new fact with a simple configuration.
|
|
26
|
+
* @param predicate - The fact's predicate
|
|
27
|
+
* @param args - The fact's arguments
|
|
28
|
+
*/
|
|
29
|
+
addFact(predicate: string, ...args: ClingoArgument[]): ClingoProgramBuilder {
|
|
30
|
+
const fact = new ClingoFactBuilder(predicate).addArguments(...args);
|
|
31
|
+
this.rows.push(fact);
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Adds a custom fact allowing use of the builder methods directly for more control.
|
|
37
|
+
* @param predicate - The fact's predicate
|
|
38
|
+
* @param configure - Function to configure the fact with builder methods
|
|
39
|
+
*/
|
|
40
|
+
addCustomFact(
|
|
41
|
+
predicate: string,
|
|
42
|
+
configure: (builder: ClingoFactBuilder) => ClingoFactBuilder,
|
|
43
|
+
): ClingoProgramBuilder {
|
|
44
|
+
const factBuilder = new ClingoFactBuilder(predicate);
|
|
45
|
+
// Allow configuration of the fact
|
|
46
|
+
this.rows.push(configure(factBuilder));
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Adds an import to the clingo program
|
|
51
|
+
*/
|
|
52
|
+
addImport(path: string): ClingoProgramBuilder {
|
|
53
|
+
this.rows.push({ build: () => `#include "${path}".` });
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Adds a comment
|
|
59
|
+
*/
|
|
60
|
+
addComment(comment: string): ClingoProgramBuilder {
|
|
61
|
+
this.rows.push({ build: () => `% ${comment}` });
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Builds all facts and returns them as a single string with each fact on a new line.
|
|
67
|
+
*/
|
|
68
|
+
buildAll(): string {
|
|
69
|
+
return this.rows.map((row) => row.build()).join('\n') + '\n';
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
/**
|
|
14
|
+
* Makes deep comparison between two objects.
|
|
15
|
+
* @param arg1 First object to compare.
|
|
16
|
+
* @param arg2 Second object to compare.
|
|
17
|
+
* @returns true, if objects are the same, false otherwise.
|
|
18
|
+
*/
|
|
19
|
+
export function deepCompare(arg1: object, arg2: object): boolean {
|
|
20
|
+
if (
|
|
21
|
+
Object.prototype.toString.call(arg1) ===
|
|
22
|
+
Object.prototype.toString.call(arg2)
|
|
23
|
+
) {
|
|
24
|
+
if (
|
|
25
|
+
Object.prototype.toString.call(arg1) === '[object Object]' ||
|
|
26
|
+
Object.prototype.toString.call(arg1) === '[object Array]'
|
|
27
|
+
) {
|
|
28
|
+
if (Object.keys(arg1).length !== Object.keys(arg2).length) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return Object.keys(arg1).every(function (key) {
|
|
32
|
+
return deepCompare(
|
|
33
|
+
arg1[key as keyof typeof arg1],
|
|
34
|
+
arg2[key as keyof typeof arg2],
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return arg1 === arg2;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if string could be represented as BigInt.
|
|
45
|
+
* @param value String value
|
|
46
|
+
* @returns true, if 'value' can be represented as BigInt; false otherwise.
|
|
47
|
+
*/
|
|
48
|
+
export function isBigInt(value: string): boolean {
|
|
49
|
+
try {
|
|
50
|
+
return BigInt(parseInt(value, 10)) !== BigInt(value);
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { PredefinedCardMetadata } from '../interfaces/project-interfaces.js';
|
|
2
|
+
|
|
3
|
+
export const INT32_MAX = 2147483647; // 2^31-1
|
|
4
|
+
/**
|
|
5
|
+
Cyberismo
|
|
6
|
+
Copyright © Cyberismo Ltd and contributors 2024
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
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.
|
|
11
|
+
|
|
12
|
+
You should have received a copy of the GNU Affero General Public
|
|
13
|
+
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* These are names of the fields that are non-custom fields that present in metadata
|
|
18
|
+
*/
|
|
19
|
+
export const PREDEFINED_FIELDS = [
|
|
20
|
+
'rank',
|
|
21
|
+
'cardType',
|
|
22
|
+
'title',
|
|
23
|
+
'workflowState',
|
|
24
|
+
'lastUpdated',
|
|
25
|
+
'lastTransitioned',
|
|
26
|
+
] satisfies (keyof PredefinedCardMetadata)[];
|
|
27
|
+
|
|
28
|
+
export function isPredefinedField(
|
|
29
|
+
value: string,
|
|
30
|
+
): value is keyof PredefinedCardMetadata {
|
|
31
|
+
return (PREDEFINED_FIELDS as string[]).includes(value);
|
|
32
|
+
}
|