euparliamentmonitor 0.8.4

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 (276) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1005 -0
  3. package/SECURITY.md +151 -0
  4. package/package.json +131 -0
  5. package/scripts/constants/committee-indicator-map.d.ts +199 -0
  6. package/scripts/constants/committee-indicator-map.d.ts.map +1 -0
  7. package/scripts/constants/committee-indicator-map.js +1224 -0
  8. package/scripts/constants/committee-indicator-map.js.map +1 -0
  9. package/scripts/constants/config.d.ts +38 -0
  10. package/scripts/constants/config.d.ts.map +1 -0
  11. package/scripts/constants/config.js +66 -0
  12. package/scripts/constants/config.js.map +1 -0
  13. package/scripts/constants/language-articles.d.ts +84 -0
  14. package/scripts/constants/language-articles.d.ts.map +1 -0
  15. package/scripts/constants/language-articles.js +6771 -0
  16. package/scripts/constants/language-articles.js.map +1 -0
  17. package/scripts/constants/language-core.d.ts +38 -0
  18. package/scripts/constants/language-core.d.ts.map +1 -0
  19. package/scripts/constants/language-core.js +90 -0
  20. package/scripts/constants/language-core.js.map +1 -0
  21. package/scripts/constants/language-ui.d.ts +82 -0
  22. package/scripts/constants/language-ui.d.ts.map +1 -0
  23. package/scripts/constants/language-ui.js +889 -0
  24. package/scripts/constants/language-ui.js.map +1 -0
  25. package/scripts/constants/languages.d.ts +14 -0
  26. package/scripts/constants/languages.d.ts.map +1 -0
  27. package/scripts/constants/languages.js +15 -0
  28. package/scripts/constants/languages.js.map +1 -0
  29. package/scripts/generators/analysis-builders.d.ts +266 -0
  30. package/scripts/generators/analysis-builders.d.ts.map +1 -0
  31. package/scripts/generators/analysis-builders.js +2903 -0
  32. package/scripts/generators/analysis-builders.js.map +1 -0
  33. package/scripts/generators/breaking-content.d.ts +45 -0
  34. package/scripts/generators/breaking-content.d.ts.map +1 -0
  35. package/scripts/generators/breaking-content.js +530 -0
  36. package/scripts/generators/breaking-content.js.map +1 -0
  37. package/scripts/generators/committee-helpers.d.ts +54 -0
  38. package/scripts/generators/committee-helpers.d.ts.map +1 -0
  39. package/scripts/generators/committee-helpers.js +154 -0
  40. package/scripts/generators/committee-helpers.js.map +1 -0
  41. package/scripts/generators/dashboard-content.d.ts +95 -0
  42. package/scripts/generators/dashboard-content.d.ts.map +1 -0
  43. package/scripts/generators/dashboard-content.js +630 -0
  44. package/scripts/generators/dashboard-content.js.map +1 -0
  45. package/scripts/generators/deep-analysis-content.d.ts +23 -0
  46. package/scripts/generators/deep-analysis-content.d.ts.map +1 -0
  47. package/scripts/generators/deep-analysis-content.js +831 -0
  48. package/scripts/generators/deep-analysis-content.js.map +1 -0
  49. package/scripts/generators/mindmap-content.d.ts +55 -0
  50. package/scripts/generators/mindmap-content.d.ts.map +1 -0
  51. package/scripts/generators/mindmap-content.js +512 -0
  52. package/scripts/generators/mindmap-content.js.map +1 -0
  53. package/scripts/generators/motions-content.d.ts +50 -0
  54. package/scripts/generators/motions-content.d.ts.map +1 -0
  55. package/scripts/generators/motions-content.js +391 -0
  56. package/scripts/generators/motions-content.js.map +1 -0
  57. package/scripts/generators/news-enhanced.d.ts +14 -0
  58. package/scripts/generators/news-enhanced.d.ts.map +1 -0
  59. package/scripts/generators/news-enhanced.js +169 -0
  60. package/scripts/generators/news-enhanced.js.map +1 -0
  61. package/scripts/generators/news-indexes.d.ts +31 -0
  62. package/scripts/generators/news-indexes.d.ts.map +1 -0
  63. package/scripts/generators/news-indexes.js +410 -0
  64. package/scripts/generators/news-indexes.js.map +1 -0
  65. package/scripts/generators/pipeline/fetch-stage.d.ts +352 -0
  66. package/scripts/generators/pipeline/fetch-stage.d.ts.map +1 -0
  67. package/scripts/generators/pipeline/fetch-stage.js +1522 -0
  68. package/scripts/generators/pipeline/fetch-stage.js.map +1 -0
  69. package/scripts/generators/pipeline/generate-stage.d.ts +43 -0
  70. package/scripts/generators/pipeline/generate-stage.d.ts.map +1 -0
  71. package/scripts/generators/pipeline/generate-stage.js +204 -0
  72. package/scripts/generators/pipeline/generate-stage.js.map +1 -0
  73. package/scripts/generators/pipeline/output-stage.d.ts +48 -0
  74. package/scripts/generators/pipeline/output-stage.d.ts.map +1 -0
  75. package/scripts/generators/pipeline/output-stage.js +145 -0
  76. package/scripts/generators/pipeline/output-stage.js.map +1 -0
  77. package/scripts/generators/pipeline/transform-stage.d.ts +57 -0
  78. package/scripts/generators/pipeline/transform-stage.d.ts.map +1 -0
  79. package/scripts/generators/pipeline/transform-stage.js +111 -0
  80. package/scripts/generators/pipeline/transform-stage.js.map +1 -0
  81. package/scripts/generators/propositions-content.d.ts +29 -0
  82. package/scripts/generators/propositions-content.d.ts.map +1 -0
  83. package/scripts/generators/propositions-content.js +90 -0
  84. package/scripts/generators/propositions-content.js.map +1 -0
  85. package/scripts/generators/sankey-content.d.ts +45 -0
  86. package/scripts/generators/sankey-content.d.ts.map +1 -0
  87. package/scripts/generators/sankey-content.js +227 -0
  88. package/scripts/generators/sankey-content.js.map +1 -0
  89. package/scripts/generators/sitemap.d.ts +66 -0
  90. package/scripts/generators/sitemap.d.ts.map +1 -0
  91. package/scripts/generators/sitemap.js +562 -0
  92. package/scripts/generators/sitemap.js.map +1 -0
  93. package/scripts/generators/strategies/article-strategy.d.ts +146 -0
  94. package/scripts/generators/strategies/article-strategy.d.ts.map +1 -0
  95. package/scripts/generators/strategies/article-strategy.js +4 -0
  96. package/scripts/generators/strategies/article-strategy.js.map +1 -0
  97. package/scripts/generators/strategies/breaking-news-strategy.d.ts +64 -0
  98. package/scripts/generators/strategies/breaking-news-strategy.d.ts.map +1 -0
  99. package/scripts/generators/strategies/breaking-news-strategy.js +246 -0
  100. package/scripts/generators/strategies/breaking-news-strategy.js.map +1 -0
  101. package/scripts/generators/strategies/committee-reports-strategy.d.ts +93 -0
  102. package/scripts/generators/strategies/committee-reports-strategy.d.ts.map +1 -0
  103. package/scripts/generators/strategies/committee-reports-strategy.js +447 -0
  104. package/scripts/generators/strategies/committee-reports-strategy.js.map +1 -0
  105. package/scripts/generators/strategies/month-ahead-strategy.d.ts +60 -0
  106. package/scripts/generators/strategies/month-ahead-strategy.d.ts.map +1 -0
  107. package/scripts/generators/strategies/month-ahead-strategy.js +175 -0
  108. package/scripts/generators/strategies/month-ahead-strategy.js.map +1 -0
  109. package/scripts/generators/strategies/monthly-review-strategy.d.ts +66 -0
  110. package/scripts/generators/strategies/monthly-review-strategy.d.ts.map +1 -0
  111. package/scripts/generators/strategies/monthly-review-strategy.js +204 -0
  112. package/scripts/generators/strategies/monthly-review-strategy.js.map +1 -0
  113. package/scripts/generators/strategies/motions-strategy.d.ts +61 -0
  114. package/scripts/generators/strategies/motions-strategy.d.ts.map +1 -0
  115. package/scripts/generators/strategies/motions-strategy.js +215 -0
  116. package/scripts/generators/strategies/motions-strategy.js.map +1 -0
  117. package/scripts/generators/strategies/propositions-strategy.d.ts +60 -0
  118. package/scripts/generators/strategies/propositions-strategy.d.ts.map +1 -0
  119. package/scripts/generators/strategies/propositions-strategy.js +257 -0
  120. package/scripts/generators/strategies/propositions-strategy.js.map +1 -0
  121. package/scripts/generators/strategies/week-ahead-strategy.d.ts +57 -0
  122. package/scripts/generators/strategies/week-ahead-strategy.d.ts.map +1 -0
  123. package/scripts/generators/strategies/week-ahead-strategy.js +178 -0
  124. package/scripts/generators/strategies/week-ahead-strategy.js.map +1 -0
  125. package/scripts/generators/strategies/weekly-review-strategy.d.ts +63 -0
  126. package/scripts/generators/strategies/weekly-review-strategy.d.ts.map +1 -0
  127. package/scripts/generators/strategies/weekly-review-strategy.js +211 -0
  128. package/scripts/generators/strategies/weekly-review-strategy.js.map +1 -0
  129. package/scripts/generators/swot-content.d.ts +42 -0
  130. package/scripts/generators/swot-content.d.ts.map +1 -0
  131. package/scripts/generators/swot-content.js +366 -0
  132. package/scripts/generators/swot-content.js.map +1 -0
  133. package/scripts/generators/week-ahead-content.d.ts +103 -0
  134. package/scripts/generators/week-ahead-content.d.ts.map +1 -0
  135. package/scripts/generators/week-ahead-content.js +610 -0
  136. package/scripts/generators/week-ahead-content.js.map +1 -0
  137. package/scripts/index.d.ts +40 -0
  138. package/scripts/index.d.ts.map +1 -0
  139. package/scripts/index.js +53 -0
  140. package/scripts/index.js.map +1 -0
  141. package/scripts/mcp/ep-mcp-client.d.ts +471 -0
  142. package/scripts/mcp/ep-mcp-client.d.ts.map +1 -0
  143. package/scripts/mcp/ep-mcp-client.js +734 -0
  144. package/scripts/mcp/ep-mcp-client.js.map +1 -0
  145. package/scripts/mcp/mcp-connection.d.ts +264 -0
  146. package/scripts/mcp/mcp-connection.d.ts.map +1 -0
  147. package/scripts/mcp/mcp-connection.js +790 -0
  148. package/scripts/mcp/mcp-connection.js.map +1 -0
  149. package/scripts/mcp/mcp-health.d.ts +75 -0
  150. package/scripts/mcp/mcp-health.d.ts.map +1 -0
  151. package/scripts/mcp/mcp-health.js +78 -0
  152. package/scripts/mcp/mcp-health.js.map +1 -0
  153. package/scripts/mcp/mcp-retry.d.ts +94 -0
  154. package/scripts/mcp/mcp-retry.d.ts.map +1 -0
  155. package/scripts/mcp/mcp-retry.js +127 -0
  156. package/scripts/mcp/mcp-retry.js.map +1 -0
  157. package/scripts/mcp/wb-mcp-client.d.ts +38 -0
  158. package/scripts/mcp/wb-mcp-client.d.ts.map +1 -0
  159. package/scripts/mcp/wb-mcp-client.js +112 -0
  160. package/scripts/mcp/wb-mcp-client.js.map +1 -0
  161. package/scripts/templates/article-template.d.ts +9 -0
  162. package/scripts/templates/article-template.d.ts.map +1 -0
  163. package/scripts/templates/article-template.js +378 -0
  164. package/scripts/templates/article-template.js.map +1 -0
  165. package/scripts/templates/section-builders.d.ts +28 -0
  166. package/scripts/templates/section-builders.d.ts.map +1 -0
  167. package/scripts/templates/section-builders.js +142 -0
  168. package/scripts/templates/section-builders.js.map +1 -0
  169. package/scripts/types/analysis.d.ts +115 -0
  170. package/scripts/types/analysis.d.ts.map +1 -0
  171. package/scripts/types/analysis.js +4 -0
  172. package/scripts/types/analysis.js.map +1 -0
  173. package/scripts/types/common.d.ts +584 -0
  174. package/scripts/types/common.d.ts.map +1 -0
  175. package/scripts/types/common.js +96 -0
  176. package/scripts/types/common.js.map +1 -0
  177. package/scripts/types/generation.d.ts +104 -0
  178. package/scripts/types/generation.d.ts.map +1 -0
  179. package/scripts/types/generation.js +4 -0
  180. package/scripts/types/generation.js.map +1 -0
  181. package/scripts/types/index.d.ts +24 -0
  182. package/scripts/types/index.d.ts.map +1 -0
  183. package/scripts/types/index.js +16 -0
  184. package/scripts/types/index.js.map +1 -0
  185. package/scripts/types/intelligence.d.ts +129 -0
  186. package/scripts/types/intelligence.d.ts.map +1 -0
  187. package/scripts/types/intelligence.js +4 -0
  188. package/scripts/types/intelligence.js.map +1 -0
  189. package/scripts/types/mcp.d.ts +418 -0
  190. package/scripts/types/mcp.d.ts.map +1 -0
  191. package/scripts/types/mcp.js +4 -0
  192. package/scripts/types/mcp.js.map +1 -0
  193. package/scripts/types/parliament.d.ts +388 -0
  194. package/scripts/types/parliament.d.ts.map +1 -0
  195. package/scripts/types/parliament.js +4 -0
  196. package/scripts/types/parliament.js.map +1 -0
  197. package/scripts/types/quality.d.ts +114 -0
  198. package/scripts/types/quality.d.ts.map +1 -0
  199. package/scripts/types/quality.js +4 -0
  200. package/scripts/types/quality.js.map +1 -0
  201. package/scripts/types/stakeholder.d.ts +88 -0
  202. package/scripts/types/stakeholder.d.ts.map +1 -0
  203. package/scripts/types/stakeholder.js +16 -0
  204. package/scripts/types/stakeholder.js.map +1 -0
  205. package/scripts/types/visualization.d.ts +708 -0
  206. package/scripts/types/visualization.d.ts.map +1 -0
  207. package/scripts/types/visualization.js +4 -0
  208. package/scripts/types/visualization.js.map +1 -0
  209. package/scripts/types/world-bank.d.ts +85 -0
  210. package/scripts/types/world-bank.d.ts.map +1 -0
  211. package/scripts/types/world-bank.js +4 -0
  212. package/scripts/types/world-bank.js.map +1 -0
  213. package/scripts/utils/article-category.d.ts +18 -0
  214. package/scripts/utils/article-category.d.ts.map +1 -0
  215. package/scripts/utils/article-category.js +49 -0
  216. package/scripts/utils/article-category.js.map +1 -0
  217. package/scripts/utils/article-quality-scorer.d.ts +87 -0
  218. package/scripts/utils/article-quality-scorer.d.ts.map +1 -0
  219. package/scripts/utils/article-quality-scorer.js +1048 -0
  220. package/scripts/utils/article-quality-scorer.js.map +1 -0
  221. package/scripts/utils/content-metadata.d.ts +34 -0
  222. package/scripts/utils/content-metadata.d.ts.map +1 -0
  223. package/scripts/utils/content-metadata.js +249 -0
  224. package/scripts/utils/content-metadata.js.map +1 -0
  225. package/scripts/utils/content-validator.d.ts +94 -0
  226. package/scripts/utils/content-validator.d.ts.map +1 -0
  227. package/scripts/utils/content-validator.js +489 -0
  228. package/scripts/utils/content-validator.js.map +1 -0
  229. package/scripts/utils/copy-test-reports.d.ts +9 -0
  230. package/scripts/utils/copy-test-reports.d.ts.map +1 -0
  231. package/scripts/utils/copy-test-reports.js +508 -0
  232. package/scripts/utils/copy-test-reports.js.map +1 -0
  233. package/scripts/utils/file-utils.d.ts +144 -0
  234. package/scripts/utils/file-utils.d.ts.map +1 -0
  235. package/scripts/utils/file-utils.js +374 -0
  236. package/scripts/utils/file-utils.js.map +1 -0
  237. package/scripts/utils/fix-articles.d.ts +27 -0
  238. package/scripts/utils/fix-articles.d.ts.map +1 -0
  239. package/scripts/utils/fix-articles.js +510 -0
  240. package/scripts/utils/fix-articles.js.map +1 -0
  241. package/scripts/utils/generate-docs-index.d.ts +8 -0
  242. package/scripts/utils/generate-docs-index.d.ts.map +1 -0
  243. package/scripts/utils/generate-docs-index.js +275 -0
  244. package/scripts/utils/generate-docs-index.js.map +1 -0
  245. package/scripts/utils/html-sanitize.d.ts +18 -0
  246. package/scripts/utils/html-sanitize.d.ts.map +1 -0
  247. package/scripts/utils/html-sanitize.js +57 -0
  248. package/scripts/utils/html-sanitize.js.map +1 -0
  249. package/scripts/utils/intelligence-analysis.d.ts +173 -0
  250. package/scripts/utils/intelligence-analysis.d.ts.map +1 -0
  251. package/scripts/utils/intelligence-analysis.js +936 -0
  252. package/scripts/utils/intelligence-analysis.js.map +1 -0
  253. package/scripts/utils/intelligence-index.d.ts +126 -0
  254. package/scripts/utils/intelligence-index.d.ts.map +1 -0
  255. package/scripts/utils/intelligence-index.js +731 -0
  256. package/scripts/utils/intelligence-index.js.map +1 -0
  257. package/scripts/utils/metadata-utils.d.ts +14 -0
  258. package/scripts/utils/metadata-utils.d.ts.map +1 -0
  259. package/scripts/utils/metadata-utils.js +18 -0
  260. package/scripts/utils/metadata-utils.js.map +1 -0
  261. package/scripts/utils/news-metadata.d.ts +47 -0
  262. package/scripts/utils/news-metadata.d.ts.map +1 -0
  263. package/scripts/utils/news-metadata.js +259 -0
  264. package/scripts/utils/news-metadata.js.map +1 -0
  265. package/scripts/utils/validate-articles.d.ts +2 -0
  266. package/scripts/utils/validate-articles.d.ts.map +1 -0
  267. package/scripts/utils/validate-articles.js +284 -0
  268. package/scripts/utils/validate-articles.js.map +1 -0
  269. package/scripts/utils/validate-ep-api.d.ts +51 -0
  270. package/scripts/utils/validate-ep-api.d.ts.map +1 -0
  271. package/scripts/utils/validate-ep-api.js +160 -0
  272. package/scripts/utils/validate-ep-api.js.map +1 -0
  273. package/scripts/utils/world-bank-data.d.ts +84 -0
  274. package/scripts/utils/world-bank-data.d.ts.map +1 -0
  275. package/scripts/utils/world-bank-data.js +311 -0
  276. package/scripts/utils/world-bank-data.js.map +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-stage.d.ts","sourceRoot":"","sources":["../../../src/generators/pipeline/transform-stage.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAIH,0CAA0C;AAC1C,MAAM,WAAW,gBAAgB;IAC/B,6CAA6C;IAC7C,KAAK,EAAE,OAAO,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAqBD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,gBAAgB,CAkCrF;AAID;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASzD;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,111 @@
