riksdagsmonitor 0.8.59 → 0.8.62

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 (65) hide show
  1. package/dist/lib/cia/csv-utils.d.ts +75 -0
  2. package/dist/lib/cia/csv-utils.d.ts.map +1 -0
  3. package/dist/lib/cia/csv-utils.js +141 -0
  4. package/dist/lib/cia/csv-utils.js.map +1 -0
  5. package/dist/lib/cia/data-loader.d.ts +38 -348
  6. package/dist/lib/cia/data-loader.d.ts.map +1 -1
  7. package/dist/lib/cia/data-loader.js +54 -766
  8. package/dist/lib/cia/data-loader.js.map +1 -1
  9. package/dist/lib/cia/election-predictions.d.ts +1 -1
  10. package/dist/lib/cia/election-predictions.d.ts.map +1 -1
  11. package/dist/lib/cia/loaders/committees.d.ts +25 -0
  12. package/dist/lib/cia/loaders/committees.d.ts.map +1 -0
  13. package/dist/lib/cia/loaders/committees.js +110 -0
  14. package/dist/lib/cia/loaders/committees.js.map +1 -0
  15. package/dist/lib/cia/loaders/demographics.d.ts +22 -0
  16. package/dist/lib/cia/loaders/demographics.d.ts.map +1 -0
  17. package/dist/lib/cia/loaders/demographics.js +48 -0
  18. package/dist/lib/cia/loaders/demographics.js.map +1 -0
  19. package/dist/lib/cia/loaders/documents.d.ts +22 -0
  20. package/dist/lib/cia/loaders/documents.d.ts.map +1 -0
  21. package/dist/lib/cia/loaders/documents.js +51 -0
  22. package/dist/lib/cia/loaders/documents.js.map +1 -0
  23. package/dist/lib/cia/loaders/election.d.ts +24 -0
  24. package/dist/lib/cia/loaders/election.d.ts.map +1 -0
  25. package/dist/lib/cia/loaders/election.js +111 -0
  26. package/dist/lib/cia/loaders/election.js.map +1 -0
  27. package/dist/lib/cia/loaders/index.d.ts +26 -0
  28. package/dist/lib/cia/loaders/index.d.ts.map +1 -0
  29. package/dist/lib/cia/loaders/index.js +26 -0
  30. package/dist/lib/cia/loaders/index.js.map +1 -0
  31. package/dist/lib/cia/loaders/ministries.d.ts +22 -0
  32. package/dist/lib/cia/loaders/ministries.d.ts.map +1 -0
  33. package/dist/lib/cia/loaders/ministries.js +41 -0
  34. package/dist/lib/cia/loaders/ministries.js.map +1 -0
  35. package/dist/lib/cia/loaders/overview.d.ts +24 -0
  36. package/dist/lib/cia/loaders/overview.d.ts.map +1 -0
  37. package/dist/lib/cia/loaders/overview.js +96 -0
  38. package/dist/lib/cia/loaders/overview.js.map +1 -0
  39. package/dist/lib/cia/loaders/parties.d.ts +24 -0
  40. package/dist/lib/cia/loaders/parties.d.ts.map +1 -0
  41. package/dist/lib/cia/loaders/parties.js +92 -0
  42. package/dist/lib/cia/loaders/parties.js.map +1 -0
  43. package/dist/lib/cia/loaders/risk.d.ts +22 -0
  44. package/dist/lib/cia/loaders/risk.d.ts.map +1 -0
  45. package/dist/lib/cia/loaders/risk.js +38 -0
  46. package/dist/lib/cia/loaders/risk.js.map +1 -0
  47. package/dist/lib/cia/loaders/top10.d.ts +24 -0
  48. package/dist/lib/cia/loaders/top10.d.ts.map +1 -0
  49. package/dist/lib/cia/loaders/top10.js +68 -0
  50. package/dist/lib/cia/loaders/top10.js.map +1 -0
  51. package/dist/lib/cia/loaders/voting.d.ts +27 -0
  52. package/dist/lib/cia/loaders/voting.d.ts.map +1 -0
  53. package/dist/lib/cia/loaders/voting.js +108 -0
  54. package/dist/lib/cia/loaders/voting.js.map +1 -0
  55. package/dist/lib/cia/sources.d.ts +29 -0
  56. package/dist/lib/cia/sources.d.ts.map +1 -0
  57. package/dist/lib/cia/sources.js +162 -0
  58. package/dist/lib/cia/sources.js.map +1 -0
  59. package/dist/lib/cia/types.d.ts +324 -0
  60. package/dist/lib/cia/types.d.ts.map +1 -0
  61. package/dist/lib/cia/types.js +24 -0
  62. package/dist/lib/cia/types.js.map +1 -0
  63. package/dist/lib/cia/visualizations.d.ts +1 -1
  64. package/dist/lib/cia/visualizations.d.ts.map +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ /**
2
+ * @module CIA/CSVUtils
3
+ * @category Intelligence Platform - Data Acquisition & Pipeline Management
4
+ *
5
+ * @description
6
+ * CSV parsing and HTTP loading helpers for the CIA data pipeline.
7
+ *
8
+ * Originally lived as private/public methods on `CIADataLoader`; extracted as
9
+ * free functions so each per-domain loader (`loaders/*.ts`) can use them
10
+ * directly without instantiating the orchestrator class. Mockable in tests
11
+ * by stubbing `globalThis.fetch`.
12
+ *
13
+ * @author Hack23 AB - Data Pipeline Engineering
14
+ * @license Apache-2.0
15
+ * @since 2026
16
+ */
17
+ import type { CSVRow } from './types.js';
18
+ /** Signature used by per-domain loaders to fetch and parse a single CSV. */
19
+ export type LoadCSV = (localPath: string, fallbackPath?: string) => Promise<CSVRow[]>;
20
+ /**
21
+ * Parse CSV text into an array of header-keyed rows with auto-typed values.
22
+ *
23
+ * Handles basic quoting (`"value, with, commas"`) and converts numeric strings
24
+ * to numbers. Empty cells are kept as the empty string. Returns `[]` for
25
+ * inputs without at least a header and one data row.
26
+ *
27
+ * @param csvText - Raw CSV text
28
+ * @returns Parsed rows (empty array if header-only or empty)
29
+ */
30
+ export declare function parseCSV(csvText: string): CSVRow[];
31
+ /**
32
+ * Join a base URL with a relative path using exactly one slash between them.
33
+ *
34
+ * Tolerant of base URLs that omit the trailing slash and of paths that include
35
+ * a leading slash — both common foot-guns when callers concatenate URL strings
36
+ * by hand. Empty inputs are passed through: an empty `base` returns `path`
37
+ * unchanged, and an empty `path` returns `base` unchanged (useful for directory
38
+ * listings or when the path is computed conditionally).
39
+ *
40
+ * @param base - Base URL (with or without trailing slash); empty string returns `path` as-is
41
+ * @param path - Relative path (with or without leading slash); empty string returns `base` as-is
42
+ * @returns The two segments joined by exactly one `/`, or whichever input is non-empty when one is empty
43
+ */
44
+ export declare function joinURL(base: string, path: string): string;
45
+ /**
46
+ * Load a CSV with local-first fallback.
47
+ *
48
+ * Tries `joinURL(csvBaseURL, localPath)` first. If the response is non-OK or
49
+ * yields zero rows, falls back to `joinURL(fallbackURL, fallbackPath ?? localPath)`
50
+ * when a `fallbackURL` is provided. Network errors are logged as warnings
51
+ * rather than thrown so the page can degrade gracefully when offline.
52
+ *
53
+ * URL joining is tolerant of missing trailing slashes on the base URL and
54
+ * leading slashes on the path; callers do not need to worry about the slash
55
+ * boundary.
56
+ *
57
+ * @param csvBaseURL - Base URL for the local-first CSV directory
58
+ * @param fallbackURL - Optional remote fallback URL (e.g. raw.githubusercontent.com mirror); empty string disables fallback
59
+ * @param localPath - Path relative to `csvBaseURL`
60
+ * @param fallbackPath - Optional path on the fallback host (defaults to `localPath`)
61
+ * @returns Parsed CSV rows; `[]` when no source returned data
62
+ */
63
+ export declare function loadCSV(csvBaseURL: string, fallbackURL: string, localPath: string, fallbackPath?: string): Promise<CSVRow[]>;
64
+ /**
65
+ * Build a `LoadCSV` closure bound to a `csvBaseURL` / `fallbackURL` pair.
66
+ *
67
+ * Per-domain loaders accept this closure so they can be unit-tested without
68
+ * any reference to the URL configuration of a specific environment.
69
+ *
70
+ * @param csvBaseURL - Base URL for the local-first CSV directory
71
+ * @param fallbackURL - Optional remote fallback URL (empty string disables fallback)
72
+ * @returns A `LoadCSV` function bound to those URLs
73
+ */
74
+ export declare function createLoadCSV(csvBaseURL: string, fallbackURL?: string): LoadCSV;
75
+ //# sourceMappingURL=csv-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv-utils.d.ts","sourceRoot":"","sources":["../../../src/browser/cia/csv-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,4EAA4E;AAC5E,MAAM,MAAM,OAAO,GAAG,CACpB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,KAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AAEvB;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqClD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,OAAO,CAC3B,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqBnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,SAAK,GAAG,OAAO,CAG3E"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * @module CIA/CSVUtils
3
+ * @category Intelligence Platform - Data Acquisition & Pipeline Management
4
+ *
5
+ * @description
6
+ * CSV parsing and HTTP loading helpers for the CIA data pipeline.
7
+ *
8
+ * Originally lived as private/public methods on `CIADataLoader`; extracted as
9
+ * free functions so each per-domain loader (`loaders/*.ts`) can use them
10
+ * directly without instantiating the orchestrator class. Mockable in tests
11
+ * by stubbing `globalThis.fetch`.
12
+ *
13
+ * @author Hack23 AB - Data Pipeline Engineering
14
+ * @license Apache-2.0
15
+ * @since 2026
16
+ */
17
+ /**
18
+ * Parse CSV text into an array of header-keyed rows with auto-typed values.
19
+ *
20
+ * Handles basic quoting (`"value, with, commas"`) and converts numeric strings
21
+ * to numbers. Empty cells are kept as the empty string. Returns `[]` for
22
+ * inputs without at least a header and one data row.
23
+ *
24
+ * @param csvText - Raw CSV text
25
+ * @returns Parsed rows (empty array if header-only or empty)
26
+ */
27
+ export function parseCSV(csvText) {
28
+ const lines = csvText.trim().split('\n');
29
+ if (lines.length < 2)
30
+ return [];
31
+ const headers = lines[0].split(',').map(h => h.trim().replace(/^"|"$/g, ''));
32
+ const rows = [];
33
+ for (let i = 1; i < lines.length; i++) {
34
+ const line = lines[i].trim();
35
+ if (!line)
36
+ continue;
37
+ // Simple CSV parsing (handles basic quoting)
38
+ const values = [];
39
+ let current = '';
40
+ let inQuotes = false;
41
+ for (let j = 0; j < line.length; j++) {
42
+ const ch = line[j];
43
+ if (ch === '"') {
44
+ inQuotes = !inQuotes;
45
+ }
46
+ else if (ch === ',' && !inQuotes) {
47
+ values.push(current.trim());
48
+ current = '';
49
+ }
50
+ else {
51
+ current += ch;
52
+ }
53
+ }
54
+ values.push(current.trim());
55
+ const row = {};
56
+ headers.forEach((h, idx) => {
57
+ const val = values[idx] || '';
58
+ const num = Number(val);
59
+ row[h] = val !== '' && !isNaN(num) ? num : val;
60
+ });
61
+ rows.push(row);
62
+ }
63
+ return rows;
64
+ }
65
+ /**
66
+ * Join a base URL with a relative path using exactly one slash between them.
67
+ *
68
+ * Tolerant of base URLs that omit the trailing slash and of paths that include
69
+ * a leading slash — both common foot-guns when callers concatenate URL strings
70
+ * by hand. Empty inputs are passed through: an empty `base` returns `path`
71
+ * unchanged, and an empty `path` returns `base` unchanged (useful for directory
72
+ * listings or when the path is computed conditionally).
73
+ *
74
+ * @param base - Base URL (with or without trailing slash); empty string returns `path` as-is
75
+ * @param path - Relative path (with or without leading slash); empty string returns `base` as-is
76
+ * @returns The two segments joined by exactly one `/`, or whichever input is non-empty when one is empty
77
+ */
78
+ export function joinURL(base, path) {
79
+ if (!base)
80
+ return path;
81
+ if (!path)
82
+ return base;
83
+ const trimmedBase = base.replace(/\/+$/, '');
84
+ const trimmedPath = path.replace(/^\/+/, '');
85
+ return `${trimmedBase}/${trimmedPath}`;
86
+ }
87
+ /**
88
+ * Load a CSV with local-first fallback.
89
+ *
90
+ * Tries `joinURL(csvBaseURL, localPath)` first. If the response is non-OK or
91
+ * yields zero rows, falls back to `joinURL(fallbackURL, fallbackPath ?? localPath)`
92
+ * when a `fallbackURL` is provided. Network errors are logged as warnings
93
+ * rather than thrown so the page can degrade gracefully when offline.
94
+ *
95
+ * URL joining is tolerant of missing trailing slashes on the base URL and
96
+ * leading slashes on the path; callers do not need to worry about the slash
97
+ * boundary.
98
+ *
99
+ * @param csvBaseURL - Base URL for the local-first CSV directory
100
+ * @param fallbackURL - Optional remote fallback URL (e.g. raw.githubusercontent.com mirror); empty string disables fallback
101
+ * @param localPath - Path relative to `csvBaseURL`
102
+ * @param fallbackPath - Optional path on the fallback host (defaults to `localPath`)
103
+ * @returns Parsed CSV rows; `[]` when no source returned data
104
+ */
105
+ export async function loadCSV(csvBaseURL, fallbackURL, localPath, fallbackPath) {
106
+ const urls = [joinURL(csvBaseURL, localPath)];
107
+ if (fallbackURL) {
108
+ urls.push(joinURL(fallbackURL, fallbackPath ?? localPath));
109
+ }
110
+ for (const url of urls) {
111
+ try {
112
+ const response = await fetch(url);
113
+ if (!response.ok)
114
+ continue;
115
+ const text = await response.text();
116
+ const rows = parseCSV(text);
117
+ if (rows.length > 0)
118
+ return rows;
119
+ }
120
+ catch (e) {
121
+ const message = e instanceof Error ? e.message : String(e);
122
+ console.warn(`Failed to load CSV from ${url}:`, message);
123
+ }
124
+ }
125
+ console.warn(`No data loaded for ${localPath}`);
126
+ return [];
127
+ }
128
+ /**
129
+ * Build a `LoadCSV` closure bound to a `csvBaseURL` / `fallbackURL` pair.
130
+ *
131
+ * Per-domain loaders accept this closure so they can be unit-tested without
132
+ * any reference to the URL configuration of a specific environment.
133
+ *
134
+ * @param csvBaseURL - Base URL for the local-first CSV directory
135
+ * @param fallbackURL - Optional remote fallback URL (empty string disables fallback)
136
+ * @returns A `LoadCSV` function bound to those URLs
137
+ */
138
+ export function createLoadCSV(csvBaseURL, fallbackURL = '') {
139
+ return (localPath, fallbackPath) => loadCSV(csvBaseURL, fallbackURL, localPath, fallbackPath);
140
+ }
141
+ //# sourceMappingURL=csv-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"csv-utils.js","sourceRoot":"","sources":["../../../src/browser/cia/csv-utils.ts"],"names":[],"mappings":"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"}
@@ -4,340 +4,54 @@
4
4
  *
