euparliamentmonitor 0.9.2 → 0.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "euparliamentmonitor",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "type": "module",
5
5
  "description": "European Parliament Intelligence Platform - Monitor political activity with systematic transparency",
6
6
  "main": "scripts/index.js",
@@ -163,9 +163,9 @@
163
163
  "happy-dom": "20.9.0",
164
164
  "htmlhint": "1.9.2",
165
165
  "husky": "9.1.7",
166
- "jscpd": "4.0.9",
166
+ "jscpd": "4.1.0",
167
167
  "knip": "^6.7.0",
168
- "lint-staged": "17.0.3",
168
+ "lint-staged": "17.0.4",
169
169
  "mermaid": "11.14.0",
170
170
  "papaparse": "5.5.3",
171
171
  "prettier": "3.8.3",
@@ -115,6 +115,17 @@ export declare function renderProvenanceBlock(params: {
115
115
  * @returns Markdown block with two subsections (methodologies, templates)
116
116
  */
117
117
  export declare function renderTradecraftAppendix(files: readonly string[]): string;
118
+ /**
119
+ * Public re-export of the internal `humanize` helper so other aggregator
120
+ * modules (in particular `article-html.ts`) can derive the same display
121
+ * title from a file stem when no curated title is available. Keeping the
122
+ * single canonical implementation here avoids duplicate humanisation
123
+ * rules drifting across modules.
124
+ *
125
+ * @param stem - File stem (e.g. `electoral-cycle-methodology`)
126
+ * @returns Humanised title (e.g. `Electoral Cycle Methodology`)
127
+ */
128
+ export declare function humanizeStem(stem: string): string;
118
129
  /**
119
130
  * Render the analysis-index appendix — a compact table of every included
120
131
  * artifact and its section, plus a direct link to the manifest.
@@ -213,19 +213,25 @@ export function renderTradecraftAppendix(files) {
213
213
  'This article is produced under the [Hack23 AB](https://hack23.com) intelligence tradecraft library. Every methodology and artifact template applied to this run is linked below.',
214
214
  '',
215
215
  ];
216
- if (methods.length > 0) {
217
- block.push('### Methodologies');
216
+ // Order: Artifact templates first (concrete deliverables readers
217
+ // recognise from the article body), then Methodologies (the underlying
218
+ // tradecraft library). This matches the natural reader flow — the
219
+ // article is built from artifacts, and the methodologies explain how
220
+ // each artifact is produced — and pairs with the contextual, kind-
221
+ // aware "View …" CTAs rendered in `enhanceTradecraftCards`.
222
+ if (templates.length > 0) {
223
+ block.push('### Artifact templates');
218
224
  block.push('');
219
- for (const rel of methods) {
225
+ for (const rel of templates) {
220
226
  const stem = rel.split('/').pop()?.replace(/\.md$/i, '') ?? rel;
221
227
  block.push(`- [${humanize(stem)}](${githubBlobUrl(rel)})`);
222
228
  }
223
229
  block.push('');
224
230
  }
225
- if (templates.length > 0) {
226
- block.push('### Artifact templates');
231
+ if (methods.length > 0) {
232
+ block.push('### Methodologies');
227
233
  block.push('');
228
- for (const rel of templates) {
234
+ for (const rel of methods) {
229
235
  const stem = rel.split('/').pop()?.replace(/\.md$/i, '') ?? rel;
230
236
  block.push(`- [${humanize(stem)}](${githubBlobUrl(rel)})`);
231
237
  }
@@ -233,6 +239,19 @@ export function renderTradecraftAppendix(files) {
233
239
  }
234
240
  return block.join('\n');
235
241
  }
242
+ /**
243
+ * Public re-export of the internal `humanize` helper so other aggregator
244
+ * modules (in particular `article-html.ts`) can derive the same display
245
+ * title from a file stem when no curated title is available. Keeping the
246
+ * single canonical implementation here avoids duplicate humanisation
247
+ * rules drifting across modules.
248
+ *
249
+ * @param stem - File stem (e.g. `electoral-cycle-methodology`)
250
+ * @returns Humanised title (e.g. `Electoral Cycle Methodology`)
251
+ */
252
+ export function humanizeStem(stem) {
253
+ return humanize(stem);
254
+ }
236
255
  /**
237
256
  * Render the analysis-index appendix — a compact table of every included
238
257
  * artifact and its section, plus a direct link to the manifest.
@@ -29,7 +29,7 @@ import { resolveRunId as _resolveRunId } from './manifest/index.js';
29
29
  import { resolveArticleMetadata, extractStrongProseLine, } from './article-metadata.js';
30
30
  import { buildArticleMeta, serializeArticleMeta } from './article-meta.js';
31
31
  import { renderMarkdown } from './markdown-renderer.js';
32
- import { wrapArticleHtml, getArticleFilename, localizeArticleBody } from './article-html.js';
32
+ import { wrapArticleHtml, getArticleFilename, localizeArticleBody, enhanceTradecraftCards, enhanceAnalysisIndexCards, } from './article-html.js';
33
33
  import { buildReaderIntelligenceGuideHtml, stripInlineReaderGuide, } from './reader-intelligence-guide.js';
34
34
  import { ALL_LANGUAGES } from '../constants/language-core.js';
35
35
  import { blobUrl } from './infra/github-urls.js';
@@ -364,6 +364,12 @@ function writeLanguageVariant(lang, slug, aggregated, englishHtml, chromeOptions
364
364
  // Localize Tradecraft References, Analysis Index, and other appendix
365
365
  // section headings and content into the target language.
366
366
  bodyHtml = localizeArticleBody(bodyHtml, lang);
367
+ // Replace the plain Tradecraft References bullet lists and the
368
+ // Analysis Index table with `pi-card-grid` cards. Runs for every
369
+ // language (including English) so the "much nicer" rendering matches
370
+ // the political-intelligence.html visual vocabulary site-wide.
371
+ bodyHtml = enhanceTradecraftCards(bodyHtml, lang);
372
+ bodyHtml = enhanceAnalysisIndexCards(bodyHtml, lang);
367
373
  // When a per-language translated source exists, prefer a summary derived
368
374
  // from it so the `<meta description>` matches the visible prose. The
369
375
  // editorial title still comes from the English resolver (per-language
@@ -73,8 +73,10 @@ export declare function buildArticleHreflangLinks(articleSlug: string): string;
73
73
  * Build the article-level Table of Contents nav. Renders a labelled
74
74
  * `<nav class="article-toc">` with one `<a>` per H2 section, keyed by the
75
75
  * stable fragment ids produced by the aggregator. The containing `<aside>`
76
- * is styled as a sticky sidebar on wide viewports and collapses into a
77
- * `<details>` disclosure on narrow viewports via `styles.css`.
76
+ * is styled as a sticky, full-height sidebar on wide viewports and
77
+ * collapses into a `<details>` disclosure on narrow viewports via
78
+ * `styles.css`. Each entry is prefixed with a contextual emoji icon so
79
+ * readers can scan the navigation visually as well as textually.
78
80
  *
79
81
  * Returns an empty string when `entries` is empty so low-signal
80
82
  * `ANALYSIS_ONLY` articles (few sections, no value in a TOC) stay compact.
@@ -94,6 +96,46 @@ export declare function buildArticleToc(entries: readonly ArticleTocEntry[], lan
94
96
  * @returns HTML body with localized appendix sections
95
97
  */
96
98
  export declare function localizeArticleBody(bodyHtml: string, lang: LanguageCode): string;
99
+ /**
100
+ * Replace the rendered Tradecraft References bullet lists with a
101
+ * `pi-card-grid` of richly described cards (icon, curated title,
102
+ * curated description, kind-aware CTA). The cards reuse the exact same
103
+ * class hooks as `political-intelligence.html`, so the site-wide CSS
104
+ * already styles them — no additional CSS is required.
105
+ *
106
+ * After the April-2026 reorder the rendered Markdown emits Artifact
107
+ * templates as the first sub-heading and Methodologies as the second,
108
+ * matching how readers encounter the run (artifacts first, methodology
109
+ * library second). The card upgrade follows the same order so the H3
110
+ * positions stay aligned with the kind-aware CTA labels.
111
+ *
112
+ * Falls back to the original Markdown-rendered list when the expected
113
+ * structure (H2 → intro paragraph → Artifact-templates sub-heading →
114
+ * `<ul>` → Methodologies sub-heading → `<ul>`) is missing, so partially
115
+ * stripped or unusual articles are not silently corrupted.
116
+ *
117
+ * @param bodyHtml - The (already-localised) article body HTML
118
+ * @param lang - Target language code for curated titles/descriptions
119
+ * @returns Body HTML with the tradecraft section upgraded to cards
120
+ */
121
+ export declare function enhanceTradecraftCards(bodyHtml: string, lang: LanguageCode): string;
122
+ /**
123
+ * Replace the Analysis Index `<table>` with a `pi-card-grid` of cards,
124
+ * one per included artifact. Each card renders the artifact's curated
125
+ * localised title + description, the section it contributed to, the
126
+ * run-relative path as inline `<code>`, and a "View on GitHub" CTA.
127
+ *
128
+ * Strategy: parse the rendered table's `<tbody>` rows (each row carries
129
+ * `[sectionId, <a href="…">stem</a>, runRelPath]`) and re-render the
130
+ * region between the table's opening wrapper and `</table>` as a card
131
+ * grid. The wrapping `<div class="table-scroll">` is dropped because
132
+ * the card grid handles its own responsive layout via flex/grid.
133
+ *
134
+ * @param bodyHtml - Article body HTML
135
+ * @param lang - Target language code
136
+ * @returns Body HTML with the Analysis Index upgraded to a card grid
137
+ */
138
+ export declare function enhanceAnalysisIndexCards(bodyHtml: string, lang: LanguageCode): string;
97
139
  /**
98
140
  * Render the full article HTML document with the shared chrome.
99
141
  *