zotero-bridge 1.0.1

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/src/pdf.ts ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * ZoteroBridge - PDF Processing Module
3
+ *
4
+ * Handles PDF text extraction and content analysis
5
+ *
6
+ * @author Combjellyshen
7
+ */
8
+
9
+ import { readFileSync, existsSync } from 'fs';
10
+ import { join } from 'path';
11
+ // @ts-ignore - pdf-parse doesn't have type definitions
12
+ import pdfParse from 'pdf-parse';
13
+ import { ZoteroDatabase } from './database.js';
14
+
15
+ export interface PDFContent {
16
+ text: string;
17
+ numPages: number;
18
+ info: Record<string, any>;
19
+ metadata: Record<string, any> | null;
20
+ }
21
+
22
+ export interface PDFSummary {
23
+ itemID: number;
24
+ title: string;
25
+ numPages: number;
26
+ wordCount: number;
27
+ preview: string;
28
+ path: string;
29
+ }
30
+
31
+ export class PDFProcessor {
32
+ private db: ZoteroDatabase;
33
+
34
+ constructor(db: ZoteroDatabase) {
35
+ this.db = db;
36
+ }
37
+
38
+ /**
39
+ * Extract text from a PDF file
40
+ */
41
+ async extractText(pdfPath: string): Promise<PDFContent> {
42
+ if (!existsSync(pdfPath)) {
43
+ throw new Error(`PDF file not found: ${pdfPath}`);
44
+ }
45
+
46
+ const buffer = readFileSync(pdfPath);
47
+ const data = await pdfParse(buffer);
48
+
49
+ return {
50
+ text: data.text,
51
+ numPages: data.numpages,
52
+ info: data.info || {},
53
+ metadata: data.metadata || null
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Extract text from a PDF attachment by item ID
59
+ */
60
+ async extractTextFromAttachment(attachmentItemID: number): Promise<PDFContent | null> {
61
+ const path = this.db.getAttachmentPath(attachmentItemID);
62
+
63
+ if (!path) {
64
+ return null;
65
+ }
66
+
67
+ return this.extractText(path);
68
+ }
69
+
70
+ /**
71
+ * Extract text from all PDF attachments of a parent item
72
+ */
73
+ async extractTextFromItem(parentItemID: number): Promise<Map<number, PDFContent>> {
74
+ const attachments = this.db.getPDFAttachments(parentItemID);
75
+ const results = new Map<number, PDFContent>();
76
+
77
+ for (const att of attachments) {
78
+ const path = this.db.getAttachmentPath(att.itemID);
79
+ if (path && existsSync(path)) {
80
+ try {
81
+ const content = await this.extractText(path);
82
+ results.set(att.itemID, content);
83
+ } catch (error) {
84
+ console.error(`Failed to extract PDF ${att.itemID}: ${error}`);
85
+ }
86
+ }
87
+ }
88
+
89
+ return results;
90
+ }
91
+
92
+ /**
93
+ * Get a summary of a PDF attachment
94
+ */
95
+ async getPDFSummary(attachmentItemID: number): Promise<PDFSummary | null> {
96
+ const path = this.db.getAttachmentPath(attachmentItemID);
97
+
98
+ if (!path || !existsSync(path)) {
99
+ return null;
100
+ }
101
+
102
+ try {
103
+ const content = await this.extractText(path);
104
+ const title = content.info?.Title || path.split(/[/\\]/).pop() || 'Unknown';
105
+ const wordCount = content.text.split(/\s+/).length;
106
+ const preview = content.text.substring(0, 500).replace(/\s+/g, ' ').trim();
107
+
108
+ return {
109
+ itemID: attachmentItemID,
110
+ title,
111
+ numPages: content.numPages,
112
+ wordCount,
113
+ preview,
114
+ path
115
+ };
116
+ } catch (error) {
117
+ return null;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Generate an abstract/summary from PDF content
123
+ * This is a simple extraction - for AI-generated summaries,
124
+ * use the extracted text with an LLM
125
+ */
126
+ generateSimpleSummary(content: PDFContent, maxLength: number = 1000): string {
127
+ const text = content.text;
128
+
129
+ // Try to find abstract section
130
+ const abstractMatch = text.match(/abstract[:\s]*\n?([\s\S]{100,2000}?)(?=\n\s*(?:introduction|keywords|1\.|background))/i);
131
+ if (abstractMatch) {
132
+ return abstractMatch[1].replace(/\s+/g, ' ').trim().substring(0, maxLength);
133
+ }
134
+
135
+ // Try to find introduction
136
+ const introMatch = text.match(/introduction[:\s]*\n?([\s\S]{100,2000}?)(?=\n\s*(?:2\.|background|related|method))/i);
137
+ if (introMatch) {
138
+ return introMatch[1].replace(/\s+/g, ' ').trim().substring(0, maxLength);
139
+ }
140
+
141
+ // Fall back to first paragraph
142
+ const paragraphs = text.split(/\n\s*\n/).filter(p => p.trim().length > 100);
143
+ if (paragraphs.length > 0) {
144
+ return paragraphs[0].replace(/\s+/g, ' ').trim().substring(0, maxLength);
145
+ }
146
+
147
+ return text.substring(0, maxLength).replace(/\s+/g, ' ').trim();
148
+ }
149
+
150
+ /**
151
+ * Search for text within PDF content
152
+ */
153
+ searchInPDF(content: PDFContent, query: string, caseSensitive: boolean = false): string[] {
154
+ const text = caseSensitive ? content.text : content.text.toLowerCase();
155
+ const searchQuery = caseSensitive ? query : query.toLowerCase();
156
+
157
+ const results: string[] = [];
158
+ const lines = text.split('\n');
159
+
160
+ for (let i = 0; i < lines.length; i++) {
161
+ if (lines[i].includes(searchQuery)) {
162
+ // Get context (previous and next lines)
163
+ const start = Math.max(0, i - 1);
164
+ const end = Math.min(lines.length - 1, i + 1);
165
+ const context = lines.slice(start, end + 1).join(' ').replace(/\s+/g, ' ').trim();
166
+ results.push(context);
167
+ }
168
+ }
169
+
170
+ return results;
171
+ }
172
+
173
+ /**
174
+ * Get PDF info/metadata
175
+ */
176
+ async getPDFInfo(pdfPath: string): Promise<Record<string, any>> {
177
+ const content = await this.extractText(pdfPath);
178
+ return {
179
+ ...content.info,
180
+ numPages: content.numPages,
181
+ metadata: content.metadata
182
+ };
183
+ }
184
+ }
package/src/tools.ts ADDED
@@ -0,0 +1,489 @@
1
+ /**
2
+ * ZoteroBridge - MCP Tool Definitions
3
+ *
4
+ * Defines all available MCP tools for Zotero operations
5
+ *
6
+ * @author Combjellyshen
7
+ */
8
+
9
+ import { z } from 'zod';
10
+
11
+ // ============================================
12
+ // Collection/Directory Tools
13
+ // ============================================
14
+
15
+ export const listCollectionsSchema = z.object({
16
+ libraryID: z.number().optional().default(1).describe('Library ID (default: 1 for personal library)')
17
+ });
18
+
19
+ export const getCollectionSchema = z.object({
20
+ collectionID: z.number().optional().describe('Collection ID'),
21
+ name: z.string().optional().describe('Collection name'),
22
+ libraryID: z.number().optional().default(1).describe('Library ID')
23
+ });
24
+
25
+ export const createCollectionSchema = z.object({
26
+ name: z.string().describe('Name of the new collection'),
27
+ parentCollectionID: z.number().optional().describe('Parent collection ID (null for root)'),
28
+ libraryID: z.number().optional().default(1).describe('Library ID')
29
+ });
30
+
31
+ export const renameCollectionSchema = z.object({
32
+ collectionID: z.number().describe('Collection ID to rename'),
33
+ newName: z.string().describe('New name for the collection')
34
+ });
35
+
36
+ export const moveCollectionSchema = z.object({
37
+ collectionID: z.number().describe('Collection ID to move'),
38
+ newParentID: z.number().nullable().describe('New parent collection ID (null for root)')
39
+ });
40
+
41
+ export const deleteCollectionSchema = z.object({
42
+ collectionID: z.number().describe('Collection ID to delete')
43
+ });
44
+
45
+ export const getSubcollectionsSchema = z.object({
46
+ parentCollectionID: z.number().describe('Parent collection ID')
47
+ });
48
+
49
+ // ============================================
50
+ // Tag Tools
51
+ // ============================================
52
+
53
+ export const listTagsSchema = z.object({});
54
+
55
+ export const addTagSchema = z.object({
56
+ itemID: z.number().describe('Item ID to add tag to'),
57
+ tagName: z.string().describe('Tag name to add'),
58
+ type: z.number().optional().default(0).describe('Tag type (0=user, 1=automatic)')
59
+ });
60
+
61
+ export const removeTagSchema = z.object({
62
+ itemID: z.number().describe('Item ID to remove tag from'),
63
+ tagName: z.string().describe('Tag name to remove')
64
+ });
65
+
66
+ export const getItemTagsSchema = z.object({
67
+ itemID: z.number().describe('Item ID to get tags for')
68
+ });
69
+
70
+ export const createTagSchema = z.object({
71
+ name: z.string().describe('Tag name to create'),
72
+ type: z.number().optional().default(0).describe('Tag type')
73
+ });
74
+
75
+ // ============================================
76
+ // Item Tools
77
+ // ============================================
78
+
79
+ export const searchItemsSchema = z.object({
80
+ query: z.string().describe('Search query for item titles'),
81
+ limit: z.number().optional().default(50).describe('Maximum number of results'),
82
+ libraryID: z.number().optional().default(1).describe('Library ID')
83
+ });
84
+
85
+ export const getItemDetailsSchema = z.object({
86
+ itemID: z.number().optional().describe('Item ID'),
87
+ itemKey: z.string().optional().describe('Item key')
88
+ });
89
+
90
+ export const addItemToCollectionSchema = z.object({
91
+ itemID: z.number().describe('Item ID to add'),
92
+ collectionID: z.number().describe('Collection ID to add item to')
93
+ });
94
+
95
+ export const removeItemFromCollectionSchema = z.object({
96
+ itemID: z.number().describe('Item ID to remove'),
97
+ collectionID: z.number().describe('Collection ID to remove item from')
98
+ });
99
+
100
+ export const getCollectionItemsSchema = z.object({
101
+ collectionID: z.number().describe('Collection ID to get items from')
102
+ });
103
+
104
+ // ============================================
105
+ // Abstract/Note Tools
106
+ // ============================================
107
+
108
+ export const getItemAbstractSchema = z.object({
109
+ itemID: z.number().describe('Item ID to get abstract for')
110
+ });
111
+
112
+ export const setItemAbstractSchema = z.object({
113
+ itemID: z.number().describe('Item ID to set abstract for'),
114
+ abstract: z.string().describe('Abstract text')
115
+ });
116
+
117
+ export const getItemNotesSchema = z.object({
118
+ itemID: z.number().describe('Item ID to get notes for')
119
+ });
120
+
121
+ export const addItemNoteSchema = z.object({
122
+ itemID: z.number().describe('Parent item ID'),
123
+ content: z.string().describe('Note content (can include HTML)'),
124
+ title: z.string().optional().default('').describe('Note title')
125
+ });
126
+
127
+ // ============================================
128
+ // PDF Tools
129
+ // ============================================
130
+
131
+ export const extractPDFTextSchema = z.object({
132
+ attachmentItemID: z.number().describe('Attachment item ID of the PDF')
133
+ });
134
+
135
+ export const getPDFSummarySchema = z.object({
136
+ attachmentItemID: z.number().describe('Attachment item ID of the PDF')
137
+ });
138
+
139
+ export const getItemPDFsSchema = z.object({
140
+ parentItemID: z.number().describe('Parent item ID to get PDFs from')
141
+ });
142
+
143
+ export const searchPDFSchema = z.object({
144
+ attachmentItemID: z.number().describe('Attachment item ID of the PDF'),
145
+ query: z.string().describe('Search query'),
146
+ caseSensitive: z.boolean().optional().default(false).describe('Case sensitive search')
147
+ });
148
+
149
+ export const generateAbstractFromPDFSchema = z.object({
150
+ attachmentItemID: z.number().describe('Attachment item ID of the PDF'),
151
+ maxLength: z.number().optional().default(1000).describe('Maximum length of generated abstract'),
152
+ saveToItem: z.boolean().optional().default(false).describe('Save generated abstract to parent item')
153
+ });
154
+
155
+ // ============================================
156
+ // Identifier Tools (DOI/ISBN)
157
+ // ============================================
158
+
159
+ export const findByDOISchema = z.object({
160
+ doi: z.string().describe('DOI to search for (with or without doi.org prefix)')
161
+ });
162
+
163
+ export const findByISBNSchema = z.object({
164
+ isbn: z.string().describe('ISBN to search for (with or without hyphens)')
165
+ });
166
+
167
+ export const findByIdentifierSchema = z.object({
168
+ identifier: z.string().describe('Identifier value (DOI, ISBN, PMID, etc.)'),
169
+ type: z.string().optional().describe('Identifier type: doi, isbn, pmid, arxiv, url')
170
+ });
171
+
172
+ // ============================================
173
+ // Annotation Tools
174
+ // ============================================
175
+
176
+ export const getItemAnnotationsSchema = z.object({
177
+ itemID: z.number().describe('Parent item ID to get annotations from')
178
+ });
179
+
180
+ export const getAttachmentAnnotationsSchema = z.object({
181
+ attachmentID: z.number().describe('Attachment item ID to get annotations from')
182
+ });
183
+
184
+ export const getAnnotationsByTypeSchema = z.object({
185
+ itemID: z.number().describe('Parent item ID'),
186
+ types: z.array(z.string()).describe('Annotation types: highlight, note, image, ink, underline')
187
+ });
188
+
189
+ export const getAnnotationsByColorSchema = z.object({
190
+ itemID: z.number().describe('Parent item ID'),
191
+ colors: z.array(z.string()).describe('Annotation colors (hex codes like #ffff00)')
192
+ });
193
+
194
+ export const searchAnnotationsSchema = z.object({
195
+ query: z.string().describe('Search query for annotation text/comments'),
196
+ itemID: z.number().optional().describe('Limit search to specific item')
197
+ });
198
+
199
+ // ============================================
200
+ // Fulltext Search Tools
201
+ // ============================================
202
+
203
+ export const searchFulltextSchema = z.object({
204
+ query: z.string().describe('Search query for fulltext content'),
205
+ libraryID: z.number().optional().default(1).describe('Library ID')
206
+ });
207
+
208
+ export const getFulltextContentSchema = z.object({
209
+ attachmentID: z.number().describe('Attachment item ID to get fulltext from')
210
+ });
211
+
212
+ export const searchFulltextWithContextSchema = z.object({
213
+ query: z.string().describe('Search query'),
214
+ contextLength: z.number().optional().default(100).describe('Characters of context around matches'),
215
+ libraryID: z.number().optional().default(1).describe('Library ID')
216
+ });
217
+
218
+ // ============================================
219
+ // Similar Items Tools
220
+ // ============================================
221
+
222
+ export const getRelatedItemsSchema = z.object({
223
+ itemID: z.number().describe('Item ID to get related items for')
224
+ });
225
+
226
+ export const findSimilarByTagsSchema = z.object({
227
+ itemID: z.number().describe('Item ID to find similar items for'),
228
+ minSharedTags: z.number().optional().default(2).describe('Minimum number of shared tags')
229
+ });
230
+
231
+ export const findSimilarByCreatorsSchema = z.object({
232
+ itemID: z.number().describe('Item ID to find similar items for')
233
+ });
234
+
235
+ export const findSimilarByCollectionSchema = z.object({
236
+ itemID: z.number().describe('Item ID to find similar items for')
237
+ });
238
+
239
+ // ============================================
240
+ // Utility Tools
241
+ // ============================================
242
+
243
+ export const getDatabaseInfoSchema = z.object({});
244
+
245
+ export const rawQuerySchema = z.object({
246
+ sql: z.string().describe('SQL query to execute (SELECT only)'),
247
+ params: z.array(z.any()).optional().default([]).describe('Query parameters')
248
+ });
249
+
250
+ // ============================================
251
+ // Tool Definitions
252
+ // ============================================
253
+
254
+ export const toolDefinitions = [
255
+ // Collection Tools
256
+ {
257
+ name: 'list_collections',
258
+ description: 'List all collections (folders) in the Zotero library',
259
+ inputSchema: listCollectionsSchema
260
+ },
261
+ {
262
+ name: 'get_collection',
263
+ description: 'Get a collection by ID or name',
264
+ inputSchema: getCollectionSchema
265
+ },
266
+ {
267
+ name: 'create_collection',
268
+ description: 'Create a new collection (folder)',
269
+ inputSchema: createCollectionSchema
270
+ },
271
+ {
272
+ name: 'rename_collection',
273
+ description: 'Rename an existing collection',
274
+ inputSchema: renameCollectionSchema
275
+ },
276
+ {
277
+ name: 'move_collection',
278
+ description: 'Move a collection to a new parent (or root)',
279
+ inputSchema: moveCollectionSchema
280
+ },
281
+ {
282
+ name: 'delete_collection',
283
+ description: 'Delete a collection',
284
+ inputSchema: deleteCollectionSchema
285
+ },
286
+ {
287
+ name: 'get_subcollections',
288
+ description: 'Get all subcollections of a collection',
289
+ inputSchema: getSubcollectionsSchema
290
+ },
291
+
292
+ // Tag Tools
293
+ {
294
+ name: 'list_tags',
295
+ description: 'List all tags in the library',
296
+ inputSchema: listTagsSchema
297
+ },
298
+ {
299
+ name: 'add_tag',
300
+ description: 'Add a tag to an item',
301
+ inputSchema: addTagSchema
302
+ },
303
+ {
304
+ name: 'remove_tag',
305
+ description: 'Remove a tag from an item',
306
+ inputSchema: removeTagSchema
307
+ },
308
+ {
309
+ name: 'get_item_tags',
310
+ description: 'Get all tags for an item',
311
+ inputSchema: getItemTagsSchema
312
+ },
313
+ {
314
+ name: 'create_tag',
315
+ description: 'Create a new tag',
316
+ inputSchema: createTagSchema
317
+ },
318
+
319
+ // Item Tools
320
+ {
321
+ name: 'search_items',
322
+ description: 'Search items by title',
323
+ inputSchema: searchItemsSchema
324
+ },
325
+ {
326
+ name: 'get_item_details',
327
+ description: 'Get detailed information about an item',
328
+ inputSchema: getItemDetailsSchema
329
+ },
330
+ {
331
+ name: 'add_item_to_collection',
332
+ description: 'Add an item to a collection',
333
+ inputSchema: addItemToCollectionSchema
334
+ },
335
+ {
336
+ name: 'remove_item_from_collection',
337
+ description: 'Remove an item from a collection',
338
+ inputSchema: removeItemFromCollectionSchema
339
+ },
340
+ {
341
+ name: 'get_collection_items',
342
+ description: 'Get all items in a collection',
343
+ inputSchema: getCollectionItemsSchema
344
+ },
345
+
346
+ // Abstract/Note Tools
347
+ {
348
+ name: 'get_item_abstract',
349
+ description: 'Get the abstract of an item',
350
+ inputSchema: getItemAbstractSchema
351
+ },
352
+ {
353
+ name: 'set_item_abstract',
354
+ description: 'Set or update the abstract of an item',
355
+ inputSchema: setItemAbstractSchema
356
+ },
357
+ {
358
+ name: 'get_item_notes',
359
+ description: 'Get all notes attached to an item',
360
+ inputSchema: getItemNotesSchema
361
+ },
362
+ {
363
+ name: 'add_item_note',
364
+ description: 'Add a note to an item',
365
+ inputSchema: addItemNoteSchema
366
+ },
367
+
368
+ // PDF Tools
369
+ {
370
+ name: 'extract_pdf_text',
371
+ description: 'Extract full text from a PDF attachment',
372
+ inputSchema: extractPDFTextSchema
373
+ },
374
+ {
375
+ name: 'get_pdf_summary',
376
+ description: 'Get summary information about a PDF',
377
+ inputSchema: getPDFSummarySchema
378
+ },
379
+ {
380
+ name: 'get_item_pdfs',
381
+ description: 'Get all PDF attachments for an item',
382
+ inputSchema: getItemPDFsSchema
383
+ },
384
+ {
385
+ name: 'search_pdf',
386
+ description: 'Search within a PDF for specific text',
387
+ inputSchema: searchPDFSchema
388
+ },
389
+ {
390
+ name: 'generate_abstract_from_pdf',
391
+ description: 'Extract and generate an abstract from PDF content',
392
+ inputSchema: generateAbstractFromPDFSchema
393
+ },
394
+
395
+ // Identifier Tools
396
+ {
397
+ name: 'find_by_doi',
398
+ description: 'Find an item by its DOI',
399
+ inputSchema: findByDOISchema
400
+ },
401
+ {
402
+ name: 'find_by_isbn',
403
+ description: 'Find an item by its ISBN',
404
+ inputSchema: findByISBNSchema
405
+ },
406
+ {
407
+ name: 'find_by_identifier',
408
+ description: 'Find an item by any identifier (DOI, ISBN, PMID, arXiv, URL)',
409
+ inputSchema: findByIdentifierSchema
410
+ },
411
+
412
+ // Annotation Tools
413
+ {
414
+ name: 'get_item_annotations',
415
+ description: 'Get all annotations (highlights, notes, etc.) from an item\'s PDF attachments',
416
+ inputSchema: getItemAnnotationsSchema
417
+ },
418
+ {
419
+ name: 'get_attachment_annotations',
420
+ description: 'Get annotations from a specific PDF attachment',
421
+ inputSchema: getAttachmentAnnotationsSchema
422
+ },
423
+ {
424
+ name: 'get_annotations_by_type',
425
+ description: 'Get annotations filtered by type (highlight, note, image, ink, underline)',
426
+ inputSchema: getAnnotationsByTypeSchema
427
+ },
428
+ {
429
+ name: 'get_annotations_by_color',
430
+ description: 'Get annotations filtered by color',
431
+ inputSchema: getAnnotationsByColorSchema
432
+ },
433
+ {
434
+ name: 'search_annotations',
435
+ description: 'Search annotations by text content',
436
+ inputSchema: searchAnnotationsSchema
437
+ },
438
+
439
+ // Fulltext Search Tools
440
+ {
441
+ name: 'search_fulltext',
442
+ description: 'Search in Zotero\'s fulltext index (searches indexed PDF content)',
443
+ inputSchema: searchFulltextSchema
444
+ },
445
+ {
446
+ name: 'get_fulltext_content',
447
+ description: 'Get the indexed fulltext content of an attachment',
448
+ inputSchema: getFulltextContentSchema
449
+ },
450
+ {
451
+ name: 'search_fulltext_with_context',
452
+ description: 'Search fulltext and return matching context snippets',
453
+ inputSchema: searchFulltextWithContextSchema
454
+ },
455
+
456
+ // Similar Items Tools
457
+ {
458
+ name: 'get_related_items',
459
+ description: 'Get manually linked related items',
460
+ inputSchema: getRelatedItemsSchema
461
+ },
462
+ {
463
+ name: 'find_similar_by_tags',
464
+ description: 'Find items with similar tags',
465
+ inputSchema: findSimilarByTagsSchema
466
+ },
467
+ {
468
+ name: 'find_similar_by_creators',
469
+ description: 'Find items by the same authors/creators',
470
+ inputSchema: findSimilarByCreatorsSchema
471
+ },
472
+ {
473
+ name: 'find_similar_by_collection',
474
+ description: 'Find items in the same collections',
475
+ inputSchema: findSimilarByCollectionSchema
476
+ },
477
+
478
+ // Utility Tools
479
+ {
480
+ name: 'get_database_info',
481
+ description: 'Get information about the Zotero database',
482
+ inputSchema: getDatabaseInfoSchema
483
+ },
484
+ {
485
+ name: 'raw_query',
486
+ description: 'Execute a raw SQL SELECT query (read-only)',
487
+ inputSchema: rawQuerySchema
488
+ }
489
+ ];
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true,
16
+ "resolveJsonModule": true
17
+ },
18
+ "include": ["src/**/*"],
19
+ "exclude": ["node_modules", "dist"]
20
+ }