1
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Validate the first item of a content array is a non-null object with a
5
+ * `text` string field. Returns an error description or null when valid.
6
+ *
7
+ * @param item - First element of the content array
8
+ * @returns Error message or null
9
+ */
10
+ function validateFirstContentItem(item) {
11
+ if (item === null || item === undefined || typeof item !== 'object' || Array.isArray(item)) {
12
+ return "First content item is missing a 'text' string field";
13
+ }
14
+ const obj = item;
15
+ return typeof obj['text'] === 'string'
16
+ ? null
17
+ : "First content item is missing a 'text' string field";
18
+ }
19
+ // ─── MCP Response validation ──────────────────────────────────────────────────
20
+ /**
21
+ * Validate that an MCP tool response has the standard envelope shape:
22
+ * `{ content: [{ text: string }] }`.
23
+ *
24
+ * Does **not** throw — returns a {@link ValidationResult} so callers can
25
+ * choose their own degradation strategy.
26
+ *
27
+ * @param toolName - Tool name used in warning messages
28
+ * @param data - Raw response to validate
29
+ * @returns Validation result with any error descriptions
30
+ */
31
+ export function validateMCPResponse(toolName, data) {
32
+ const errors = [];
33
+ if (data === null || data === undefined) {
34
+ errors.push('Response is null or undefined');
35
+ console.warn(`⚠️ MCP validation failed for ${toolName}: response is null/undefined`);
36
+ return { valid: false, errors };
37
+ }
38
+ if (typeof data !== 'object' || Array.isArray(data)) {
39
+ errors.push(`Expected object, got ${Array.isArray(data) ? 'array' : typeof data}`);
40
+ console.warn(`⚠️ MCP validation failed for ${toolName}:`, errors.join(', '));
41
+ return { valid: false, errors };
42
+ }
43
+ const response = data;
44
+ if (!Array.isArray(response['content'])) {
45
+ errors.push("Missing or invalid 'content' array");
46
+ }
47
+ else {
48
+ const content = response['content'];
49
+ if (content.length === 0) {
50
+ errors.push('Empty content array');
51
+ }
52
+ else {
53
+ const itemError = validateFirstContentItem(content[0]);
54
+ if (itemError)
55
+ errors.push(itemError);
56
+ }
57
+ }
58
+ if (errors.length > 0) {
59
+ console.warn(`⚠️ MCP validation failed for ${toolName}:`, errors.join(', '));
60
+ }
61
+ return { valid: errors.length === 0, errors };
62
+ }
63
+ // ─── Data normalisation helpers ───────────────────────────────────────────────
64
+ /**
65
+ * Normalise a date string to YYYY-MM-DD ISO 8601 format.
66
+ * Returns the input unchanged when parsing fails.
67
+ *
68
+ * @param date - Raw date string
69
+ * @returns Normalised ISO 8601 date string
70
+ */
71
+ export function normalizeISO8601Date(date) {
72
+ if (!date)
73
+ return date;
74
+ try {
75
+ const parsed = new Date(date);
76
+ if (isNaN(parsed.getTime()))
77
+ return date;
78
+ return parsed.toISOString().split('T')[0] ?? date;
79
+ }
80
+ catch {
81
+ return date;
82
+ }
83
+ }
84
+ /**
85
+ * Sanitise a text string by collapsing internal whitespace and trimming edges.
86
+ *
87
+ * @param text - Raw text string
88
+ * @returns Sanitised text string
89
+ */
90
+ export function sanitizeText(text) {
91
+ return text.replace(/\s+/g, ' ').trim();
92
+ }
93
+ /**
94
+ * Validate that a country code matches the ISO 3166-1 alpha-2 pattern.
95
+ *
96
+ * @param code - Two-letter country code
97
+ * @returns `true` when the code matches `[A-Z]{2}`
98
+ */
99
+ export function isValidCountryCode(code) {
100
+ return /^[A-Z]{2}$/.test(code);
101
+ }
102
+ /**
103
+ * Validate that a language code matches the ISO 639-1 alpha-2 pattern.
104
+ *
105
+ * @param code - Two-letter language code
106
+ * @returns `true` when the code matches `[a-z]{2}`
107
+ */
108
+ export function isValidLanguageCode(code) {
109
+ return /^[a-z]{2}$/.test(code);
110
+ }
111
+ //# sourceMappingURL=transform-stage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform-stage.js","sourceRoot":"","sources":["../../../src/generators/pipeline/transform-stage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { PropositionsStrings } from '../types/index.js';
2
+ /** Structured pipeline data returned from MCP before language-specific rendering */
3
+ export interface PipelineData {
4
+ healthScore: number;
5
+ throughput: number;
6
+ procRowsHtml: string;
7
+ }
8
+ /**
9
+ * Build propositions article HTML content with localized strings.
10
+ *
11
+ * **Security contract**: `proposalsHtml`, `adoptedTextsHtml`, `procedureHtml`,
12
+ * and `pipelineData.procRowsHtml` MUST be pre-sanitized HTML — all external
13
+ * (MCP-sourced) values must have been passed through `escapeHTML()` before
14
+ * being interpolated into these strings. The fetch helpers
15
+ * (`fetchProposalsFromMCP`, `fetchPipelineFromMCP`,
16
+ * `fetchProcedureStatusFromMCP`) fulfil this contract; callers must do the
17
+ * same if they construct these arguments independently.
18
+ *
19
+ * @param proposalsHtml - Pre-sanitized HTML for legislative procedures list section
20
+ * @param adoptedTextsHtml - Pre-sanitized HTML for recently adopted texts section (may be empty)
21
+ * @param pipelineData - Structured pipeline data from MCP (null when unavailable);
22
+ * `pipelineData.procRowsHtml` must be pre-sanitized HTML
23
+ * @param procedureHtml - Pre-sanitized HTML for tracked procedure status section (may be empty)
24
+ * @param strings - Localized string set for the target language
25
+ * @param lang - Language code for editorial string headings (default: 'en')
26
+ * @returns Full article HTML content string
27
+ */
28
+ export declare function buildPropositionsContent(proposalsHtml: string, adoptedTextsHtml: string, pipelineData: PipelineData | null, procedureHtml: string, strings: PropositionsStrings, lang?: string): string;
29
+ //# sourceMappingURL=propositions-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propositions-content.d.ts","sourceRoot":"","sources":["../../src/generators/propositions-content.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,SAAO,GACV,MAAM,CA2DR"}
@@ -0,0 +1,90 @@
1
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * @module Generators/PropositionsContent
5
+ * @description Pure function for building propositions article HTML with
6
+ * localized strings and pre-sanitized MCP data.
7
+ */
8
+ import { escapeHTML } from '../utils/file-utils.js';
9
+ import { getLocalizedString, EDITORIAL_STRINGS } from '../constants/languages.js';
10
+ /**
11
+ * Build propositions article HTML content with localized strings.
12
+ *
13
+ * **Security contract**: `proposalsHtml`, `adoptedTextsHtml`, `procedureHtml`,
14
+ * and `pipelineData.procRowsHtml` MUST be pre-sanitized HTML — all external
15
+ * (MCP-sourced) values must have been passed through `escapeHTML()` before
16
+ * being interpolated into these strings. The fetch helpers
17
+ * (`fetchProposalsFromMCP`, `fetchPipelineFromMCP`,
18
+ * `fetchProcedureStatusFromMCP`) fulfil this contract; callers must do the
19
+ * same if they construct these arguments independently.
20
+ *
21
+ * @param proposalsHtml - Pre-sanitized HTML for legislative procedures list section
22
+ * @param adoptedTextsHtml - Pre-sanitized HTML for recently adopted texts section (may be empty)
23
+ * @param pipelineData - Structured pipeline data from MCP (null when unavailable);
24
+ * `pipelineData.procRowsHtml` must be pre-sanitized HTML
25
+ * @param procedureHtml - Pre-sanitized HTML for tracked procedure status section (may be empty)
26
+ * @param strings - Localized string set for the target language
27
+ * @param lang - Language code for editorial string headings (default: 'en')
28
+ * @returns Full article HTML content string
29
+ */
30
+ export function buildPropositionsContent(proposalsHtml, adoptedTextsHtml, pipelineData, procedureHtml, strings, lang = 'en') {
31
+ const editorial = getLocalizedString(EDITORIAL_STRINGS, lang);
32
+ const pipelineHtml = pipelineData
33
+ ? `
34
+ <div class="pipeline-metrics">
35
+ <div class="metric" aria-label="${escapeHTML(strings.pipelineHealthLabel)}">
36
+ <span class="metric-label">${escapeHTML(strings.pipelineHealthLabel)}</span>
37
+ <span class="metric-value">${escapeHTML(String(Math.round(pipelineData.healthScore * 100)))}%</span>
38
+ </div>
39
+ <div class="metric" aria-label="${escapeHTML(strings.throughputRateLabel)}">
40
+ <span class="metric-label">${escapeHTML(strings.throughputRateLabel)}</span>
41
+ <span class="metric-value">${escapeHTML(String(pipelineData.throughput))}</span>
42
+ </div>
43
+ </div>
44
+ ${pipelineData.procRowsHtml}`
45
+ : '';
46
+ const procedureSection = procedureHtml
47
+ ? `
48
+ <section class="procedure-status">
49
+ <h2>${escapeHTML(strings.procedureHeading)}</h2>
50
+ ${procedureHtml}
51
+ </section>`
52
+ : '';
53
+ const adoptedTextsSection = adoptedTextsHtml
54
+ ? `
55
+ <section class="adopted-texts-section">
56
+ <h2>${escapeHTML(strings.adoptedTextsHeading)}</h2>
57
+ ${adoptedTextsHtml}
58
+ </section>`
59
+ : '';
60
+ const proposalsSection = proposalsHtml
61
+ ? `
62
+ <section class="proposals-list">
63
+ <h2>${escapeHTML(strings.proposalsHeading)}</h2>
64
+ ${proposalsHtml}
65
+ </section>`
66
+ : '';
67
+ return `
68
+ <div class="article-content">
69
+ <section class="lede">
70
+ <p>${escapeHTML(strings.lede)}</p>
71
+ </section>
72
+ ${proposalsSection}
73
+ ${adoptedTextsSection}
74
+ <section class="pipeline-status">
75
+ <h2>${escapeHTML(strings.pipelineHeading)}</h2>
76
+ ${pipelineHtml}
77
+ </section>
78
+ ${procedureSection}
79
+ <section class="analysis">
80
+ <h2>${escapeHTML(strings.analysisHeading)}</h2>
81
+ <p>${escapeHTML(strings.analysis)}</p>
82
+ </section>
83
+ <section class="why-this-matters">
84
+ <h2>${escapeHTML(editorial.whyThisMatters)}</h2>
85
+ <p>${escapeHTML(strings.whyThisMatters)}</p>
86
+ </section>
87
+ </div>
88
+ `;
89
+ }
90
+ //# sourceMappingURL=propositions-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propositions-content.js","sourceRoot":"","sources":["../../src/generators/propositions-content.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,sCAAsC;AAEtC;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAUlF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,wBAAwB,CACtC,aAAqB,EACrB,gBAAwB,EACxB,YAAiC,EACjC,aAAqB,EACrB,OAA4B,EAC5B,IAAI,GAAG,IAAI;IAEX,MAAM,SAAS,GAAG,kBAAkB,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG,YAAY;QAC/B,CAAC,CAAC;;wCAEkC,UAAU,CAAC,OAAO,CAAC,mBAAmB,CAAC;qCAC1C,UAAU,CAAC,OAAO,CAAC,mBAAmB,CAAC;qCACvC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,GAAG,GAAG,CAAC,CAAC,CAAC;;wCAE3D,UAAU,CAAC,OAAO,CAAC,mBAAmB,CAAC;qCAC1C,UAAU,CAAC,OAAO,CAAC,mBAAmB,CAAC;qCACvC,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;;;MAG1E,YAAY,CAAC,YAAY,EAAE;QAC7B,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,gBAAgB,GAAG,aAAa;QACpC,CAAC,CAAC;;kBAEY,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC;cACxC,aAAa;qBACN;QACjB,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,mBAAmB,GAAG,gBAAgB;QAC1C,CAAC,CAAC;;kBAEY,UAAU,CAAC,OAAO,CAAC,mBAAmB,CAAC;cAC3C,gBAAgB;qBACT;QACjB,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,gBAAgB,GAAG,aAAa;QACpC,CAAC,CAAC;;kBAEY,UAAU,CAAC,OAAO,CAAC,gBAAgB,CAAC;cACxC,aAAa;qBACN;QACjB,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;;;iBAGQ,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;;YAE7B,gBAAgB;YAChB,mBAAmB;;kBAEb,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC;cACvC,YAAY;;YAEd,gBAAgB;;kBAEV,UAAU,CAAC,OAAO,CAAC,eAAe,CAAC;iBACpC,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC;;;kBAG3B,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC;iBACrC,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC;;;OAG5C,CAAC;AACR,CAAC"}
@@ -0,0 +1,45 @@
1
+ /** Pre-defined semantic color categories for Sankey nodes. */
2
+ export type SankeyNodeColor = 'cyan' | 'magenta' | 'yellow' | 'green' | 'purple' | 'orange' | 'blue' | 'red';
3
+ /** A node in the Sankey diagram. */
4
+ export interface SankeyNode {
5
+ /** Unique identifier (used in flows to reference source/target). */
6
+ readonly id: string;
7
+ /** Display label. */
8
+ readonly label: string;
9
+ /** Semantic color. */
10
+ readonly color: SankeyNodeColor;
11
+ }
12
+ /** A directed flow between two nodes. */
13
+ export interface SankeyFlow {
14
+ /** Source node id. */
15
+ readonly source: string;
16
+ /** Target node id. */
17
+ readonly target: string;
18
+ /** Flow magnitude (relative — values are scaled to fit the SVG height). */
19
+ readonly value: number;
20
+ /** Optional label shown on the flow path. */
21
+ readonly label?: string | undefined;
22
+ }
23
+ /** Full Sankey diagram configuration. */
24
+ export interface SankeyConfig {
25
+ /** Array of nodes (must have at least two: one source, one target). */
26
+ readonly nodes: readonly SankeyNode[];
27
+ /** Array of directed flows between nodes. */
28
+ readonly flows: readonly SankeyFlow[];
29
+ /** Optional narrative summary. */
30
+ readonly summary?: string | undefined;
31
+ }
32
+ /**
33
+ * Generate a Sankey flow chart section as an HTML string with inline SVG.
34
+ *
35
+ * Returns an empty string when `config` is null/undefined or has no flows,
36
+ * following the same convention as `buildSwotSection` and
37
+ * `buildDashboardSection`.
38
+ *
39
+ * @param config - Sankey data (nodes, flows, optional summary).
40
+ * @param lang - BCP 47 language code for the section heading.
41
+ * @param heading - Optional heading override.
42
+ * @returns HTML string for the sankey section, or empty string.
43
+ */
44
+ export declare function buildSankeySection(config: SankeyConfig | null | undefined, lang?: string, heading?: string): string;
45
+ //# sourceMappingURL=sankey-content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sankey-content.d.ts","sourceRoot":"","sources":["../../src/generators/sankey-content.ts"],"names":[],"mappings":"AAyBA,8DAA8D;AAC9D,MAAM,MAAM,eAAe,GACvB,MAAM,GACN,SAAS,GACT,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,KAAK,CAAC;AAEV,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;CACjC;AAED,yCAAyC;AACzC,MAAM,WAAW,UAAU;IACzB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,yCAAyC;AACzC,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAkOD;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EACvC,IAAI,GAAE,MAAa,EACnB,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CA4BR"}
@@ -0,0 +1,227 @@
1
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Generates a Sankey (flow) chart as inline SVG — no JavaScript or
5
+ * third-party libraries required.
6
+ *
7
+ * A Sankey diagram visualises quantities flowing from source nodes to target
8
+ * nodes. Node heights and flow-path widths are proportional to the values,
9
+ * making it easy to see dominant flows at a glance.
10
+ *
11
+ * Typical usage in articles:
12
+ * - Parliamentary flow: political group → document type → legislative outcome
13
+ * - Policy flow: policy domain → committee → outcome (adopted/rejected/pending)
14
+ * - Budget flow: programme area → committee → spending category
15
+ *
16
+ * @module generators/sankey-content
17
+ */
18
+ import { escapeHTML } from '../utils/file-utils.js';
19
+ // ---------------------------------------------------------------------------
20
+ // Color palette
21
+ // ---------------------------------------------------------------------------
22
+ const NODE_COLORS = {
23
+ cyan: { fill: '#e3f2fd', stroke: '#1565c0', text: '#1565c0' },
24
+ magenta: { fill: '#fce4ec', stroke: '#c62828', text: '#c62828' },
25
+ yellow: { fill: '#fff8e1', stroke: '#f57f17', text: '#f57f17' },
26
+ green: { fill: '#e8f5e9', stroke: '#2e7d32', text: '#2e7d32' },
27
+ purple: { fill: '#f3e5f5', stroke: '#7b1fa2', text: '#7b1fa2' },
28
+ orange: { fill: '#fff3e0', stroke: '#e65100', text: '#e65100' },
29
+ blue: { fill: '#e8eaf6', stroke: '#283593', text: '#283593' },
30
+ red: { fill: '#ffebee', stroke: '#b71c1c', text: '#b71c1c' },
31
+ };
32
+ // ---------------------------------------------------------------------------
33
+ // Section heading labels (14 languages)
34
+ // ---------------------------------------------------------------------------
35
+ const SANKEY_HEADINGS = {
36
+ en: 'Policy Flow',
37
+ sv: 'Politikflöde',
38
+ da: 'Politikflow',
39
+ no: 'Politikkflyt',
40
+ fi: 'Politiikkavirta',
41
+ de: 'Politikfluss',
42
+ fr: 'Flux législatif',
43
+ es: 'Flujo legislativo',
44
+ nl: 'Beleidsflow',
45
+ ar: 'تدفق السياسات',
46
+ he: 'זרימת מדיניות',
47
+ ja: '政策フロー',
48
+ ko: '정책 흐름',
49
+ zh: '政策流向图',
50
+ };
51
+ // ---------------------------------------------------------------------------
52
+ // SVG layout engine
53
+ // ---------------------------------------------------------------------------
54
+ const SVG_WIDTH = 600;
55
+ const NODE_WIDTH = 22;
56
+ const NODE_GAP = 14;
57
+ const COL_LEFT = 20;
58
+ const COL_RIGHT = SVG_WIDTH - NODE_WIDTH - 20;
59
+ /**
60
+ * Build a cubic bezier SVG path between two columns.
61
+ *
62
+ * @param x1 - Start x coordinate.
63
+ * @param y1 - Start y coordinate.
64
+ * @param x2 - End x coordinate.
65
+ * @param y2 - End y coordinate.
66
+ * @param h - Height of the flow path.
67
+ * @returns SVG path data string.
68
+ */
69
+ function buildBezierPath(x1, y1, x2, y2, h) {
70
+ const mx = (x1 + x2) / 2;
71
+ return [
72
+ `M${x1},${y1}`,
73
+ `C${mx},${y1} ${mx},${y2} ${x2},${y2}`,
74
+ `L${x2},${y2 + h}`,
75
+ `C${mx},${y2 + h} ${mx},${y1 + h} ${x1},${y1 + h}`,
76
+ 'Z',
77
+ ].join(' ');
78
+ }
79
+ /**
80
+ * Compute SVG element strings for the Sankey diagram.
81
+ *
82
+ * @param nodes - Array of Sankey nodes.
83
+ * @param flows - Array of directed flows between nodes.
84
+ * @param svgHeight - Height of the SVG canvas in pixels.
85
+ * @returns Array of SVG element strings.
86
+ */
87
+ function layoutSankey(nodes, flows, svgHeight) {
88
+ const sourceIds = new Set(flows.map((f) => f.source));
89
+ const targetIds = new Set(flows.map((f) => f.target));
90
+ const valuePer = {};
91
+ for (const f of flows) {
92
+ valuePer[f.source] = (valuePer[f.source] ?? 0) + f.value;
93
+ valuePer[f.target] = (valuePer[f.target] ?? 0) + f.value;
94
+ }
95
+ const totalValue = Object.values(valuePer).reduce((a, b) => a + b, 0) || 1;
96
+ const usableHeight = svgHeight - 40;
97
+ const scaleFactor = usableHeight / (totalValue / 2 + (nodes.length - 1) * NODE_GAP);
98
+ const leftNodes = nodes.filter((n) => sourceIds.has(n.id) || !targetIds.has(n.id));
99
+ const rightNodes = nodes.filter((n) => targetIds.has(n.id) && !sourceIds.has(n.id));
100
+ function placeNodes(nds) {
101
+ const result = [];
102
+ let yOffset = 20;
103
+ for (const n of nds) {
104
+ const total = valuePer[n.id] ?? 0;
105
+ const height = Math.max(18, Math.round(total * scaleFactor));
106
+ result.push({
107
+ id: n.id,
108
+ label: n.label,
109
+ color: n.color,
110
+ totalValue: total,
111
+ y: yOffset,
112
+ height,
113
+ srcOffset: 0,
114
+ tgtOffset: 0,
115
+ });
116
+ yOffset += height + NODE_GAP;
117
+ }
118
+ return result;
119
+ }
120
+ const leftLayout = placeNodes(leftNodes);
121
+ const rightLayout = placeNodes(rightNodes);
122
+ const allLayout = [...leftLayout, ...rightLayout];
123
+ const layoutMap = new Map(allLayout.map((n) => [n.id, n]));
124
+ const svgElements = [];
125
+ for (const ln of allLayout) {
126
+ const palette = NODE_COLORS[ln.color] ?? NODE_COLORS.cyan;
127
+ const isLeft = leftLayout.some((l) => l.id === ln.id);
128
+ const xPos = isLeft ? COL_LEFT : COL_RIGHT;
129
+ const labelX = isLeft ? xPos + NODE_WIDTH + 6 : xPos - 6;
130
+ const textAnchor = isLeft ? 'start' : 'end';
131
+ svgElements.push(`<rect x="${xPos}" y="${ln.y}" width="${NODE_WIDTH}" height="${ln.height}" fill="${palette.fill}" stroke="${palette.stroke}" stroke-width="2" rx="3"/>`, `<text x="${labelX}" y="${ln.y + ln.height / 2}" text-anchor="${textAnchor}" dominant-baseline="middle" font-size="11" fill="${palette.text}" font-family="sans-serif">${escapeHTML(ln.label)}</text>`);
132
+ }
133
+ for (const flow of flows) {
134
+ const srcNode = layoutMap.get(flow.source);
135
+ const tgtNode = layoutMap.get(flow.target);
136
+ if (!srcNode || !tgtNode)
137
+ continue;
138
+ const srcPalette = NODE_COLORS[srcNode.color] ?? NODE_COLORS.cyan;
139
+ const tgtVal = valuePer[tgtNode.id] ?? 1;
140
+ const scaledH = Math.max(4, Math.round(((flow.value / Math.max(tgtVal, valuePer[srcNode.id] ?? 1)) *
141
+ (srcNode.height + tgtNode.height)) /
142
+ 2));
143
+ const srcIsLeft = leftLayout.some((l) => l.id === srcNode.id);
144
+ const x1 = srcIsLeft ? COL_LEFT + NODE_WIDTH : COL_RIGHT;
145
+ const x2 = COL_RIGHT;
146
+ const y1 = srcNode.y + srcNode.srcOffset;
147
+ const y2 = tgtNode.y + tgtNode.tgtOffset;
148
+ srcNode.srcOffset += scaledH + 2;
149
+ tgtNode.tgtOffset += scaledH + 2;
150
+ const pathD = buildBezierPath(x1, y1, x2, y2, scaledH);
151
+ svgElements.push(`<path d="${pathD}" fill="${srcPalette.stroke}33" stroke="${srcPalette.stroke}" stroke-width="0.5" opacity="0.7"/>`);
152
+ if (flow.label) {
153
+ const midX = SVG_WIDTH / 2;
154
+ const midY = (y1 + y2) / 2 + scaledH / 2;
155
+ svgElements.push(`<text x="${midX}" y="${midY}" text-anchor="middle" dominant-baseline="middle" font-size="9" fill="#495057" font-family="sans-serif">${escapeHTML(flow.label)}</text>`);
156
+ }
157
+ }
158
+ return svgElements;
159
+ }
160
+ // ---------------------------------------------------------------------------
161
+ // Accessible table fallback
162
+ // ---------------------------------------------------------------------------
163
+ function renderFallbackTable(nodes, flows) {
164
+ const rows = flows
165
+ .map((f) => {
166
+ const srcNode = nodes.find((n) => n.id === f.source);
167
+ const tgtNode = nodes.find((n) => n.id === f.target);
168
+ return ` <tr>
169
+ <td>${escapeHTML(srcNode?.label ?? f.source)}</td>
170
+ <td>${escapeHTML(tgtNode?.label ?? f.target)}</td>
171
+ <td>${f.value}</td>
172
+ ${f.label ? `<td>${escapeHTML(f.label)}</td>` : '<td></td>'}
173
+ </tr>`;
174
+ })
175
+ .join('\n');
176
+ return `<noscript>
177
+ <table class="sankey-fallback-table" aria-label="Sankey data">
178
+ <caption>Flow data</caption>
179
+ <thead><tr><th>Source</th><th>Target</th><th>Value</th><th>Note</th></tr></thead>
180
+ <tbody>
181
+ ${rows}
182
+ </tbody>
183
+ </table>
184
+ </noscript>`;
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // Public API
188
+ // ---------------------------------------------------------------------------
189
+ /**
190
+ * Generate a Sankey flow chart section as an HTML string with inline SVG.
191
+ *
192
+ * Returns an empty string when `config` is null/undefined or has no flows,
193
+ * following the same convention as `buildSwotSection` and
194
+ * `buildDashboardSection`.
195
+ *
196
+ * @param config - Sankey data (nodes, flows, optional summary).
197
+ * @param lang - BCP 47 language code for the section heading.
198
+ * @param heading - Optional heading override.
199
+ * @returns HTML string for the sankey section, or empty string.
200
+ */
201
+ export function buildSankeySection(config, lang = 'en', heading) {
202
+ if (!config || !config.flows || config.flows.length === 0) {
203
+ return '';
204
+ }
205
+ const svgHeight = 340;
206
+ const titleText = heading?.trim() || SANKEY_HEADINGS[lang] || 'Policy Flow';
207
+ const summaryBlock = config.summary?.trim()
208
+ ? ` <p class="sankey-summary">${escapeHTML(config.summary.trim())}</p>\n`
209
+ : '';
210
+ const svgElements = layoutSankey(config.nodes, config.flows, svgHeight);
211
+ const svgContent = svgElements.join('\n ');
212
+ const fallbackTable = renderFallbackTable(config.nodes, config.flows);
213
+ return `<section class="sankey-section" role="region" aria-label="${escapeHTML(titleText)}">
214
+ <h2>${escapeHTML(titleText)}</h2>
215
+ ${summaryBlock} <div class="sankey-chart-wrapper">
216
+ <svg viewBox="0 0 ${SVG_WIDTH} ${svgHeight}" xmlns="http://www.w3.org/2000/svg"
217
+ role="img" aria-label="${escapeHTML(titleText)}"
218
+ style="width:100%;height:auto;max-width:${SVG_WIDTH}px;display:block;">
219
+ <title>${escapeHTML(titleText)}</title>
220
+ <rect width="${SVG_WIDTH}" height="${svgHeight}" fill="var(--surface, #f8f9fa)" rx="8"/>
221
+ ${svgContent}
222
+ </svg>
223
+ </div>
224
+ ${fallbackTable}
225
+ </section>`;
226
+ }
227
+ //# sourceMappingURL=sankey-content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sankey-content.js","sourceRoot":"","sources":["../../src/generators/sankey-content.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,sCAAsC;AAEtC;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAiDpD,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,WAAW,GAEb;IACF,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC7D,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAChE,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC/D,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC9D,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC/D,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC/D,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;IAC7D,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;CAC7D,CAAC;AAEF,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAE9E,MAAM,eAAe,GAAqC;IACxD,EAAE,EAAE,aAAa;IACjB,EAAE,EAAE,cAAc;IAClB,EAAE,EAAE,aAAa;IACjB,EAAE,EAAE,cAAc;IAClB,EAAE,EAAE,iBAAiB;IACrB,EAAE,EAAE,cAAc;IAClB,EAAE,EAAE,iBAAiB;IACrB,EAAE,EAAE,mBAAmB;IACvB,EAAE,EAAE,aAAa;IACjB,EAAE,EAAE,eAAe;IACnB,EAAE,EAAE,eAAe;IACnB,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;IACX,EAAE,EAAE,OAAO;CACZ,CAAC;AAEF,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,MAAM,UAAU,GAAG,EAAE,CAAC;AACtB,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,QAAQ,GAAG,EAAE,CAAC;AACpB,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,EAAE,CAAC;AAa9C;;;;;;;;;GASG;AACH,SAAS,eAAe,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,CAAS;IAChF,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IACzB,OAAO;QACL,IAAI,EAAE,IAAI,EAAE,EAAE;QACd,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACtC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE;QAClB,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE;QAClD,GAAG;KACJ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CACnB,KAA4B,EAC5B,KAA4B,EAC5B,SAAiB;IAEjB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtD,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QACzD,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAC3D,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAC3E,MAAM,YAAY,GAAG,SAAS,GAAG,EAAE,CAAC;IACpC,MAAM,WAAW,GAAG,YAAY,GAAG,CAAC,UAAU,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;IAEpF,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEpF,SAAS,UAAU,CAAC,GAA0B;QAC5C,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAClC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC,CAAC;YAC7D,MAAM,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,UAAU,EAAE,KAAK;gBACjB,CAAC,EAAE,OAAO;gBACV,MAAM;gBACN,SAAS,EAAE,CAAC;gBACZ,SAAS,EAAE,CAAC;aACb,CAAC,CAAC;YACH,OAAO,IAAI,MAAM,GAAG,QAAQ,CAAC;QAC/B,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,UAAU,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,SAAS,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAqB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,MAAM,WAAW,GAAa,EAAE,CAAC;IAEjC,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;QAC1D,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QACzD,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;QAC5C,WAAW,CAAC,IAAI,CACd,YAAY,IAAI,QAAQ,EAAE,CAAC,CAAC,YAAY,UAAU,aAAa,EAAE,CAAC,MAAM,WAAW,OAAO,CAAC,IAAI,aAAa,OAAO,CAAC,MAAM,6BAA6B,EACvJ,YAAY,MAAM,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,MAAM,GAAG,CAAC,kBAAkB,UAAU,qDAAqD,OAAO,CAAC,IAAI,8BAA8B,UAAU,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,CACvM,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;YAAE,SAAS;QAEnC,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC;QAClE,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CACtB,CAAC,EACD,IAAI,CAAC,KAAK,CACR,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACzD,CAAC,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAClC,CAAC,CACJ,CACF,CAAC;QAEF,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9D,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QACzD,MAAM,EAAE,GAAG,SAAS,CAAC;QACrB,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;QACzC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;QAEzC,OAAO,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC;QACjC,OAAO,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC,CAAC;QAEjC,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QACvD,WAAW,CAAC,IAAI,CACd,YAAY,KAAK,WAAW,UAAU,CAAC,MAAM,eAAe,UAAU,CAAC,MAAM,sCAAsC,CACpH,CAAC;QAEF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,SAAS,GAAG,CAAC,CAAC;YAC3B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC;YACzC,WAAW,CAAC,IAAI,CACd,YAAY,IAAI,QAAQ,IAAI,2GAA2G,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CACvK,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,8EAA8E;AAC9E,4BAA4B;AAC5B,8EAA8E;AAE9E,SAAS,mBAAmB,CAAC,KAA4B,EAAE,KAA4B;IACrF,MAAM,IAAI,GAAG,KAAK;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC;QACrD,OAAO;cACC,UAAU,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;cACtC,UAAU,CAAC,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC;cACtC,CAAC,CAAC,KAAK;UACX,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;YACvD,CAAC;IACT,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;;;;EAKP,IAAI;;;cAGQ,CAAC;AACf,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,kBAAkB,CAChC,MAAuC,EACvC,OAAe,IAAI,EACnB,OAAgB;IAEhB,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1D,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,SAAS,GAAG,GAAG,CAAC;IACtB,MAAM,SAAS,GAAW,OAAO,EAAE,IAAI,EAAE,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,aAAa,CAAC;IACpF,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE;QACzC,CAAC,CAAC,+BAA+B,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,QAAQ;QAC1E,CAAC,CAAC,EAAE,CAAC;IAEP,MAAM,WAAW,GAAG,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,mBAAmB,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAEtE,OAAO,6DAA6D,UAAU,CAAC,SAAS,CAAC;QACnF,UAAU,CAAC,SAAS,CAAC;EAC3B,YAAY;wBACU,SAAS,IAAI,SAAS;kCACZ,UAAU,CAAC,SAAS,CAAC;mDACJ,SAAS;eAC7C,UAAU,CAAC,SAAS,CAAC;qBACf,SAAS,aAAa,SAAS;MAC9C,UAAU;;;IAGZ,aAAa;WACN,CAAC;AACZ,CAAC"}
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Recursively collect all HTML files under a directory, returning paths
4
+ * relative to the project root.
5
+ *
6
+ * @param dir - Directory to scan
7
+ * @param rootDir - Project root for computing relative paths
8
+ * @returns Array of relative paths (e.g. "docs/api/index.html")
9
+ */
10
+ export declare function collectDocsHtmlFiles(dir: string, rootDir?: string): string[];
11
+ /**
12
+ * Generate sitemap XML including index pages, news articles, sitemap HTML pages,
13
+ * and documentation files from the docs/ folder.
14
+ *
15
+ * @param articles - List of article filenames
16
+ * @param docsFiles - Relative paths to docs HTML files (e.g. "docs/api/index.html")
17
+ * @returns Complete sitemap XML string
18
+ */
19
+ export declare function generateSitemap(articles: string[], docsFiles?: string[]): string;
20
+ /**
21
+ * Get the sitemap HTML filename for a given language code.
22
+ *
23
+ * @param lang - Language code
24
+ * @returns Filename string
25
+ */
26
+ export declare function getSitemapFilename(lang: string): string;
27
+ /**
28
+ * Article info extracted for sitemap HTML display
29
+ */
30
+ interface SitemapArticleInfo {
31
+ filename: string;
32
+ date: string;
33
+ title: string;
34
+ description: string;
35
+ }
36
+ /**
37
+ * Generate a sitemap HTML page for a specific language.
38
+ * Lists all articles for that language with titles and descriptions,
39
+ * plus a high-level documentation section.
40
+ *
41
+ * @param lang - Language code
42
+ * @param articleInfos - Article info (title/description) for this language
43
+ * @param hasDocsDir - Whether the docs directory exists
44
+ * @returns Complete HTML document string
45
+ */
46
+ export declare function generateSitemapHTML(lang: string, articleInfos: SitemapArticleInfo[], hasDocsDir?: boolean): string;
47
+ /**
48
+ * RSS feed item data.
49
+ */
50
+ interface RssItem {
51
+ title: string;
52
+ link: string;
53
+ description: string;
54
+ pubDate: string;
55
+ lang: string;
56
+ }
57
+ /**
58
+ * Generate RSS 2.0 XML feed with all news articles across all languages.
59
+ * Articles are sorted newest-first. Each item includes the article language.
60
+ *
61
+ * @param articleInfos - Article metadata sorted newest first
62
+ * @returns Complete RSS 2.0 XML string
63
+ */
64
+ export declare function generateRssFeed(articleInfos: RssItem[]): string;
65
+ export {};
66
+ //# sourceMappingURL=sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/generators/sitemap.ts"],"names":[],"mappings":";AAuCA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,MAAqB,GAAG,MAAM,EAAE,CAe1F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,MAAM,CA6EpF;AA+HD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AA6CD;;GAEG;AACH,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,kBAAkB,EAAE,EAClC,UAAU,GAAE,OAAe,GAC1B,MAAM,CAwJR;AAED;;GAEG;AACH,UAAU,OAAO;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAiBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,OAAO,EAAE,GAAG,MAAM,CA8B/D"}