@crypto512/jicon-mcp 2.2.1 → 2.3.19

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 (228) hide show
  1. package/PROMPT.md +10 -28
  2. package/README.md +39 -6
  3. package/TOOL_LIST.md +542 -407
  4. package/dist/config/constants.d.ts +28 -0
  5. package/dist/config/constants.d.ts.map +1 -1
  6. package/dist/config/constants.js +34 -0
  7. package/dist/config/constants.js.map +1 -1
  8. package/dist/config/loader.d.ts.map +1 -1
  9. package/dist/config/loader.js +12 -2
  10. package/dist/config/loader.js.map +1 -1
  11. package/dist/config/types.d.ts +49 -6
  12. package/dist/config/types.d.ts.map +1 -1
  13. package/dist/config/types.js +18 -0
  14. package/dist/config/types.js.map +1 -1
  15. package/dist/confluence/client.d.ts.map +1 -1
  16. package/dist/confluence/client.js +7 -2
  17. package/dist/confluence/client.js.map +1 -1
  18. package/dist/confluence/formatters.d.ts +20 -0
  19. package/dist/confluence/formatters.d.ts.map +1 -1
  20. package/dist/confluence/formatters.js +74 -8
  21. package/dist/confluence/formatters.js.map +1 -1
  22. package/dist/confluence/tools.d.ts +16 -20
  23. package/dist/confluence/tools.d.ts.map +1 -1
  24. package/dist/confluence/tools.js +71 -68
  25. package/dist/confluence/tools.js.map +1 -1
  26. package/dist/credentials/extractor.d.ts +15 -5
  27. package/dist/credentials/extractor.d.ts.map +1 -1
  28. package/dist/credentials/extractor.js +99 -12
  29. package/dist/credentials/extractor.js.map +1 -1
  30. package/dist/credentials/index.d.ts +4 -3
  31. package/dist/credentials/index.d.ts.map +1 -1
  32. package/dist/credentials/index.js +3 -2
  33. package/dist/credentials/index.js.map +1 -1
  34. package/dist/credentials/types.d.ts +22 -0
  35. package/dist/credentials/types.d.ts.map +1 -1
  36. package/dist/credentials/types.js.map +1 -1
  37. package/dist/index.js +211 -176
  38. package/dist/index.js.map +1 -1
  39. package/dist/jira/activity-tools.d.ts +8 -15
  40. package/dist/jira/activity-tools.d.ts.map +1 -1
  41. package/dist/jira/activity-tools.js +131 -90
  42. package/dist/jira/activity-tools.js.map +1 -1
  43. package/dist/jira/client.d.ts +24 -0
  44. package/dist/jira/client.d.ts.map +1 -1
  45. package/dist/jira/client.js +65 -6
  46. package/dist/jira/client.js.map +1 -1
  47. package/dist/jira/formatters.d.ts +61 -0
  48. package/dist/jira/formatters.d.ts.map +1 -1
  49. package/dist/jira/formatters.js +83 -11
  50. package/dist/jira/formatters.js.map +1 -1
  51. package/dist/jira/tools.d.ts +78 -26
  52. package/dist/jira/tools.d.ts.map +1 -1
  53. package/dist/jira/tools.js +293 -130
  54. package/dist/jira/tools.js.map +1 -1
  55. package/dist/permissions/filter.d.ts.map +1 -1
  56. package/dist/permissions/filter.js +8 -4
  57. package/dist/permissions/filter.js.map +1 -1
  58. package/dist/permissions/tool-registry.d.ts +15 -13
  59. package/dist/permissions/tool-registry.d.ts.map +1 -1
  60. package/dist/permissions/tool-registry.js +19 -10
  61. package/dist/permissions/tool-registry.js.map +1 -1
  62. package/dist/session/context.d.ts +81 -0
  63. package/dist/session/context.d.ts.map +1 -0
  64. package/dist/session/context.js +107 -0
  65. package/dist/session/context.js.map +1 -0
  66. package/dist/session/index.d.ts +12 -0
  67. package/dist/session/index.d.ts.map +1 -0
  68. package/dist/session/index.js +22 -0
  69. package/dist/session/index.js.map +1 -0
  70. package/dist/session/manager.d.ts +186 -0
  71. package/dist/session/manager.d.ts.map +1 -0
  72. package/dist/session/manager.js +383 -0
  73. package/dist/session/manager.js.map +1 -0
  74. package/dist/tempo/client.d.ts +14 -0
  75. package/dist/tempo/client.d.ts.map +1 -1
  76. package/dist/tempo/client.js +57 -0
  77. package/dist/tempo/client.js.map +1 -1
  78. package/dist/tempo/formatters.d.ts +13 -0
  79. package/dist/tempo/formatters.d.ts.map +1 -1
  80. package/dist/tempo/formatters.js +106 -20
  81. package/dist/tempo/formatters.js.map +1 -1
  82. package/dist/tempo/tools.d.ts +14 -13
  83. package/dist/tempo/tools.d.ts.map +1 -1
  84. package/dist/tempo/tools.js +203 -33
  85. package/dist/tempo/tools.js.map +1 -1
  86. package/dist/tempo/types.d.ts +20 -6
  87. package/dist/tempo/types.d.ts.map +1 -1
  88. package/dist/transport/http.d.ts +21 -5
  89. package/dist/transport/http.d.ts.map +1 -1
  90. package/dist/transport/http.js +193 -22
  91. package/dist/transport/http.js.map +1 -1
  92. package/dist/transport/index.d.ts +7 -2
  93. package/dist/transport/index.d.ts.map +1 -1
  94. package/dist/transport/index.js +10 -4
  95. package/dist/transport/index.js.map +1 -1
  96. package/dist/utils/buffer-tools.d.ts +48 -724
  97. package/dist/utils/buffer-tools.d.ts.map +1 -1
  98. package/dist/utils/buffer-tools.js +337 -170
  99. package/dist/utils/buffer-tools.js.map +1 -1
  100. package/dist/utils/content-buffer.d.ts +10 -31
  101. package/dist/utils/content-buffer.d.ts.map +1 -1
  102. package/dist/utils/content-buffer.js +12 -86
  103. package/dist/utils/content-buffer.js.map +1 -1
  104. package/dist/utils/http-client.d.ts.map +1 -1
  105. package/dist/utils/http-client.js +99 -2
  106. package/dist/utils/http-client.js.map +1 -1
  107. package/dist/utils/jicon-help.d.ts +3 -3
  108. package/dist/utils/jicon-help.d.ts.map +1 -1
  109. package/dist/utils/jicon-help.js +164 -312
  110. package/dist/utils/jicon-help.js.map +1 -1
  111. package/dist/utils/logger.d.ts +43 -0
  112. package/dist/utils/logger.d.ts.map +1 -0
  113. package/dist/utils/logger.js +102 -0
  114. package/dist/utils/logger.js.map +1 -0
  115. package/dist/utils/plantuml/tools.d.ts.map +1 -1
  116. package/dist/utils/plantuml/tools.js +10 -9
  117. package/dist/utils/plantuml/tools.js.map +1 -1
  118. package/dist/utils/response-formatter.d.ts +20 -2
  119. package/dist/utils/response-formatter.d.ts.map +1 -1
  120. package/dist/utils/response-formatter.js +147 -17
  121. package/dist/utils/response-formatter.js.map +1 -1
  122. package/dist/utils/sandbox/formatters.d.ts +25 -0
  123. package/dist/utils/sandbox/formatters.d.ts.map +1 -0
  124. package/dist/utils/sandbox/formatters.js +690 -0
  125. package/dist/utils/sandbox/formatters.js.map +1 -0
  126. package/dist/utils/sandbox/helpers.d.ts +16 -0
  127. package/dist/utils/sandbox/helpers.d.ts.map +1 -0
  128. package/dist/utils/sandbox/helpers.js +252 -0
  129. package/dist/utils/sandbox/helpers.js.map +1 -0
  130. package/dist/utils/sandbox/index.d.ts +19 -0
  131. package/dist/utils/sandbox/index.d.ts.map +1 -0
  132. package/dist/utils/sandbox/index.js +269 -0
  133. package/dist/utils/sandbox/index.js.map +1 -0
  134. package/dist/utils/sandbox/schema.d.ts +55 -0
  135. package/dist/utils/sandbox/schema.d.ts.map +1 -0
  136. package/dist/utils/sandbox/schema.js +39 -0
  137. package/dist/utils/sandbox/schema.js.map +1 -0
  138. package/dist/utils/sandbox/types.d.ts +179 -0
  139. package/dist/utils/sandbox/types.d.ts.map +1 -0
  140. package/dist/utils/sandbox/types.js +8 -0
  141. package/dist/utils/sandbox/types.js.map +1 -0
  142. package/dist/utils/schemas/confluence.d.ts +41 -0
  143. package/dist/utils/schemas/confluence.d.ts.map +1 -0
  144. package/dist/utils/schemas/confluence.js +105 -0
  145. package/dist/utils/schemas/confluence.js.map +1 -0
  146. package/dist/utils/schemas/index.d.ts +77 -0
  147. package/dist/utils/schemas/index.d.ts.map +1 -0
  148. package/dist/utils/schemas/index.js +107 -0
  149. package/dist/utils/schemas/index.js.map +1 -0
  150. package/dist/utils/schemas/jira.d.ts +49 -0
  151. package/dist/utils/schemas/jira.d.ts.map +1 -0
  152. package/dist/utils/schemas/jira.js +153 -0
  153. package/dist/utils/schemas/jira.js.map +1 -0
  154. package/dist/utils/schemas/tempo.d.ts +29 -0
  155. package/dist/utils/schemas/tempo.d.ts.map +1 -0
  156. package/dist/utils/schemas/tempo.js +72 -0
  157. package/dist/utils/schemas/tempo.js.map +1 -0
  158. package/dist/utils/whoami-tools.d.ts +17 -0
  159. package/dist/utils/whoami-tools.d.ts.map +1 -0
  160. package/dist/utils/whoami-tools.js +90 -0
  161. package/dist/utils/whoami-tools.js.map +1 -0
  162. package/dist/utils/xhtml/error-locator.js +5 -5
  163. package/dist/utils/xhtml/error-locator.js.map +1 -1
  164. package/package.json +10 -9
  165. package/dist/credentials/client-factory.d.ts +0 -64
  166. package/dist/credentials/client-factory.d.ts.map +0 -1
  167. package/dist/credentials/client-factory.js +0 -110
  168. package/dist/credentials/client-factory.js.map +0 -1
  169. package/dist/credentials/context.d.ts +0 -25
  170. package/dist/credentials/context.d.ts.map +0 -1
  171. package/dist/credentials/context.js +0 -35
  172. package/dist/credentials/context.js.map +0 -1
  173. package/dist/utils/buffer-pipeline/index.d.ts +0 -30
  174. package/dist/utils/buffer-pipeline/index.d.ts.map +0 -1
  175. package/dist/utils/buffer-pipeline/index.js +0 -317
  176. package/dist/utils/buffer-pipeline/index.js.map +0 -1
  177. package/dist/utils/buffer-pipeline/output/csv.d.ts +0 -20
  178. package/dist/utils/buffer-pipeline/output/csv.d.ts.map +0 -1
  179. package/dist/utils/buffer-pipeline/output/csv.js +0 -117
  180. package/dist/utils/buffer-pipeline/output/csv.js.map +0 -1
  181. package/dist/utils/buffer-pipeline/output/json.d.ts +0 -16
  182. package/dist/utils/buffer-pipeline/output/json.d.ts.map +0 -1
  183. package/dist/utils/buffer-pipeline/output/json.js +0 -48
  184. package/dist/utils/buffer-pipeline/output/json.js.map +0 -1
  185. package/dist/utils/buffer-pipeline/output/markdown.d.ts +0 -15
  186. package/dist/utils/buffer-pipeline/output/markdown.d.ts.map +0 -1
  187. package/dist/utils/buffer-pipeline/output/markdown.js +0 -105
  188. package/dist/utils/buffer-pipeline/output/markdown.js.map +0 -1
  189. package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts +0 -16
  190. package/dist/utils/buffer-pipeline/output/xhtml-list.d.ts.map +0 -1
  191. package/dist/utils/buffer-pipeline/output/xhtml-list.js +0 -81
  192. package/dist/utils/buffer-pipeline/output/xhtml-list.js.map +0 -1
  193. package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts +0 -15
  194. package/dist/utils/buffer-pipeline/output/xhtml-table.d.ts.map +0 -1
  195. package/dist/utils/buffer-pipeline/output/xhtml-table.js +0 -176
  196. package/dist/utils/buffer-pipeline/output/xhtml-table.js.map +0 -1
  197. package/dist/utils/buffer-pipeline/schema.d.ts +0 -1878
  198. package/dist/utils/buffer-pipeline/schema.d.ts.map +0 -1
  199. package/dist/utils/buffer-pipeline/schema.js +0 -168
  200. package/dist/utils/buffer-pipeline/schema.js.map +0 -1
  201. package/dist/utils/buffer-pipeline/stages/filter.d.ts +0 -32
  202. package/dist/utils/buffer-pipeline/stages/filter.d.ts.map +0 -1
  203. package/dist/utils/buffer-pipeline/stages/filter.js +0 -208
  204. package/dist/utils/buffer-pipeline/stages/filter.js.map +0 -1
  205. package/dist/utils/buffer-pipeline/stages/format.d.ts +0 -45
  206. package/dist/utils/buffer-pipeline/stages/format.d.ts.map +0 -1
  207. package/dist/utils/buffer-pipeline/stages/format.js +0 -160
  208. package/dist/utils/buffer-pipeline/stages/format.js.map +0 -1
  209. package/dist/utils/buffer-pipeline/stages/group-by.d.ts +0 -25
  210. package/dist/utils/buffer-pipeline/stages/group-by.d.ts.map +0 -1
  211. package/dist/utils/buffer-pipeline/stages/group-by.js +0 -190
  212. package/dist/utils/buffer-pipeline/stages/group-by.js.map +0 -1
  213. package/dist/utils/buffer-pipeline/stages/select.d.ts +0 -54
  214. package/dist/utils/buffer-pipeline/stages/select.d.ts.map +0 -1
  215. package/dist/utils/buffer-pipeline/stages/select.js +0 -228
  216. package/dist/utils/buffer-pipeline/stages/select.js.map +0 -1
  217. package/dist/utils/buffer-pipeline/stages/sort.d.ts +0 -20
  218. package/dist/utils/buffer-pipeline/stages/sort.d.ts.map +0 -1
  219. package/dist/utils/buffer-pipeline/stages/sort.js +0 -96
  220. package/dist/utils/buffer-pipeline/stages/sort.js.map +0 -1
  221. package/dist/utils/buffer-pipeline/types.d.ts +0 -277
  222. package/dist/utils/buffer-pipeline/types.d.ts.map +0 -1
  223. package/dist/utils/buffer-pipeline/types.js +0 -8
  224. package/dist/utils/buffer-pipeline/types.js.map +0 -1
  225. package/dist/utils/plantuml/docker-manager.d.ts +0 -37
  226. package/dist/utils/plantuml/docker-manager.d.ts.map +0 -1
  227. package/dist/utils/plantuml/docker-manager.js +0 -284
  228. package/dist/utils/plantuml/docker-manager.js.map +0 -1
