@kirrosh/apitool 0.4.3

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 (191) hide show
  1. package/.github/workflows/ci.yml +27 -0
  2. package/.github/workflows/release.yml +97 -0
  3. package/.mcp.json +9 -0
  4. package/APITOOL.md +195 -0
  5. package/BACKLOG.md +62 -0
  6. package/CHANGELOG.md +88 -0
  7. package/LICENSE +21 -0
  8. package/README.md +105 -0
  9. package/bun.lock +291 -0
  10. package/docs/GLOSSARY.md +182 -0
  11. package/docs/INDEX.md +21 -0
  12. package/docs/agent.md +135 -0
  13. package/docs/archive/APITOOL-pre-M22.md +831 -0
  14. package/docs/archive/BACKLOG-AI-NATIVE.md +56 -0
  15. package/docs/archive/M1-M2-parser-runner.md +216 -0
  16. package/docs/archive/M4-M7-reporter-cli.md +179 -0
  17. package/docs/archive/M5-M7-storage-junit.md +300 -0
  18. package/docs/archive/M6-webui.md +339 -0
  19. package/docs/ci.md +274 -0
  20. package/docs/generation-issues.md +67 -0
  21. package/generated/.env.yaml +3 -0
  22. package/install.ps1 +80 -0
  23. package/install.sh +113 -0
  24. package/package.json +46 -0
  25. package/scripts/run-mocked-tests.ts +45 -0
  26. package/seed-demo.ts +53 -0
  27. package/self-tests/auth.yaml +18 -0
  28. package/self-tests/collections-crud.yaml +46 -0
  29. package/self-tests/environments-crud.yaml +48 -0
  30. package/self-tests/export.yaml +32 -0
  31. package/self-tests/runs.yaml +16 -0
  32. package/src/bun-types.d.ts +5 -0
  33. package/src/cli/commands/add-api.ts +51 -0
  34. package/src/cli/commands/ai-generate.ts +106 -0
  35. package/src/cli/commands/chat.ts +43 -0
  36. package/src/cli/commands/ci-init.ts +126 -0
  37. package/src/cli/commands/collections.ts +41 -0
  38. package/src/cli/commands/coverage.ts +65 -0
  39. package/src/cli/commands/doctor.ts +127 -0
  40. package/src/cli/commands/envs.ts +218 -0
  41. package/src/cli/commands/init.ts +84 -0
  42. package/src/cli/commands/mcp.ts +16 -0
  43. package/src/cli/commands/run.ts +137 -0
  44. package/src/cli/commands/runs.ts +108 -0
  45. package/src/cli/commands/serve.ts +22 -0
  46. package/src/cli/commands/update.ts +142 -0
  47. package/src/cli/commands/validate.ts +18 -0
  48. package/src/cli/index.ts +500 -0
  49. package/src/cli/output.ts +24 -0
  50. package/src/cli/runtime.ts +7 -0
  51. package/src/core/agent/agent-loop.ts +116 -0
  52. package/src/core/agent/context-manager.ts +41 -0
  53. package/src/core/agent/system-prompt.ts +33 -0
  54. package/src/core/agent/tools/diagnose-failure.ts +51 -0
  55. package/src/core/agent/tools/explore-api.ts +40 -0
  56. package/src/core/agent/tools/index.ts +48 -0
  57. package/src/core/agent/tools/manage-environment.ts +40 -0
  58. package/src/core/agent/tools/query-results.ts +40 -0
  59. package/src/core/agent/tools/run-tests.ts +38 -0
  60. package/src/core/agent/tools/send-request.ts +44 -0
  61. package/src/core/agent/tools/validate-tests.ts +23 -0
  62. package/src/core/agent/types.ts +22 -0
  63. package/src/core/generator/ai/ai-generator.ts +61 -0
  64. package/src/core/generator/ai/llm-client.ts +159 -0
  65. package/src/core/generator/ai/output-parser.ts +307 -0
  66. package/src/core/generator/ai/prompt-builder.ts +153 -0
  67. package/src/core/generator/ai/types.ts +56 -0
  68. package/src/core/generator/coverage-scanner.ts +87 -0
  69. package/src/core/generator/data-factory.ts +115 -0
  70. package/src/core/generator/index.ts +10 -0
  71. package/src/core/generator/openapi-reader.ts +142 -0
  72. package/src/core/generator/schema-utils.ts +52 -0
  73. package/src/core/generator/serializer.ts +189 -0
  74. package/src/core/generator/types.ts +47 -0
  75. package/src/core/parser/filter.ts +14 -0
  76. package/src/core/parser/index.ts +21 -0
  77. package/src/core/parser/schema.ts +175 -0
  78. package/src/core/parser/types.ts +50 -0
  79. package/src/core/parser/variables.ts +146 -0
  80. package/src/core/parser/yaml-parser.ts +85 -0
  81. package/src/core/reporter/console.ts +175 -0
  82. package/src/core/reporter/index.ts +23 -0
  83. package/src/core/reporter/json.ts +9 -0
  84. package/src/core/reporter/junit.ts +78 -0
  85. package/src/core/reporter/types.ts +12 -0
  86. package/src/core/runner/assertions.ts +172 -0
  87. package/src/core/runner/execute-run.ts +75 -0
  88. package/src/core/runner/executor.ts +150 -0
  89. package/src/core/runner/http-client.ts +69 -0
  90. package/src/core/runner/index.ts +12 -0
  91. package/src/core/runner/types.ts +48 -0
  92. package/src/core/setup-api.ts +97 -0
  93. package/src/core/utils.ts +9 -0
  94. package/src/db/queries.ts +868 -0
  95. package/src/db/schema.ts +215 -0
  96. package/src/mcp/server.ts +47 -0
  97. package/src/mcp/tools/ci-init.ts +57 -0
  98. package/src/mcp/tools/coverage-analysis.ts +58 -0
  99. package/src/mcp/tools/explore-api.ts +84 -0
  100. package/src/mcp/tools/generate-missing-tests.ts +80 -0
  101. package/src/mcp/tools/generate-tests-guide.ts +353 -0
  102. package/src/mcp/tools/manage-environment.ts +123 -0
  103. package/src/mcp/tools/manage-server.ts +87 -0
  104. package/src/mcp/tools/query-db.ts +141 -0
  105. package/src/mcp/tools/run-tests.ts +66 -0
  106. package/src/mcp/tools/save-test-suite.ts +164 -0
  107. package/src/mcp/tools/send-request.ts +53 -0
  108. package/src/mcp/tools/setup-api.ts +49 -0
  109. package/src/mcp/tools/validate-tests.ts +42 -0
  110. package/src/tui/chat-ui.ts +150 -0
  111. package/src/web/routes/api.ts +234 -0
  112. package/src/web/routes/dashboard.ts +348 -0
  113. package/src/web/routes/runs.ts +64 -0
  114. package/src/web/schemas.ts +121 -0
  115. package/src/web/server.ts +134 -0
  116. package/src/web/static/htmx.min.js +1 -0
  117. package/src/web/static/style.css +265 -0
  118. package/src/web/views/layout.ts +46 -0
  119. package/src/web/views/results.ts +209 -0
  120. package/tests/agent/agent-loop.test.ts +61 -0
  121. package/tests/agent/context-manager.test.ts +59 -0
  122. package/tests/agent/system-prompt.test.ts +42 -0
  123. package/tests/agent/tools/diagnose-failure.test.ts +85 -0
  124. package/tests/agent/tools/explore-api.test.ts +59 -0
  125. package/tests/agent/tools/manage-environment.test.ts +78 -0
  126. package/tests/agent/tools/query-results.test.ts +77 -0
  127. package/tests/agent/tools/run-tests.test.ts +89 -0
  128. package/tests/agent/tools/send-request.test.ts +78 -0
  129. package/tests/agent/tools/validate-tests.test.ts +59 -0
  130. package/tests/ai/ai-generator.integration.test.ts +131 -0
  131. package/tests/ai/llm-client.test.ts +145 -0
  132. package/tests/ai/output-parser.test.ts +132 -0
  133. package/tests/ai/prompt-builder.test.ts +67 -0
  134. package/tests/ai/types.test.ts +55 -0
  135. package/tests/cli/args.test.ts +63 -0
  136. package/tests/cli/chat.test.ts +38 -0
  137. package/tests/cli/ci-init.test.ts +112 -0
  138. package/tests/cli/commands.test.ts +316 -0
  139. package/tests/cli/coverage.test.ts +58 -0
  140. package/tests/cli/doctor.test.ts +39 -0
  141. package/tests/cli/envs.test.ts +181 -0
  142. package/tests/cli/init.test.ts +80 -0
  143. package/tests/cli/runs.test.ts +94 -0
  144. package/tests/cli/safe-run.test.ts +103 -0
  145. package/tests/cli/update.test.ts +32 -0
  146. package/tests/core/generator/schema-utils.test.ts +108 -0
  147. package/tests/core/parser/nested-assertions.test.ts +80 -0
  148. package/tests/core/runner/root-body-assertions.test.ts +70 -0
  149. package/tests/db/chat-queries.test.ts +88 -0
  150. package/tests/db/chat-schema.test.ts +37 -0
  151. package/tests/db/environments.test.ts +131 -0
  152. package/tests/db/queries.test.ts +409 -0
  153. package/tests/db/schema.test.ts +141 -0
  154. package/tests/fixtures/.env.yaml +3 -0
  155. package/tests/fixtures/auth-token-test.yaml +8 -0
  156. package/tests/fixtures/bail/suite-a.yaml +6 -0
  157. package/tests/fixtures/bail/suite-b.yaml +6 -0
  158. package/tests/fixtures/crud.yaml +35 -0
  159. package/tests/fixtures/invalid-missing-name.yaml +5 -0
  160. package/tests/fixtures/invalid-no-method.yaml +6 -0
  161. package/tests/fixtures/petstore-auth.json +295 -0
  162. package/tests/fixtures/petstore-simple.json +151 -0
  163. package/tests/fixtures/post-only.yaml +12 -0
  164. package/tests/fixtures/simple.yaml +6 -0
  165. package/tests/fixtures/valid/.env.yaml +1 -0
  166. package/tests/fixtures/valid/a.yaml +5 -0
  167. package/tests/fixtures/valid/b.yml +5 -0
  168. package/tests/generator/coverage-scanner.test.ts +129 -0
  169. package/tests/generator/data-factory.test.ts +133 -0
  170. package/tests/generator/openapi-reader.test.ts +131 -0
  171. package/tests/integration/auth-flow.test.ts +217 -0
  172. package/tests/mcp/coverage-analysis.test.ts +64 -0
  173. package/tests/mcp/explore-api-schemas.test.ts +105 -0
  174. package/tests/mcp/explore-api.test.ts +49 -0
  175. package/tests/mcp/generate-missing-tests.test.ts +69 -0
  176. package/tests/mcp/manage-environment.test.ts +89 -0
  177. package/tests/mcp/save-test-suite.test.ts +116 -0
  178. package/tests/mcp/send-request.test.ts +79 -0
  179. package/tests/mcp/setup-api.test.ts +106 -0
  180. package/tests/mcp/tools.test.ts +248 -0
  181. package/tests/parser/schema.test.ts +134 -0
  182. package/tests/parser/variables.test.ts +227 -0
  183. package/tests/parser/yaml-parser.test.ts +69 -0
  184. package/tests/reporter/console.test.ts +256 -0
  185. package/tests/reporter/json.test.ts +98 -0
  186. package/tests/reporter/junit.test.ts +284 -0
  187. package/tests/runner/assertions.test.ts +262 -0
  188. package/tests/runner/executor.test.ts +310 -0
  189. package/tests/runner/http-client.test.ts +138 -0
  190. package/tests/web/routes.test.ts +160 -0
  191. package/tsconfig.json +31 -0
@@ -0,0 +1,138 @@
1
+ import { describe, test, expect, mock, beforeEach, afterEach } from "bun:test";
2
+ import { executeRequest } from "../../src/core/runner/http-client.ts";
3
+
4
+ describe("executeRequest", () => {
5
+ const originalFetch = globalThis.fetch;
6
+
7
+ afterEach(() => {
8
+ globalThis.fetch = originalFetch;
9
+ });
10
+
11
+ test("sends GET request and returns structured response", async () => {
12
+ globalThis.fetch = mock(async () => {
13
+ return new Response(JSON.stringify({ id: 1, name: "John" }), {
14
+ status: 200,
15
+ headers: { "Content-Type": "application/json" },
16
+ });
17
+ }) as unknown as typeof fetch;
18
+
19
+ const response = await executeRequest({
20
+ method: "GET",
21
+ url: "http://example.com/users/1",
22
+ headers: {},
23
+ });
24
+
25
+ expect(response.status).toBe(200);
26
+ expect(response.body_parsed).toEqual({ id: 1, name: "John" });
27
+ expect(response.headers["content-type"]).toBe("application/json");
28
+ expect(response.duration_ms).toBeGreaterThanOrEqual(0);
29
+ });
30
+
31
+ test("sends POST with body", async () => {
32
+ let capturedInit: RequestInit | undefined;
33
+ globalThis.fetch = mock(async (_url: string | URL | Request, init?: RequestInit) => {
34
+ capturedInit = init;
35
+ return new Response("{}", { status: 201, headers: { "Content-Type": "application/json" } });
36
+ }) as unknown as typeof fetch;
37
+
38
+ await executeRequest({
39
+ method: "POST",
40
+ url: "http://example.com/users",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify({ name: "John" }),
43
+ });
44
+
45
+ expect(capturedInit!.method).toBe("POST");
46
+ expect(capturedInit!.body).toBe('{"name":"John"}');
47
+ });
48
+
49
+ test("parses JSON response when content-type is application/json", async () => {
50
+ globalThis.fetch = mock(async () => {
51
+ return new Response('{"key": "value"}', {
52
+ status: 200,
53
+ headers: { "Content-Type": "application/json; charset=utf-8" },
54
+ });
55
+ }) as unknown as typeof fetch;
56
+
57
+ const response = await executeRequest({ method: "GET", url: "http://example.com", headers: {} });
58
+ expect(response.body_parsed).toEqual({ key: "value" });
59
+ });
60
+
61
+ test("does not parse body when content-type is not JSON", async () => {
62
+ globalThis.fetch = mock(async () => {
63
+ return new Response("<html>Hello</html>", {
64
+ status: 200,
65
+ headers: { "Content-Type": "text/html" },
66
+ });
67
+ }) as unknown as typeof fetch;
68
+
69
+ const response = await executeRequest({ method: "GET", url: "http://example.com", headers: {} });
70
+ expect(response.body_parsed).toBeUndefined();
71
+ expect(response.body).toBe("<html>Hello</html>");
72
+ });
73
+
74
+ test("retries on network error and succeeds", async () => {
75
+ let callCount = 0;
76
+ globalThis.fetch = mock(async () => {
77
+ callCount++;
78
+ if (callCount === 1) throw new Error("Network error");
79
+ return new Response("{}", { status: 200, headers: { "Content-Type": "application/json" } });
80
+ }) as unknown as typeof fetch;
81
+
82
+ const response = await executeRequest(
83
+ { method: "GET", url: "http://example.com", headers: {} },
84
+ { retries: 1, retry_delay: 10 },
85
+ );
86
+ expect(response.status).toBe(200);
87
+ expect(callCount).toBe(2);
88
+ });
89
+
90
+ test("throws after all retries exhausted", async () => {
91
+ globalThis.fetch = mock(async () => {
92
+ throw new Error("Network error");
93
+ }) as unknown as typeof fetch;
94
+
95
+ await expect(
96
+ executeRequest(
97
+ { method: "GET", url: "http://example.com", headers: {} },
98
+ { retries: 1, retry_delay: 10 },
99
+ ),
100
+ ).rejects.toThrow("Network error");
101
+ });
102
+
103
+ test("does NOT retry on HTTP error status", async () => {
104
+ let callCount = 0;
105
+ globalThis.fetch = mock(async () => {
106
+ callCount++;
107
+ return new Response("Not Found", { status: 404, headers: {} });
108
+ }) as unknown as typeof fetch;
109
+
110
+ const response = await executeRequest(
111
+ { method: "GET", url: "http://example.com", headers: {} },
112
+ { retries: 2, retry_delay: 10 },
113
+ );
114
+ expect(response.status).toBe(404);
115
+ expect(callCount).toBe(1); // Only one call — no retry on HTTP errors
116
+ });
117
+
118
+ test("timeout aborts the request", async () => {
119
+ globalThis.fetch = mock(async (_url: string | URL | Request, init?: RequestInit) => {
120
+ // Simulate slow response
121
+ await new Promise((resolve, reject) => {
122
+ const timer = setTimeout(resolve, 5000);
123
+ init?.signal?.addEventListener("abort", () => {
124
+ clearTimeout(timer);
125
+ reject(new DOMException("The operation was aborted.", "AbortError"));
126
+ });
127
+ });
128
+ return new Response("{}", { status: 200, headers: {} });
129
+ }) as unknown as typeof fetch;
130
+
131
+ await expect(
132
+ executeRequest(
133
+ { method: "GET", url: "http://example.com", headers: {} },
134
+ { timeout: 50 },
135
+ ),
136
+ ).rejects.toThrow();
137
+ });
138
+ });
@@ -0,0 +1,160 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from "bun:test";
2
+ import { createApp } from "../../src/web/server.ts";
3
+ import { getDb, closeDb } from "../../src/db/schema.ts";
4
+ import { createRun, finalizeRun, saveResults, createCollection } from "../../src/db/queries.ts";
5
+ import type { TestRunResult } from "../../src/core/runner/types.ts";
6
+ import { unlinkSync } from "fs";
7
+ import { tmpdir } from "os";
8
+ import { join } from "path";
9
+
10
+ const TEST_DB = join(tmpdir(), `apitool-web-routes-${Date.now()}.db`);
11
+
12
+ function seedData() {
13
+ // Create a collection first
14
+ const colId = createCollection({ name: "Test API", test_path: "./tests/pet" });
15
+
16
+ const results: TestRunResult[] = [
17
+ {
18
+ suite_name: "petstore",
19
+ started_at: "2025-01-01T00:00:00.000Z",
20
+ finished_at: "2025-01-01T00:00:01.500Z",
21
+ total: 3,
22
+ passed: 2,
23
+ failed: 1,
24
+ skipped: 0,
25
+ steps: [
26
+ {
27
+ name: "List pets",
28
+ status: "pass",
29
+ duration_ms: 120,
30
+ request: { method: "GET", url: "http://localhost/pets", headers: {} },
31
+ response: { status: 200, headers: {}, body: "[]", duration_ms: 120 },
32
+ assertions: [{ field: "status", rule: "equals 200", passed: true, actual: 200, expected: 200 }],
33
+ captures: {},
34
+ },
35
+ {
36
+ name: "Create pet",
37
+ status: "pass",
38
+ duration_ms: 200,
39
+ request: { method: "POST", url: "http://localhost/pets", headers: {}, body: '{"name":"Buddy"}' },
40
+ response: { status: 201, headers: {}, body: '{"id":1}', duration_ms: 200 },
41
+ assertions: [{ field: "status", rule: "equals 201", passed: true, actual: 201, expected: 201 }],
42
+ captures: { petId: 1 },
43
+ },
44
+ {
45
+ name: "Delete pet",
46
+ status: "fail",
47
+ duration_ms: 50,
48
+ request: { method: "DELETE", url: "http://localhost/pets/1", headers: {} },
49
+ response: { status: 500, headers: {}, body: "error", duration_ms: 50 },
50
+ assertions: [{ field: "status", rule: "equals 204", passed: false, actual: 500, expected: 204 }],
51
+ captures: {},
52
+ },
53
+ ],
54
+ },
55
+ ];
56
+
57
+ const runId = createRun({ started_at: "2025-01-01T00:00:00.000Z", environment: "test", collection_id: colId });
58
+ finalizeRun(runId, results);
59
+ saveResults(runId, results);
60
+ return { runId, colId };
61
+ }
62
+
63
+ describe("Web routes", () => {
64
+ let app: ReturnType<typeof createApp>;
65
+ let runId: number;
66
+
67
+ beforeAll(() => {
68
+ try { unlinkSync(TEST_DB); } catch {}
69
+ getDb(TEST_DB);
70
+ const seed = seedData();
71
+ runId = seed.runId;
72
+ app = createApp();
73
+ });
74
+
75
+ afterAll(() => {
76
+ closeDb();
77
+ try { unlinkSync(TEST_DB); } catch {}
78
+ });
79
+
80
+ it("GET / returns 200 with dashboard", async () => {
81
+ const res = await app.request("/");
82
+ expect(res.status).toBe(200);
83
+ const html = await res.text();
84
+ expect(html).toContain("apitool");
85
+ expect(html).toContain("Test API");
86
+ });
87
+
88
+ it("GET / auto-selects single collection", async () => {
89
+ const res = await app.request("/");
90
+ expect(res.status).toBe(200);
91
+ const html = await res.text();
92
+ // Should auto-select the only collection and show action bar
93
+ expect(html).toContain("Run Tests");
94
+ });
95
+
96
+ it("GET /runs/:id returns 200 for existing run", async () => {
97
+ const res = await app.request(`/runs/${runId}`);
98
+ expect(res.status).toBe(200);
99
+ const html = await res.text();
100
+ expect(html).toContain(`Run #${runId}`);
101
+ expect(html).toContain("petstore");
102
+ expect(html).toContain("List pets");
103
+ expect(html).toContain("Delete pet");
104
+ });
105
+
106
+ it("GET /runs/:id returns 404 for non-existent run", async () => {
107
+ const res = await app.request("/runs/99999");
108
+ expect(res.status).toBe(404);
109
+ const html = await res.text();
110
+ expect(html).toContain("Run not found");
111
+ });
112
+
113
+ it("GET /runs/:id returns 400 for invalid id", async () => {
114
+ const res = await app.request("/runs/abc");
115
+ expect(res.status).toBe(400);
116
+ });
117
+
118
+ it("GET /static/style.css returns 200 with CSS", async () => {
119
+ const res = await app.request("/static/style.css");
120
+ expect(res.status).toBe(200);
121
+ expect(res.headers.get("content-type")).toContain("text/css");
122
+ const css = await res.text();
123
+ expect(css).toContain(":root");
124
+ });
125
+
126
+ it("GET /static/nonexistent returns 404", async () => {
127
+ const res = await app.request("/static/nope.js");
128
+ expect(res.status).toBe(404);
129
+ });
130
+
131
+ it("HTMX requests return fragment without layout", async () => {
132
+ const res = await app.request("/", { headers: { "HX-Request": "true" } });
133
+ expect(res.status).toBe(200);
134
+ const html = await res.text();
135
+ // Should not have full HTML boilerplate
136
+ expect(html).not.toContain("<!DOCTYPE html>");
137
+ });
138
+
139
+ it("GET /panels/results returns results for collection", async () => {
140
+ const res = await app.request("/panels/results?collection_id=1");
141
+ expect(res.status).toBe(200);
142
+ const html = await res.text();
143
+ expect(html).toContain("Run #");
144
+ });
145
+
146
+ it("GET /panels/history returns run history", async () => {
147
+ const res = await app.request("/panels/history?collection_id=1");
148
+ expect(res.status).toBe(200);
149
+ const html = await res.text();
150
+ expect(html).toContain("Run History");
151
+ });
152
+
153
+ it("removed routes return 404", async () => {
154
+ const removed = ["/explorer", "/environments", "/collections/1"];
155
+ for (const path of removed) {
156
+ const res = await app.request(path);
157
+ expect(res.status).toBe(404);
158
+ }
159
+ });
160
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "include": ["src/**/*.ts", "tests/**/*.ts"],
3
+ "exclude": ["node_modules"],
4
+ "compilerOptions": {
5
+ // Environment setup & latest features
6
+ "lib": ["ESNext"],
7
+ "target": "ESNext",
8
+ "module": "Preserve",
9
+ "moduleDetection": "force",
10
+ "jsx": "react-jsx",
11
+ "allowJs": true,
12
+
13
+ // Bundler mode
14
+ "moduleResolution": "bundler",
15
+ "allowImportingTsExtensions": true,
16
+ "verbatimModuleSyntax": true,
17
+ "noEmit": true,
18
+
19
+ // Best practices
20
+ "strict": true,
21
+ "skipLibCheck": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedIndexedAccess": true,
24
+ "noImplicitOverride": true,
25
+
26
+ // Some stricter flags (disabled by default)
27
+ "noUnusedLocals": false,
28
+ "noUnusedParameters": false,
29
+ "noPropertyAccessFromIndexSignature": false
30
+ }
31
+ }