@ridit/lens 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/LENS.md +25 -0
- package/LICENSE +21 -0
- package/README.md +0 -0
- package/dist/index.js +49363 -0
- package/package.json +38 -0
- package/src/colors.ts +1 -0
- package/src/commands/chat.tsx +23 -0
- package/src/commands/provider.tsx +224 -0
- package/src/commands/repo.tsx +120 -0
- package/src/commands/review.tsx +294 -0
- package/src/commands/task.tsx +36 -0
- package/src/commands/timeline.tsx +22 -0
- package/src/components/chat/ChatMessage.tsx +176 -0
- package/src/components/chat/ChatOverlays.tsx +329 -0
- package/src/components/chat/ChatRunner.tsx +732 -0
- package/src/components/provider/ApiKeyStep.tsx +243 -0
- package/src/components/provider/ModelStep.tsx +73 -0
- package/src/components/provider/ProviderTypeStep.tsx +54 -0
- package/src/components/provider/RemoveProviderStep.tsx +83 -0
- package/src/components/repo/DiffViewer.tsx +175 -0
- package/src/components/repo/FileReviewer.tsx +70 -0
- package/src/components/repo/FileViewer.tsx +60 -0
- package/src/components/repo/IssueFixer.tsx +666 -0
- package/src/components/repo/LensFileMenu.tsx +122 -0
- package/src/components/repo/NoProviderPrompt.tsx +28 -0
- package/src/components/repo/PreviewRunner.tsx +217 -0
- package/src/components/repo/ProviderPicker.tsx +76 -0
- package/src/components/repo/RepoAnalysis.tsx +343 -0
- package/src/components/repo/StepRow.tsx +69 -0
- package/src/components/task/TaskRunner.tsx +396 -0
- package/src/components/timeline/CommitDetail.tsx +274 -0
- package/src/components/timeline/CommitList.tsx +174 -0
- package/src/components/timeline/TimelineChat.tsx +167 -0
- package/src/components/timeline/TimelineRunner.tsx +1209 -0
- package/src/index.tsx +60 -0
- package/src/types/chat.ts +69 -0
- package/src/types/config.ts +20 -0
- package/src/types/repo.ts +42 -0
- package/src/utils/ai.ts +233 -0
- package/src/utils/chat.ts +833 -0
- package/src/utils/config.ts +61 -0
- package/src/utils/files.ts +104 -0
- package/src/utils/git.ts +155 -0
- package/src/utils/history.ts +86 -0
- package/src/utils/lensfile.ts +77 -0
- package/src/utils/llm.ts +81 -0
- package/src/utils/preview.ts +119 -0
- package/src/utils/repo.ts +69 -0
- package/src/utils/stats.ts +174 -0
- package/src/utils/thinking.tsx +191 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import os from "os";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { exec } from "child_process";
|
|
5
|
+
|
|
6
|
+
type CloneResult =
|
|
7
|
+
| { done: true }
|
|
8
|
+
| { done: false; folderExists: true; repoPath: string }
|
|
9
|
+
| { done: false; folderExists?: false; error: string };
|
|
10
|
+
|
|
11
|
+
export function cloneRepo(
|
|
12
|
+
url: string,
|
|
13
|
+
repoPath: string,
|
|
14
|
+
): Promise<{ done: boolean; error?: string }> {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
exec(`git clone "${url}" "${repoPath}"`, (err) => {
|
|
17
|
+
if (err) {
|
|
18
|
+
resolve({ done: false, error: err.message });
|
|
19
|
+
} else {
|
|
20
|
+
resolve({ done: true });
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function deleteRepoFolder(repoPath: string): void {
|
|
27
|
+
fs.rmSync(repoPath, { recursive: true, force: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export async function startCloneRepo(
|
|
31
|
+
url: string,
|
|
32
|
+
opts: { forceReclone?: boolean } = {},
|
|
33
|
+
): Promise<CloneResult> {
|
|
34
|
+
let parsedUrl: URL;
|
|
35
|
+
try {
|
|
36
|
+
parsedUrl = new URL(url);
|
|
37
|
+
} catch {
|
|
38
|
+
return { done: false, error: `Invalid URL: ${url}` };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const repoName = path.basename(parsedUrl.pathname).replace(/\.git$/, "");
|
|
42
|
+
if (!repoName) {
|
|
43
|
+
return {
|
|
44
|
+
done: false,
|
|
45
|
+
error: "Could not determine repository name from URL.",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const repoPath = path.join(os.tmpdir(), repoName);
|
|
50
|
+
|
|
51
|
+
const firstTry = await cloneRepo(url, repoPath);
|
|
52
|
+
if (!firstTry.error) {
|
|
53
|
+
return { done: true };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (firstTry.error.includes("already exists")) {
|
|
57
|
+
if (!opts.forceReclone) {
|
|
58
|
+
return { done: false, folderExists: true, repoPath };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
deleteRepoFolder(repoPath);
|
|
62
|
+
const secondTry = await cloneRepo(url, repoPath);
|
|
63
|
+
return secondTry.error
|
|
64
|
+
? { done: false, error: secondTry.error }
|
|
65
|
+
: { done: true };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return { done: false, error: firstTry.error };
|
|
69
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
export type CodeStats = {
|
|
5
|
+
totalFiles: number;
|
|
6
|
+
totalLines: number;
|
|
7
|
+
languages: Record<string, number>;
|
|
8
|
+
functions: number;
|
|
9
|
+
classes: number;
|
|
10
|
+
blankLines: number;
|
|
11
|
+
commentLines: number;
|
|
12
|
+
codeLines: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const LANG_MAP: Record<string, string> = {
|
|
16
|
+
".ts": "TS",
|
|
17
|
+
".tsx": "TSX",
|
|
18
|
+
".js": "JS",
|
|
19
|
+
".jsx": "JSX",
|
|
20
|
+
".css": "CSS",
|
|
21
|
+
".scss": "SCSS",
|
|
22
|
+
".json": "JSON",
|
|
23
|
+
".md": "MD",
|
|
24
|
+
".py": "PY",
|
|
25
|
+
".go": "GO",
|
|
26
|
+
".rs": "RS",
|
|
27
|
+
".java": "Java",
|
|
28
|
+
".cpp": "C++",
|
|
29
|
+
".c": "C",
|
|
30
|
+
".html": "HTML",
|
|
31
|
+
".yaml": "YAML",
|
|
32
|
+
".yml": "YAML",
|
|
33
|
+
".sh": "SH",
|
|
34
|
+
".env": "ENV",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const SKIP_DIRS = new Set([
|
|
38
|
+
"node_modules",
|
|
39
|
+
".git",
|
|
40
|
+
"dist",
|
|
41
|
+
"build",
|
|
42
|
+
".next",
|
|
43
|
+
"out",
|
|
44
|
+
"coverage",
|
|
45
|
+
"__pycache__",
|
|
46
|
+
".cache",
|
|
47
|
+
"vendor",
|
|
48
|
+
".venv",
|
|
49
|
+
"venv",
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
function isBinary(filePath: string): boolean {
|
|
53
|
+
const binaryExts = new Set([
|
|
54
|
+
".png",
|
|
55
|
+
".jpg",
|
|
56
|
+
".jpeg",
|
|
57
|
+
".gif",
|
|
58
|
+
".webp",
|
|
59
|
+
".ico",
|
|
60
|
+
".svg",
|
|
61
|
+
".woff",
|
|
62
|
+
".woff2",
|
|
63
|
+
".ttf",
|
|
64
|
+
".eot",
|
|
65
|
+
".mp4",
|
|
66
|
+
".mp3",
|
|
67
|
+
".wav",
|
|
68
|
+
".zip",
|
|
69
|
+
".tar",
|
|
70
|
+
".gz",
|
|
71
|
+
".pdf",
|
|
72
|
+
".lock",
|
|
73
|
+
]);
|
|
74
|
+
return binaryExts.has(path.extname(filePath).toLowerCase());
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function countFunctionsAndClasses(
|
|
78
|
+
content: string,
|
|
79
|
+
ext: string,
|
|
80
|
+
): { functions: number; classes: number } {
|
|
81
|
+
let functions = 0;
|
|
82
|
+
let classes = 0;
|
|
83
|
+
|
|
84
|
+
if ([".ts", ".tsx", ".js", ".jsx"].includes(ext)) {
|
|
85
|
+
const fnMatches = content.match(
|
|
86
|
+
/(?:^|\s)(?:function\s+\w+|const\s+\w+\s*=\s*(?:async\s*)?\(|(?:async\s+)?\w+\s*\([^)]*\)\s*(?::\s*\w+)?\s*\{|\w+\s*=\s*(?:async\s*)?\([^)]*\)\s*=>)/gm,
|
|
87
|
+
);
|
|
88
|
+
functions = fnMatches?.length ?? 0;
|
|
89
|
+
|
|
90
|
+
const classMatches = content.match(/(?:^|\s)class\s+\w+/gm);
|
|
91
|
+
classes = classMatches?.length ?? 0;
|
|
92
|
+
} else if (ext === ".py") {
|
|
93
|
+
const fnMatches = content.match(/^\s*def\s+\w+/gm);
|
|
94
|
+
functions = fnMatches?.length ?? 0;
|
|
95
|
+
const classMatches = content.match(/^\s*class\s+\w+/gm);
|
|
96
|
+
classes = classMatches?.length ?? 0;
|
|
97
|
+
} else if ([".go", ".rs"].includes(ext)) {
|
|
98
|
+
const fnMatches = content.match(/^\s*(?:func|fn)\s+\w+/gm);
|
|
99
|
+
functions = fnMatches?.length ?? 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return { functions, classes };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function computeStats(repoPath: string, files: string[]): CodeStats {
|
|
106
|
+
const stats: CodeStats = {
|
|
107
|
+
totalFiles: 0,
|
|
108
|
+
totalLines: 0,
|
|
109
|
+
languages: {},
|
|
110
|
+
functions: 0,
|
|
111
|
+
classes: 0,
|
|
112
|
+
blankLines: 0,
|
|
113
|
+
commentLines: 0,
|
|
114
|
+
codeLines: 0,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
for (const filePath of files) {
|
|
118
|
+
const parts = filePath.split(/[/\\]/);
|
|
119
|
+
if (parts.some((p) => SKIP_DIRS.has(p))) continue;
|
|
120
|
+
if (isBinary(filePath)) continue;
|
|
121
|
+
|
|
122
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
123
|
+
const lang = LANG_MAP[ext];
|
|
124
|
+
if (!lang) continue;
|
|
125
|
+
|
|
126
|
+
stats.totalFiles++;
|
|
127
|
+
stats.languages[lang] = (stats.languages[lang] ?? 0) + 1;
|
|
128
|
+
|
|
129
|
+
try {
|
|
130
|
+
const content = readFileSync(path.join(repoPath, filePath), "utf-8");
|
|
131
|
+
const lines = content.split("\n");
|
|
132
|
+
stats.totalLines += lines.length;
|
|
133
|
+
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
const trimmed = line.trim();
|
|
136
|
+
if (trimmed === "") {
|
|
137
|
+
stats.blankLines++;
|
|
138
|
+
} else if (
|
|
139
|
+
trimmed.startsWith("//") ||
|
|
140
|
+
trimmed.startsWith("#") ||
|
|
141
|
+
trimmed.startsWith("*") ||
|
|
142
|
+
trimmed.startsWith("/*") ||
|
|
143
|
+
trimmed.startsWith("<!--")
|
|
144
|
+
) {
|
|
145
|
+
stats.commentLines++;
|
|
146
|
+
} else {
|
|
147
|
+
stats.codeLines++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const { functions, classes } = countFunctionsAndClasses(content, ext);
|
|
152
|
+
stats.functions += functions;
|
|
153
|
+
stats.classes += classes;
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return stats;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function formatNumber(n: number): string {
|
|
161
|
+
if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
|
|
162
|
+
return n.toString();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function topLanguages(
|
|
166
|
+
languages: Record<string, number>,
|
|
167
|
+
limit = 5,
|
|
168
|
+
): string {
|
|
169
|
+
return Object.entries(languages)
|
|
170
|
+
.sort((a, b) => b[1] - a[1])
|
|
171
|
+
.slice(0, limit)
|
|
172
|
+
.map(([lang]) => lang)
|
|
173
|
+
.join(", ");
|
|
174
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
const PHRASES: Record<string, string[]> = {
|
|
4
|
+
general: [
|
|
5
|
+
// ── cooking ──────────────────────────────────────────────────
|
|
6
|
+
"marinating on that...",
|
|
7
|
+
"letting it simmer...",
|
|
8
|
+
"preheating the brain...",
|
|
9
|
+
"seasoning the response...",
|
|
10
|
+
"slow cooking an answer...",
|
|
11
|
+
"whisking it together...",
|
|
12
|
+
"folding in the context...",
|
|
13
|
+
"reducing the codebase...",
|
|
14
|
+
"deglazing with tokens...",
|
|
15
|
+
"plating the thoughts...",
|
|
16
|
+
|
|
17
|
+
// ── dev ──────────────────────────────────────────────────────
|
|
18
|
+
"shipping neurons...",
|
|
19
|
+
"diffing the vibes...",
|
|
20
|
+
"grepping the matrix...",
|
|
21
|
+
"pushing to brainstem...",
|
|
22
|
+
"rebasing thoughts...",
|
|
23
|
+
"compiling feelings...",
|
|
24
|
+
"hot reloading ideas...",
|
|
25
|
+
"touching grass mentally...",
|
|
26
|
+
"npm install wisdom...",
|
|
27
|
+
"resolving merge conflicts in head...",
|
|
28
|
+
"squashing dumb thoughts...",
|
|
29
|
+
"git blame on myself...",
|
|
30
|
+
"yarn linking synapses...",
|
|
31
|
+
"type checking the universe...",
|
|
32
|
+
"tree shaking nonsense...",
|
|
33
|
+
|
|
34
|
+
// ── gen z ────────────────────────────────────────────────────
|
|
35
|
+
"no cap, thinking hard...",
|
|
36
|
+
"lowkey computing...",
|
|
37
|
+
"in my bag rn...",
|
|
38
|
+
"it's giving... processing...",
|
|
39
|
+
"understood the assignment...",
|
|
40
|
+
"era of thinking...",
|
|
41
|
+
"main character moment...",
|
|
42
|
+
"this is the way...",
|
|
43
|
+
"based response incoming...",
|
|
44
|
+
"big brain time...",
|
|
45
|
+
"galaxy brained...",
|
|
46
|
+
"cooked something up...",
|
|
47
|
+
"chefkiss incoming...",
|
|
48
|
+
"slay mode: on...",
|
|
49
|
+
"rizzing up an answer...",
|
|
50
|
+
|
|
51
|
+
// ── existential ──────────────────────────────────────────────
|
|
52
|
+
"consulting the void...",
|
|
53
|
+
"asking my other personalities...",
|
|
54
|
+
"reading the codebase tea leaves...",
|
|
55
|
+
"vibing with your files...",
|
|
56
|
+
"channeling senior engineer energy...",
|
|
57
|
+
"pretending i know what i'm doing...",
|
|
58
|
+
"staring at the wall (productively)...",
|
|
59
|
+
"definitely not making this up...",
|
|
60
|
+
],
|
|
61
|
+
|
|
62
|
+
cloning: [
|
|
63
|
+
"cloning at the speed of git...",
|
|
64
|
+
"negotiating with github...",
|
|
65
|
+
"untangling the object graph...",
|
|
66
|
+
"counting commits like sheep...",
|
|
67
|
+
"shallow clone, deep thoughts...",
|
|
68
|
+
"fetching the whole iceberg...",
|
|
69
|
+
"packing objects...",
|
|
70
|
+
"resolving deltas...",
|
|
71
|
+
"checking out the vibes...",
|
|
72
|
+
"recursing into submodules...",
|
|
73
|
+
"buffering the bits...",
|
|
74
|
+
"git is being git...",
|
|
75
|
+
"praying to the network gods...",
|
|
76
|
+
"downloading the internet (just your repo)...",
|
|
77
|
+
],
|
|
78
|
+
|
|
79
|
+
analyzing: [
|
|
80
|
+
"reading every file (skimming)...",
|
|
81
|
+
"building a mental model...",
|
|
82
|
+
"reverse engineering intent...",
|
|
83
|
+
"parsing the chaos...",
|
|
84
|
+
"connecting the dots...",
|
|
85
|
+
"finding the load-bearing files...",
|
|
86
|
+
"mapping the dependency graph...",
|
|
87
|
+
"absorbing the architecture...",
|
|
88
|
+
"noticing things...",
|
|
89
|
+
"judging your folder structure...",
|
|
90
|
+
"appreciating the tech debt...",
|
|
91
|
+
"counting your TODOs...",
|
|
92
|
+
"reading between the lines...",
|
|
93
|
+
"anthropic-ifying your codebase...",
|
|
94
|
+
"following the import trail...",
|
|
95
|
+
"speed-reading your life's work...",
|
|
96
|
+
"pretending to understand your monorepo...",
|
|
97
|
+
],
|
|
98
|
+
|
|
99
|
+
model: [
|
|
100
|
+
"deciding which files matter...",
|
|
101
|
+
"picking the important ones...",
|
|
102
|
+
"triaging your codebase...",
|
|
103
|
+
"figuring out where to look...",
|
|
104
|
+
"consulting the file oracle...",
|
|
105
|
+
"narrowing it down...",
|
|
106
|
+
"skimming the directory...",
|
|
107
|
+
"choosing wisely...",
|
|
108
|
+
"not reading everything (smart)...",
|
|
109
|
+
"filtering the noise...",
|
|
110
|
+
"asking the oracle...",
|
|
111
|
+
"pinging the motherbrain...",
|
|
112
|
+
"waiting on the neurons...",
|
|
113
|
+
"tokens incoming...",
|
|
114
|
+
"model is cooking...",
|
|
115
|
+
"inference in progress...",
|
|
116
|
+
"the GPU is thinking...",
|
|
117
|
+
"attention is all we need...",
|
|
118
|
+
"cross-attending to your vibes...",
|
|
119
|
+
"softmaxing the options...",
|
|
120
|
+
"sampling from the distribution...",
|
|
121
|
+
"temperature: just right...",
|
|
122
|
+
"context window: not full yet...",
|
|
123
|
+
"next token any second now...",
|
|
124
|
+
"beaming thoughts from the datacenter...",
|
|
125
|
+
"anthropic servers sweating...",
|
|
126
|
+
"matrix multiply in progress...",
|
|
127
|
+
],
|
|
128
|
+
summary: [
|
|
129
|
+
"synthesizing the chaos...",
|
|
130
|
+
"forming an opinion...",
|
|
131
|
+
"writing the verdict...",
|
|
132
|
+
"digesting everything...",
|
|
133
|
+
"putting it all together...",
|
|
134
|
+
"crafting the overview...",
|
|
135
|
+
"making sense of it all...",
|
|
136
|
+
"distilling the essence...",
|
|
137
|
+
"summarizing your life's work...",
|
|
138
|
+
"turning files into feelings...",
|
|
139
|
+
"extracting signal from noise...",
|
|
140
|
+
"generating hot takes...",
|
|
141
|
+
"cooking up the analysis...",
|
|
142
|
+
"almost done judging your code...",
|
|
143
|
+
"writing the report card...",
|
|
144
|
+
],
|
|
145
|
+
|
|
146
|
+
task: [
|
|
147
|
+
"thinking about your ask...",
|
|
148
|
+
"processing the request...",
|
|
149
|
+
"on it...",
|
|
150
|
+
"got it, working...",
|
|
151
|
+
"considering the angles...",
|
|
152
|
+
"thinking this through...",
|
|
153
|
+
"working on it...",
|
|
154
|
+
"cooking up a plan...",
|
|
155
|
+
"breaking it down...",
|
|
156
|
+
"figuring out the approach...",
|
|
157
|
+
"strategizing...",
|
|
158
|
+
"mapping out the steps...",
|
|
159
|
+
"scoping the work...",
|
|
160
|
+
"locking in...",
|
|
161
|
+
"challenge accepted...",
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
function pick(list: string[], lastIndex: number): number {
|
|
166
|
+
let next = Math.floor(Math.random() * list.length);
|
|
167
|
+
if (next === lastIndex) next = (next + 1) % list.length;
|
|
168
|
+
return next;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export type ThinkingKind = keyof typeof PHRASES;
|
|
172
|
+
|
|
173
|
+
export function useThinkingPhrase(
|
|
174
|
+
active: boolean,
|
|
175
|
+
kind: ThinkingKind = "general",
|
|
176
|
+
intervalMs = 4321,
|
|
177
|
+
): string {
|
|
178
|
+
const list = PHRASES[kind]!;
|
|
179
|
+
const [index, setIndex] = useState(() =>
|
|
180
|
+
Math.floor(Math.random() * list.length),
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
useEffect(() => {
|
|
184
|
+
if (!active) return;
|
|
185
|
+
setIndex((i) => pick(list, i));
|
|
186
|
+
const id = setInterval(() => setIndex((i) => pick(list, i)), intervalMs);
|
|
187
|
+
return () => clearInterval(id);
|
|
188
|
+
}, [active, kind, intervalMs]);
|
|
189
|
+
|
|
190
|
+
return list[index]!;
|
|
191
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["ESNext"],
|
|
4
|
+
"target": "ESNext",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
// "allowImportingTsExtensions": true,
|
|
11
|
+
"verbatimModuleSyntax": true,
|
|
12
|
+
|
|
13
|
+
"strict": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"noFallthroughCasesInSwitch": true,
|
|
16
|
+
"noUncheckedIndexedAccess": true,
|
|
17
|
+
"noImplicitOverride": true,
|
|
18
|
+
|
|
19
|
+
"noUnusedLocals": false,
|
|
20
|
+
"noUnusedParameters": false,
|
|
21
|
+
"noPropertyAccessFromIndexSignature": false
|
|
22
|
+
},
|
|
23
|
+
"include": ["src"]
|
|
24
|
+
}
|