@cyberismo/data-handler 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/command-handler.d.ts +11 -2
- package/dist/command-handler.js +61 -18
- package/dist/command-handler.js.map +1 -1
- package/dist/command-manager.js +8 -8
- package/dist/command-manager.js.map +1 -1
- package/dist/commands/calculate.d.ts +7 -44
- package/dist/commands/calculate.js +8 -389
- package/dist/commands/calculate.js.map +1 -1
- package/dist/commands/create.d.ts +6 -3
- package/dist/commands/create.js +27 -5
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/edit.d.ts +15 -3
- package/dist/commands/edit.js +52 -9
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/export.d.ts +11 -9
- package/dist/commands/export.js +80 -28
- package/dist/commands/export.js.map +1 -1
- package/dist/commands/import.d.ts +7 -0
- package/dist/commands/import.js +13 -0
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/move.d.ts +11 -12
- package/dist/commands/move.js +12 -13
- package/dist/commands/move.js.map +1 -1
- package/dist/commands/remove.d.ts +1 -3
- package/dist/commands/remove.js +4 -6
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/rename.d.ts +1 -3
- package/dist/commands/rename.js +3 -6
- package/dist/commands/rename.js.map +1 -1
- package/dist/commands/show.d.ts +37 -5
- package/dist/commands/show.js +89 -8
- package/dist/commands/show.js.map +1 -1
- package/dist/commands/transition.d.ts +1 -3
- package/dist/commands/transition.js +3 -5
- package/dist/commands/transition.js.map +1 -1
- package/dist/commands/update.d.ts +5 -1
- package/dist/commands/update.js +7 -1
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.d.ts +7 -0
- package/dist/commands/validate.js +31 -4
- package/dist/commands/validate.js.map +1 -1
- package/dist/containers/card-container.d.ts +6 -0
- package/dist/containers/card-container.js +61 -0
- package/dist/containers/card-container.js.map +1 -1
- package/dist/containers/project/calculation-engine.d.ts +90 -0
- package/dist/containers/project/calculation-engine.js +402 -0
- package/dist/containers/project/calculation-engine.js.map +1 -0
- package/dist/containers/project/resource-collector.js +9 -13
- package/dist/containers/project/resource-collector.js.map +1 -1
- package/dist/containers/project.d.ts +18 -1
- package/dist/containers/project.js +28 -55
- package/dist/containers/project.js.map +1 -1
- package/dist/containers/template.d.ts +5 -0
- package/dist/containers/template.js +9 -0
- package/dist/containers/template.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/macros.d.ts +4 -2
- package/dist/interfaces/project-interfaces.d.ts +21 -0
- package/dist/interfaces/project-interfaces.js +4 -0
- package/dist/interfaces/project-interfaces.js.map +1 -1
- package/dist/interfaces/resource-interfaces.d.ts +4 -2
- package/dist/interfaces/resource-interfaces.js.map +1 -1
- package/dist/macros/base-macro.d.ts +2 -1
- package/dist/macros/base-macro.js +14 -2
- package/dist/macros/base-macro.js.map +1 -1
- package/dist/macros/common.d.ts +16 -9
- package/dist/macros/common.js +22 -9
- package/dist/macros/common.js.map +1 -1
- package/dist/macros/createCards/index.d.ts +2 -2
- package/dist/macros/createCards/index.js +4 -0
- package/dist/macros/createCards/index.js.map +1 -1
- package/dist/macros/graph/index.d.ts +1 -3
- package/dist/macros/graph/index.js +1 -6
- package/dist/macros/graph/index.js.map +1 -1
- package/dist/macros/image/index.d.ts +39 -0
- package/dist/macros/image/index.js +82 -0
- package/dist/macros/image/index.js.map +1 -0
- package/dist/macros/image/metadata.d.ts +18 -0
- package/dist/macros/image/metadata.js +22 -0
- package/dist/macros/image/metadata.js.map +1 -0
- package/dist/macros/include/index.d.ts +31 -0
- package/dist/macros/include/index.js +94 -0
- package/dist/macros/include/index.js.map +1 -0
- package/dist/macros/include/metadata.d.ts +15 -0
- package/dist/macros/include/metadata.js +19 -0
- package/dist/macros/include/metadata.js.map +1 -0
- package/dist/macros/index.d.ts +33 -31
- package/dist/macros/index.js +142 -71
- package/dist/macros/index.js.map +1 -1
- package/dist/macros/percentage/index.d.ts +28 -0
- package/dist/macros/percentage/index.js +33 -0
- package/dist/macros/percentage/index.js.map +1 -0
- package/dist/macros/percentage/metadata.d.ts +15 -0
- package/dist/macros/percentage/metadata.js +19 -0
- package/dist/macros/percentage/metadata.js.map +1 -0
- package/dist/macros/report/index.d.ts +2 -6
- package/dist/macros/report/index.js +3 -7
- package/dist/macros/report/index.js.map +1 -1
- package/dist/macros/scoreCard/index.d.ts +14 -15
- package/dist/macros/scoreCard/index.js +14 -18
- package/dist/macros/scoreCard/index.js.map +1 -1
- package/dist/macros/vega/index.d.ts +28 -0
- package/dist/macros/vega/index.js +27 -0
- package/dist/macros/vega/index.js.map +1 -0
- package/dist/macros/vega/metadata.d.ts +15 -0
- package/dist/macros/vega/metadata.js +7 -0
- package/dist/macros/vega/metadata.js.map +1 -0
- package/dist/macros/vegalite/index.d.ts +26 -0
- package/dist/macros/vegalite/index.js +24 -0
- package/dist/macros/vegalite/index.js.map +1 -0
- package/dist/macros/vegalite/metadata.d.ts +15 -0
- package/dist/macros/vegalite/metadata.js +7 -0
- package/dist/macros/vegalite/metadata.js.map +1 -0
- package/dist/macros/xref/index.d.ts +26 -0
- package/dist/macros/xref/index.js +53 -0
- package/dist/macros/xref/index.js.map +1 -0
- package/dist/macros/xref/metadata.d.ts +15 -0
- package/dist/macros/xref/metadata.js +19 -0
- package/dist/macros/xref/metadata.js.map +1 -0
- package/dist/module-manager.d.ts +1 -0
- package/dist/module-manager.js +14 -4
- package/dist/module-manager.js.map +1 -1
- package/dist/permissions/action-guard.d.ts +2 -2
- package/dist/permissions/action-guard.js +1 -1
- package/dist/permissions/action-guard.js.map +1 -1
- package/dist/resources/card-type-resource.d.ts +2 -0
- package/dist/resources/card-type-resource.js +63 -0
- package/dist/resources/card-type-resource.js.map +1 -1
- package/dist/resources/file-resource.d.ts +2 -0
- package/dist/resources/file-resource.js +12 -4
- package/dist/resources/file-resource.js.map +1 -1
- package/dist/resources/folder-resource.d.ts +19 -0
- package/dist/resources/folder-resource.js +51 -2
- package/dist/resources/folder-resource.js.map +1 -1
- package/dist/resources/graph-model-resource.js +1 -1
- package/dist/resources/graph-model-resource.js.map +1 -1
- package/dist/resources/graph-view-resource.js +1 -1
- package/dist/resources/graph-view-resource.js.map +1 -1
- package/dist/resources/report-resource.js +1 -1
- package/dist/resources/report-resource.js.map +1 -1
- package/dist/resources/resource-object.d.ts +8 -0
- package/dist/resources/resource-object.js +10 -1
- package/dist/resources/resource-object.js.map +1 -1
- package/dist/resources/template-resource.js +1 -1
- package/dist/resources/template-resource.js.map +1 -1
- package/dist/resources/workflow-resource.d.ts +2 -0
- package/dist/resources/workflow-resource.js +53 -9
- package/dist/resources/workflow-resource.js.map +1 -1
- package/dist/svg/index.d.ts +15 -0
- package/dist/svg/index.js +16 -0
- package/dist/svg/index.js.map +1 -0
- package/dist/svg/lib.d.ts +9 -0
- package/dist/svg/lib.js +26 -0
- package/dist/svg/lib.js.map +1 -0
- package/dist/svg/percentage.d.ts +25 -0
- package/dist/svg/percentage.js +90 -0
- package/dist/svg/percentage.js.map +1 -0
- package/dist/svg/scoreCard.d.ts +19 -0
- package/dist/svg/scoreCard.js +55 -0
- package/dist/svg/scoreCard.js.map +1 -0
- package/dist/types/queries.d.ts +8 -7
- package/dist/types/queries.js.map +1 -1
- package/dist/utils/card-utils.d.ts +6 -0
- package/dist/utils/card-utils.js +12 -0
- package/dist/utils/card-utils.js.map +1 -1
- package/dist/utils/clingo-facts.d.ts +2 -1
- package/dist/utils/clingo-facts.js +19 -2
- package/dist/utils/clingo-facts.js.map +1 -1
- package/dist/utils/clingo-parser.d.ts +1 -0
- package/dist/utils/clingo-parser.js +22 -100
- package/dist/utils/clingo-parser.js.map +1 -1
- package/dist/utils/constants.d.ts +7 -0
- package/dist/utils/constants.js +14 -0
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/csv.js.map +1 -1
- package/dist/utils/report.d.ts +17 -3
- package/dist/utils/report.js +38 -2
- package/dist/utils/report.js.map +1 -1
- package/dist/utils/resource-utils.d.ts +2 -1
- package/dist/utils/resource-utils.js +12 -3
- package/dist/utils/resource-utils.js.map +1 -1
- package/dist/utils/user-preferences.d.ts +1 -11
- package/dist/utils/user-preferences.js +30 -13
- package/dist/utils/user-preferences.js.map +1 -1
- package/dist/utils/validate.d.ts +2 -3
- package/dist/utils/validate.js +2 -2
- package/dist/utils/validate.js.map +1 -1
- package/package.json +8 -6
- package/src/command-handler.ts +96 -17
- package/src/command-manager.ts +8 -8
- package/src/commands/calculate.ts +11 -525
- package/src/commands/create.ts +35 -6
- package/src/commands/edit.ts +94 -11
- package/src/commands/export.ts +104 -31
- package/src/commands/import.ts +16 -0
- package/src/commands/move.ts +12 -15
- package/src/commands/remove.ts +4 -8
- package/src/commands/rename.ts +3 -12
- package/src/commands/show.ts +126 -9
- package/src/commands/transition.ts +3 -7
- package/src/commands/update.ts +6 -0
- package/src/commands/validate.ts +41 -13
- package/src/containers/card-container.ts +74 -0
- package/src/containers/project/calculation-engine.ts +535 -0
- package/src/containers/project/resource-collector.ts +13 -15
- package/src/containers/project.ts +30 -66
- package/src/containers/template.ts +16 -0
- package/src/index.ts +13 -2
- package/src/interfaces/macros.ts +4 -1
- package/src/interfaces/project-interfaces.ts +27 -0
- package/src/interfaces/resource-interfaces.ts +5 -2
- package/src/macros/base-macro.ts +19 -4
- package/src/macros/common.ts +22 -9
- package/src/macros/createCards/index.ts +6 -2
- package/src/macros/graph/index.ts +6 -10
- package/src/macros/image/index.ts +128 -0
- package/src/macros/image/metadata.ts +25 -0
- package/src/macros/include/index.ts +143 -0
- package/src/macros/include/metadata.ts +22 -0
- package/src/macros/index.ts +150 -98
- package/src/macros/percentage/index.ts +50 -0
- package/src/macros/percentage/metadata.ts +22 -0
- package/src/macros/report/index.ts +4 -12
- package/src/macros/scoreCard/index.ts +21 -25
- package/src/macros/vega/index.ts +55 -0
- package/src/macros/vega/metadata.ts +21 -0
- package/src/macros/vegalite/index.ts +46 -0
- package/src/macros/vegalite/metadata.ts +21 -0
- package/src/macros/xref/index.ts +73 -0
- package/src/macros/xref/metadata.ts +22 -0
- package/src/module-manager.ts +15 -5
- package/src/permissions/action-guard.ts +3 -3
- package/src/resources/card-type-resource.ts +100 -0
- package/src/resources/file-resource.ts +16 -4
- package/src/resources/folder-resource.ts +59 -2
- package/src/resources/graph-model-resource.ts +1 -1
- package/src/resources/graph-view-resource.ts +1 -1
- package/src/resources/report-resource.ts +1 -1
- package/src/resources/resource-object.ts +19 -1
- package/src/resources/template-resource.ts +1 -1
- package/src/resources/workflow-resource.ts +68 -13
- package/src/svg/index.ts +15 -0
- package/src/svg/lib.ts +31 -0
- package/src/svg/percentage.ts +97 -0
- package/src/svg/scoreCard.ts +88 -0
- package/src/types/queries.ts +8 -7
- package/src/types/string-pixel-width.d.ts +23 -0
- package/src/utils/card-utils.ts +13 -0
- package/src/utils/clingo-facts.ts +65 -3
- package/src/utils/clingo-parser.ts +31 -144
- package/src/utils/constants.ts +16 -0
- package/src/utils/csv.ts +1 -1
- package/src/utils/report.ts +45 -4
- package/src/utils/resource-utils.ts +12 -2
- package/src/utils/user-preferences.ts +32 -14
- package/src/utils/validate.ts +3 -3
|
@@ -0,0 +1,143 @@
|
|
|
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 { evaluateMacros, validateMacroContent } from '../index.js';
|
|
15
|
+
|
|
16
|
+
import type { MacroGenerationContext } from '../../interfaces/macros.js';
|
|
17
|
+
import macroMetadata from './metadata.js';
|
|
18
|
+
import BaseMacro from '../base-macro.js';
|
|
19
|
+
import type TaskQueue from '../task-queue.js';
|
|
20
|
+
import { MAX_LEVEL_OFFSET } from '../../utils/constants.js';
|
|
21
|
+
|
|
22
|
+
export interface IncludeMacroOptions {
|
|
23
|
+
cardKey: string;
|
|
24
|
+
levelOffset?: string;
|
|
25
|
+
title?: 'include' | 'exclude' | 'only';
|
|
26
|
+
pageTitles?: 'normal' | 'discrete';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default class IncludeMacro extends BaseMacro {
|
|
30
|
+
constructor(tasksQueue: TaskQueue) {
|
|
31
|
+
super(macroMetadata, tasksQueue);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
handleValidate = (input: unknown) => {
|
|
35
|
+
this.validate(input);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
handleStatic = async (
|
|
39
|
+
context: MacroGenerationContext,
|
|
40
|
+
input: unknown,
|
|
41
|
+
): Promise<string> => {
|
|
42
|
+
const options = this.validate(input);
|
|
43
|
+
if (!options.title) {
|
|
44
|
+
options.title = 'include';
|
|
45
|
+
}
|
|
46
|
+
if (!options.pageTitles) {
|
|
47
|
+
options.pageTitles = 'normal';
|
|
48
|
+
}
|
|
49
|
+
const card = await context.project.cardDetailsById(options.cardKey, {
|
|
50
|
+
content: true,
|
|
51
|
+
metadata: true,
|
|
52
|
+
});
|
|
53
|
+
if (!card) {
|
|
54
|
+
throw new Error(`Card key ${options.cardKey} not found`);
|
|
55
|
+
}
|
|
56
|
+
const newContext = {
|
|
57
|
+
...context,
|
|
58
|
+
cardKey: options.cardKey,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const anchor = this.generateAnchor(options);
|
|
62
|
+
const title = this.generateTitle(options, card.metadata?.title);
|
|
63
|
+
const cardContent = await this.generateCardContent(
|
|
64
|
+
options,
|
|
65
|
+
card.content,
|
|
66
|
+
newContext,
|
|
67
|
+
);
|
|
68
|
+
const content = `\n\n${anchor}${title}${cardContent}`;
|
|
69
|
+
|
|
70
|
+
let levelOffset = 0;
|
|
71
|
+
if (options.levelOffset) {
|
|
72
|
+
levelOffset = parseInt(options.levelOffset, 10);
|
|
73
|
+
if (isNaN(levelOffset)) {
|
|
74
|
+
throw new Error(`Invalid level offset: ${options.levelOffset}`);
|
|
75
|
+
}
|
|
76
|
+
levelOffset = Math.min(
|
|
77
|
+
Math.max(levelOffset, -MAX_LEVEL_OFFSET),
|
|
78
|
+
MAX_LEVEL_OFFSET,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const adjustedContent = this.adjustTitles(
|
|
83
|
+
content,
|
|
84
|
+
levelOffset,
|
|
85
|
+
options.pageTitles === 'discrete',
|
|
86
|
+
);
|
|
87
|
+
return adjustedContent;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
private validate(input: unknown): IncludeMacroOptions {
|
|
91
|
+
return validateMacroContent<IncludeMacroOptions>(this.metadata, input);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private generateAnchor(options: IncludeMacroOptions): string {
|
|
95
|
+
return options.title !== 'exclude' && options.pageTitles === 'normal'
|
|
96
|
+
? `[[${options.cardKey}]]\n`
|
|
97
|
+
: '';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private generateTitle(
|
|
101
|
+
options: IncludeMacroOptions,
|
|
102
|
+
cardTitle?: string,
|
|
103
|
+
): string {
|
|
104
|
+
if (options.title === 'only' || options.title === 'include') {
|
|
105
|
+
return `= ${cardTitle}\n\n`;
|
|
106
|
+
}
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private async generateCardContent(
|
|
111
|
+
options: IncludeMacroOptions,
|
|
112
|
+
cardContent: string | undefined,
|
|
113
|
+
context: MacroGenerationContext,
|
|
114
|
+
): Promise<string> {
|
|
115
|
+
if (options.title !== 'only') {
|
|
116
|
+
return await evaluateMacros(cardContent ?? '', context, true);
|
|
117
|
+
}
|
|
118
|
+
return '';
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Adjust asciidoc titles to match the level offset
|
|
122
|
+
private adjustTitles(
|
|
123
|
+
content: string,
|
|
124
|
+
levelOffset: number,
|
|
125
|
+
discrete: boolean,
|
|
126
|
+
) {
|
|
127
|
+
const lines = content.split('\n');
|
|
128
|
+
const adjustedLines = lines.map((line) => {
|
|
129
|
+
const match = line.match(/^(\s*)([=#]+)(.*?)\s*$/);
|
|
130
|
+
if (match) {
|
|
131
|
+
const currentLevel = match[2].length;
|
|
132
|
+
const newLevel = Math.min(
|
|
133
|
+
Math.max(1, currentLevel + levelOffset),
|
|
134
|
+
MAX_LEVEL_OFFSET + 1,
|
|
135
|
+
);
|
|
136
|
+
const equals = '='.repeat(newLevel);
|
|
137
|
+
return `${discrete ? '[discrete]\n' : ''}${match[1]}${equals} ${match[3].trim()}`;
|
|
138
|
+
}
|
|
139
|
+
return line;
|
|
140
|
+
});
|
|
141
|
+
return adjustedLines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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 { MacroMetadata } from '../../interfaces/macros.js';
|
|
15
|
+
|
|
16
|
+
const macroMetadata: MacroMetadata = {
|
|
17
|
+
name: 'include',
|
|
18
|
+
tagName: 'include',
|
|
19
|
+
schema: 'includeMacroSchema',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default macroMetadata;
|
package/src/macros/index.ts
CHANGED
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
Cyberismo
|
|
3
|
+
Copyright © Cyberismo Ltd and contributors 2024
|
|
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/>.
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import Handlebars from 'handlebars';
|
|
14
15
|
|
|
15
16
|
import createCards from './createCards/index.js';
|
|
16
17
|
import graph from './graph/index.js';
|
|
18
|
+
import image from './image/index.js';
|
|
19
|
+
import include from './include/index.js';
|
|
17
20
|
import report from './report/index.js';
|
|
18
21
|
import scoreCard from './scoreCard/index.js';
|
|
22
|
+
import xref from './xref/index.js';
|
|
23
|
+
import percentage from './percentage/index.js';
|
|
24
|
+
import vega from './vega/index.js';
|
|
25
|
+
import vegaLite from './vegalite/index.js';
|
|
19
26
|
|
|
20
27
|
import { validateJson } from '../utils/validate.js';
|
|
21
28
|
import { DHValidationError, MacroError } from '../exceptions/index.js';
|
|
22
29
|
import type { AdmonitionType } from '../interfaces/adoc.js';
|
|
23
|
-
import type { Validator } from 'jsonschema';
|
|
24
30
|
import type {
|
|
25
31
|
MacroGenerationContext,
|
|
26
32
|
MacroMetadata,
|
|
@@ -28,10 +34,86 @@ import type {
|
|
|
28
34
|
} from '../interfaces/macros.js';
|
|
29
35
|
import type BaseMacro from './base-macro.js';
|
|
30
36
|
import TaskQueue from './task-queue.js';
|
|
31
|
-
import type { Calculate } from '../commands/index.js';
|
|
32
37
|
import { ClingoError } from '@cyberismo/node-clingo';
|
|
38
|
+
import type { Schema } from 'jsonschema';
|
|
33
39
|
const CURLY_LEFT = '{';
|
|
34
40
|
const CURLY_RIGHT = '}';
|
|
41
|
+
const RAW_BLOCK_OPEN = '{{#raw}}';
|
|
42
|
+
const RAW_BLOCK_CLOSE = '{{/raw}}';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Pre-processes the content to handle {{#raw}} blocks by escaping all handlebars syntax inside them
|
|
46
|
+
* @param content The template content to process
|
|
47
|
+
* @returns The processed content with raw blocks escaped
|
|
48
|
+
* @throws Error if nested raw blocks are found or if a raw block is not properly closed
|
|
49
|
+
*/
|
|
50
|
+
function preprocessRawBlocks(content: string): string {
|
|
51
|
+
const result: string[] = [];
|
|
52
|
+
let i = 0;
|
|
53
|
+
|
|
54
|
+
// Helper function to check if a target string matches at a given position without creating substrings
|
|
55
|
+
const matchesAt = (pos: number, target: string): boolean => {
|
|
56
|
+
if (pos + target.length > content.length) return false;
|
|
57
|
+
for (let k = 0; k < target.length; k++) {
|
|
58
|
+
if (content[pos + k] !== target[k]) return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Helper function to get line number at position
|
|
64
|
+
const getLineNumber = (pos: number): number => {
|
|
65
|
+
let lineNum = 1;
|
|
66
|
+
for (let k = 0; k < pos; k++) {
|
|
67
|
+
if (content[k] === '\n') {
|
|
68
|
+
lineNum++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return lineNum;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
while (i < content.length) {
|
|
75
|
+
// Check for {{#raw}}
|
|
76
|
+
if (matchesAt(i, RAW_BLOCK_OPEN)) {
|
|
77
|
+
const openingLine = getLineNumber(i);
|
|
78
|
+
// Find the matching {{/raw}} - no nesting allowed
|
|
79
|
+
let j = i + RAW_BLOCK_OPEN.length;
|
|
80
|
+
|
|
81
|
+
while (j < content.length) {
|
|
82
|
+
if (matchesAt(j, RAW_BLOCK_OPEN)) {
|
|
83
|
+
// Found nested raw block - not supported
|
|
84
|
+
const nestedLine = getLineNumber(j);
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Nested ${RAW_BLOCK_OPEN} blocks are not supported. Found nested raw block inside another raw block on line ${nestedLine} (original raw block started on line ${openingLine}).`,
|
|
87
|
+
);
|
|
88
|
+
} else if (matchesAt(j, RAW_BLOCK_CLOSE)) {
|
|
89
|
+
// Found matching closing tag
|
|
90
|
+
const rawContent = content.slice(i + RAW_BLOCK_OPEN.length, j);
|
|
91
|
+
const escapedContent = rawContent
|
|
92
|
+
.replaceAll('{', CURLY_LEFT)
|
|
93
|
+
.replaceAll('}', CURLY_RIGHT);
|
|
94
|
+
result.push(escapedContent);
|
|
95
|
+
i = j + RAW_BLOCK_CLOSE.length;
|
|
96
|
+
break;
|
|
97
|
+
} else {
|
|
98
|
+
j++;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// If we reached the end without finding a closing tag
|
|
103
|
+
if (j >= content.length) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Unclosed ${RAW_BLOCK_OPEN} block found on line ${openingLine}. Every ${RAW_BLOCK_OPEN} must have a matching ${RAW_BLOCK_CLOSE}.`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// Not a raw block, keep as-is
|
|
110
|
+
result.push(content[i]);
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return result.join('');
|
|
116
|
+
}
|
|
35
117
|
|
|
36
118
|
/**
|
|
37
119
|
* Constructor for all macros except report macros
|
|
@@ -44,7 +126,7 @@ export interface SimpleMacroConstructor {
|
|
|
44
126
|
* Constructor for report macros
|
|
45
127
|
*/
|
|
46
128
|
export interface ReportMacroConstructor {
|
|
47
|
-
new (tasks: TaskQueue
|
|
129
|
+
new (tasks: TaskQueue): BaseMacro;
|
|
48
130
|
}
|
|
49
131
|
|
|
50
132
|
/**
|
|
@@ -57,21 +139,26 @@ export const macros: {
|
|
|
57
139
|
} = {
|
|
58
140
|
createCards,
|
|
59
141
|
graph,
|
|
142
|
+
image,
|
|
143
|
+
include,
|
|
60
144
|
report,
|
|
61
145
|
scoreCard,
|
|
146
|
+
xref,
|
|
147
|
+
percentage,
|
|
148
|
+
vega,
|
|
149
|
+
vegaLite,
|
|
62
150
|
};
|
|
63
151
|
|
|
64
152
|
/**
|
|
65
153
|
* Validates the content inside a macro
|
|
66
154
|
* @param macro - The macro to validate the content of
|
|
67
155
|
* @param data - The data to validate
|
|
68
|
-
* @param validator - The validator to use
|
|
69
156
|
* @returns The validated data
|
|
70
157
|
*/
|
|
71
158
|
export function validateMacroContent<T>(
|
|
72
159
|
macro: MacroMetadata,
|
|
73
160
|
data: unknown,
|
|
74
|
-
|
|
161
|
+
schema?: Schema,
|
|
75
162
|
): T {
|
|
76
163
|
if (!macro.schema) {
|
|
77
164
|
throw new Error(`Macro ${macro.name} does not have a schema`);
|
|
@@ -80,7 +167,7 @@ export function validateMacroContent<T>(
|
|
|
80
167
|
try {
|
|
81
168
|
return validateJson<T>(data, {
|
|
82
169
|
schemaId: macro.schema,
|
|
83
|
-
|
|
170
|
+
schema,
|
|
84
171
|
});
|
|
85
172
|
} catch (error) {
|
|
86
173
|
let message = `Error: ${error instanceof Error ? error.message : 'Unknown error'}`;
|
|
@@ -99,33 +186,17 @@ export function registerMacros(
|
|
|
99
186
|
instance: typeof Handlebars,
|
|
100
187
|
context: MacroGenerationContext,
|
|
101
188
|
tasks: TaskQueue,
|
|
102
|
-
calculate: Calculate,
|
|
103
189
|
) {
|
|
104
190
|
const macroInstances: BaseMacro[] = [];
|
|
105
191
|
for (const macro of Object.keys(macros) as MacroName[]) {
|
|
106
192
|
const MacroClass = macros[macro];
|
|
107
|
-
const macroInstance = new MacroClass(tasks
|
|
193
|
+
const macroInstance = new MacroClass(tasks);
|
|
108
194
|
instance.registerHelper(macro, function (this: unknown, options) {
|
|
109
|
-
if (
|
|
110
|
-
this != null &&
|
|
111
|
-
typeof this === 'object' &&
|
|
112
|
-
'__isRaw' in this &&
|
|
113
|
-
this.__isRaw
|
|
114
|
-
) {
|
|
115
|
-
// we use escaped chars so that they will not be re-run
|
|
116
|
-
return `${CURLY_LEFT}${CURLY_LEFT}#${macro}${CURLY_RIGHT}${CURLY_RIGHT}${options.fn(this)}${CURLY_LEFT}${CURLY_LEFT}/${macro}${CURLY_RIGHT}${CURLY_RIGHT}`;
|
|
117
|
-
}
|
|
118
195
|
return macroInstance.invokeMacro(context, options);
|
|
119
196
|
});
|
|
120
197
|
macroInstances.push(macroInstance);
|
|
121
198
|
}
|
|
122
199
|
|
|
123
|
-
instance.registerHelper('raw', function (options) {
|
|
124
|
-
return options.fn({
|
|
125
|
-
__isRaw: true,
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
|
|
129
200
|
return macroInstances;
|
|
130
201
|
}
|
|
131
202
|
/**
|
|
@@ -155,25 +226,26 @@ export function registerEmptyMacros(instance: typeof Handlebars) {
|
|
|
155
226
|
/**
|
|
156
227
|
* Handle the macros in the content
|
|
157
228
|
* @param content - The content to handle the macros in
|
|
158
|
-
* @param
|
|
229
|
+
* @param context - The context for macro generation
|
|
230
|
+
* @param calculate - The calculate function
|
|
231
|
+
* @param preserveRawBlocks - If true, don't unescape raw blocks at the end (for nested evaluations)
|
|
159
232
|
*/
|
|
160
233
|
export async function evaluateMacros(
|
|
161
234
|
content: string,
|
|
162
235
|
context: MacroGenerationContext,
|
|
163
|
-
|
|
164
|
-
maxTries: number = 10,
|
|
236
|
+
preserveRawBlocks: boolean = false,
|
|
165
237
|
) {
|
|
166
238
|
const handlebars = Handlebars.create();
|
|
167
239
|
const tasks = new TaskQueue();
|
|
168
|
-
registerMacros(handlebars, context, tasks
|
|
240
|
+
registerMacros(handlebars, context, tasks);
|
|
169
241
|
let result = content;
|
|
170
|
-
while (maxTries
|
|
242
|
+
while ((context.maxTries ?? 10) > 0) {
|
|
171
243
|
tasks.reset();
|
|
172
|
-
const compiled = handlebars.compile(result, {
|
|
173
|
-
strict: true,
|
|
174
|
-
});
|
|
175
244
|
try {
|
|
176
|
-
|
|
245
|
+
const compiled = handlebars.compile(preprocessRawBlocks(result), {
|
|
246
|
+
strict: true,
|
|
247
|
+
});
|
|
248
|
+
result = compiled({ cardKey: context.cardKey });
|
|
177
249
|
|
|
178
250
|
await tasks.waitAll();
|
|
179
251
|
|
|
@@ -194,7 +266,10 @@ export async function evaluateMacros(
|
|
|
194
266
|
context,
|
|
195
267
|
);
|
|
196
268
|
}
|
|
197
|
-
|
|
269
|
+
// Only unescape raw blocks if we're not preserving them for nested evaluations
|
|
270
|
+
return preserveRawBlocks
|
|
271
|
+
? result
|
|
272
|
+
: result.replaceAll(CURLY_LEFT, '{').replaceAll(CURLY_RIGHT, '}');
|
|
198
273
|
}
|
|
199
274
|
|
|
200
275
|
/**
|
|
@@ -278,57 +353,19 @@ export function handleMacroError(
|
|
|
278
353
|
// There might be a better way to do this
|
|
279
354
|
let macroCounter = 0;
|
|
280
355
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
* Macro options can be a flat object or a nested object
|
|
285
|
-
* The nested object will be flattened into dot notation attributes
|
|
286
|
-
*/
|
|
287
|
-
export type MacroOptions = {
|
|
288
|
-
[key: string]: Value | MacroOptions;
|
|
289
|
-
};
|
|
356
|
+
function objectToBase64(obj: unknown): string {
|
|
357
|
+
return Buffer.from(JSON.stringify(obj), 'utf-8').toString('base64');
|
|
358
|
+
}
|
|
290
359
|
/**
|
|
291
|
-
* Creates
|
|
292
|
-
*
|
|
293
|
-
* @param
|
|
360
|
+
* Creates a placeholder for a macro
|
|
361
|
+
* Options are encoded as base64
|
|
362
|
+
* @param macro - The macro to create a placeholder for
|
|
363
|
+
* @param options - The options for the macro
|
|
364
|
+
* @returns The placeholder for the macro
|
|
294
365
|
*/
|
|
295
|
-
export function createHtmlPlaceholder(
|
|
296
|
-
|
|
297
|
-
options
|
|
298
|
-
) {
|
|
299
|
-
// Flatten nested objects into dot notation attributes
|
|
300
|
-
const flattenedOptions: Record<string, Value> = {};
|
|
301
|
-
|
|
302
|
-
// Helper function to flatten nested objects
|
|
303
|
-
const flatten = (obj: MacroOptions, prefix = ''): void => {
|
|
304
|
-
Object.entries(obj).forEach(([key, value]) => {
|
|
305
|
-
const newKey = prefix ? `${prefix}.${key}` : key;
|
|
306
|
-
|
|
307
|
-
if (
|
|
308
|
-
value !== null &&
|
|
309
|
-
typeof value === 'object' &&
|
|
310
|
-
!Array.isArray(value)
|
|
311
|
-
) {
|
|
312
|
-
// Recursively flatten nested objects
|
|
313
|
-
flatten(value, newKey);
|
|
314
|
-
} else {
|
|
315
|
-
// Add leaf values to flattened options
|
|
316
|
-
flattenedOptions[newKey] = value as Value;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
flatten(options);
|
|
322
|
-
|
|
323
|
-
// Convert flattened options to attribute strings
|
|
324
|
-
const attributeStrings = Object.entries(flattenedOptions)
|
|
325
|
-
.filter(([, value]) => value !== undefined)
|
|
326
|
-
.map(([key, value]) => `${key}="${value}"`);
|
|
327
|
-
|
|
328
|
-
const optionString = attributeStrings.join(' ');
|
|
329
|
-
|
|
330
|
-
// start with a line change to ensure that inline passthrough +++ is on its own line
|
|
331
|
-
return `\n+++\n<${macro.tagName}${optionString ? ` ${optionString}` : ''} key="macro-${macroCounter++}"></${macro.tagName}>\n+++\n`;
|
|
366
|
+
export function createHtmlPlaceholder(macro: MacroMetadata, options: unknown) {
|
|
367
|
+
const optionsBase64 = objectToBase64(options);
|
|
368
|
+
return `\n\n++++\n<${macro.tagName} options="${optionsBase64}" key="macro-${macroCounter++}"></${macro.tagName}>\n++++\n\n`;
|
|
332
369
|
}
|
|
333
370
|
|
|
334
371
|
/**
|
|
@@ -360,15 +397,30 @@ export function createCodeBlock(content: string) {
|
|
|
360
397
|
* @param image base64 encoded image
|
|
361
398
|
* @returns valid asciidoc with the image
|
|
362
399
|
*/
|
|
363
|
-
export function createImage(image: string) {
|
|
400
|
+
export function createImage(image: string, controls: boolean = true) {
|
|
364
401
|
if (process.env.EXPORT_FORMAT) {
|
|
365
402
|
return `image::data:image/svg+xml;base64,${image}[]\n`;
|
|
366
403
|
} else {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
${
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
404
|
+
const svg = Buffer.from(image, 'base64').toString('utf-8');
|
|
405
|
+
if (controls) {
|
|
406
|
+
return `++++\n<div class="cyberismo-svg-wrapper" data-type="cyberismo-svg-wrapper">\n${svg}\n</div>\n++++\n`;
|
|
407
|
+
} else {
|
|
408
|
+
return `++++\n${svg}\n++++\n`;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Creates a Handlebars macro block string with the given macro name and options.
|
|
415
|
+
*
|
|
416
|
+
* @param macro - The name of the macro to create (e.g., 'scoreCard', 'include').
|
|
417
|
+
* @param options - The options object to be stringified and inserted as macro content.
|
|
418
|
+
* @returns The Handlebars macro block as a string, e.g. {{#macro}}...{{/macro}}
|
|
419
|
+
*/
|
|
420
|
+
export function createMacro(macro: MacroName, options: unknown) {
|
|
421
|
+
let optionsString = JSON.stringify(options, null, 0);
|
|
422
|
+
if (optionsString.length > 1) {
|
|
423
|
+
optionsString = optionsString.slice(1, -1);
|
|
373
424
|
}
|
|
425
|
+
return `{{#${macro}}}${optionsString}{{/${macro}}}`;
|
|
374
426
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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 { createImage, validateMacroContent } from '../index.js';
|
|
15
|
+
|
|
16
|
+
import type { MacroGenerationContext } from '../../interfaces/macros.js';
|
|
17
|
+
import macroMetadata from './metadata.js';
|
|
18
|
+
import BaseMacro from '../base-macro.js';
|
|
19
|
+
import type TaskQueue from '../task-queue.js';
|
|
20
|
+
import { percentage } from '../../svg/index.js';
|
|
21
|
+
|
|
22
|
+
export interface PercentageOptions {
|
|
23
|
+
title: string;
|
|
24
|
+
value: number;
|
|
25
|
+
legend: string;
|
|
26
|
+
colour?: 'blue' | 'green' | 'yellow' | 'red' | 'orange' | 'purple';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class PercentageMacro extends BaseMacro {
|
|
30
|
+
constructor(tasksQueue: TaskQueue) {
|
|
31
|
+
super(macroMetadata, tasksQueue);
|
|
32
|
+
}
|
|
33
|
+
handleValidate = (data: string) => {
|
|
34
|
+
this.validate(data);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
handleStatic = async (_: MacroGenerationContext, input: unknown) => {
|
|
38
|
+
const options = this.validate(input);
|
|
39
|
+
return createImage(
|
|
40
|
+
Buffer.from(percentage(options)).toString('base64'),
|
|
41
|
+
false,
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
private validate(input: unknown): PercentageOptions {
|
|
46
|
+
return validateMacroContent<PercentageOptions>(this.metadata, input);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default PercentageMacro;
|
|
@@ -0,0 +1,22 @@
|
|
|
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 type { MacroMetadata } from '../../interfaces/macros.js';
|
|
15
|
+
|
|
16
|
+
const macroMetadata: MacroMetadata = {
|
|
17
|
+
name: 'percentage',
|
|
18
|
+
tagName: 'percentage',
|
|
19
|
+
schema: 'percentageMacroSchema',
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default macroMetadata;
|
|
@@ -12,11 +12,9 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { validateMacroContent } from '../index.js';
|
|
15
|
-
import type { MacroOptions } from '../index.js';
|
|
16
15
|
|
|
17
16
|
import type { MacroGenerationContext } from '../../interfaces/macros.js';
|
|
18
17
|
import macroMetadata from './metadata.js';
|
|
19
|
-
import type { Calculate } from '../../commands/index.js';
|
|
20
18
|
import BaseMacro from '../base-macro.js';
|
|
21
19
|
import { validateJson } from '../../utils/validate.js';
|
|
22
20
|
import type TaskQueue from '../task-queue.js';
|
|
@@ -25,15 +23,12 @@ import { resourceName } from '../../utils/resource-utils.js';
|
|
|
25
23
|
import { generateReportContent } from '../../utils/report.js';
|
|
26
24
|
import { ClingoError } from '@cyberismo/node-clingo';
|
|
27
25
|
|
|
28
|
-
export interface ReportOptions
|
|
26
|
+
export interface ReportOptions {
|
|
29
27
|
name: string;
|
|
30
28
|
}
|
|
31
29
|
|
|
32
30
|
class ReportMacro extends BaseMacro {
|
|
33
|
-
constructor(
|
|
34
|
-
tasks: TaskQueue,
|
|
35
|
-
private readonly calculate: Calculate,
|
|
36
|
-
) {
|
|
31
|
+
constructor(tasks: TaskQueue) {
|
|
37
32
|
super(macroMetadata, tasks);
|
|
38
33
|
}
|
|
39
34
|
handleValidate = (input: unknown) => {
|
|
@@ -41,10 +36,6 @@ class ReportMacro extends BaseMacro {
|
|
|
41
36
|
};
|
|
42
37
|
|
|
43
38
|
handleStatic = async (context: MacroGenerationContext, data: unknown) => {
|
|
44
|
-
return this.handleInject(context, data);
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
handleInject = async (context: MacroGenerationContext, data: unknown) => {
|
|
48
39
|
const options = this.validate(data);
|
|
49
40
|
const resource = new ReportResource(
|
|
50
41
|
context.project,
|
|
@@ -61,13 +52,14 @@ class ReportMacro extends BaseMacro {
|
|
|
61
52
|
}
|
|
62
53
|
try {
|
|
63
54
|
return await generateReportContent({
|
|
64
|
-
calculate:
|
|
55
|
+
calculate: context.project.calculationEngine,
|
|
65
56
|
contentTemplate: report.contentTemplate,
|
|
66
57
|
queryTemplate: report.queryTemplate,
|
|
67
58
|
options: {
|
|
68
59
|
cardKey: context.cardKey,
|
|
69
60
|
...options,
|
|
70
61
|
},
|
|
62
|
+
context: context.context,
|
|
71
63
|
});
|
|
72
64
|
} catch (error) {
|
|
73
65
|
if (error instanceof ClingoError) {
|