@rog0x/mcp-testing-tools 1.0.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.
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Parse test files and source files to identify untested functions
3
+ * and suggest which functions need tests most, based on complexity
4
+ * and public API surface.
5
+ */
6
+
7
+ interface FunctionInfo {
8
+ name: string;
9
+ line: number;
10
+ isExported: boolean;
11
+ isAsync: boolean;
12
+ paramCount: number;
13
+ estimatedComplexity: number;
14
+ hasBranching: boolean;
15
+ }
16
+
17
+ interface CoverageResult {
18
+ sourceFile: string;
19
+ totalFunctions: number;
20
+ exportedFunctions: number;
21
+ testedFunctions: string[];
22
+ untestedFunctions: FunctionInfo[];
23
+ suggestions: Suggestion[];
24
+ }
25
+
26
+ interface Suggestion {
27
+ functionName: string;
28
+ priority: "high" | "medium" | "low";
29
+ reason: string;
30
+ }
31
+
32
+ function extractFunctions(sourceCode: string): FunctionInfo[] {
33
+ const functions: FunctionInfo[] = [];
34
+ const lines = sourceCode.split("\n");
35
+
36
+ // Patterns for function declarations
37
+ const patterns = [
38
+ // export function name(...)
39
+ /^(\s*)(export\s+)?(async\s+)?function\s+(\w+)\s*\(([^)]*)\)/,
40
+ // export const name = (...) =>
41
+ /^(\s*)(export\s+)?(const|let|var)\s+(\w+)\s*=\s*(async\s+)?\(([^)]*)\)\s*(:\s*\S+)?\s*=>/,
42
+ // export const name = function(...)
43
+ /^(\s*)(export\s+)?(const|let|var)\s+(\w+)\s*=\s*(async\s+)?function\s*\(([^)]*)\)/,
44
+ // class method: name(...) or async name(...)
45
+ /^(\s+)(public\s+|private\s+|protected\s+)?(static\s+)?(async\s+)?(\w+)\s*\(([^)]*)\)\s*(:\s*\S+)?\s*\{/,
46
+ ];
47
+
48
+ for (let i = 0; i < lines.length; i++) {
49
+ const line = lines[i];
50
+
51
+ // Standard function declaration
52
+ const funcMatch = line.match(patterns[0]);
53
+ if (funcMatch) {
54
+ const name = funcMatch[4];
55
+ const isExported = !!funcMatch[2];
56
+ const isAsync = !!funcMatch[3];
57
+ const params = funcMatch[5].trim();
58
+ const paramCount = params ? params.split(",").length : 0;
59
+ const complexity = estimateComplexity(sourceCode, i, lines);
60
+ functions.push({
61
+ name,
62
+ line: i + 1,
63
+ isExported,
64
+ isAsync,
65
+ paramCount,
66
+ estimatedComplexity: complexity,
67
+ hasBranching: complexity > 1,
68
+ });
69
+ continue;
70
+ }
71
+
72
+ // Arrow function
73
+ const arrowMatch = line.match(patterns[1]);
74
+ if (arrowMatch) {
75
+ const name = arrowMatch[4];
76
+ const isExported = !!arrowMatch[2];
77
+ const isAsync = !!arrowMatch[5];
78
+ const params = arrowMatch[6].trim();
79
+ const paramCount = params ? params.split(",").length : 0;
80
+ const complexity = estimateComplexity(sourceCode, i, lines);
81
+ functions.push({
82
+ name,
83
+ line: i + 1,
84
+ isExported,
85
+ isAsync,
86
+ paramCount,
87
+ estimatedComplexity: complexity,
88
+ hasBranching: complexity > 1,
89
+ });
90
+ continue;
91
+ }
92
+
93
+ // Function expression
94
+ const exprMatch = line.match(patterns[2]);
95
+ if (exprMatch) {
96
+ const name = exprMatch[4];
97
+ const isExported = !!exprMatch[2];
98
+ const isAsync = !!exprMatch[5];
99
+ const params = exprMatch[6].trim();
100
+ const paramCount = params ? params.split(",").length : 0;
101
+ const complexity = estimateComplexity(sourceCode, i, lines);
102
+ functions.push({
103
+ name,
104
+ line: i + 1,
105
+ isExported,
106
+ isAsync,
107
+ paramCount,
108
+ estimatedComplexity: complexity,
109
+ hasBranching: complexity > 1,
110
+ });
111
+ continue;
112
+ }
113
+
114
+ // Class method
115
+ const methodMatch = line.match(patterns[3]);
116
+ if (methodMatch) {
117
+ const name = methodMatch[5];
118
+ if (name === "constructor" || name === "if" || name === "for" || name === "while" || name === "switch") continue;
119
+ const visibility = (methodMatch[2] || "").trim();
120
+ const isExported = visibility !== "private";
121
+ const isAsync = !!methodMatch[4];
122
+ const params = methodMatch[6].trim();
123
+ const paramCount = params ? params.split(",").length : 0;
124
+ const complexity = estimateComplexity(sourceCode, i, lines);
125
+ functions.push({
126
+ name,
127
+ line: i + 1,
128
+ isExported,
129
+ isAsync,
130
+ paramCount,
131
+ estimatedComplexity: complexity,
132
+ hasBranching: complexity > 1,
133
+ });
134
+ }
135
+ }
136
+
137
+ return functions;
138
+ }
139
+
140
+ function estimateComplexity(source: string, startLine: number, lines: string[]): number {
141
+ // Count branching keywords in the function body (approximate)
142
+ let complexity = 1; // base complexity
143
+ let braceDepth = 0;
144
+ let started = false;
145
+
146
+ for (let i = startLine; i < Math.min(startLine + 200, lines.length); i++) {
147
+ const line = lines[i];
148
+ for (const ch of line) {
149
+ if (ch === "{") {
150
+ braceDepth++;
151
+ started = true;
152
+ }
153
+ if (ch === "}") braceDepth--;
154
+ }
155
+ if (started && braceDepth === 0) break;
156
+
157
+ // Count branching constructs
158
+ if (/\bif\s*\(/.test(line)) complexity++;
159
+ if (/\belse\s+if\s*\(/.test(line)) complexity++;
160
+ if (/\belse\s*\{/.test(line)) complexity++;
161
+ if (/\bfor\s*\(/.test(line)) complexity++;
162
+ if (/\bwhile\s*\(/.test(line)) complexity++;
163
+ if (/\bswitch\s*\(/.test(line)) complexity++;
164
+ if (/\bcase\s+/.test(line)) complexity++;
165
+ if (/\bcatch\s*\(/.test(line)) complexity++;
166
+ if (/\?\?/.test(line)) complexity++;
167
+ if (/\?\./.test(line)) complexity++;
168
+ if (/\b\?\s/.test(line) && /:/.test(line)) complexity++; // ternary
169
+ }
170
+
171
+ return complexity;
172
+ }
173
+
174
+ function extractTestedNames(testCode: string): string[] {
175
+ const tested = new Set<string>();
176
+
177
+ // Match patterns like: describe("functionName" / it("should ... functionName"
178
+ const describeMatches = testCode.matchAll(/describe\s*\(\s*["'`]([^"'`]+)["'`]/g);
179
+ for (const m of describeMatches) {
180
+ const name = m[1].trim();
181
+ // If it looks like a function name (single word, camelCase, etc.)
182
+ if (/^\w+$/.test(name)) {
183
+ tested.add(name);
184
+ }
185
+ }
186
+
187
+ // Match direct function calls in test blocks
188
+ const callMatches = testCode.matchAll(/(?:expect|assert)\s*\(\s*(?:await\s+)?(\w+)\s*\(/g);
189
+ for (const m of callMatches) {
190
+ tested.add(m[1]);
191
+ }
192
+
193
+ // Match imports
194
+ const importMatches = testCode.matchAll(/import\s*\{([^}]+)\}/g);
195
+ for (const m of importMatches) {
196
+ const names = m[1].split(",").map((n) => n.trim().split(/\s+as\s+/)[0].trim());
197
+ for (const name of names) {
198
+ if (name) tested.add(name);
199
+ }
200
+ }
201
+
202
+ // Match require destructuring
203
+ const requireMatches = testCode.matchAll(/const\s*\{([^}]+)\}\s*=\s*require/g);
204
+ for (const m of requireMatches) {
205
+ const names = m[1].split(",").map((n) => n.trim().split(/\s*:\s*/)[0].trim());
206
+ for (const name of names) {
207
+ if (name) tested.add(name);
208
+ }
209
+ }
210
+
211
+ return Array.from(tested);
212
+ }
213
+
214
+ function prioritize(fn: FunctionInfo): { priority: "high" | "medium" | "low"; reason: string } {
215
+ const reasons: string[] = [];
216
+ let score = 0;
217
+
218
+ if (fn.isExported) {
219
+ score += 3;
220
+ reasons.push("exported/public API");
221
+ }
222
+ if (fn.estimatedComplexity > 5) {
223
+ score += 3;
224
+ reasons.push(`high complexity (${fn.estimatedComplexity})`);
225
+ } else if (fn.estimatedComplexity > 2) {
226
+ score += 2;
227
+ reasons.push(`moderate complexity (${fn.estimatedComplexity})`);
228
+ }
229
+ if (fn.paramCount >= 3) {
230
+ score += 1;
231
+ reasons.push(`${fn.paramCount} parameters`);
232
+ }
233
+ if (fn.hasBranching) {
234
+ score += 1;
235
+ reasons.push("contains branching logic");
236
+ }
237
+ if (fn.isAsync) {
238
+ score += 1;
239
+ reasons.push("async (potential error paths)");
240
+ }
241
+
242
+ const priority = score >= 5 ? "high" : score >= 3 ? "medium" : "low";
243
+ return { priority, reason: reasons.join("; ") };
244
+ }
245
+
246
+ export function analyzeCoverage(
247
+ sourceCode: string,
248
+ testCode: string,
249
+ sourceFileName: string = "source.ts"
250
+ ): CoverageResult {
251
+ const functions = extractFunctions(sourceCode);
252
+ const testedNames = extractTestedNames(testCode);
253
+
254
+ const testedFunctions: string[] = [];
255
+ const untestedFunctions: FunctionInfo[] = [];
256
+
257
+ for (const fn of functions) {
258
+ if (testedNames.includes(fn.name)) {
259
+ testedFunctions.push(fn.name);
260
+ } else {
261
+ untestedFunctions.push(fn);
262
+ }
263
+ }
264
+
265
+ const suggestions: Suggestion[] = untestedFunctions
266
+ .map((fn) => {
267
+ const { priority, reason } = prioritize(fn);
268
+ return { functionName: fn.name, priority, reason };
269
+ })
270
+ .sort((a, b) => {
271
+ const order = { high: 0, medium: 1, low: 2 };
272
+ return order[a.priority] - order[b.priority];
273
+ });
274
+
275
+ return {
276
+ sourceFile: sourceFileName,
277
+ totalFunctions: functions.length,
278
+ exportedFunctions: functions.filter((f) => f.isExported).length,
279
+ testedFunctions,
280
+ untestedFunctions,
281
+ suggestions,
282
+ };
283
+ }
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Generate test cases from a function signature.
3
+ * Produces happy path, edge cases, error cases, and boundary value tests
4
+ * as Jest/Vitest-compatible test code.
5
+ */
6
+
7
+ interface FunctionParam {
8
+ name: string;
9
+ type: string;
10
+ optional?: boolean;
11
+ defaultValue?: string;
12
+ }
13
+
14
+ interface ParsedSignature {
15
+ name: string;
16
+ params: FunctionParam[];
17
+ returnType: string;
18
+ isAsync: boolean;
19
+ }
20
+
21
+ function parseSignature(signature: string): ParsedSignature {
22
+ const asyncMatch = signature.trim().startsWith("async");
23
+ const cleaned = signature.replace(/^(export\s+)?(async\s+)?function\s+/, "").trim();
24
+ const nameMatch = cleaned.match(/^(\w+)/);
25
+ const name = nameMatch ? nameMatch[1] : "unknownFunction";
26
+
27
+ const paramsMatch = cleaned.match(/\(([^)]*)\)/);
28
+ const paramsStr = paramsMatch ? paramsMatch[1].trim() : "";
29
+ const returnMatch = cleaned.match(/\):\s*(.+?)(\s*\{|$)/);
30
+ const returnType = returnMatch ? returnMatch[1].trim() : "void";
31
+
32
+ const params: FunctionParam[] = [];
33
+ if (paramsStr) {
34
+ const paramParts = splitParams(paramsStr);
35
+ for (const part of paramParts) {
36
+ const trimmed = part.trim();
37
+ if (!trimmed) continue;
38
+ const optional = trimmed.includes("?:");
39
+ const defaultMatch = trimmed.match(/=\s*(.+)$/);
40
+ const cleanPart = trimmed.replace(/\s*=\s*.+$/, "").trim();
41
+ const colonIdx = cleanPart.indexOf(":");
42
+ let paramName: string;
43
+ let paramType: string;
44
+ if (colonIdx !== -1) {
45
+ paramName = cleanPart.slice(0, colonIdx).replace("?", "").trim();
46
+ paramType = cleanPart.slice(colonIdx + 1).trim();
47
+ } else {
48
+ paramName = cleanPart.replace("?", "").trim();
49
+ paramType = "unknown";
50
+ }
51
+ params.push({
52
+ name: paramName,
53
+ type: paramType,
54
+ optional: optional || !!defaultMatch,
55
+ defaultValue: defaultMatch ? defaultMatch[1].trim() : undefined,
56
+ });
57
+ }
58
+ }
59
+
60
+ return { name, params, returnType, isAsync: asyncMatch };
61
+ }
62
+
63
+ function splitParams(str: string): string[] {
64
+ const results: string[] = [];
65
+ let depth = 0;
66
+ let current = "";
67
+ for (const ch of str) {
68
+ if (ch === "<" || ch === "(" || ch === "[" || ch === "{") depth++;
69
+ if (ch === ">" || ch === ")" || ch === "]" || ch === "}") depth--;
70
+ if (ch === "," && depth === 0) {
71
+ results.push(current);
72
+ current = "";
73
+ } else {
74
+ current += ch;
75
+ }
76
+ }
77
+ if (current.trim()) results.push(current);
78
+ return results;
79
+ }
80
+
81
+ function sampleValueForType(type: string, variant: "happy" | "edge" | "boundary"): string {
82
+ const t = type.toLowerCase().replace(/\s/g, "");
83
+
84
+ if (t === "string" || t.includes("string")) {
85
+ switch (variant) {
86
+ case "happy": return '"hello world"';
87
+ case "edge": return '""';
88
+ case "boundary": return '"a".repeat(10000)';
89
+ }
90
+ }
91
+ if (t === "number" || t.includes("number")) {
92
+ switch (variant) {
93
+ case "happy": return "42";
94
+ case "edge": return "0";
95
+ case "boundary": return "Number.MAX_SAFE_INTEGER";
96
+ }
97
+ }
98
+ if (t === "boolean" || t.includes("boolean")) {
99
+ return variant === "happy" ? "true" : "false";
100
+ }
101
+ if (t.endsWith("[]") || t.startsWith("array")) {
102
+ switch (variant) {
103
+ case "happy": return "[1, 2, 3]";
104
+ case "edge": return "[]";
105
+ case "boundary": return "Array.from({ length: 10000 }, (_, i) => i)";
106
+ }
107
+ }
108
+ if (t === "object" || t.startsWith("{")) {
109
+ switch (variant) {
110
+ case "happy": return '{ key: "value" }';
111
+ case "edge": return "{}";
112
+ case "boundary": return "Object.create(null)";
113
+ }
114
+ }
115
+ if (t === "date") {
116
+ switch (variant) {
117
+ case "happy": return 'new Date("2025-06-15")';
118
+ case "edge": return "new Date(0)";
119
+ case "boundary": return 'new Date("9999-12-31")';
120
+ }
121
+ }
122
+ if (t.includes("|")) {
123
+ const parts = t.split("|").map((p) => p.trim());
124
+ return sampleValueForType(parts[0], variant);
125
+ }
126
+ if (t === "null") return "null";
127
+ if (t === "undefined") return "undefined";
128
+ return variant === "happy" ? "{}" : "undefined";
129
+ }
130
+
131
+ function buildArgs(params: FunctionParam[], variant: "happy" | "edge" | "boundary", omitOptional: boolean): string {
132
+ const args: string[] = [];
133
+ for (const p of params) {
134
+ if (omitOptional && p.optional) continue;
135
+ args.push(sampleValueForType(p.type, variant));
136
+ }
137
+ return args.join(", ");
138
+ }
139
+
140
+ function generateReturnAssertion(returnType: string, callExpr: string, isAsync: boolean): string {
141
+ const awaited = isAsync ? `await ${callExpr}` : callExpr;
142
+ const t = returnType.toLowerCase().replace(/\s/g, "");
143
+
144
+ if (t === "void" || t === "promise<void>") {
145
+ return ` expect(${awaited}).toBeUndefined();`;
146
+ }
147
+ if (t === "boolean" || t === "promise<boolean>") {
148
+ return ` expect(typeof (${awaited})).toBe("boolean");`;
149
+ }
150
+ if (t === "string" || t === "promise<string>") {
151
+ return ` expect(typeof (${awaited})).toBe("string");`;
152
+ }
153
+ if (t === "number" || t === "promise<number>") {
154
+ return ` expect(typeof (${awaited})).toBe("number");`;
155
+ }
156
+ if (t.endsWith("[]") || t.startsWith("array") || t.includes("promise<") && t.includes("[]")) {
157
+ return ` const result = ${awaited};\n expect(Array.isArray(result)).toBe(true);`;
158
+ }
159
+ return ` const result = ${awaited};\n expect(result).toBeDefined();`;
160
+ }
161
+
162
+ export function generateTests(
163
+ signature: string,
164
+ framework: string = "vitest",
165
+ modulePath: string = "./module"
166
+ ): string {
167
+ const parsed = parseSignature(signature);
168
+ const fn = parsed.isAsync ? "async " : "";
169
+ const importStatement =
170
+ framework === "jest"
171
+ ? `const { ${parsed.name} } = require("${modulePath}");`
172
+ : `import { ${parsed.name} } from "${modulePath}";`;
173
+
174
+ const lines: string[] = [];
175
+ lines.push(importStatement);
176
+ lines.push("");
177
+ lines.push(`describe("${parsed.name}", () => {`);
178
+
179
+ // Happy path
180
+ lines.push(` describe("happy path", () => {`);
181
+ const happyArgs = buildArgs(parsed.params, "happy", false);
182
+ lines.push(` it("should return expected result with valid inputs", ${fn}() => {`);
183
+ lines.push(generateReturnAssertion(parsed.returnType, `${parsed.name}(${happyArgs})`, parsed.isAsync));
184
+ lines.push(" });");
185
+
186
+ if (parsed.params.some((p) => p.optional)) {
187
+ const minArgs = buildArgs(parsed.params, "happy", true);
188
+ lines.push("");
189
+ lines.push(` it("should work with only required parameters", ${fn}() => {`);
190
+ lines.push(generateReturnAssertion(parsed.returnType, `${parsed.name}(${minArgs})`, parsed.isAsync));
191
+ lines.push(" });");
192
+ }
193
+ lines.push(" });");
194
+
195
+ // Edge cases
196
+ lines.push("");
197
+ lines.push(` describe("edge cases", () => {`);
198
+ const edgeArgs = buildArgs(parsed.params, "edge", false);
199
+ lines.push(` it("should handle edge-case inputs gracefully", ${fn}() => {`);
200
+ if (parsed.isAsync) {
201
+ lines.push(` await expect(${parsed.name}(${edgeArgs})).resolves.toBeDefined();`);
202
+ } else {
203
+ lines.push(` expect(() => ${parsed.name}(${edgeArgs})).not.toThrow();`);
204
+ }
205
+ lines.push(" });");
206
+
207
+ // null/undefined for each param
208
+ for (const param of parsed.params) {
209
+ if (!param.optional) {
210
+ lines.push("");
211
+ lines.push(` it("should handle null ${param.name}", ${fn}() => {`);
212
+ const nullArgs = parsed.params.map((p) => (p.name === param.name ? "null as any" : sampleValueForType(p.type, "happy"))).join(", ");
213
+ if (parsed.isAsync) {
214
+ lines.push(` await expect(${parsed.name}(${nullArgs})).rejects.toThrow();`);
215
+ } else {
216
+ lines.push(` expect(() => ${parsed.name}(${nullArgs})).toThrow();`);
217
+ }
218
+ lines.push(" });");
219
+ }
220
+ }
221
+ lines.push(" });");
222
+
223
+ // Error cases
224
+ lines.push("");
225
+ lines.push(` describe("error cases", () => {`);
226
+ if (parsed.params.length > 0) {
227
+ lines.push(` it("should throw when called with no arguments", ${fn}() => {`);
228
+ if (parsed.isAsync) {
229
+ lines.push(` // @ts-expect-error testing missing arguments`);
230
+ lines.push(` await expect(${parsed.name}()).rejects.toThrow();`);
231
+ } else {
232
+ lines.push(` // @ts-expect-error testing missing arguments`);
233
+ lines.push(` expect(() => ${parsed.name}()).toThrow();`);
234
+ }
235
+ lines.push(" });");
236
+
237
+ lines.push("");
238
+ lines.push(` it("should throw with wrong argument types", ${fn}() => {`);
239
+ const wrongArgs = parsed.params.map(() => "Symbol() as any").join(", ");
240
+ if (parsed.isAsync) {
241
+ lines.push(` await expect(${parsed.name}(${wrongArgs})).rejects.toThrow();`);
242
+ } else {
243
+ lines.push(` expect(() => ${parsed.name}(${wrongArgs})).toThrow();`);
244
+ }
245
+ lines.push(" });");
246
+ } else {
247
+ lines.push(` // No parameters — limited error scenarios`);
248
+ lines.push(` it("should not throw when called", ${fn}() => {`);
249
+ if (parsed.isAsync) {
250
+ lines.push(` await expect(${parsed.name}()).resolves.toBeDefined();`);
251
+ } else {
252
+ lines.push(` expect(() => ${parsed.name}()).not.toThrow();`);
253
+ }
254
+ lines.push(" });");
255
+ }
256
+ lines.push(" });");
257
+
258
+ // Boundary values
259
+ lines.push("");
260
+ lines.push(` describe("boundary values", () => {`);
261
+ const boundaryArgs = buildArgs(parsed.params, "boundary", false);
262
+ lines.push(` it("should handle extreme values", ${fn}() => {`);
263
+ if (parsed.isAsync) {
264
+ lines.push(` await expect(${parsed.name}(${boundaryArgs})).resolves.toBeDefined();`);
265
+ } else {
266
+ lines.push(` expect(() => ${parsed.name}(${boundaryArgs})).not.toThrow();`);
267
+ }
268
+ lines.push(" });");
269
+
270
+ // Negative numbers for number params
271
+ const numericParams = parsed.params.filter((p) => p.type.toLowerCase().includes("number"));
272
+ for (const param of numericParams) {
273
+ lines.push("");
274
+ lines.push(` it("should handle negative value for ${param.name}", ${fn}() => {`);
275
+ const negArgs = parsed.params.map((p) => (p.name === param.name ? "-1" : sampleValueForType(p.type, "happy"))).join(", ");
276
+ lines.push(` const call = () => ${parsed.name}(${negArgs});`);
277
+ if (parsed.isAsync) {
278
+ lines.push(` // Depending on implementation, may resolve or reject`);
279
+ lines.push(` await expect(call()).resolves.toBeDefined();`);
280
+ } else {
281
+ lines.push(` // Depending on implementation, may return or throw`);
282
+ lines.push(` expect(call).not.toThrow();`);
283
+ }
284
+ lines.push(" });");
285
+
286
+ lines.push("");
287
+ lines.push(` it("should handle NaN for ${param.name}", ${fn}() => {`);
288
+ const nanArgs = parsed.params.map((p) => (p.name === param.name ? "NaN" : sampleValueForType(p.type, "happy"))).join(", ");
289
+ if (parsed.isAsync) {
290
+ lines.push(` await expect(${parsed.name}(${nanArgs})).rejects.toThrow();`);
291
+ } else {
292
+ lines.push(` expect(() => ${parsed.name}(${nanArgs})).toThrow();`);
293
+ }
294
+ lines.push(" });");
295
+ }
296
+ lines.push(" });");
297
+
298
+ lines.push("});");
299
+ return lines.join("\n");
300
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "moduleResolution": "Node16",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }