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.
- package/LICENSE +201 -0
- package/README.md +1005 -0
- package/SECURITY.md +151 -0
- package/package.json +131 -0
- package/scripts/constants/committee-indicator-map.d.ts +199 -0
- package/scripts/constants/committee-indicator-map.d.ts.map +1 -0
- package/scripts/constants/committee-indicator-map.js +1224 -0
- package/scripts/constants/committee-indicator-map.js.map +1 -0
- package/scripts/constants/config.d.ts +38 -0
- package/scripts/constants/config.d.ts.map +1 -0
- package/scripts/constants/config.js +66 -0
- package/scripts/constants/config.js.map +1 -0
- package/scripts/constants/language-articles.d.ts +84 -0
- package/scripts/constants/language-articles.d.ts.map +1 -0
- package/scripts/constants/language-articles.js +6771 -0
- package/scripts/constants/language-articles.js.map +1 -0
- package/scripts/constants/language-core.d.ts +38 -0
- package/scripts/constants/language-core.d.ts.map +1 -0
- package/scripts/constants/language-core.js +90 -0
- package/scripts/constants/language-core.js.map +1 -0
- package/scripts/constants/language-ui.d.ts +82 -0
- package/scripts/constants/language-ui.d.ts.map +1 -0
- package/scripts/constants/language-ui.js +889 -0
- package/scripts/constants/language-ui.js.map +1 -0
- package/scripts/constants/languages.d.ts +14 -0
- package/scripts/constants/languages.d.ts.map +1 -0
- package/scripts/constants/languages.js +15 -0
- package/scripts/constants/languages.js.map +1 -0
- package/scripts/generators/analysis-builders.d.ts +266 -0
- package/scripts/generators/analysis-builders.d.ts.map +1 -0
- package/scripts/generators/analysis-builders.js +2903 -0
- package/scripts/generators/analysis-builders.js.map +1 -0
- package/scripts/generators/breaking-content.d.ts +45 -0
- package/scripts/generators/breaking-content.d.ts.map +1 -0
- package/scripts/generators/breaking-content.js +530 -0
- package/scripts/generators/breaking-content.js.map +1 -0
- package/scripts/generators/committee-helpers.d.ts +54 -0
- package/scripts/generators/committee-helpers.d.ts.map +1 -0
- package/scripts/generators/committee-helpers.js +154 -0
- package/scripts/generators/committee-helpers.js.map +1 -0
- package/scripts/generators/dashboard-content.d.ts +95 -0
- package/scripts/generators/dashboard-content.d.ts.map +1 -0
- package/scripts/generators/dashboard-content.js +630 -0
- package/scripts/generators/dashboard-content.js.map +1 -0
- package/scripts/generators/deep-analysis-content.d.ts +23 -0
- package/scripts/generators/deep-analysis-content.d.ts.map +1 -0
- package/scripts/generators/deep-analysis-content.js +831 -0
- package/scripts/generators/deep-analysis-content.js.map +1 -0
- package/scripts/generators/mindmap-content.d.ts +55 -0
- package/scripts/generators/mindmap-content.d.ts.map +1 -0
- package/scripts/generators/mindmap-content.js +512 -0
- package/scripts/generators/mindmap-content.js.map +1 -0
- package/scripts/generators/motions-content.d.ts +50 -0
- package/scripts/generators/motions-content.d.ts.map +1 -0
- package/scripts/generators/motions-content.js +391 -0
- package/scripts/generators/motions-content.js.map +1 -0
- package/scripts/generators/news-enhanced.d.ts +14 -0
- package/scripts/generators/news-enhanced.d.ts.map +1 -0
- package/scripts/generators/news-enhanced.js +169 -0
- package/scripts/generators/news-enhanced.js.map +1 -0
- package/scripts/generators/news-indexes.d.ts +31 -0
- package/scripts/generators/news-indexes.d.ts.map +1 -0
- package/scripts/generators/news-indexes.js +410 -0
- package/scripts/generators/news-indexes.js.map +1 -0
- package/scripts/generators/pipeline/fetch-stage.d.ts +352 -0
- package/scripts/generators/pipeline/fetch-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/fetch-stage.js +1522 -0
- package/scripts/generators/pipeline/fetch-stage.js.map +1 -0
- package/scripts/generators/pipeline/generate-stage.d.ts +43 -0
- package/scripts/generators/pipeline/generate-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/generate-stage.js +204 -0
- package/scripts/generators/pipeline/generate-stage.js.map +1 -0
- package/scripts/generators/pipeline/output-stage.d.ts +48 -0
- package/scripts/generators/pipeline/output-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/output-stage.js +145 -0
- package/scripts/generators/pipeline/output-stage.js.map +1 -0
- package/scripts/generators/pipeline/transform-stage.d.ts +57 -0
- package/scripts/generators/pipeline/transform-stage.d.ts.map +1 -0
- package/scripts/generators/pipeline/transform-stage.js +111 -0
- package/scripts/generators/pipeline/transform-stage.js.map +1 -0
- package/scripts/generators/propositions-content.d.ts +29 -0
- package/scripts/generators/propositions-content.d.ts.map +1 -0
- package/scripts/generators/propositions-content.js +90 -0
- package/scripts/generators/propositions-content.js.map +1 -0
- package/scripts/generators/sankey-content.d.ts +45 -0
- package/scripts/generators/sankey-content.d.ts.map +1 -0
- package/scripts/generators/sankey-content.js +227 -0
- package/scripts/generators/sankey-content.js.map +1 -0
- package/scripts/generators/sitemap.d.ts +66 -0
- package/scripts/generators/sitemap.d.ts.map +1 -0
- package/scripts/generators/sitemap.js +562 -0
- package/scripts/generators/sitemap.js.map +1 -0
- package/scripts/generators/strategies/article-strategy.d.ts +146 -0
- package/scripts/generators/strategies/article-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/article-strategy.js +4 -0
- package/scripts/generators/strategies/article-strategy.js.map +1 -0
- package/scripts/generators/strategies/breaking-news-strategy.d.ts +64 -0
- package/scripts/generators/strategies/breaking-news-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/breaking-news-strategy.js +246 -0
- package/scripts/generators/strategies/breaking-news-strategy.js.map +1 -0
- package/scripts/generators/strategies/committee-reports-strategy.d.ts +93 -0
- package/scripts/generators/strategies/committee-reports-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/committee-reports-strategy.js +447 -0
- package/scripts/generators/strategies/committee-reports-strategy.js.map +1 -0
- package/scripts/generators/strategies/month-ahead-strategy.d.ts +60 -0
- package/scripts/generators/strategies/month-ahead-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/month-ahead-strategy.js +175 -0
- package/scripts/generators/strategies/month-ahead-strategy.js.map +1 -0
- package/scripts/generators/strategies/monthly-review-strategy.d.ts +66 -0
- package/scripts/generators/strategies/monthly-review-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/monthly-review-strategy.js +204 -0
- package/scripts/generators/strategies/monthly-review-strategy.js.map +1 -0
- package/scripts/generators/strategies/motions-strategy.d.ts +61 -0
- package/scripts/generators/strategies/motions-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/motions-strategy.js +215 -0
- package/scripts/generators/strategies/motions-strategy.js.map +1 -0
- package/scripts/generators/strategies/propositions-strategy.d.ts +60 -0
- package/scripts/generators/strategies/propositions-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/propositions-strategy.js +257 -0
- package/scripts/generators/strategies/propositions-strategy.js.map +1 -0
- package/scripts/generators/strategies/week-ahead-strategy.d.ts +57 -0
- package/scripts/generators/strategies/week-ahead-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/week-ahead-strategy.js +178 -0
- package/scripts/generators/strategies/week-ahead-strategy.js.map +1 -0
- package/scripts/generators/strategies/weekly-review-strategy.d.ts +63 -0
- package/scripts/generators/strategies/weekly-review-strategy.d.ts.map +1 -0
- package/scripts/generators/strategies/weekly-review-strategy.js +211 -0
- package/scripts/generators/strategies/weekly-review-strategy.js.map +1 -0
- package/scripts/generators/swot-content.d.ts +42 -0
- package/scripts/generators/swot-content.d.ts.map +1 -0
- package/scripts/generators/swot-content.js +366 -0
- package/scripts/generators/swot-content.js.map +1 -0
- package/scripts/generators/week-ahead-content.d.ts +103 -0
- package/scripts/generators/week-ahead-content.d.ts.map +1 -0
- package/scripts/generators/week-ahead-content.js +610 -0
- package/scripts/generators/week-ahead-content.js.map +1 -0
- package/scripts/index.d.ts +40 -0
- package/scripts/index.d.ts.map +1 -0
- package/scripts/index.js +53 -0
- package/scripts/index.js.map +1 -0
- package/scripts/mcp/ep-mcp-client.d.ts +471 -0
- package/scripts/mcp/ep-mcp-client.d.ts.map +1 -0
- package/scripts/mcp/ep-mcp-client.js +734 -0
- package/scripts/mcp/ep-mcp-client.js.map +1 -0
- package/scripts/mcp/mcp-connection.d.ts +264 -0
- package/scripts/mcp/mcp-connection.d.ts.map +1 -0
- package/scripts/mcp/mcp-connection.js +790 -0
- package/scripts/mcp/mcp-connection.js.map +1 -0
- package/scripts/mcp/mcp-health.d.ts +75 -0
- package/scripts/mcp/mcp-health.d.ts.map +1 -0
- package/scripts/mcp/mcp-health.js +78 -0
- package/scripts/mcp/mcp-health.js.map +1 -0
- package/scripts/mcp/mcp-retry.d.ts +94 -0
- package/scripts/mcp/mcp-retry.d.ts.map +1 -0
- package/scripts/mcp/mcp-retry.js +127 -0
- package/scripts/mcp/mcp-retry.js.map +1 -0
- package/scripts/mcp/wb-mcp-client.d.ts +38 -0
- package/scripts/mcp/wb-mcp-client.d.ts.map +1 -0
- package/scripts/mcp/wb-mcp-client.js +112 -0
- package/scripts/mcp/wb-mcp-client.js.map +1 -0
- package/scripts/templates/article-template.d.ts +9 -0
- package/scripts/templates/article-template.d.ts.map +1 -0
- package/scripts/templates/article-template.js +378 -0
- package/scripts/templates/article-template.js.map +1 -0
- package/scripts/templates/section-builders.d.ts +28 -0
- package/scripts/templates/section-builders.d.ts.map +1 -0
- package/scripts/templates/section-builders.js +142 -0
- package/scripts/templates/section-builders.js.map +1 -0
- package/scripts/types/analysis.d.ts +115 -0
- package/scripts/types/analysis.d.ts.map +1 -0
- package/scripts/types/analysis.js +4 -0
- package/scripts/types/analysis.js.map +1 -0
- package/scripts/types/common.d.ts +584 -0
- package/scripts/types/common.d.ts.map +1 -0
- package/scripts/types/common.js +96 -0
- package/scripts/types/common.js.map +1 -0
- package/scripts/types/generation.d.ts +104 -0
- package/scripts/types/generation.d.ts.map +1 -0
- package/scripts/types/generation.js +4 -0
- package/scripts/types/generation.js.map +1 -0
- package/scripts/types/index.d.ts +24 -0
- package/scripts/types/index.d.ts.map +1 -0
- package/scripts/types/index.js +16 -0
- package/scripts/types/index.js.map +1 -0
- package/scripts/types/intelligence.d.ts +129 -0
- package/scripts/types/intelligence.d.ts.map +1 -0
- package/scripts/types/intelligence.js +4 -0
- package/scripts/types/intelligence.js.map +1 -0
- package/scripts/types/mcp.d.ts +418 -0
- package/scripts/types/mcp.d.ts.map +1 -0
- package/scripts/types/mcp.js +4 -0
- package/scripts/types/mcp.js.map +1 -0
- package/scripts/types/parliament.d.ts +388 -0
- package/scripts/types/parliament.d.ts.map +1 -0
- package/scripts/types/parliament.js +4 -0
- package/scripts/types/parliament.js.map +1 -0
- package/scripts/types/quality.d.ts +114 -0
- package/scripts/types/quality.d.ts.map +1 -0
- package/scripts/types/quality.js +4 -0
- package/scripts/types/quality.js.map +1 -0
- package/scripts/types/stakeholder.d.ts +88 -0
- package/scripts/types/stakeholder.d.ts.map +1 -0
- package/scripts/types/stakeholder.js +16 -0
- package/scripts/types/stakeholder.js.map +1 -0
- package/scripts/types/visualization.d.ts +708 -0
- package/scripts/types/visualization.d.ts.map +1 -0
- package/scripts/types/visualization.js +4 -0
- package/scripts/types/visualization.js.map +1 -0
- package/scripts/types/world-bank.d.ts +85 -0
- package/scripts/types/world-bank.d.ts.map +1 -0
- package/scripts/types/world-bank.js +4 -0
- package/scripts/types/world-bank.js.map +1 -0
- package/scripts/utils/article-category.d.ts +18 -0
- package/scripts/utils/article-category.d.ts.map +1 -0
- package/scripts/utils/article-category.js +49 -0
- package/scripts/utils/article-category.js.map +1 -0
- package/scripts/utils/article-quality-scorer.d.ts +87 -0
- package/scripts/utils/article-quality-scorer.d.ts.map +1 -0
- package/scripts/utils/article-quality-scorer.js +1048 -0
- package/scripts/utils/article-quality-scorer.js.map +1 -0
- package/scripts/utils/content-metadata.d.ts +34 -0
- package/scripts/utils/content-metadata.d.ts.map +1 -0
- package/scripts/utils/content-metadata.js +249 -0
- package/scripts/utils/content-metadata.js.map +1 -0
- package/scripts/utils/content-validator.d.ts +94 -0
- package/scripts/utils/content-validator.d.ts.map +1 -0
- package/scripts/utils/content-validator.js +489 -0
- package/scripts/utils/content-validator.js.map +1 -0
- package/scripts/utils/copy-test-reports.d.ts +9 -0
- package/scripts/utils/copy-test-reports.d.ts.map +1 -0
- package/scripts/utils/copy-test-reports.js +508 -0
- package/scripts/utils/copy-test-reports.js.map +1 -0
- package/scripts/utils/file-utils.d.ts +144 -0
- package/scripts/utils/file-utils.d.ts.map +1 -0
- package/scripts/utils/file-utils.js +374 -0
- package/scripts/utils/file-utils.js.map +1 -0
- package/scripts/utils/fix-articles.d.ts +27 -0
- package/scripts/utils/fix-articles.d.ts.map +1 -0
- package/scripts/utils/fix-articles.js +510 -0
- package/scripts/utils/fix-articles.js.map +1 -0
- package/scripts/utils/generate-docs-index.d.ts +8 -0
- package/scripts/utils/generate-docs-index.d.ts.map +1 -0
- package/scripts/utils/generate-docs-index.js +275 -0
- package/scripts/utils/generate-docs-index.js.map +1 -0
- package/scripts/utils/html-sanitize.d.ts +18 -0
- package/scripts/utils/html-sanitize.d.ts.map +1 -0
- package/scripts/utils/html-sanitize.js +57 -0
- package/scripts/utils/html-sanitize.js.map +1 -0
- package/scripts/utils/intelligence-analysis.d.ts +173 -0
- package/scripts/utils/intelligence-analysis.d.ts.map +1 -0
- package/scripts/utils/intelligence-analysis.js +936 -0
- package/scripts/utils/intelligence-analysis.js.map +1 -0
- package/scripts/utils/intelligence-index.d.ts +126 -0
- package/scripts/utils/intelligence-index.d.ts.map +1 -0
- package/scripts/utils/intelligence-index.js +731 -0
- package/scripts/utils/intelligence-index.js.map +1 -0
- package/scripts/utils/metadata-utils.d.ts +14 -0
- package/scripts/utils/metadata-utils.d.ts.map +1 -0
- package/scripts/utils/metadata-utils.js +18 -0
- package/scripts/utils/metadata-utils.js.map +1 -0
- package/scripts/utils/news-metadata.d.ts +47 -0
- package/scripts/utils/news-metadata.d.ts.map +1 -0
- package/scripts/utils/news-metadata.js +259 -0
- package/scripts/utils/news-metadata.js.map +1 -0
- package/scripts/utils/validate-articles.d.ts +2 -0
- package/scripts/utils/validate-articles.d.ts.map +1 -0
- package/scripts/utils/validate-articles.js +284 -0
- package/scripts/utils/validate-articles.js.map +1 -0
- package/scripts/utils/validate-ep-api.d.ts +51 -0
- package/scripts/utils/validate-ep-api.d.ts.map +1 -0
- package/scripts/utils/validate-ep-api.js +160 -0
- package/scripts/utils/validate-ep-api.js.map +1 -0
- package/scripts/utils/world-bank-data.d.ts +84 -0
- package/scripts/utils/world-bank-data.d.ts.map +1 -0
- package/scripts/utils/world-bank-data.js +311 -0
- 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 & 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 & 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 `"`. 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"}
|