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,508 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-FileCopyrightText: 2024-2026 Hack23 AB
3
+ // SPDX-License-Identifier: Apache-2.0
4
+ /**
5
+ * @module Utils/CopyTestReports
6
+ * @description Copies test reports and coverage data to the docs/ directory
7
+ * for inclusion in the documentation bundle. Generates comprehensive HTML
8
+ * index pages for test results with links to all available reports.
9
+ */
10
+ import { promises as fs } from 'fs';
11
+ import { join, resolve } from 'path';
12
+ import { pathToFileURL } from 'url';
13
+ import { PROJECT_ROOT } from '../constants/config.js';
14
+ const DOCS_DIR = join(PROJECT_ROOT, 'docs');
15
+ const BUILDS_DIR = join(PROJECT_ROOT, 'builds');
16
+ const TEST_RESULTS_DIRNAME = 'test-results';
17
+ const INDEX_FILENAME = 'index.html';
18
+ const ESLINT_REPORT_BASE = 'eslint-report';
19
+ const E2E_PREFIX = 'e2e-';
20
+ const PLAYWRIGHT_REPORT_DIRNAME = 'playwright-report';
21
+ /**
22
+ * Recursively copy directory
23
+ *
24
+ * @param src - Source directory
25
+ * @param dest - Destination directory
26
+ */
27
+ export async function copyDirectory(src, dest) {
28
+ try {
29
+ await fs.mkdir(dest, { recursive: true });
30
+ const entries = await fs.readdir(src, { withFileTypes: true });
31
+ for (const entry of entries) {
32
+ const srcPath = join(src, entry.name);
33
+ const destPath = join(dest, entry.name);
34
+ if (entry.isDirectory()) {
35
+ await copyDirectory(srcPath, destPath);
36
+ }
37
+ else {
38
+ await fs.copyFile(srcPath, destPath);
39
+ }
40
+ }
41
+ }
42
+ catch (error) {
43
+ const nodeError = error;
44
+ if (nodeError.code === 'ENOENT') {
45
+ console.warn(` ⚠️ Source directory not found (skipped): ${src}`);
46
+ }
47
+ else {
48
+ throw error;
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Copy a single file safely
54
+ *
55
+ * @param src - Source file path
56
+ * @param dest - Destination file path
57
+ * @returns Whether the copy succeeded
58
+ */
59
+ async function copyFileSafe(src, dest) {
60
+ try {
61
+ await fs.copyFile(src, dest);
62
+ return true;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ /**
69
+ * Check if a file or directory exists
70
+ *
71
+ * @param path - Path to check
72
+ * @returns Whether the path exists
73
+ */
74
+ async function pathExists(path) {
75
+ try {
76
+ await fs.access(path);
77
+ return true;
78
+ }
79
+ catch {
80
+ return false;
81
+ }
82
+ }
83
+ /** Report file names within test-results directory */
84
+ const REPORT_FILES = {
85
+ vitestHtml: join('html', INDEX_FILENAME),
86
+ vitestJson: 'results.json',
87
+ vitestJunit: 'junit.xml',
88
+ e2eJson: `${E2E_PREFIX}results.json`,
89
+ e2eJunit: `${E2E_PREFIX}junit.xml`,
90
+ eslintHtml: `${ESLINT_REPORT_BASE}.html`,
91
+ eslintJson: `${ESLINT_REPORT_BASE}.json`,
92
+ };
93
+ /**
94
+ * Check which report files exist in the test-results directory
95
+ *
96
+ * @param testResultsDir - Path to test-results directory
97
+ * @returns Map of report key to existence boolean
98
+ */
99
+ async function checkReportFiles(testResultsDir) {
100
+ const results = {};
101
+ for (const [key, relativePath] of Object.entries(REPORT_FILES)) {
102
+ results[key] = await pathExists(join(testResultsDir, relativePath));
103
+ }
104
+ return results;
105
+ }
106
+ /**
107
+ * Parse vitest JSON results file for summary data
108
+ *
109
+ * @param filePath - Path to vitest results.json
110
+ * @returns Summary or null if unavailable
111
+ */
112
+ async function parseVitestSummary(filePath) {
113
+ try {
114
+ const raw = await fs.readFile(filePath, 'utf8');
115
+ const data = JSON.parse(raw);
116
+ const total = data.numTotalTests ?? 0;
117
+ const passed = data.numPassedTests ?? 0;
118
+ const failed = data.numFailedTests ?? 0;
119
+ let duration = 0;
120
+ if (Array.isArray(data.testResults)) {
121
+ for (const r of data.testResults) {
122
+ if (r.perfStats?.end && r.perfStats?.start) {
123
+ duration += r.perfStats.end - r.perfStats.start;
124
+ }
125
+ }
126
+ }
127
+ return { tests: total, passed, failed, duration: Math.round(duration) };
128
+ }
129
+ catch {
130
+ return null;
131
+ }
132
+ }
133
+ /**
134
+ * Parse Playwright JSON results file for summary data
135
+ *
136
+ * @param filePath - Path to e2e-results.json
137
+ * @returns Summary or null if unavailable
138
+ */
139
+ async function parseE2eSummary(filePath) {
140
+ try {
141
+ const raw = await fs.readFile(filePath, 'utf8');
142
+ const data = JSON.parse(raw);
143
+ if (data.stats) {
144
+ const passed = data.stats.expected ?? 0;
145
+ const failed = data.stats.unexpected ?? 0;
146
+ const flaky = data.stats.flaky ?? 0;
147
+ return { tests: passed + failed + flaky, passed, failed };
148
+ }
149
+ return null;
150
+ }
151
+ catch {
152
+ return null;
153
+ }
154
+ }
155
+ /**
156
+ * Gather report availability info for index generation
157
+ *
158
+ * @returns Object describing which reports are available
159
+ */
160
+ async function gatherReportInfo() {
161
+ const testResultsDir = join(DOCS_DIR, TEST_RESULTS_DIRNAME);
162
+ const fileStatus = await checkReportFiles(testResultsDir);
163
+ const info = {
164
+ hasVitestHtml: fileStatus['vitestHtml'] ?? false,
165
+ hasVitestJson: fileStatus['vitestJson'] ?? false,
166
+ hasVitestJunit: fileStatus['vitestJunit'] ?? false,
167
+ hasE2eJson: fileStatus['e2eJson'] ?? false,
168
+ hasE2eJunit: fileStatus['e2eJunit'] ?? false,
169
+ hasEslintHtml: fileStatus['eslintHtml'] ?? false,
170
+ hasEslintJson: fileStatus['eslintJson'] ?? false,
171
+ hasCoverage: await pathExists(join(DOCS_DIR, 'coverage', INDEX_FILENAME)),
172
+ hasPlaywright: await pathExists(join(DOCS_DIR, PLAYWRIGHT_REPORT_DIRNAME, INDEX_FILENAME)),
173
+ vitestSummary: null,
174
+ e2eSummary: null,
175
+ };
176
+ if (info.hasVitestJson) {
177
+ info.vitestSummary = await parseVitestSummary(join(testResultsDir, REPORT_FILES.vitestJson));
178
+ }
179
+ if (info.hasE2eJson) {
180
+ info.e2eSummary = await parseE2eSummary(join(testResultsDir, REPORT_FILES.e2eJson));
181
+ }
182
+ return info;
183
+ }
184
+ /**
185
+ * Build stat-card HTML for a test summary
186
+ *
187
+ * @param summary - Test summary data
188
+ * @param isE2e - Whether this is an E2E summary
189
+ * @returns HTML string for stat cards
190
+ */
191
+ function buildStatCards(summary, isE2e) {
192
+ const failedClass = summary.failed > 0 ? 'failed' : 'passed';
193
+ const durationCard = summary.duration !== undefined
194
+ ? `<div class="stat-card">
195
+ <div class="stat-number">${(summary.duration / 1000).toFixed(1)}s</div>
196
+ <div class="stat-label">Duration</div>
197
+ </div>`
198
+ : '';
199
+ const totalLabel = isE2e ? 'Total E2E' : 'Total Tests';
200
+ return `<div class="stat-card passed">
201
+ <div class="stat-number">${summary.passed}</div>
202
+ <div class="stat-label">Passed</div>
203
+ </div>
204
+ <div class="stat-card ${failedClass}">
205
+ <div class="stat-number">${summary.failed}</div>
206
+ <div class="stat-label">Failed</div>
207
+ </div>
208
+ <div class="stat-card">
209
+ <div class="stat-number">${summary.tests}</div>
210
+ <div class="stat-label">${totalLabel}</div>
211
+ </div>${durationCard}`;
212
+ }
213
+ /**
214
+ * Create a comprehensive HTML index for test results
215
+ *
216
+ * @param info - Report availability information
217
+ * @returns HTML content
218
+ */
219
+ function createTestResultsIndex(info) {
220
+ const currentDate = new Date().toISOString().split('T')[0] ?? '';
221
+ const vitestStats = info.vitestSummary ? buildStatCards(info.vitestSummary, false) : '';
222
+ const e2eStats = info.e2eSummary ? buildStatCards(info.e2eSummary, true) : '';
223
+ return `<!DOCTYPE html>
224
+ <html lang="en">
225
+ <head>
226
+ <meta charset="UTF-8">
227
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
228
+ <meta name="description" content="EU Parliament Monitor - Comprehensive Test Results and Quality Reports">
229
+ <title>Test Results - EU Parliament Monitor</title>
230
+ <style>
231
+ * { margin: 0; padding: 0; box-sizing: border-box; }
232
+ body {
233
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
234
+ line-height: 1.6;
235
+ color: #333;
236
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
237
+ min-height: 100vh;
238
+ padding: 2rem;
239
+ }
240
+ .container {
241
+ max-width: 1200px;
242
+ margin: 0 auto;
243
+ background: white;
244
+ border-radius: 12px;
245
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
246
+ overflow: hidden;
247
+ }
248
+ header {
249
+ background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
250
+ color: white;
251
+ padding: 2.5rem 2rem;
252
+ text-align: center;
253
+ }
254
+ h1 { font-size: 2.2rem; margin-bottom: 0.5rem; font-weight: 700; }
255
+ .subtitle { font-size: 1.1rem; opacity: 0.9; }
256
+ .last-updated { font-size: 0.85rem; opacity: 0.7; margin-top: 0.75rem; }
257
+ main { padding: 2rem; }
258
+ h2 { color: #1e3c72; font-size: 1.5rem; margin: 2rem 0 1rem; border-bottom: 2px solid #e9ecef; padding-bottom: 0.5rem; }
259
+ .stats-grid {
260
+ display: flex;
261
+ gap: 1rem;
262
+ flex-wrap: wrap;
263
+ margin-bottom: 1.5rem;
264
+ }
265
+ .stat-card {
266
+ background: #f8f9fa;
267
+ border: 2px solid #e9ecef;
268
+ border-radius: 8px;
269
+ padding: 1rem 1.5rem;
270
+ text-align: center;
271
+ min-width: 100px;
272
+ flex: 1;
273
+ }
274
+ .stat-card.passed { border-color: #28a745; background: #d4edda; }
275
+ .stat-card.failed { border-color: #dc3545; background: #f8d7da; }
276
+ .stat-number { font-size: 1.8rem; font-weight: 700; color: #1e3c72; }
277
+ .stat-label { font-size: 0.85rem; color: #666; text-transform: uppercase; letter-spacing: 0.5px; }
278
+ .reports-grid {
279
+ display: grid;
280
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
281
+ gap: 1rem;
282
+ margin: 1rem 0;
283
+ }
284
+ .report-card {
285
+ background: #f8f9fa;
286
+ border: 2px solid #e9ecef;
287
+ border-radius: 8px;
288
+ padding: 1.25rem;
289
+ transition: all 0.3s ease;
290
+ text-decoration: none;
291
+ color: inherit;
292
+ display: block;
293
+ }
294
+ .report-card:hover {
295
+ transform: translateY(-3px);
296
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
297
+ border-color: #667eea;
298
+ }
299
+ .report-card.unavailable {
300
+ opacity: 0.5;
301
+ pointer-events: none;
302
+ }
303
+ .report-card h3 { color: #1e3c72; font-size: 1.1rem; margin-bottom: 0.25rem; }
304
+ .report-card .icon { font-size: 1.5rem; margin-bottom: 0.25rem; }
305
+ .report-card p { color: #666; font-size: 0.85rem; line-height: 1.4; }
306
+ .badge {
307
+ display: inline-block;
308
+ padding: 0.15rem 0.5rem;
309
+ border-radius: 10px;
310
+ font-size: 0.7rem;
311
+ font-weight: 600;
312
+ margin-top: 0.5rem;
313
+ }
314
+ .badge-html { background: #667eea; color: white; }
315
+ .badge-json { background: #28a745; color: white; }
316
+ .badge-xml { background: #fd7e14; color: white; }
317
+ .badge-vitest { background: #fcc72b; color: #333; }
318
+ .badge-playwright { background: #2ead33; color: white; }
319
+ .badge-eslint { background: #4b32c3; color: white; }
320
+ footer {
321
+ background: #f8f9fa;
322
+ padding: 1.5rem 2rem;
323
+ text-align: center;
324
+ color: #666;
325
+ border-top: 1px solid #e9ecef;
326
+ }
327
+ footer a { color: #667eea; text-decoration: none; }
328
+ footer a:hover { text-decoration: underline; }
329
+ @media (max-width: 768px) {
330
+ body { padding: 1rem; }
331
+ h1 { font-size: 1.8rem; }
332
+ .reports-grid { grid-template-columns: 1fr; }
333
+ .stats-grid { flex-direction: column; }
334
+ }
335
+ </style>
336
+ </head>
337
+ <body>
338
+ <div class="container">
339
+ <header>
340
+ <h1>📊 Test Results &amp; Quality Reports</h1>
341
+ <div class="subtitle">EU Parliament Monitor - Comprehensive Test Dashboard</div>
342
+ <div class="last-updated">Generated: ${currentDate}</div>
343
+ </header>
344
+
345
+ <main>
346
+ ${vitestStats ? `<h2>🧪 Unit &amp; Integration Tests (Vitest)</h2><div class="stats-grid">${vitestStats}</div>` : ''}
347
+
348
+ ${e2eStats ? `<h2>🎭 End-to-End Tests (Playwright)</h2><div class="stats-grid">${e2eStats}</div>` : ''}
349
+
350
+ <h2>📋 Interactive Reports</h2>
351
+ <div class="reports-grid">
352
+ <a href="html/index.html" class="report-card${info.hasVitestHtml ? '' : ' unavailable'}">
353
+ <div class="icon">🧪</div>
354
+ <h3>Vitest HTML Report</h3>
355
+ <p>Interactive test explorer with detailed results for all unit and integration tests.</p>
356
+ <span class="badge badge-vitest">Vitest</span>
357
+ <span class="badge badge-html">HTML</span>
358
+ </a>
359
+
360
+ <a href="../coverage/index.html" class="report-card${info.hasCoverage ? '' : ' unavailable'}">
361
+ <div class="icon">📊</div>
362
+ <h3>Code Coverage Report</h3>
363
+ <p>Line, branch, function, and statement coverage with per-file drill-down.</p>
364
+ <span class="badge badge-vitest">Vitest V8</span>
365
+ <span class="badge badge-html">HTML</span>
366
+ </a>
367
+
368
+ <a href="../playwright-report/index.html" class="report-card${info.hasPlaywright ? '' : ' unavailable'}">
369
+ <div class="icon">🎭</div>
370
+ <h3>Playwright E2E Report</h3>
371
+ <p>End-to-end test results with screenshots, traces, and accessibility checks.</p>
372
+ <span class="badge badge-playwright">Playwright</span>
373
+ <span class="badge badge-html">HTML</span>
374
+ </a>
375
+
376
+ <a href="eslint-report.html" class="report-card${info.hasEslintHtml ? '' : ' unavailable'}">
377
+ <div class="icon">🔍</div>
378
+ <h3>ESLint Report</h3>
379
+ <p>Static analysis results showing code quality issues, warnings, and style compliance.</p>
380
+ <span class="badge badge-eslint">ESLint</span>
381
+ <span class="badge badge-html">HTML</span>
382
+ </a>
383
+ </div>
384
+
385
+ <h2>📁 Machine-Readable Reports</h2>
386
+ <div class="reports-grid">
387
+ <a href="results.json" class="report-card${info.hasVitestJson ? '' : ' unavailable'}">
388
+ <div class="icon">📄</div>
389
+ <h3>Vitest Results (JSON)</h3>
390
+ <p>Machine-readable unit test results in JSON format for CI/CD integration.</p>
391
+ <span class="badge badge-vitest">Vitest</span>
392
+ <span class="badge badge-json">JSON</span>
393
+ </a>
394
+
395
+ <a href="junit.xml" class="report-card${info.hasVitestJunit ? '' : ' unavailable'}">
396
+ <div class="icon">📄</div>
397
+ <h3>Vitest Results (JUnit XML)</h3>
398
+ <p>JUnit XML format for CI dashboard integration and test trend analysis.</p>
399
+ <span class="badge badge-vitest">Vitest</span>
400
+ <span class="badge badge-xml">XML</span>
401
+ </a>
402
+
403
+ <a href="e2e-results.json" class="report-card${info.hasE2eJson ? '' : ' unavailable'}">
404
+ <div class="icon">📄</div>
405
+ <h3>E2E Results (JSON)</h3>
406
+ <p>Playwright end-to-end test results in JSON format with detailed timing data.</p>
407
+ <span class="badge badge-playwright">Playwright</span>
408
+ <span class="badge badge-json">JSON</span>
409
+ </a>
410
+
411
+ <a href="e2e-junit.xml" class="report-card${info.hasE2eJunit ? '' : ' unavailable'}">
412
+ <div class="icon">📄</div>
413
+ <h3>E2E Results (JUnit XML)</h3>
414
+ <p>E2E test results in JUnit XML format for cross-platform CI integration.</p>
415
+ <span class="badge badge-playwright">Playwright</span>
416
+ <span class="badge badge-xml">XML</span>
417
+ </a>
418
+
419
+ <a href="eslint-report.json" class="report-card${info.hasEslintJson ? '' : ' unavailable'}">
420
+ <div class="icon">📄</div>
421
+ <h3>ESLint Report (JSON)</h3>
422
+ <p>Detailed linting results in JSON format for automated quality gates.</p>
423
+ <span class="badge badge-eslint">ESLint</span>
424
+ <span class="badge badge-json">JSON</span>
425
+ </a>
426
+ </div>
427
+ </main>
428
+
429
+ <footer>
430
+ <p><a href="../index.html">← Back to Documentation Index</a></p>
431
+ <p style="margin-top: 0.5rem;">
432
+ <strong>EU Parliament Monitor</strong> -
433
+ European Parliament Intelligence Platform
434
+ </p>
435
+ </footer>
436
+ </div>
437
+ </body>
438
+ </html>`;
439
+ }
440
+ /**
441
+ * Main execution function
442
+ */
443
+ async function main() {
444
+ console.log('📋 Copying test reports to documentation directory...');
445
+ try {
446
+ await fs.mkdir(DOCS_DIR, { recursive: true });
447
+ // 1. Copy coverage report (from vitest)
448
+ const coverageSrc = join(BUILDS_DIR, 'coverage');
449
+ const coverageDest = join(DOCS_DIR, 'coverage');
450
+ console.log(' 📊 Copying coverage report...');
451
+ await copyDirectory(coverageSrc, coverageDest);
452
+ console.log(' ✅ Coverage report copied');
453
+ // 2. Copy API documentation (from typedoc)
454
+ const apiSrc = join(BUILDS_DIR, 'api');
455
+ const apiDest = join(DOCS_DIR, 'api');
456
+ console.log(' 📖 Copying API docs...');
457
+ await copyDirectory(apiSrc, apiDest);
458
+ console.log(' ✅ API docs copied');
459
+ // 3. Copy Playwright E2E report
460
+ const playwrightSrc = join(BUILDS_DIR, PLAYWRIGHT_REPORT_DIRNAME);
461
+ const playwrightDest = join(DOCS_DIR, PLAYWRIGHT_REPORT_DIRNAME);
462
+ console.log(' 🎭 Copying Playwright report...');
463
+ await copyDirectory(playwrightSrc, playwrightDest);
464
+ console.log(' ✅ Playwright report copied');
465
+ // 4. Copy test results directory (vitest HTML, JSON, JUnit, ESLint reports)
466
+ const buildTestResultsDir = join(BUILDS_DIR, TEST_RESULTS_DIRNAME);
467
+ const docsTestResultsDir = join(DOCS_DIR, TEST_RESULTS_DIRNAME);
468
+ await fs.mkdir(docsTestResultsDir, { recursive: true });
469
+ // 4a. Copy vitest HTML test report
470
+ console.log(' 🧪 Copying Vitest HTML report...');
471
+ await copyDirectory(join(buildTestResultsDir, 'html'), join(docsTestResultsDir, 'html'));
472
+ console.log(' ✅ Vitest HTML report copied');
473
+ // 4b-4g. Copy individual report files
474
+ const reportCopyTasks = [
475
+ { file: REPORT_FILES.vitestJson, label: 'Vitest JSON results', icon: '📄' },
476
+ { file: REPORT_FILES.vitestJunit, label: 'Vitest JUnit XML results', icon: '📄' },
477
+ { file: REPORT_FILES.e2eJson, label: 'E2E JSON results', icon: '📄' },
478
+ { file: REPORT_FILES.e2eJunit, label: 'E2E JUnit XML results', icon: '📄' },
479
+ { file: REPORT_FILES.eslintHtml, label: 'ESLint HTML report', icon: '🔍' },
480
+ { file: REPORT_FILES.eslintJson, label: 'ESLint JSON report', icon: '🔍' },
481
+ ];
482
+ for (const task of reportCopyTasks) {
483
+ console.log(` ${task.icon} Copying ${task.label}...`);
484
+ if (await copyFileSafe(join(buildTestResultsDir, task.file), join(docsTestResultsDir, task.file))) {
485
+ console.log(` ✅ ${task.label} copied`);
486
+ }
487
+ else {
488
+ console.warn(` ⚠️ ${task.label} not found (skipped)`);
489
+ }
490
+ }
491
+ // 5. Gather report info and generate comprehensive index
492
+ console.log(' 📊 Generating test results index...');
493
+ const reportInfo = await gatherReportInfo();
494
+ await fs.writeFile(join(docsTestResultsDir, INDEX_FILENAME), createTestResultsIndex(reportInfo), 'utf8');
495
+ console.log(' ✅ Test results index generated');
496
+ console.log('✅ All test reports copied successfully');
497
+ }
498
+ catch (error) {
499
+ const message = error instanceof Error ? error.message : String(error);
500
+ console.error('❌ Error copying test reports:', message);
501
+ process.exit(1);
502
+ }
503
+ }
504
+ // Only run main when executed directly (not when imported)
505
+ if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
506
+ main();
507
+ }
508
+ //# sourceMappingURL=copy-test-reports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy-test-reports.js","sourceRoot":"","sources":["../../src/utils/copy-test-reports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,144 @@
1
+ import type { ParsedArticle } from '../types/index.js';
2
+ /**
3
+ * Get all news article HTML files from the news directory
4
+ *
5
+ * @param newsDir - News directory path (defaults to NEWS_DIR)
6
+ * @returns List of article filenames
7
+ */
8
+ export declare function getNewsArticles(newsDir?: string): string[];
9
+ /**
10
+ * Parse article filename to extract metadata
11
+ *
12
+ * @param filename - Article filename (e.g., "2025-01-15-week-ahead-en.html")
13
+ * @returns Parsed metadata or null if filename doesn't match pattern
14
+ */
15
+ export declare function parseArticleFilename(filename: string): ParsedArticle | null;
16
+ /**
17
+ * Group articles by language code
18
+ *
19
+ * @param articles - List of article filenames
20
+ * @param languages - Supported language codes
21
+ * @returns Articles grouped by language, sorted newest first
22
+ */
23
+ export declare function groupArticlesByLanguage(articles: string[], languages: readonly string[]): Record<string, ParsedArticle[]>;
24
+ /**
25
+ * Format slug for display (hyphen-separated to Title Case)
26
+ *
27
+ * @param slug - Hyphen-separated slug string
28
+ * @returns Formatted title string
29
+ */
30
+ export declare function formatSlug(slug: string): string;
31
+ /**
32
+ * Get file modification time as YYYY-MM-DD string
33
+ *
34
+ * @param filepath - Path to file
35
+ * @returns Last modified date in YYYY-MM-DD format
36
+ */
37
+ export declare function getModifiedDate(filepath: string): string;
38
+ /**
39
+ * Format date for article slug
40
+ *
41
+ * @param date - Date to format (defaults to now)
42
+ * @returns Formatted date string (YYYY-MM-DD)
43
+ */
44
+ export declare function formatDateForSlug(date?: Date): string;
45
+ /**
46
+ * Calculate read time estimate from content
47
+ *
48
+ * @param content - Article content text
49
+ * @param wordsPerMinute - Reading speed (default 250)
50
+ * @returns Estimated read time in minutes
51
+ */
52
+ export declare function calculateReadTime(content: string, wordsPerMinute?: number): number;
53
+ /**
54
+ * Ensure a directory exists, creating it recursively if needed
55
+ *
56
+ * @param dirPath - Directory path to ensure
57
+ */
58
+ export declare function ensureDirectoryExists(dirPath: string): void;
59
+ /**
60
+ * Write content to a file with UTF-8 encoding
61
+ *
62
+ * @param filepath - Output file path
63
+ * @param content - File content
64
+ */
65
+ export declare function writeFileContent(filepath: string, content: string): void;
66
+ /**
67
+ * Write content to a file atomically.
68
+ *
69
+ * Writes to a uniquely-named temporary file in the same directory first, then
70
+ * renames it to the final path. The temp filename includes the PID and a random
71
+ * UUID so that concurrent callers targeting the same destination never collide
72
+ * on the intermediate file. If the rename fails the temp file is cleaned up in
73
+ * a `finally` block. On platforms where `renameSync` does not overwrite an
74
+ * existing destination (e.g. Windows), the error is caught and the target is
75
+ * removed before retrying the rename.
76
+ *
77
+ * @param filepath - Final output file path
78
+ * @param content - File content to write
79
+ */
80
+ export declare function atomicWrite(filepath: string, content: string): void;
81
+ /**
82
+ * Check whether a news article file already exists on disk.
83
+ *
84
+ * This is used by generation pipelines to skip work when a prior workflow run
85
+ * (or the same run) has already produced the article, avoiding unnecessary
86
+ * regeneration and potential merge conflicts.
87
+ *
88
+ * @param slug - Article slug including date prefix (e.g. `"2025-01-15-week-ahead"`)
89
+ * @param lang - Language code (e.g. `"en"`)
90
+ * @param newsDir - Absolute path to the news output directory (defaults to NEWS_DIR)
91
+ * @returns `true` when the article file exists
92
+ */
93
+ export declare function checkArticleExists(slug: string, lang: string, newsDir?: string): boolean;
94
+ /**
95
+ * Extract title and description from a generated article HTML file.
96
+ * Reads the predictable template structure produced by article-template.ts.
97
+ * Falls back to empty strings when the file cannot be read.
98
+ * HTML entities from the template are decoded to produce plain text.
99
+ *
100
+ * NOTE: The meta description regex relies on the template's use of escapeHTML(),
101
+ * which converts `"` to `&quot;`. Because descriptions are always stored with
102
+ * double-quote delimiters and inner quotes are HTML-encoded, the `[^"]+` pattern
103
+ * safely captures the full value. If the template ever changes its quoting
104
+ * convention this regex must be updated accordingly.
105
+ *
106
+ * @param filepath - Path to the article HTML file
107
+ * @returns Object with title (from first h1) and description (from meta description)
108
+ */
109
+ export declare function extractArticleMeta(filepath: string): {
110
+ title: string;
111
+ description: string;
112
+ };
113
+ /**
114
+ * Escape special HTML characters to prevent XSS
115
+ *
116
+ * @param str - Raw string to escape
117
+ * @returns HTML-safe string
118
+ */
119
+ export declare function escapeHTML(str: string): string;
120
+ /**
121
+ * Validate that a URL uses a safe scheme (http or https)
122
+ *
123
+ * @param url - URL string to validate
124
+ * @returns true if URL has a safe scheme
125
+ */
126
+ export declare function isSafeURL(url: string): boolean;
127
+ /** Result of article HTML validation */
128
+ export interface ArticleValidationResult {
129
+ /** Whether the article passes all structural checks */
130
+ valid: boolean;
131
+ /** List of missing elements */
132
+ errors: readonly string[];
133
+ }
134
+ /**
135
+ * Validate that generated article HTML includes all required structural elements.
136
+ *
137
+ * This is the primary validation gate — articles must be generated correctly
138
+ * by the template. The fix-articles script is only a fallback for legacy articles.
139
+ *
140
+ * @param html - Complete HTML string of the article
141
+ * @returns Validation result with errors list (empty if valid)
142
+ */
143
+ export declare function validateArticleHTML(html: string): ArticleValidationResult;
144
+ //# sourceMappingURL=file-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-utils.d.ts","sourceRoot":"","sources":["../../src/utils/file-utils.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAErE;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,MAAiB,GAAG,MAAM,EAAE,CAQpE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAkB3E;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,EAClB,SAAS,EAAE,SAAS,MAAM,EAAE,GAC3B,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,CAoBjC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIxD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAGjE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,GAAE,MAAY,GAAG,MAAM,CAGvF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI3D;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIxE;AAqED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAoBnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAiB,GACzB,OAAO,CAGT;AAuBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAmB3F;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO9C;AAED,wCAAwC;AACxC,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,KAAK,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAczE"}