@@ -0,0 +1,690 @@
1
+ /**
2
+ * Sandbox Formatters
3
+ *
4
+ * XHTML table and list generation functions for the sandbox.
5
+ * These are injected as JavaScript code that gets evaluated in the sandbox.
6
+ *
7
+ * The formatters support:
8
+ * - Column configuration (field, header, width, alignment)
9
+ * - Auto-linking (Jira, Confluence, custom URL templates)
10
+ * - Conditional styling (color, bold, icons based on conditions)
11
+ * - Row numbering
12
+ * - Template-based lists with {{field}} placeholders
13
+ */
14
+ /**
15
+ * JavaScript code for formatter functions.
16
+ * This gets evaluated in the sandbox to define toTable() and toList().
17
+ *
18
+ * Note: JIRA_URL and CONFLUENCE_URL are injected separately as context variables.
19
+ */
20
+ export const FORMATTER_FUNCTIONS_JS = `
21
+ // ============================================================================
22
+ // XML Escaping
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Escape XML special characters
27
+ */
28
+ function escapeXml(str) {
29
+ if (str == null) return '';
30
+ return String(str)
31
+ .replace(/&/g, '&')
32
+ .replace(/</g, '&lt;')
33
+ .replace(/>/g, '&gt;')
34
+ .replace(/"/g, '&quot;')
35
+ .replace(/'/g, '&apos;');
36
+ }
37
+
38
+ // ============================================================================
39
+ // Conditional Formatting
40
+ // ============================================================================
41
+
42
+ /**
43
+ * Evaluate a single filter condition
44
+ */
45
+ function evaluateCondition(item, condition) {
46
+ const value = get(item, condition.field);
47
+ const compareValue = condition.value;
48
+
49
+ let matches = false;
50
+
51
+ switch (condition.operator) {
52
+ case 'eq':
53
+ matches = value == compareValue;
54
+ break;
55
+ case 'ne':
56
+ matches = value != compareValue;
57
+ break;
58
+ case 'gt':
59
+ matches = value > compareValue;
60
+ break;
61
+ case 'lt':
62
+ matches = value < compareValue;
63
+ break;
64
+ case 'gte':
65
+ matches = value >= compareValue;
66
+ break;
67
+ case 'lte':
68
+ matches = value <= compareValue;
69
+ break;
70
+ case 'contains':
71
+ matches = String(value ?? '').toLowerCase().includes(String(compareValue ?? '').toLowerCase());
72
+ break;
73
+ case 'startsWith':
74
+ matches = String(value ?? '').toLowerCase().startsWith(String(compareValue ?? '').toLowerCase());
75
+ break;
76
+ case 'endsWith':
77
+ matches = String(value ?? '').toLowerCase().endsWith(String(compareValue ?? '').toLowerCase());
78
+ break;
79
+ case 'in':
80
+ matches = Array.isArray(compareValue) && compareValue.includes(value);
81
+ break;
82
+ case 'notIn':
83
+ matches = !Array.isArray(compareValue) || !compareValue.includes(value);
84
+ break;
85
+ case 'exists':
86
+ matches = value !== null && value !== undefined;
87
+ break;
88
+ case 'notExists':
89
+ matches = value === null || value === undefined;
90
+ break;
91
+ case 'regex':
92
+ try {
93
+ matches = new RegExp(compareValue).test(String(value ?? ''));
94
+ } catch (e) {
95
+ matches = false;
96
+ }
97
+ break;
98
+ case 'empty':
99
+ matches = value == null || value === '' || (Array.isArray(value) && value.length === 0);
100
+ break;
101
+ case 'notEmpty':
102
+ matches = value != null && value !== '' && (!Array.isArray(value) || value.length > 0);
103
+ break;
104
+ default:
105
+ matches = false;
106
+ }
107
+
108
+ // Handle OR conditions
109
+ if (!matches && condition.or && Array.isArray(condition.or)) {
110
+ for (const orCondition of condition.or) {
111
+ if (evaluateCondition(item, orCondition)) {
112
+ matches = true;
113
+ break;
114
+ }
115
+ }
116
+ }
117
+
118
+ return matches;
119
+ }
120
+
121
+ /**
122
+ * Evaluate format rules and return styles
123
+ */
124
+ function evaluateFormats(item, formats) {
125
+ const fieldStyles = {};
126
+ let rowStyle = {};
127
+
128
+ if (!formats || !Array.isArray(formats)) {
129
+ return { fieldStyles, rowStyle };
130
+ }
131
+
132
+ for (const format of formats) {
133
+ if (evaluateCondition(item, format.condition)) {
134
+ if (format.fields && format.fields.length > 0) {
135
+ // Apply to specific fields
136
+ for (const field of format.fields) {
137
+ fieldStyles[field] = { ...(fieldStyles[field] || {}), ...format.style };
138
+ }
139
+ } else {
140
+ // Apply to entire row
141
+ rowStyle = { ...rowStyle, ...format.style };
142
+ }
143
+ }
144
+ }
145
+
146
+ return { fieldStyles, rowStyle };
147
+ }
148
+
149
+ /**
150
+ * Convert style config to inline CSS
151
+ */
152
+ function styleToInlineCss(style) {
153
+ if (!style) return '';
154
+ const parts = [];
155
+ if (style.color) parts.push('color: ' + style.color);
156
+ if (style.backgroundColor) parts.push('background-color: ' + style.backgroundColor);
157
+ if (style.bold) parts.push('font-weight: bold');
158
+ if (style.italic) parts.push('font-style: italic');
159
+ return parts.join('; ');
160
+ }
161
+
162
+ /**
163
+ * Apply text decorations (prefix, suffix, icon)
164
+ */
165
+ function applyTextDecorations(value, style) {
166
+ if (!style) return value;
167
+ let result = value;
168
+ if (style.icon) result = style.icon + ' ' + result;
169
+ if (style.prefix) result = style.prefix + result;
170
+ if (style.suffix) result = result + style.suffix;
171
+ return result;
172
+ }
173
+
174
+ /**
175
+ * Format cell value with styling
176
+ */
177
+ function formatCellXhtml(value, style) {
178
+ // Convert value to string
179
+ let strValue;
180
+ if (value == null) {
181
+ strValue = '';
182
+ } else if (Array.isArray(value)) {
183
+ strValue = value.join(', ');
184
+ } else if (typeof value === 'object') {
185
+ strValue = JSON.stringify(value);
186
+ } else {
187
+ strValue = String(value);
188
+ }
189
+
190
+ // Escape HTML
191
+ strValue = escapeXml(strValue);
192
+
193
+ // Apply decorations
194
+ if (style) {
195
+ strValue = applyTextDecorations(strValue, style);
196
+ }
197
+
198
+ // Wrap in styled span if needed
199
+ if (style) {
200
+ const inlineCss = styleToInlineCss(style);
201
+ if (inlineCss || style.cssClass) {
202
+ const attrs = [];
203
+ if (style.cssClass) attrs.push('class="' + escapeXml(style.cssClass) + '"');
204
+ if (inlineCss) attrs.push('style="' + escapeXml(inlineCss) + '"');
205
+ return '<span ' + attrs.join(' ') + '>' + strValue + '</span>';
206
+ }
207
+ }
208
+
209
+ return strValue;
210
+ }
211
+
212
+ /**
213
+ * Get effective style for a field (merge row and field styles)
214
+ */
215
+ function getEffectiveStyle(fieldStyles, rowStyle, field) {
216
+ const fieldStyle = fieldStyles[field];
217
+ if (!fieldStyle && !rowStyle) return null;
218
+ if (!fieldStyle) return rowStyle;
219
+ if (!rowStyle) return fieldStyle;
220
+ return { ...rowStyle, ...fieldStyle };
221
+ }
222
+
223
+ // ============================================================================
224
+ // Link Generation
225
+ // ============================================================================
226
+
227
+ /**
228
+ * Generate link URL based on config
229
+ */
230
+ function generateLinkUrl(value, item, link) {
231
+ const strValue = value == null ? '' : String(value);
232
+ if (!strValue) return null;
233
+
234
+ switch (link.type) {
235
+ case 'jira':
236
+ if (typeof JIRA_URL !== 'undefined' && JIRA_URL) {
237
+ return JIRA_URL + '/browse/' + strValue;
238
+ }
239
+ return null;
240
+ case 'confluence':
241
+ if (typeof CONFLUENCE_URL !== 'undefined' && CONFLUENCE_URL) {
242
+ return CONFLUENCE_URL + '/pages/viewpage.action?pageId=' + strValue;
243
+ }
244
+ return null;
245
+ case 'tempo':
246
+ return null;
247
+ case 'custom':
248
+ if (link.template) {
249
+ let url = link.template;
250
+ const placeholders = url.match(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g) || [];
251
+ for (const placeholder of placeholders) {
252
+ const fieldPath = placeholder.slice(2, -2);
253
+ const fieldValue = fieldPath === 'value' ? strValue : get(item, fieldPath);
254
+ url = url.replace(placeholder, encodeURIComponent(String(fieldValue ?? '')));
255
+ }
256
+ return url;
257
+ }
258
+ return null;
259
+ default:
260
+ return null;
261
+ }
262
+ }
263
+
264
+ // ============================================================================
265
+ // toTable() - Confluence Table Generator
266
+ // ============================================================================
267
+
268
+ /**
269
+ * Generate XHTML table from array of objects
270
+ *
271
+ * @param {Array} array - Array of objects to display
272
+ * @param {Object} config - Table configuration
273
+ * @param {string} [config.title] - Optional h2 title above table
274
+ * @param {Array} config.columns - Column definitions
275
+ * @param {string} config.columns[].field - Field path (dot notation supported)
276
+ * @param {string} config.columns[].header - Column header text
277
+ * @param {Object} [config.columns[].link] - Link configuration
278
+ * @param {string} [config.columns[].width] - CSS width
279
+ * @param {string} [config.columns[].align] - Text alignment
280
+ * @param {boolean} [config.showRowNumbers] - Add row number column
281
+ * @param {string} [config.tableClass] - CSS class for table
282
+ * @param {Array} [config.format] - Conditional formatting rules
283
+ * @returns {Object} { __xhtml: true, content: string }
284
+ */
285
+ function toTable(array, config) {
286
+ if (!Array.isArray(array)) {
287
+ throw new Error('toTable: first argument must be an array');
288
+ }
289
+ if (!config || !config.columns || !Array.isArray(config.columns)) {
290
+ throw new Error('toTable: config.columns is required and must be an array');
291
+ }
292
+
293
+ const lines = [];
294
+
295
+ // Add title if present
296
+ if (config.title) {
297
+ lines.push('<h2>' + escapeXml(config.title) + '</h2>');
298
+ }
299
+
300
+ // Table attributes
301
+ const tableAttrs = config.tableClass ? ' class="' + escapeXml(config.tableClass) + '"' : '';
302
+
303
+ // Table start
304
+ lines.push('<table' + tableAttrs + '>');
305
+
306
+ // Header row
307
+ lines.push('<thead>');
308
+ const headerCells = [];
309
+ if (config.showRowNumbers) {
310
+ headerCells.push('<th style="text-align: right; width: 30px">#</th>');
311
+ }
312
+ for (const col of config.columns) {
313
+ const attrs = [];
314
+ if (col.align && col.align !== 'left') {
315
+ attrs.push('style="text-align: ' + col.align + '"');
316
+ }
317
+ if (col.width) {
318
+ const existingStyle = attrs.find(a => a.startsWith('style='));
319
+ if (existingStyle) {
320
+ const idx = attrs.indexOf(existingStyle);
321
+ attrs[idx] = existingStyle.replace('style="', 'style="width: ' + col.width + '; ');
322
+ } else {
323
+ attrs.push('style="width: ' + col.width + '"');
324
+ }
325
+ }
326
+ const attrStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';
327
+ headerCells.push('<th' + attrStr + '>' + escapeXml(col.header) + '</th>');
328
+ }
329
+ lines.push('<tr>' + headerCells.join('') + '</tr>');
330
+ lines.push('</thead>');
331
+
332
+ // Body rows
333
+ lines.push('<tbody>');
334
+ array.forEach(function(item, index) {
335
+ const { fieldStyles, rowStyle } = evaluateFormats(item, config.format);
336
+ const cells = [];
337
+
338
+ // Row number
339
+ if (config.showRowNumbers) {
340
+ cells.push('<td style="text-align: right; width: 30px">' + (index + 1) + '</td>');
341
+ }
342
+
343
+ // Data cells
344
+ for (const col of config.columns) {
345
+ const value = get(item, col.field);
346
+ const style = getEffectiveStyle(fieldStyles, rowStyle, col.field);
347
+ let content = formatCellXhtml(value, style);
348
+
349
+ // Add link if configured
350
+ if (col.link) {
351
+ const url = generateLinkUrl(value, item, col.link);
352
+ if (url) {
353
+ content = '<a href="' + escapeXml(url) + '">' + content + '</a>';
354
+ }
355
+ }
356
+
357
+ // Cell attributes
358
+ const cellAttrs = [];
359
+ if (col.align && col.align !== 'left') {
360
+ cellAttrs.push('style="text-align: ' + col.align + '"');
361
+ }
362
+ if (col.width) {
363
+ const existingStyle = cellAttrs.find(a => a.startsWith('style='));
364
+ if (existingStyle) {
365
+ const idx = cellAttrs.indexOf(existingStyle);
366
+ cellAttrs[idx] = existingStyle.replace('style="', 'style="width: ' + col.width + '; ');
367
+ } else {
368
+ cellAttrs.push('style="width: ' + col.width + '"');
369
+ }
370
+ }
371
+ const cellAttrStr = cellAttrs.length > 0 ? ' ' + cellAttrs.join(' ') : '';
372
+ cells.push('<td' + cellAttrStr + '>' + content + '</td>');
373
+ }
374
+
375
+ // Row attributes
376
+ let rowAttrs = '';
377
+ if (rowStyle) {
378
+ const rowCss = styleToInlineCss(rowStyle);
379
+ if (rowCss) rowAttrs = ' style="' + escapeXml(rowCss) + '"';
380
+ if (rowStyle.cssClass) rowAttrs += ' class="' + escapeXml(rowStyle.cssClass) + '"';
381
+ }
382
+
383
+ lines.push('<tr' + rowAttrs + '>' + cells.join('') + '</tr>');
384
+ });
385
+ lines.push('</tbody>');
386
+
387
+ // Table end
388
+ lines.push('</table>');
389
+
390
+ // Return marked XHTML object with toString for string concatenation
391
+ const xhtml = lines.join('\\n');
392
+ return { __xhtml: true, content: xhtml, toString: function() { return xhtml; } };
393
+ }
394
+
395
+ // ============================================================================
396
+ // toList() - Confluence List Generator
397
+ // ============================================================================
398
+
399
+ /**
400
+ * Generate XHTML list from array of objects
401
+ *
402
+ * @param {Array} array - Array of objects to display
403
+ * @param {Object} config - List configuration
404
+ * @param {string} [config.title] - Optional h2 title above list
405
+ * @param {string} config.template - Template with {{field}} placeholders
406
+ * @param {string} [config.style] - List style: "bullet", "numbered", "none"
407
+ * @param {Array} [config.format] - Conditional formatting rules
408
+ * @returns {Object} { __xhtml: true, content: string }
409
+ */
410
+ function toList(array, config) {
411
+ if (!Array.isArray(array)) {
412
+ throw new Error('toList: first argument must be an array');
413
+ }
414
+ if (!config || typeof config.template !== 'string') {
415
+ throw new Error('toList: config.template is required and must be a string');
416
+ }
417
+
418
+ const lines = [];
419
+
420
+ // Add title if present
421
+ if (config.title) {
422
+ lines.push('<h2>' + escapeXml(config.title) + '</h2>');
423
+ }
424
+
425
+ // Determine list tag
426
+ const listStyle = config.style || 'bullet';
427
+ const listTag = listStyle === 'numbered' ? 'ol' : 'ul';
428
+ const listAttr = listStyle === 'none' ? ' style="list-style-type: none"' : '';
429
+
430
+ // List start
431
+ lines.push('<' + listTag + listAttr + '>');
432
+
433
+ // List items
434
+ for (const item of array) {
435
+ const { fieldStyles, rowStyle } = evaluateFormats(item, config.format);
436
+
437
+ // Process template
438
+ let content = config.template;
439
+ const placeholders = content.match(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g) || [];
440
+ for (const placeholder of placeholders) {
441
+ const fieldPath = placeholder.slice(2, -2);
442
+ const value = get(item, fieldPath);
443
+ const style = getEffectiveStyle(fieldStyles, rowStyle, fieldPath);
444
+ const formattedValue = formatCellXhtml(value, style);
445
+ content = content.replace(placeholder, formattedValue);
446
+ }
447
+
448
+ // Item attributes
449
+ let liAttrs = '';
450
+ if (rowStyle) {
451
+ const css = styleToInlineCss(rowStyle);
452
+ if (css) liAttrs = ' style="' + escapeXml(css) + '"';
453
+ if (rowStyle.cssClass) liAttrs += ' class="' + escapeXml(rowStyle.cssClass) + '"';
454
+ }
455
+
456
+ lines.push('<li' + liAttrs + '>' + content + '</li>');
457
+ }
458
+
459
+ // List end
460
+ lines.push('</' + listTag + '>');
461
+
462
+ // Return marked XHTML object with toString for string concatenation
463
+ const xhtml = lines.join('\\n');
464
+ return { __xhtml: true, content: xhtml, toString: function() { return xhtml; } };
465
+ }
466
+
467
+ // ============================================================================
468
+ // Markdown Formatters
469
+ // ============================================================================
470
+
471
+ /**
472
+ * Escape Markdown special characters in text
473
+ * Note: We intentionally do NOT escape [ and ] because:
474
+ * 1. They don't break markdown tables (only | does)
475
+ * 2. Some frontends interpret \\[...\\] as LaTeX math mode
476
+ */
477
+ function escapeMd(str) {
478
+ if (str == null) return '';
479
+ return String(str)
480
+ .replace(/\\\\/g, '\\\\\\\\')
481
+ .replace(/\\|/g, '\\\\|')
482
+ .replace(/\\n/g, ' ');
483
+ }
484
+
485
+ /**
486
+ * Format cell value for Markdown with optional styling
487
+ */
488
+ function formatCellMarkdown(value, style) {
489
+ // Convert value to string
490
+ let strValue;
491
+ if (value == null) {
492
+ strValue = '';
493
+ } else if (Array.isArray(value)) {
494
+ strValue = value.join(', ');
495
+ } else if (typeof value === 'object') {
496
+ strValue = JSON.stringify(value);
497
+ } else {
498
+ strValue = String(value);
499
+ }
500
+
501
+ // Escape markdown special chars
502
+ strValue = escapeMd(strValue);
503
+
504
+ // Apply decorations
505
+ if (style) {
506
+ strValue = applyTextDecorations(strValue, style);
507
+
508
+ // Apply markdown formatting
509
+ if (style.bold) {
510
+ strValue = '**' + strValue + '**';
511
+ }
512
+ if (style.italic) {
513
+ strValue = '_' + strValue + '_';
514
+ }
515
+ }
516
+
517
+ return strValue;
518
+ }
519
+
520
+ /**
521
+ * Generate Markdown link
522
+ */
523
+ function generateMarkdownLink(value, item, link) {
524
+ const url = generateLinkUrl(value, item, link);
525
+ if (!url) return null;
526
+ return { url, text: value == null ? '' : String(value) };
527
+ }
528
+
529
+ /**
530
+ * Generate Markdown table from array of objects
531
+ *
532
+ * @param {Array} array - Array of objects to display
533
+ * @param {Object} config - Table configuration
534
+ * @param {string} [config.title] - Optional title above table
535
+ * @param {Array} config.columns - Column definitions
536
+ * @param {string} config.columns[].field - Field path (dot notation supported)
537
+ * @param {string} config.columns[].header - Column header text
538
+ * @param {Object} [config.columns[].link] - Link configuration
539
+ * @param {string} [config.columns[].align] - Text alignment (left, center, right)
540
+ * @param {boolean} [config.showRowNumbers] - Add row number column
541
+ * @param {Array} [config.format] - Conditional formatting rules
542
+ * @returns {Object} { __markdown: true, content: string }
543
+ */
544
+ function toMarkdownTable(array, config) {
545
+ if (!Array.isArray(array)) {
546
+ throw new Error('toMarkdownTable: first argument must be an array');
547
+ }
548
+ if (!config || !config.columns || !Array.isArray(config.columns)) {
549
+ throw new Error('toMarkdownTable: config.columns is required and must be an array');
550
+ }
551
+
552
+ const lines = [];
553
+
554
+ // Add title if present
555
+ if (config.title) {
556
+ lines.push('## ' + config.title);
557
+ lines.push('');
558
+ }
559
+
560
+ // Build header row
561
+ const headers = [];
562
+ const separators = [];
563
+
564
+ if (config.showRowNumbers) {
565
+ headers.push('#');
566
+ separators.push('--:'); // Right-aligned for numbers
567
+ }
568
+
569
+ for (const col of config.columns) {
570
+ headers.push(escapeMd(col.header));
571
+ // Alignment separator
572
+ if (col.align === 'center') {
573
+ separators.push(':--:');
574
+ } else if (col.align === 'right') {
575
+ separators.push('--:');
576
+ } else {
577
+ separators.push('---');
578
+ }
579
+ }
580
+
581
+ lines.push('| ' + headers.join(' | ') + ' |');
582
+ lines.push('| ' + separators.join(' | ') + ' |');
583
+
584
+ // Body rows
585
+ array.forEach(function(item, index) {
586
+ const { fieldStyles, rowStyle } = evaluateFormats(item, config.format);
587
+ const cells = [];
588
+
589
+ // Row number
590
+ if (config.showRowNumbers) {
591
+ cells.push(String(index + 1));
592
+ }
593
+
594
+ // Data cells
595
+ for (const col of config.columns) {
596
+ const value = get(item, col.field);
597
+ const style = getEffectiveStyle(fieldStyles, rowStyle, col.field);
598
+ let content = formatCellMarkdown(value, style);
599
+
600
+ // Add link if configured
601
+ if (col.link) {
602
+ const linkInfo = generateMarkdownLink(value, item, col.link);
603
+ if (linkInfo && linkInfo.url) {
604
+ content = '[' + escapeMd(linkInfo.text) + '](' + linkInfo.url + ')';
605
+ }
606
+ }
607
+
608
+ cells.push(content);
609
+ }
610
+
611
+ lines.push('| ' + cells.join(' | ') + ' |');
612
+ });
613
+
614
+ // Return marked Markdown object with toString for string concatenation
615
+ const md = lines.join('\\n');
616
+ return { __markdown: true, content: md, toString: function() { return md; } };
617
+ }
618
+
619
+ /**
620
+ * Generate Markdown list from array of objects
621
+ *
622
+ * @param {Array} array - Array of objects to display
623
+ * @param {Object} config - List configuration
624
+ * @param {string} [config.title] - Optional title above list
625
+ * @param {string} config.template - Template with {{field}} placeholders
626
+ * @param {string} [config.style] - List style: "bullet", "numbered", "task"
627
+ * @param {Array} [config.format] - Conditional formatting rules
628
+ * @returns {Object} { __markdown: true, content: string }
629
+ */
630
+ function toMarkdownList(array, config) {
631
+ if (!Array.isArray(array)) {
632
+ throw new Error('toMarkdownList: first argument must be an array');
633
+ }
634
+ if (!config || typeof config.template !== 'string') {
635
+ throw new Error('toMarkdownList: config.template is required and must be a string');
636
+ }
637
+
638
+ const lines = [];
639
+
640
+ // Add title if present
641
+ if (config.title) {
642
+ lines.push('## ' + config.title);
643
+ lines.push('');
644
+ }
645
+
646
+ // Determine list prefix
647
+ const listStyle = config.style || 'bullet';
648
+ let counter = 1;
649
+
650
+ // List items
651
+ for (const item of array) {
652
+ const { fieldStyles, rowStyle } = evaluateFormats(item, config.format);
653
+
654
+ // Process template
655
+ let content = config.template;
656
+ const placeholders = content.match(/\\{\\{(\\w+(?:\\.\\w+)*)\\}\\}/g) || [];
657
+ for (const placeholder of placeholders) {
658
+ const fieldPath = placeholder.slice(2, -2);
659
+ const value = get(item, fieldPath);
660
+ const style = getEffectiveStyle(fieldStyles, rowStyle, fieldPath);
661
+ const formattedValue = formatCellMarkdown(value, style);
662
+ content = content.replace(placeholder, formattedValue);
663
+ }
664
+
665
+ // Format list item
666
+ let prefix;
667
+ if (listStyle === 'numbered') {
668
+ prefix = counter + '. ';
669
+ counter++;
670
+ } else if (listStyle === 'task') {
671
+ prefix = '- [ ] ';
672
+ } else {
673
+ prefix = '- ';
674
+ }
675
+
676
+ lines.push(prefix + content);
677
+ }
678
+
679
+ // Return marked Markdown object with toString for string concatenation
680
+ const md = lines.join('\\n');
681
+ return { __markdown: true, content: md, toString: function() { return md; } };
682
+ }
683
+ `;
684
+ /**
685
+ * Get the JavaScript code for formatter functions
686
+ */
687
+ export function getFormatterFunctionsCode() {
688
+ return FORMATTER_FUNCTIONS_JS;
689
+ }
690
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../../src/utils/sandbox/formatters.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAupBrC,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO,sBAAsB,CAAC;AAChC,CAAC"}