5
5
  * @description
6
6
  * CIA Intelligence Data Loader & Pipeline Orchestrator.
7
- * Core data acquisition module implementing multi-source intelligence data loading
8
- * from the Citizen Intelligence Agency (CIA) Platform. Manages CSV export ingestion
9
- * for 19+ intelligence product categories and JSON fallback for model-generated
10
- * electoral forecasts. Provides resilient data pipeline with local-first strategy
11
- * and remote fallback capabilities.
7
+ *
8
+ * Thin orchestrator that wires together the per-domain loaders in `loaders/`
9
+ * with a single `LoadCSV` closure built from `csvBaseURL` + `fallbackURL`.
10
+ * Public API (constructor, static `CSV_SOURCES`, `parseCSV`, `loadCSV`,
11
+ * `load*()` methods, `loadAll`) is preserved for existing consumers
12
+ * (`dashboard-init.ts`, `election-predictions.ts`, `visualizations.ts`).
13
+ *
14
+ * Was originally a 1 300-line monolith; decomposed into focused modules:
15
+ * - `types.ts` — DTO interfaces
16
+ * - `sources.ts` — CSV source URL inventory + Riksdag constants
17
+ * - `csv-utils.ts` — `parseCSV` / `loadCSV` helpers
18
+ * - `loaders/*.ts` — one file per domain (10 loaders)
12
19
  *
