@ansvar/eu-regulations-mcp 0.1.0
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 +21 -0
- package/README.md +242 -0
- package/data/seed/ai-act.json +1026 -0
- package/data/seed/applicability/dora.json +92 -0
- package/data/seed/applicability/gdpr.json +74 -0
- package/data/seed/applicability/nis2.json +83 -0
- package/data/seed/cra.json +690 -0
- package/data/seed/cybersecurity-act.json +534 -0
- package/data/seed/dora.json +719 -0
- package/data/seed/gdpr.json +732 -0
- package/data/seed/mappings/iso27001-dora.json +106 -0
- package/data/seed/mappings/iso27001-gdpr.json +114 -0
- package/data/seed/mappings/iso27001-nis2.json +98 -0
- package/data/seed/nis2.json +492 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +271 -0
- package/dist/index.js.map +1 -0
- package/dist/tools/applicability.d.ts +20 -0
- package/dist/tools/applicability.d.ts.map +1 -0
- package/dist/tools/applicability.js +42 -0
- package/dist/tools/applicability.js.map +1 -0
- package/dist/tools/article.d.ts +17 -0
- package/dist/tools/article.d.ts.map +1 -0
- package/dist/tools/article.js +29 -0
- package/dist/tools/article.js.map +1 -0
- package/dist/tools/compare.d.ts +18 -0
- package/dist/tools/compare.d.ts.map +1 -0
- package/dist/tools/compare.js +60 -0
- package/dist/tools/compare.js.map +1 -0
- package/dist/tools/definitions.d.ts +14 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +26 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/list.d.ts +22 -0
- package/dist/tools/list.d.ts.map +1 -0
- package/dist/tools/list.js +67 -0
- package/dist/tools/list.js.map +1 -0
- package/dist/tools/map.d.ts +19 -0
- package/dist/tools/map.d.ts.map +1 -0
- package/dist/tools/map.js +44 -0
- package/dist/tools/map.js.map +1 -0
- package/dist/tools/search.d.ts +15 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +62 -0
- package/dist/tools/search.js.map +1 -0
- package/package.json +70 -0
- package/scripts/build-db.ts +292 -0
- package/scripts/check-updates.ts +192 -0
- package/scripts/ingest-eurlex.ts +219 -0
- package/src/index.ts +294 -0
- package/src/tools/applicability.ts +84 -0
- package/src/tools/article.ts +61 -0
- package/src/tools/compare.ts +94 -0
- package/src/tools/definitions.ts +54 -0
- package/src/tools/list.ts +116 -0
- package/src/tools/map.ts +84 -0
- package/src/tools/search.ts +95 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import Database from 'better-sqlite3';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { dirname, join } from 'path';
|
|
8
|
+
import { searchRegulations } from './tools/search.js';
|
|
9
|
+
import { getArticle } from './tools/article.js';
|
|
10
|
+
import { listRegulations } from './tools/list.js';
|
|
11
|
+
import { compareRequirements } from './tools/compare.js';
|
|
12
|
+
import { mapControls } from './tools/map.js';
|
|
13
|
+
import { checkApplicability } from './tools/applicability.js';
|
|
14
|
+
import { getDefinitions } from './tools/definitions.js';
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
// Database path - look for regulations.db in data folder
|
|
18
|
+
const DB_PATH = process.env.EU_COMPLIANCE_DB_PATH || join(__dirname, '..', 'data', 'regulations.db');
|
|
19
|
+
let db;
|
|
20
|
+
function getDatabase() {
|
|
21
|
+
if (!db) {
|
|
22
|
+
try {
|
|
23
|
+
db = new Database(DB_PATH, { readonly: true });
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw new Error(`Failed to open database at ${DB_PATH}: ${error}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return db;
|
|
30
|
+
}
|
|
31
|
+
const server = new Server({
|
|
32
|
+
name: 'eu-regulations-mcp',
|
|
33
|
+
version: '0.1.0',
|
|
34
|
+
}, {
|
|
35
|
+
capabilities: {
|
|
36
|
+
tools: {},
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
// Define available tools
|
|
40
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
41
|
+
tools: [
|
|
42
|
+
{
|
|
43
|
+
name: 'search_regulations',
|
|
44
|
+
description: 'Search across all EU regulations for articles matching a query. Returns relevant articles with snippets highlighting matches.',
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: 'object',
|
|
47
|
+
properties: {
|
|
48
|
+
query: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Search query (e.g., "incident reporting", "personal data breach")',
|
|
51
|
+
},
|
|
52
|
+
regulations: {
|
|
53
|
+
type: 'array',
|
|
54
|
+
items: { type: 'string' },
|
|
55
|
+
description: 'Optional: filter to specific regulations (e.g., ["GDPR", "NIS2"])',
|
|
56
|
+
},
|
|
57
|
+
limit: {
|
|
58
|
+
type: 'number',
|
|
59
|
+
description: 'Maximum results to return (default: 10)',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ['query'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'get_article',
|
|
67
|
+
description: 'Retrieve the full text of a specific article from a regulation.',
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: 'object',
|
|
70
|
+
properties: {
|
|
71
|
+
regulation: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
description: 'Regulation ID (e.g., "GDPR", "NIS2", "DORA")',
|
|
74
|
+
},
|
|
75
|
+
article: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Article number (e.g., "17", "23")',
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
required: ['regulation', 'article'],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'list_regulations',
|
|
85
|
+
description: 'List available regulations and their structure. Without parameters, lists all regulations. With a regulation specified, shows chapters and articles.',
|
|
86
|
+
inputSchema: {
|
|
87
|
+
type: 'object',
|
|
88
|
+
properties: {
|
|
89
|
+
regulation: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
description: 'Optional: specific regulation to get detailed structure for',
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'compare_requirements',
|
|
98
|
+
description: 'Compare requirements across multiple regulations on a specific topic. Useful for understanding differences in how regulations address similar concerns.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
topic: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
description: 'Topic to compare (e.g., "incident reporting", "risk assessment")',
|
|
105
|
+
},
|
|
106
|
+
regulations: {
|
|
107
|
+
type: 'array',
|
|
108
|
+
items: { type: 'string' },
|
|
109
|
+
description: 'Regulations to compare (e.g., ["DORA", "NIS2"])',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
required: ['topic', 'regulations'],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
name: 'map_controls',
|
|
117
|
+
description: 'Map ISO 27001:2022 controls to EU regulation requirements. Shows which articles satisfy specific security controls.',
|
|
118
|
+
inputSchema: {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: {
|
|
121
|
+
framework: {
|
|
122
|
+
type: 'string',
|
|
123
|
+
enum: ['ISO27001'],
|
|
124
|
+
description: 'Control framework (currently only ISO27001 supported)',
|
|
125
|
+
},
|
|
126
|
+
control: {
|
|
127
|
+
type: 'string',
|
|
128
|
+
description: 'Optional: specific control ID (e.g., "A.5.1", "A.6.8")',
|
|
129
|
+
},
|
|
130
|
+
regulation: {
|
|
131
|
+
type: 'string',
|
|
132
|
+
description: 'Optional: filter mappings to specific regulation',
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
required: ['framework'],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'check_applicability',
|
|
140
|
+
description: 'Determine which EU regulations apply to an organization based on sector and characteristics.',
|
|
141
|
+
inputSchema: {
|
|
142
|
+
type: 'object',
|
|
143
|
+
properties: {
|
|
144
|
+
sector: {
|
|
145
|
+
type: 'string',
|
|
146
|
+
enum: ['financial', 'healthcare', 'energy', 'transport', 'digital_infrastructure', 'public_administration', 'manufacturing', 'other'],
|
|
147
|
+
description: 'Organization sector',
|
|
148
|
+
},
|
|
149
|
+
subsector: {
|
|
150
|
+
type: 'string',
|
|
151
|
+
description: 'Optional: more specific subsector (e.g., "bank", "insurance" for financial)',
|
|
152
|
+
},
|
|
153
|
+
member_state: {
|
|
154
|
+
type: 'string',
|
|
155
|
+
description: 'Optional: EU member state (ISO country code)',
|
|
156
|
+
},
|
|
157
|
+
size: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['sme', 'large'],
|
|
160
|
+
description: 'Optional: organization size',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
required: ['sector'],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'get_definitions',
|
|
168
|
+
description: 'Look up official definitions of terms from EU regulations. Terms are defined in each regulation\'s definitions article.',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
term: {
|
|
173
|
+
type: 'string',
|
|
174
|
+
description: 'Term to look up (e.g., "personal data", "incident", "processing")',
|
|
175
|
+
},
|
|
176
|
+
regulation: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
description: 'Optional: filter to specific regulation',
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
required: ['term'],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
}));
|
|
186
|
+
// Handle tool calls
|
|
187
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
188
|
+
const { name, arguments: args } = request.params;
|
|
189
|
+
try {
|
|
190
|
+
const database = getDatabase();
|
|
191
|
+
switch (name) {
|
|
192
|
+
case 'search_regulations': {
|
|
193
|
+
const input = args;
|
|
194
|
+
const results = await searchRegulations(database, input);
|
|
195
|
+
return {
|
|
196
|
+
content: [{ type: 'text', text: JSON.stringify(results, null, 2) }],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
case 'get_article': {
|
|
200
|
+
const input = args;
|
|
201
|
+
const article = await getArticle(database, input);
|
|
202
|
+
if (!article) {
|
|
203
|
+
return {
|
|
204
|
+
content: [{ type: 'text', text: `Article ${input.article} not found in ${input.regulation}` }],
|
|
205
|
+
isError: true,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
content: [{ type: 'text', text: JSON.stringify(article, null, 2) }],
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
case 'list_regulations': {
|
|
213
|
+
const input = (args ?? {});
|
|
214
|
+
const result = await listRegulations(database, input);
|
|
215
|
+
return {
|
|
216
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
case 'compare_requirements': {
|
|
220
|
+
const input = args;
|
|
221
|
+
const result = await compareRequirements(database, input);
|
|
222
|
+
return {
|
|
223
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
case 'map_controls': {
|
|
227
|
+
const input = args;
|
|
228
|
+
const result = await mapControls(database, input);
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
case 'check_applicability': {
|
|
234
|
+
const input = args;
|
|
235
|
+
const result = await checkApplicability(database, input);
|
|
236
|
+
return {
|
|
237
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
case 'get_definitions': {
|
|
241
|
+
const input = args;
|
|
242
|
+
const result = await getDefinitions(database, input);
|
|
243
|
+
return {
|
|
244
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
default:
|
|
248
|
+
return {
|
|
249
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
250
|
+
isError: true,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
return {
|
|
256
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
257
|
+
isError: true,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
// Start the server
|
|
262
|
+
async function main() {
|
|
263
|
+
const transport = new StdioServerTransport();
|
|
264
|
+
await server.connect(transport);
|
|
265
|
+
console.error('EU Regulations MCP server started');
|
|
266
|
+
}
|
|
267
|
+
main().catch((error) => {
|
|
268
|
+
console.error('Fatal error:', error);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
});
|
|
271
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export type Sector = 'financial' | 'healthcare' | 'energy' | 'transport' | 'digital_infrastructure' | 'public_administration' | 'manufacturing' | 'other';
|
|
3
|
+
export interface ApplicabilityInput {
|
|
4
|
+
sector: Sector;
|
|
5
|
+
subsector?: string;
|
|
6
|
+
member_state?: string;
|
|
7
|
+
size?: 'sme' | 'large';
|
|
8
|
+
}
|
|
9
|
+
export interface ApplicableRegulation {
|
|
10
|
+
regulation: string;
|
|
11
|
+
confidence: 'definite' | 'likely' | 'possible';
|
|
12
|
+
basis: string | null;
|
|
13
|
+
notes: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface ApplicabilityResult {
|
|
16
|
+
entity: ApplicabilityInput;
|
|
17
|
+
applicable_regulations: ApplicableRegulation[];
|
|
18
|
+
}
|
|
19
|
+
export declare function checkApplicability(db: Database, input: ApplicabilityInput): Promise<ApplicabilityResult>;
|
|
20
|
+
//# sourceMappingURL=applicability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,MAAM,GACd,WAAW,GACX,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,wBAAwB,GACxB,uBAAuB,GACvB,eAAe,GACf,OAAO,CAAC;AAEZ,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAC/C,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,sBAAsB,EAAE,oBAAoB,EAAE,CAAC;CAChD;AAED,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAiD9B"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export async function checkApplicability(db, input) {
|
|
2
|
+
const { sector, subsector } = input;
|
|
3
|
+
// Query for matching rules - check both sector match and subsector match
|
|
4
|
+
let sql = `
|
|
5
|
+
SELECT DISTINCT
|
|
6
|
+
regulation,
|
|
7
|
+
confidence,
|
|
8
|
+
basis_article as basis,
|
|
9
|
+
notes
|
|
10
|
+
FROM applicability_rules
|
|
11
|
+
WHERE applies = 1
|
|
12
|
+
AND (
|
|
13
|
+
(sector = ? AND (subsector IS NULL OR subsector = ?))
|
|
14
|
+
OR (sector = ? AND subsector IS NULL)
|
|
15
|
+
)
|
|
16
|
+
ORDER BY
|
|
17
|
+
CASE confidence
|
|
18
|
+
WHEN 'definite' THEN 1
|
|
19
|
+
WHEN 'likely' THEN 2
|
|
20
|
+
WHEN 'possible' THEN 3
|
|
21
|
+
END,
|
|
22
|
+
regulation
|
|
23
|
+
`;
|
|
24
|
+
const rows = db.prepare(sql).all(sector, subsector || '', sector);
|
|
25
|
+
// Deduplicate by regulation, keeping highest confidence
|
|
26
|
+
const regulationMap = new Map();
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
if (!regulationMap.has(row.regulation)) {
|
|
29
|
+
regulationMap.set(row.regulation, {
|
|
30
|
+
regulation: row.regulation,
|
|
31
|
+
confidence: row.confidence,
|
|
32
|
+
basis: row.basis,
|
|
33
|
+
notes: row.notes,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
entity: input,
|
|
39
|
+
applicable_regulations: Array.from(regulationMap.values()),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=applicability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applicability.js","sourceRoot":"","sources":["../../src/tools/applicability.ts"],"names":[],"mappings":"AA+BA,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,EAAY,EACZ,KAAyB;IAEzB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAEpC,yEAAyE;IACzE,IAAI,GAAG,GAAG;;;;;;;;;;;;;;;;;;;GAmBT,CAAC;IAEF,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,EAAE,MAAM,CAK9D,CAAC;IAEH,wDAAwD;IACxD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgC,CAAC;IAC9D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE;gBAChC,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,KAAK,EAAE,GAAG,CAAC,KAAK;aACjB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM,EAAE,KAAK;QACb,sBAAsB,EAAE,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface GetArticleInput {
|
|
3
|
+
regulation: string;
|
|
4
|
+
article: string;
|
|
5
|
+
include_recitals?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface Article {
|
|
8
|
+
regulation: string;
|
|
9
|
+
article_number: string;
|
|
10
|
+
title: string | null;
|
|
11
|
+
text: string;
|
|
12
|
+
chapter: string | null;
|
|
13
|
+
recitals: string[] | null;
|
|
14
|
+
cross_references: string[] | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function getArticle(db: Database, input: GetArticleInput): Promise<Article | null>;
|
|
17
|
+
//# sourceMappingURL=article.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article.d.ts","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC1B,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CACnC;AAED,wBAAsB,UAAU,CAC9B,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,eAAe,GACrB,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAuCzB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export async function getArticle(db, input) {
|
|
2
|
+
const { regulation, article } = input;
|
|
3
|
+
const sql = `
|
|
4
|
+
SELECT
|
|
5
|
+
regulation,
|
|
6
|
+
article_number,
|
|
7
|
+
title,
|
|
8
|
+
text,
|
|
9
|
+
chapter,
|
|
10
|
+
recitals,
|
|
11
|
+
cross_references
|
|
12
|
+
FROM articles
|
|
13
|
+
WHERE regulation = ? AND article_number = ?
|
|
14
|
+
`;
|
|
15
|
+
const row = db.prepare(sql).get(regulation, article);
|
|
16
|
+
if (!row) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
regulation: row.regulation,
|
|
21
|
+
article_number: row.article_number,
|
|
22
|
+
title: row.title,
|
|
23
|
+
text: row.text,
|
|
24
|
+
chapter: row.chapter,
|
|
25
|
+
recitals: row.recitals ? JSON.parse(row.recitals) : null,
|
|
26
|
+
cross_references: row.cross_references ? JSON.parse(row.cross_references) : null,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=article.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"article.js","sourceRoot":"","sources":["../../src/tools/article.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAY,EACZ,KAAsB;IAEtB,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAEtC,MAAM,GAAG,GAAG;;;;;;;;;;;GAWX,CAAC;IAEF,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAQtC,CAAC;IAEd,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,cAAc,EAAE,GAAG,CAAC,cAAc;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI;QACxD,gBAAgB,EAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI;KACjF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface CompareInput {
|
|
3
|
+
topic: string;
|
|
4
|
+
regulations: string[];
|
|
5
|
+
}
|
|
6
|
+
export interface RegulationComparison {
|
|
7
|
+
regulation: string;
|
|
8
|
+
requirements: string[];
|
|
9
|
+
articles: string[];
|
|
10
|
+
timelines?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CompareResult {
|
|
13
|
+
topic: string;
|
|
14
|
+
regulations: RegulationComparison[];
|
|
15
|
+
key_differences?: string[];
|
|
16
|
+
}
|
|
17
|
+
export declare function compareRequirements(db: Database, input: CompareInput): Promise<CompareResult>;
|
|
18
|
+
//# sourceMappingURL=compare.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.d.ts","sourceRoot":"","sources":["../../src/tools/compare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG/C,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,oBAAoB,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAwBD,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { searchRegulations } from './search.js';
|
|
2
|
+
/**
|
|
3
|
+
* Extract timeline mentions from text (e.g., "24 hours", "72 hours")
|
|
4
|
+
*/
|
|
5
|
+
function extractTimelines(text) {
|
|
6
|
+
const timelinePatterns = [
|
|
7
|
+
/(\d+)\s*hours?/gi,
|
|
8
|
+
/(\d+)\s*days?/gi,
|
|
9
|
+
/without\s+undue\s+delay/gi,
|
|
10
|
+
/immediately/gi,
|
|
11
|
+
];
|
|
12
|
+
const matches = [];
|
|
13
|
+
for (const pattern of timelinePatterns) {
|
|
14
|
+
const found = text.match(pattern);
|
|
15
|
+
if (found) {
|
|
16
|
+
matches.push(...found);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return matches.length > 0 ? matches.join(', ') : undefined;
|
|
20
|
+
}
|
|
21
|
+
export async function compareRequirements(db, input) {
|
|
22
|
+
const { topic, regulations } = input;
|
|
23
|
+
const comparisons = [];
|
|
24
|
+
for (const regulation of regulations) {
|
|
25
|
+
// Search for articles matching the topic in this regulation
|
|
26
|
+
const results = await searchRegulations(db, {
|
|
27
|
+
query: topic,
|
|
28
|
+
regulations: [regulation],
|
|
29
|
+
limit: 5,
|
|
30
|
+
});
|
|
31
|
+
// Get full article text for timeline extraction
|
|
32
|
+
const articles = [];
|
|
33
|
+
const requirements = [];
|
|
34
|
+
let combinedText = '';
|
|
35
|
+
for (const result of results) {
|
|
36
|
+
articles.push(result.article);
|
|
37
|
+
requirements.push(result.snippet.replace(/>>>/g, '').replace(/<<</g, ''));
|
|
38
|
+
// Get full text for timeline extraction
|
|
39
|
+
const fullArticle = db.prepare(`
|
|
40
|
+
SELECT text FROM articles
|
|
41
|
+
WHERE regulation = ? AND article_number = ?
|
|
42
|
+
`).get(regulation, result.article);
|
|
43
|
+
if (fullArticle) {
|
|
44
|
+
combinedText += ' ' + fullArticle.text;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const timelines = extractTimelines(combinedText);
|
|
48
|
+
comparisons.push({
|
|
49
|
+
regulation,
|
|
50
|
+
requirements,
|
|
51
|
+
articles,
|
|
52
|
+
timelines,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
topic,
|
|
57
|
+
regulations: comparisons,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=compare.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/tools/compare.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAoBhD;;GAEG;AACH,SAAS,gBAAgB,CAAC,IAAY;IACpC,MAAM,gBAAgB,GAAG;QACvB,kBAAkB;QAClB,iBAAiB;QACjB,2BAA2B;QAC3B,eAAe;KAChB,CAAC;IAEF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,gBAAgB,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAClC,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAY,EACZ,KAAmB;IAEnB,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,KAAK,CAAC;IAErC,MAAM,WAAW,GAA2B,EAAE,CAAC;IAE/C,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,4DAA4D;QAC5D,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC,EAAE,EAAE;YAC1C,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,CAAC,UAAU,CAAC;YACzB,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,gDAAgD;QAChD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,IAAI,YAAY,GAAG,EAAE,CAAC;QAEtB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;YAE1E,wCAAwC;YACxC,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC;;;OAG9B,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAiC,CAAC;YAEnE,IAAI,WAAW,EAAE,CAAC;gBAChB,YAAY,IAAI,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC;YACzC,CAAC;QACH,CAAC;QAED,MAAM,SAAS,GAAG,gBAAgB,CAAC,YAAY,CAAC,CAAC;QAEjD,WAAW,CAAC,IAAI,CAAC;YACf,UAAU;YACV,YAAY;YACZ,QAAQ;YACR,SAAS;SACV,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,KAAK;QACL,WAAW,EAAE,WAAW;KACzB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface DefinitionsInput {
|
|
3
|
+
term: string;
|
|
4
|
+
regulation?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface Definition {
|
|
7
|
+
term: string;
|
|
8
|
+
regulation: string;
|
|
9
|
+
article: string;
|
|
10
|
+
definition: string;
|
|
11
|
+
related_terms?: string[];
|
|
12
|
+
}
|
|
13
|
+
export declare function getDefinitions(db: Database, input: DefinitionsInput): Promise<Definition[]>;
|
|
14
|
+
//# sourceMappingURL=definitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAsB,cAAc,CAClC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,UAAU,EAAE,CAAC,CAmCvB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export async function getDefinitions(db, input) {
|
|
2
|
+
const { term, regulation } = input;
|
|
3
|
+
let sql = `
|
|
4
|
+
SELECT
|
|
5
|
+
term,
|
|
6
|
+
regulation,
|
|
7
|
+
article,
|
|
8
|
+
definition
|
|
9
|
+
FROM definitions
|
|
10
|
+
WHERE term LIKE ?
|
|
11
|
+
`;
|
|
12
|
+
const params = [`%${term}%`];
|
|
13
|
+
if (regulation) {
|
|
14
|
+
sql += ` AND regulation = ?`;
|
|
15
|
+
params.push(regulation);
|
|
16
|
+
}
|
|
17
|
+
sql += ` ORDER BY regulation, term`;
|
|
18
|
+
const rows = db.prepare(sql).all(...params);
|
|
19
|
+
return rows.map(row => ({
|
|
20
|
+
term: row.term,
|
|
21
|
+
regulation: row.regulation,
|
|
22
|
+
article: row.article,
|
|
23
|
+
definition: row.definition,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=definitions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,KAAuB;IAEvB,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,KAAK,CAAC;IAEnC,IAAI,GAAG,GAAG;;;;;;;;GAQT,CAAC;IAEF,MAAM,MAAM,GAAa,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC;IAEvC,IAAI,UAAU,EAAE,CAAC;QACf,GAAG,IAAI,qBAAqB,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAED,GAAG,IAAI,4BAA4B,CAAC;IAEpC,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAKxC,CAAC;IAEH,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,UAAU,EAAE,GAAG,CAAC,UAAU;QAC1B,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Database } from 'better-sqlite3';
|
|
2
|
+
export interface ListInput {
|
|
3
|
+
regulation?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface Chapter {
|
|
6
|
+
number: string;
|
|
7
|
+
title: string;
|
|
8
|
+
articles: string[];
|
|
9
|
+
}
|
|
10
|
+
export interface RegulationInfo {
|
|
11
|
+
id: string;
|
|
12
|
+
full_name: string;
|
|
13
|
+
celex_id: string;
|
|
14
|
+
effective_date: string | null;
|
|
15
|
+
article_count: number;
|
|
16
|
+
chapters?: Chapter[];
|
|
17
|
+
}
|
|
18
|
+
export interface ListResult {
|
|
19
|
+
regulations: RegulationInfo[];
|
|
20
|
+
}
|
|
21
|
+
export declare function listRegulations(db: Database, input: ListInput): Promise<ListResult>;
|
|
22
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/tools/list.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,SAAS;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAED,wBAAsB,eAAe,CACnC,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,UAAU,CAAC,CAuFrB"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export async function listRegulations(db, input) {
|
|
2
|
+
const { regulation } = input;
|
|
3
|
+
if (regulation) {
|
|
4
|
+
// Get specific regulation with chapters
|
|
5
|
+
const regRow = db.prepare(`
|
|
6
|
+
SELECT id, full_name, celex_id, effective_date
|
|
7
|
+
FROM regulations
|
|
8
|
+
WHERE id = ?
|
|
9
|
+
`).get(regulation);
|
|
10
|
+
if (!regRow) {
|
|
11
|
+
return { regulations: [] };
|
|
12
|
+
}
|
|
13
|
+
// Get articles grouped by chapter
|
|
14
|
+
const articles = db.prepare(`
|
|
15
|
+
SELECT article_number, title, chapter
|
|
16
|
+
FROM articles
|
|
17
|
+
WHERE regulation = ?
|
|
18
|
+
ORDER BY CAST(article_number AS INTEGER)
|
|
19
|
+
`).all(regulation);
|
|
20
|
+
// Group by chapter
|
|
21
|
+
const chapterMap = new Map();
|
|
22
|
+
for (const article of articles) {
|
|
23
|
+
const chapterKey = article.chapter || 'General';
|
|
24
|
+
if (!chapterMap.has(chapterKey)) {
|
|
25
|
+
chapterMap.set(chapterKey, {
|
|
26
|
+
number: chapterKey,
|
|
27
|
+
title: `Chapter ${chapterKey}`,
|
|
28
|
+
articles: [],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
chapterMap.get(chapterKey).articles.push(article.article_number);
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
regulations: [{
|
|
35
|
+
id: regRow.id,
|
|
36
|
+
full_name: regRow.full_name,
|
|
37
|
+
celex_id: regRow.celex_id,
|
|
38
|
+
effective_date: regRow.effective_date,
|
|
39
|
+
article_count: articles.length,
|
|
40
|
+
chapters: Array.from(chapterMap.values()),
|
|
41
|
+
}],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// List all regulations with article counts
|
|
45
|
+
const rows = db.prepare(`
|
|
46
|
+
SELECT
|
|
47
|
+
r.id,
|
|
48
|
+
r.full_name,
|
|
49
|
+
r.celex_id,
|
|
50
|
+
r.effective_date,
|
|
51
|
+
COUNT(a.rowid) as article_count
|
|
52
|
+
FROM regulations r
|
|
53
|
+
LEFT JOIN articles a ON a.regulation = r.id
|
|
54
|
+
GROUP BY r.id
|
|
55
|
+
ORDER BY r.id
|
|
56
|
+
`).all();
|
|
57
|
+
return {
|
|
58
|
+
regulations: rows.map(row => ({
|
|
59
|
+
id: row.id,
|
|
60
|
+
full_name: row.full_name,
|
|
61
|
+
celex_id: row.celex_id,
|
|
62
|
+
effective_date: row.effective_date,
|
|
63
|
+
article_count: row.article_count,
|
|
64
|
+
})),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=list.js.map
|