13
20
  * @author Hack23 AB - Data Pipeline Engineering
14
21
  * @license Apache-2.0
15
- * @version 2.0.0
22
+ * @version 3.0.0
16
23
  * @since 2024
17
-
18
24
  *
19
25
  * @intelligence CIA Platform Data Pipeline Orchestrator — core data acquisition module implementing multi-source intelligence data loading from 19+ CIA product categories. Manages CSV export ingestion and JSON fallback for electoral forecasts. Provides resilient pipeline with local-first strategy and remote fallback.
20
26
  *
21
27
  * @business Data infrastructure investment — the CIA data pipeline is the foundation for all analytical products. Pipeline reliability directly impacts user experience and platform credibility. Modular architecture enables future data source expansion (European Parliament, Nordic councils).
22
28
  *
23
29
  * @marketing Data transparency asset — transparent data sourcing (CIA Platform, open government data) builds trust with all audience segments. Data pipeline documentation demonstrates commitment to accuracy and verifiability, key messaging for press and academic audiences.
24
- * */
25
- /** Definition for a single CSV data source mapping. */
26
- export interface CSVSourceDefinition {
27
- /** Relative path within the csvBaseURL directory. */
28
- local: string;
29
- /** Human-readable description of the data product. */
30
- description: string;
31
- }
32
- /** Map of all known CSV source categories. */
33
- export interface CSVSourceMap {
34
- personStatus: CSVSourceDefinition;
35
- riskByParty: CSVSourceDefinition;
36
- riskLevels: CSVSourceDefinition;
37
- annualBallots: CSVSourceDefinition;
38
- crisisResilience: CSVSourceDefinition;
39
- partyPerformance: CSVSourceDefinition;
40
- partyMetrics: CSVSourceDefinition;
41
- partyMomentum: CSVSourceDefinition;
42
- partyMembers: CSVSourceDefinition;
43
- influenceMetrics: CSVSourceDefinition;
44
- riskSummary: CSVSourceDefinition;
45
- committeeProductivity: CSVSourceDefinition;
46
- committeeActivity: CSVSourceDefinition;
47
- partyEffectiveness: CSVSourceDefinition;
48
- electionForecast: CSVSourceDefinition;
49
- coalitionScenarios: CSVSourceDefinition;
50
- coalitionAlignment: CSVSourceDefinition;
51
- genderByParty: CSVSourceDefinition;
52
- experienceByParty: CSVSourceDefinition;
53
- ministryEffectiveness: CSVSourceDefinition;
54
- annualDocTypes: CSVSourceDefinition;
55
- decisionTrends: CSVSourceDefinition;
56
- electionRegions: CSVSourceDefinition;
57
- governmentRoles: CSVSourceDefinition;
58
- riskEvolution: CSVSourceDefinition;
59
- behavioralPatterns: CSVSourceDefinition;
60
- }
61
- /** A single parsed CSV row (header-keyed, auto-typed values). */
62
- export interface CSVRow {
63
- [key: string]: string | number;
64
- }
65
- export interface KeyMetrics {
66
- totalMPs: number;
67
- totalParties: number;
68
- totalRiskRules: number;
69
- governmentCoalition: string;
70
- coalitionSeats: number;
71
- oppositionSeats: number;
72
- majorityMargin: number;
73
- }
74
- export interface RiskAlerts {
75
- critical: number;
76
- major: number;
77
- minor: number;
78
- last90Days: {
79
- critical: number;
80
- major: number;
81
- minor: number;
82
- };
83
- }
84
- export interface ParliamentActivity {
85
- votesLastMonth: number;
86
- documentsProcessed: number;
87
- motionsSubmitted: number;
88
- committeeMeetings: number;
89
- }
90
- export interface CoalitionStability {
91
- stabilityScore: number;
92
- riskLevel: string;
93
- defectionProbability: number;
94
- ideologicalTension: string;
95
- }
96
- export interface DataQuality {
97
- completeness: number;
98
- lastDataSync: string;
99
- coverage: string;
100
- }
101
- export interface OverviewDashboard {
102
- title: string;
103
- description: string;
104
- lastUpdated: string;
105
- keyMetrics: KeyMetrics;
106
- riskAlerts: RiskAlerts;
107
- parliamentActivity: ParliamentActivity;
108
- coalitionStability: CoalitionStability;
109
- dataQuality: DataQuality;
110
- _source: string;
111
- }
112
- export interface PartyMetricsData {
113
- seats: number;
114
- voteShare: number;
115
- memberCount: number;
116
- documentsAuthored: number;
117
- motionsSubmitted: number;
118
- successRate: number;
119
- }
120
- export interface PartyVoting {
121
- totalVotes: number;
122
- cohesionScore: number;
123
- rebellionRate: number;
124
- }
125
- export interface PartyTrends {
126
- supportTrend: string;
127
- activityTrend: string;
128
- performanceLevel: string;
129
- }
130
- export interface PartyEntry {
131
- id: string;
132
- partyName: string;
133
- shortName: string;
134
- metrics: PartyMetricsData;
135
- voting: PartyVoting;
136
- trends: PartyTrends;
137
- _source: string;
138
- }
139
- export interface PartyPerformance {
140
- title: string;
141
- description: string;
142
- lastUpdated: string;
143
- parties: PartyEntry[];
144
- _source: string;
145
- }
146
- export interface MPRanking {
147
- rank: number;
148
- id: string;
149
- firstName: string;
150
- lastName: string;
151
- party: string;
152
- role: string;
153
- influenceScore: number;
154
- networkConnections: number;
155
- brokerClassification: string;
156
- riskLevel: string;
157
- riskScore: number;
158
- _source: string;
159
- }
160
- export interface Top10Influential {
161
- title: string;
162
- description: string;
163
- lastUpdated: string;
164
- methodology: string;
165
- rankings: MPRanking[];
166
- _source: string;
167
- }
168
- export interface CommitteeEntry {
169
- id: string;
170
- name: string;
171
- memberCount: number;
172
- influenceScore: number;
173
- documentsProcessed: number;
174
- productivityLevel: string;
175
- meetingsPerYear: number;
176
- keyIssues: string[];
177
- _source: string;
178
- }
179
- export interface NetworkNode {
180
- id: string;
181
- name: string;
182
- size: number;
183
- }
184
- export interface NetworkEdge {
185
- source: string;
186
- target: string;
187
- weight: number;
188
- type: string;
189
- }
190
- export interface CommitteeNetwork {
191
- title: string;
192
- description: string;
193
- lastUpdated: string;
194
- committees: CommitteeEntry[];
195
- networkGraph: {
196
- nodes: NetworkNode[];
197
- edges: NetworkEdge[];
198
- };
199
- crossCommitteeMPs: unknown[];
200
- _source: string;
201
- }
202
- export interface VotingMatrix {
203
- labels: string[];
204
- partyNames: string[];
205
- agreementMatrix: number[][];
206
- }
207
- export interface RebellionEntry {
208
- party: string;
209
- rebellionRate: number;
210
- trend: string;
211
- }
212
- export interface VotingPatterns {
213
- title: string;
214
- description: string;
215
- lastUpdated: string;
216
- analysisPeriod: string;
217
- votingMatrix: VotingMatrix;
218
- keyIssues: unknown[];
219
- rebellionTracking: RebellionEntry[];
220
- _source: string;
221
- }
222
- export interface ElectionAnalysis {
223
- forecast: {
224
- parties: Array<{
225
- name: string;
226
- currentSeats: number;
227
- predictedSeats: number;
228
- change: number;
229
- voteShare: number;
230
- confidenceInterval?: {
231
- min: number;
232
- max: number;
233
- };
234
- }>;
235
- };
236
- coalitionScenarios: Array<{
237
- name: string;
238
- composition: string[];
239
- totalSeats: number;
240
- probability: number;
241
- majority: boolean;
242
- riskLevel: string;
243
- }>;
244
- keyFactors: string[];
245
- electionDate?: string;
246
- }
247
- export interface MinistryEntry {
248
- name: string;
249
- effectiveness: string;
250
- documentsProduced: number;
251
- governmentBills: number;
252
- year: number;
253
- quarter: number;
254
- }
255
- export interface MinistryDashboard {
256
- title: string;
257
- description: string;
258
- lastUpdated: string;
259
- ministries: MinistryEntry[];
260
- _source: string;
261
- }
262
- export interface GenderEntry {
263
- party: string;
264
- gender: string;
265
- count: number;
266
- }
267
- export interface ExperienceEntry {
268
- party: string;
269
- experienceLevel: string;
270
- politicianCount: number;
271
- }
272
- export interface DemographicsDashboard {
273
- title: string;
274
- description: string;
275
- lastUpdated: string;
276
- genderByParty: GenderEntry[];
277
- experienceByParty: ExperienceEntry[];
278
- _source: string;
279
- }
280
- export interface DocumentTypeEntry {
281
- year: number;
282
- documentType: string;
283
- docCount: number;
284
- }
285
- export interface DecisionTrendEntry {
286
- year: number;
287
- month: number;
288
- decisionCount: number;
289
- approvedDecisions: number;
290
- rejectedDecisions: number;
291
- approvalRate: number;
292
- }
293
- export interface DocumentActivityDashboard {
294
- title: string;
295
- description: string;
296
- lastUpdated: string;
297
- documentTypes: DocumentTypeEntry[];
298
- decisionTrends: DecisionTrendEntry[];
299
- _source: string;
300
- }
301
- export interface RiskEvolutionEntry {
302
- period: string;
303
- severity: string;
304
- politicianCount: number;
305
- avgRiskScore: number;
306
- }
307
- export interface RiskEvolutionDashboard {
308
- title: string;
309
- description: string;
310
- lastUpdated: string;
311
- entries: RiskEvolutionEntry[];
312
- _source: string;
313
- }
314
- export interface CIADataPayload {
315
- overview: OverviewDashboard;
316
- election: ElectionAnalysis;
317
- partyPerf: PartyPerformance;
318
- top10: Top10Influential;
319
- committees: CommitteeNetwork;
320
- votingPatterns: VotingPatterns;
321
- ministry: MinistryDashboard;
322
- demographics: DemographicsDashboard;
323
- documentActivity: DocumentActivityDashboard;
324
- riskEvolution: RiskEvolutionDashboard;
325
- }
30
+ */
31
+ import type { CIADataPayload, CSVRow, CSVSourceMap, CommitteeNetwork, DemographicsDashboard, DocumentActivityDashboard, ElectionAnalysis, MinistryDashboard, OverviewDashboard, PartyPerformance, RiskEvolutionDashboard, Top10Influential, VotingPatterns } from './types.js';
32
+ export type * from './types.js';
33
+ /**
34
+ * Aggregator that delegates per-domain loading to the dedicated modules in
35
+ * `loaders/`. Maintains the original public API so existing callers compile
36
+ * unchanged after the decomposition refactor.
37
+ */
326
38
  export declare class CIADataLoader {
327
39
  readonly csvBaseURL: string;
328
40
  readonly fallbackURL: string;
329
41
  /** The 8 parties represented in the Swedish Riksdag. */
330
- static readonly RIKSDAG_PARTIES: string[];
42
+ static readonly RIKSDAG_PARTIES: readonly string[];
331
43
  /** Mapping of full Swedish committee names to their Riksdag org codes. */
332
- static readonly COMMITTEE_ORG_CODES: Record<string, string>;
44
+ static readonly COMMITTEE_ORG_CODES: Readonly<Record<string, string>>;
333
45
  /**
334
46
  * Heuristic divisor to estimate meetings/year from committee document counts.
335
47
  * Assumption: ~25 published documents per active committee meeting.
336
48
  */
337
49
  static readonly COMMITTEE_DOCS_PER_MEETING_ESTIMATE = 25;
338
- constructor();
339
50
  /** CSV data source definitions – maps to real PostgreSQL view exports. */
340
- static CSV_SOURCES: CSVSourceMap;
51
+ static readonly CSV_SOURCES: Readonly<CSVSourceMap>;
52
+ /** Loader closure bound to this instance's URL configuration. */
53
+ private readonly loadCSVFn;
54
+ constructor();
341
55
  /**
342
56
  * Parse CSV text into array of objects using header row as keys.
343
57
  * @param csvText - Raw CSV text
@@ -351,53 +65,29 @@ export declare class CIADataLoader {
351
65
  * @returns Parsed CSV rows
352
66
  */
353
67
  loadCSV(localPath: string, fallbackPath?: string): Promise<CSVRow[]>;
354
- /**
355
- * Build overview dashboard from CSV sources.
356
- * Replaces overview-dashboard.json.
357
- */
68
+ /** Build overview dashboard from CSV sources. Replaces overview-dashboard.json. */
358
69
  loadOverviewDashboard(): Promise<OverviewDashboard>;
359
- /**
360
- * Build election analysis from CSV sources.
361
- * Replaces election-analysis.json.
362
- */
70
+ /** Build election analysis from CSV sources. Replaces election-analysis.json. */
363
71
  loadElectionAnalysis(): Promise<ElectionAnalysis>;
364
- /**
365
- * Build party performance from CSV sources.
366
- * Replaces party-performance.json.
367
- */
72
+ /** Build party performance from CSV sources. Replaces party-performance.json. */
368
73
  loadPartyPerformance(): Promise<PartyPerformance>;
369
- /**
370
- * Build top 10 influential MPs from CSV sources.
371
- * Replaces top10-influential-mps.json.
372
- */
74
+ /** Build top 10 influential MPs from CSV sources. Replaces top10-influential-mps.json. */
373
75
  loadTop10Influential(): Promise<Top10Influential>;
374
- /**
375
- * Build committee network from CSV sources.
376
- * Replaces committee-network.json.
377
- * Filters out INACTIVE committees and deduplicates by name.
378
- */
76
+ /** Build committee network from CSV sources. Replaces committee-network.json. */
379
77
  loadCommitteeNetwork(): Promise<CommitteeNetwork>;
380
78
  /**
381
79
  * Build voting patterns from CSV sources.
382
- * Uses real coalition alignment data for the agreement matrix
383
- * and party effectiveness trends for win rates.
80
+ * Uses real coalition alignment data for the agreement matrix when present;
81
+ * otherwise falls back to win-rate similarity.
384
82
  */
385
83
  loadVotingPatterns(): Promise<VotingPatterns>;
386
- /**
387
- * Build ministry dashboard from CSV sources.
388
- */
84
+ /** Build ministry dashboard from CSV sources. */
389
85
  loadMinistryDashboard(): Promise<MinistryDashboard>;
390
- /**
391
- * Build demographics dashboard from CSV sources.
392
- */
86
+ /** Build demographics dashboard from CSV sources. */
393
87
  loadDemographics(): Promise<DemographicsDashboard>;
394
- /**
395
- * Build document activity dashboard from CSV sources.
396
- */
88
+ /** Build document activity dashboard from CSV sources. */
397
89
  loadDocumentActivity(): Promise<DocumentActivityDashboard>;
398
- /**
399
- * Build risk evolution dashboard from CSV sources.
400
- */
90
+ /** Build risk evolution dashboard from CSV sources. */
401
91
  loadRiskEvolution(): Promise<RiskEvolutionDashboard>;
402
92
  /**
403
93
  * Load all data in parallel.