@shivaedev/quality 0.3.0 → 0.4.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/CHANGELOG.md +33 -0
- package/README.md +70 -3
- package/dist/git/base.d.ts.map +1 -1
- package/dist/git/base.js +29 -4
- package/dist/git/base.js.map +1 -1
- package/dist/git/command.d.ts +1 -1
- package/dist/git/command.d.ts.map +1 -1
- package/dist/git/command.js +2 -2
- package/dist/git/command.js.map +1 -1
- package/dist/rules/suppressions/biome/configs.d.ts +21 -10
- package/dist/rules/suppressions/biome/configs.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/configs.js +57 -21
- package/dist/rules/suppressions/biome/configs.js.map +1 -1
- package/dist/rules/suppressions/biome/declarations.d.ts +18 -0
- package/dist/rules/suppressions/biome/declarations.d.ts.map +1 -0
- package/dist/rules/suppressions/biome/declarations.js +20 -0
- package/dist/rules/suppressions/biome/declarations.js.map +1 -0
- package/dist/rules/suppressions/biome/resolve.d.ts +3 -0
- package/dist/rules/suppressions/biome/resolve.d.ts.map +1 -0
- package/dist/rules/suppressions/biome/resolve.js +70 -0
- package/dist/rules/suppressions/biome/resolve.js.map +1 -0
- package/dist/rules/suppressions/biome/weakenings.d.ts +3 -3
- package/dist/rules/suppressions/biome/weakenings.d.ts.map +1 -1
- package/dist/rules/suppressions/biome/weakenings.js +41 -33
- package/dist/rules/suppressions/biome/weakenings.js.map +1 -1
- package/dist/rules/suppressions/biome-overrides.d.ts.map +1 -1
- package/dist/rules/suppressions/biome-overrides.js +31 -23
- package/dist/rules/suppressions/biome-overrides.js.map +1 -1
- package/package.json +5 -3
- package/src/git/base.ts +40 -5
- package/src/git/command.ts +2 -2
- package/src/rules/suppressions/biome/configs.ts +97 -28
- package/src/rules/suppressions/biome/declarations.ts +37 -0
- package/src/rules/suppressions/biome/resolve.ts +86 -0
- package/src/rules/suppressions/biome/weakenings.ts +54 -37
- package/src/rules/suppressions/biome-overrides.ts +40 -31
- package/tsconfig/base.json +35 -0
- package/tsconfig/package.json +10 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
import { decodeWith } from "../../../decoded.ts";
|
|
4
|
+
import type { RuleInputs } from "../../../rule.ts";
|
|
5
|
+
|
|
6
|
+
const Manifest = Schema.Struct({
|
|
7
|
+
name: Schema.optionalKey(Schema.String),
|
|
8
|
+
main: Schema.optionalKey(Schema.String),
|
|
9
|
+
exports: Schema.optionalKey(Schema.Unknown),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
type Manifest = typeof Manifest.Type;
|
|
13
|
+
|
|
14
|
+
const manifestSchema = Schema.toStandardSchemaV1(Schema.fromJsonString(Manifest));
|
|
15
|
+
|
|
16
|
+
const CONDITIONS: ReadonlySet<string> = new Set(["biome", "default"]);
|
|
17
|
+
|
|
18
|
+
const SPECIFIER = /^((?:@[^/]+\/)?[^/]+)(?:\/(.+))?$/;
|
|
19
|
+
|
|
20
|
+
const isRecord = (value: unknown): value is Readonly<Record<string, unknown>> => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
|
+
|
|
22
|
+
const targetOf = (value: unknown, star: string | undefined): string | undefined => {
|
|
23
|
+
if (typeof value === "string") {
|
|
24
|
+
return star === undefined ? value : value.replaceAll("*", star);
|
|
25
|
+
}
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
return value.map((item: unknown) => targetOf(item, star)).find((target) => target !== undefined);
|
|
28
|
+
}
|
|
29
|
+
const condition = isRecord(value) ? Object.keys(value).find((key) => CONDITIONS.has(key)) : undefined;
|
|
30
|
+
return isRecord(value) && condition !== undefined ? targetOf(value[condition], star) : undefined;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const bySpecificity = (left: string, right: string): number => right.indexOf("*") - left.indexOf("*") || right.length - left.length;
|
|
34
|
+
|
|
35
|
+
const patternTarget = (exports: Readonly<Record<string, unknown>>, key: string): string | undefined => {
|
|
36
|
+
const pattern = Object.keys(exports)
|
|
37
|
+
.filter((candidate) => candidate.split("*").length === 2)
|
|
38
|
+
.sort(bySpecificity)
|
|
39
|
+
.find((candidate) => {
|
|
40
|
+
const [prefix = "", suffix = ""] = candidate.split("*");
|
|
41
|
+
return key.startsWith(prefix) && key !== prefix && key.endsWith(suffix) && key.length >= candidate.length;
|
|
42
|
+
});
|
|
43
|
+
const [prefix = "", suffix = ""] = pattern?.split("*") ?? [];
|
|
44
|
+
return pattern === undefined ? undefined : targetOf(exports[pattern], key.slice(prefix.length, key.length - suffix.length));
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const exported = (exports: unknown, subpath: string): string | undefined => {
|
|
48
|
+
const key = subpath === "" ? "." : `./${subpath}`;
|
|
49
|
+
if (!isRecord(exports)) {
|
|
50
|
+
return targetOf(exports, undefined);
|
|
51
|
+
}
|
|
52
|
+
return Object.hasOwn(exports, key) ? targetOf(exports[key], undefined) : (patternTarget(exports, key) ?? targetOf(exports, undefined));
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const inPackage = (directory: string, target: string | undefined): string | undefined =>
|
|
56
|
+
target?.startsWith("./") === true ? posix.join(directory, target) : undefined;
|
|
57
|
+
|
|
58
|
+
const manifestAt = async (readText: RuleInputs["readText"], path: string): Promise<Manifest | undefined> => {
|
|
59
|
+
const text = await readText(path);
|
|
60
|
+
const decoded = text === undefined ? undefined : await decodeWith(manifestSchema, text);
|
|
61
|
+
return decoded?._tag === "Valid" ? decoded.value : undefined;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const fromDependency = (directory: string, manifest: Manifest, subpath: string): string | undefined => {
|
|
65
|
+
if (manifest.exports !== undefined) {
|
|
66
|
+
return inPackage(directory, exported(manifest.exports, subpath));
|
|
67
|
+
}
|
|
68
|
+
if (subpath === "" && manifest.main !== undefined) {
|
|
69
|
+
return posix.join(directory, manifest.main);
|
|
70
|
+
}
|
|
71
|
+
return subpath === "" ? undefined : posix.join(directory, subpath);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export const resolvePackage = async (readText: RuleInputs["readText"], specifier: string): Promise<string | undefined> => {
|
|
75
|
+
const [, name, subpath = ""] = SPECIFIER.exec(specifier) ?? [];
|
|
76
|
+
if (name === undefined) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const own = await manifestAt(readText, "package.json");
|
|
80
|
+
if (own?.name === name && own.exports !== undefined && subpath !== "") {
|
|
81
|
+
return inPackage("", exported(own.exports, subpath));
|
|
82
|
+
}
|
|
83
|
+
const directory = posix.join("node_modules", name);
|
|
84
|
+
const manifest = await manifestAt(readText, posix.join(directory, "package.json"));
|
|
85
|
+
return manifest === undefined ? undefined : fromDependency(directory, manifest, subpath);
|
|
86
|
+
};
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import type { Chain, Layer } from "./configs.ts";
|
|
2
|
+
import { scoped } from "./declarations.ts";
|
|
1
3
|
import { entriesOf, isFalse, itemsOf, type Json, member, textOf } from "./json.ts";
|
|
2
4
|
|
|
3
5
|
export interface Weakening {
|
|
4
6
|
readonly rule: string;
|
|
5
7
|
readonly includes: ReadonlyArray<string>;
|
|
6
|
-
readonly file: string;
|
|
7
8
|
readonly line: number;
|
|
9
|
+
readonly layer: Layer;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
interface Setting {
|
|
11
13
|
readonly rule: string;
|
|
12
14
|
readonly line: number;
|
|
15
|
+
readonly weak: boolean;
|
|
16
|
+
readonly wholeGroup: boolean;
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
const LINT_WEAK = new Set(["off", "warn", "info"]);
|
|
@@ -18,39 +22,45 @@ const PRESETS = new Set(["recommended", "preset"]);
|
|
|
18
22
|
|
|
19
23
|
const levelOf = (node: Json): string | undefined => textOf(node) ?? textOf(member(node, "level"));
|
|
20
24
|
|
|
21
|
-
const at = (rule: string, node: Json | undefined): ReadonlyArray<Setting> =>
|
|
25
|
+
const at = (rule: string, node: Json | undefined, weak: boolean, wholeGroup = false): ReadonlyArray<Setting> =>
|
|
26
|
+
node === undefined ? [] : [{ line: node.line, rule, weak, wholeGroup }];
|
|
22
27
|
|
|
23
|
-
const
|
|
24
|
-
|
|
28
|
+
const enabled = (rule: string, section: Json | undefined): ReadonlyArray<Setting> =>
|
|
29
|
+
at(rule, member(section, "enabled"), isFalse(member(section, "enabled")));
|
|
25
30
|
|
|
26
|
-
const
|
|
27
|
-
...(
|
|
28
|
-
...(
|
|
31
|
+
const defaults = (rule: string, set: Json | undefined): ReadonlyArray<Setting> => [
|
|
32
|
+
...at(rule, member(set, "recommended"), isFalse(member(set, "recommended"))),
|
|
33
|
+
...at(rule, member(set, "preset"), textOf(member(set, "preset")) === "none"),
|
|
29
34
|
];
|
|
30
35
|
|
|
36
|
+
const ruleSettings = (group: string, weak: ReadonlySet<string>, rules: Json): ReadonlyArray<Setting> =>
|
|
37
|
+
entriesOf(rules)
|
|
38
|
+
.filter(([rule]) => !PRESETS.has(rule))
|
|
39
|
+
.flatMap(([rule, setting]) => {
|
|
40
|
+
const level = levelOf(setting);
|
|
41
|
+
return level === undefined ? [] : at(`${group}/${rule}`, setting, weak.has(level));
|
|
42
|
+
});
|
|
43
|
+
|
|
31
44
|
const groupSettings = (prefix: string, weak: ReadonlySet<string>, groups: Json | undefined): ReadonlyArray<Setting> =>
|
|
32
45
|
entriesOf(groups)
|
|
33
46
|
.filter(([group]) => !PRESETS.has(group))
|
|
34
|
-
.flatMap(([group, rules]) =>
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
]);
|
|
47
|
+
.flatMap(([group, rules]) => {
|
|
48
|
+
const severity = textOf(rules);
|
|
49
|
+
return severity === undefined
|
|
50
|
+
? [...defaults(`${prefix}/${group}`, rules), ...ruleSettings(`${prefix}/${group}`, weak, rules)]
|
|
51
|
+
: at(`${prefix}/${group}`, rules, weak.has(severity), true);
|
|
52
|
+
});
|
|
41
53
|
|
|
42
54
|
const linter = (section: Json | undefined): ReadonlyArray<Setting> => [
|
|
43
|
-
...
|
|
44
|
-
...
|
|
55
|
+
...enabled("lint", section),
|
|
56
|
+
...defaults("lint/recommended", member(section, "rules")),
|
|
45
57
|
...groupSettings("lint", LINT_WEAK, member(section, "rules")),
|
|
46
|
-
...entriesOf(member(section, "domains"))
|
|
47
|
-
.filter(([, value]) => textOf(value) === "none")
|
|
48
|
-
.flatMap(([domain, value]) => at(`lint/domains/${domain}`, value)),
|
|
58
|
+
...entriesOf(member(section, "domains")).flatMap(([domain, value]) => at(`lint/domains/${domain}`, value, textOf(value) === "none")),
|
|
49
59
|
];
|
|
50
60
|
|
|
51
61
|
const assist = (section: Json | undefined): ReadonlyArray<Setting> => [
|
|
52
|
-
...
|
|
53
|
-
...
|
|
62
|
+
...enabled("assist", section),
|
|
63
|
+
...defaults("assist/recommended", member(section, "actions")),
|
|
54
64
|
...groupSettings("assist", ASSIST_WEAK, member(section, "actions")),
|
|
55
65
|
];
|
|
56
66
|
|
|
@@ -64,17 +74,15 @@ const TOOLS: ReadonlyArray<readonly [string, string]> = [
|
|
|
64
74
|
|
|
65
75
|
const SCOPED_SECTIONS: ReadonlyArray<readonly [string, string]> = [["files", "files"], ...TOOLS];
|
|
66
76
|
|
|
67
|
-
const
|
|
77
|
+
const settingsOf = (scope: Json): ReadonlyArray<Setting> => [
|
|
68
78
|
...linter(member(scope, "linter")),
|
|
69
79
|
...assist(member(scope, "assist")),
|
|
70
|
-
...
|
|
71
|
-
...LANGUAGES.flatMap((language) => TOOLS.flatMap(([key, name]) =>
|
|
80
|
+
...enabled("format", member(scope, "formatter")),
|
|
81
|
+
...LANGUAGES.flatMap((language) => TOOLS.flatMap(([key, name]) => enabled(`${language}/${name}`, member(member(scope, language), key)))),
|
|
72
82
|
];
|
|
73
83
|
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
return base === "" ? glob : `${negation}${base}/${path}`;
|
|
77
|
-
};
|
|
84
|
+
const replaces = (later: Setting, earlier: Setting): boolean =>
|
|
85
|
+
later.rule === earlier.rule || (later.wholeGroup && earlier.rule.startsWith(`${later.rule}/`));
|
|
78
86
|
|
|
79
87
|
const includesOf = (override: Json): ReadonlyArray<string> => {
|
|
80
88
|
const includes = itemsOf(member(override, "includes")).flatMap((item) => textOf(item) ?? []);
|
|
@@ -84,19 +92,28 @@ const includesOf = (override: Json): ReadonlyArray<string> => {
|
|
|
84
92
|
const narrowsScope = (globs: ReadonlyArray<string>): boolean =>
|
|
85
93
|
globs.length > 0 && (globs.some((glob) => glob.startsWith("!")) || !globs.includes("**"));
|
|
86
94
|
|
|
87
|
-
const narrowings = (config: Json,
|
|
95
|
+
const narrowings = (config: Json, base: string): ReadonlyArray<Omit<Weakening, "layer">> =>
|
|
88
96
|
SCOPED_SECTIONS.flatMap(([key, name]) => {
|
|
89
97
|
const list = member(member(config, key), "includes");
|
|
90
98
|
const globs = itemsOf(list).flatMap((item) => textOf(item) ?? []);
|
|
91
99
|
return list === undefined || !narrowsScope(globs)
|
|
92
100
|
? []
|
|
93
|
-
: [{
|
|
101
|
+
: [{ includes: globs.map((glob) => scoped(base, glob)), line: list.line, rule: `${name}/includes` }];
|
|
94
102
|
});
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
const layerWeakenings = (layer: Layer, later: ReadonlyArray<Layer>, base: string): ReadonlyArray<Weakening> => {
|
|
105
|
+
const overriding = later.flatMap((next) => settingsOf(next.json));
|
|
106
|
+
const top = settingsOf(layer.json).filter((setting) => setting.weak && !overriding.some((next) => replaces(next, setting)));
|
|
107
|
+
return [
|
|
108
|
+
...narrowings(layer.json, base),
|
|
109
|
+
...top.map(({ line, rule }) => ({ includes: [scoped(base, "**")], line, rule })),
|
|
110
|
+
...itemsOf(member(layer.json, "overrides")).flatMap((override) =>
|
|
111
|
+
settingsOf(override)
|
|
112
|
+
.filter((setting) => setting.weak)
|
|
113
|
+
.map(({ line, rule }) => ({ includes: includesOf(override).map((glob) => scoped(base, glob)), line, rule })),
|
|
114
|
+
),
|
|
115
|
+
].map((weakening) => ({ ...weakening, layer }));
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const weakeningsOf = ({ base, layers }: Chain): ReadonlyArray<Weakening> =>
|
|
119
|
+
layers.flatMap((layer, index) => layerWeakenings(layer, layers.slice(index + 1), base));
|
|
@@ -1,43 +1,53 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import { defineRule, type Finding } from "../../rule.ts";
|
|
3
|
-
import { biomeConfigs, type
|
|
3
|
+
import { biomeConfigs, type Chain } from "./biome/configs.ts";
|
|
4
|
+
import { Declaration, matches, type Scoped, scoped, scopeText } from "./biome/declarations.ts";
|
|
4
5
|
import { type Weakening, weakeningsOf } from "./biome/weakenings.ts";
|
|
5
6
|
|
|
6
|
-
const Declaration = Schema.Struct({
|
|
7
|
-
rule: Schema.NonEmptyString,
|
|
8
|
-
includes: Schema.NonEmptyArray(Schema.NonEmptyString),
|
|
9
|
-
reason: Schema.String.check(Schema.isPattern(/\S/, { expected: "a reason that says why the scope needs the rule weakened" })),
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
type Declaration = typeof Declaration.Type;
|
|
13
|
-
|
|
14
7
|
const BiomeOverridesOptions = Schema.Struct({
|
|
15
8
|
declared: Schema.Array(Declaration).pipe(Schema.withDecodingDefaultKey(Effect.succeed([]))),
|
|
16
9
|
});
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
interface Shipped extends Scoped {
|
|
12
|
+
readonly specifier: string;
|
|
13
|
+
}
|
|
20
14
|
|
|
21
|
-
const
|
|
22
|
-
|
|
15
|
+
const shippedBy = ({ base, layers }: Chain): ReadonlyArray<Shipped> =>
|
|
16
|
+
layers.flatMap(({ preset }) =>
|
|
17
|
+
preset === undefined
|
|
18
|
+
? []
|
|
19
|
+
: preset.declared.map(({ includes, rule }) => ({ includes: includes.map((glob) => scoped(base, glob)), rule, specifier: preset.specifier })),
|
|
20
|
+
);
|
|
23
21
|
|
|
24
|
-
const
|
|
22
|
+
const undeclared = ({ includes, layer, line, rule }: Weakening): Finding =>
|
|
23
|
+
layer.preset === undefined
|
|
24
|
+
? { file: layer.path, line, message: `Weakens "${rule}" for ${scopeText(includes)} without a declaration.`, subject: rule }
|
|
25
|
+
: {
|
|
26
|
+
file: layer.preset.file,
|
|
27
|
+
line: layer.preset.line,
|
|
28
|
+
message: `Extends "${layer.preset.specifier}", which weakens "${rule}" for ${scopeText(includes)} without a declaration.`,
|
|
29
|
+
subject: rule,
|
|
30
|
+
};
|
|
25
31
|
|
|
26
|
-
const
|
|
27
|
-
file
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
subject: weakening.rule,
|
|
32
|
+
const unused = (file: string, declaration: Scoped): Finding => ({
|
|
33
|
+
file,
|
|
34
|
+
message: `Declares "${declaration.rule}" for ${scopeText(declaration.includes)}, which no Biome config weakens. Remove the declaration.`,
|
|
35
|
+
subject: declaration.rule,
|
|
31
36
|
});
|
|
32
37
|
|
|
33
|
-
const
|
|
38
|
+
const repeated = (file: string, declaration: Scoped, shipped: Shipped): Finding => ({
|
|
34
39
|
file,
|
|
35
|
-
message: `Declares "${declaration.rule}" for ${scopeText(declaration.includes)}, which
|
|
40
|
+
message: `Declares "${declaration.rule}" for ${scopeText(declaration.includes)}, which "${shipped.specifier}" already declares. Remove the declaration.`,
|
|
36
41
|
subject: declaration.rule,
|
|
37
42
|
});
|
|
38
43
|
|
|
39
|
-
const
|
|
40
|
-
|
|
44
|
+
const staleOrRepeated = (file: string, weakenings: ReadonlyArray<Weakening>, shipped: ReadonlyArray<Shipped>) => (declaration: Scoped) => {
|
|
45
|
+
if (!weakenings.some((weakening) => matches(declaration, weakening))) {
|
|
46
|
+
return [unused(file, declaration)];
|
|
47
|
+
}
|
|
48
|
+
const already = shipped.find((candidate) => matches(declaration, candidate));
|
|
49
|
+
return already === undefined ? [] : [repeated(file, declaration, already)];
|
|
50
|
+
};
|
|
41
51
|
|
|
42
52
|
export const biomeOverrides = defineRule({
|
|
43
53
|
id: "suppressions/biome-overrides",
|
|
@@ -46,16 +56,15 @@ export const biomeOverrides = defineRule({
|
|
|
46
56
|
options: Schema.toStandardSchemaV1(BiomeOverridesOptions, { parseOptions: { errors: "all", onExcessProperty: "error" } }),
|
|
47
57
|
registrable: false,
|
|
48
58
|
check: async (inputs) => {
|
|
49
|
-
const
|
|
59
|
+
const { chains, problems, root } = await biomeConfigs(inputs);
|
|
50
60
|
const { declared } = inputs.options;
|
|
51
|
-
const weakenings =
|
|
52
|
-
const
|
|
61
|
+
const weakenings = chains.flatMap(weakeningsOf);
|
|
62
|
+
const shipped = chains.flatMap(shippedBy);
|
|
63
|
+
const covered = (weakening: Weakening): boolean => [...declared, ...shipped].some((declaration) => matches(declaration, weakening));
|
|
53
64
|
return [
|
|
54
|
-
...
|
|
55
|
-
...weakenings.filter((weakening) => !
|
|
56
|
-
...declared
|
|
57
|
-
.filter((declaration) => !weakenings.some((weakening) => matches(declaration, weakening)))
|
|
58
|
-
.map((declaration) => unused(root, declaration)),
|
|
65
|
+
...problems,
|
|
66
|
+
...weakenings.filter((weakening) => !covered(weakening)).map(undeclared),
|
|
67
|
+
...declared.flatMap(staleOrRepeated(root, weakenings, shipped)),
|
|
59
68
|
];
|
|
60
69
|
},
|
|
61
70
|
});
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ESNext",
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"verbatimModuleSyntax": true,
|
|
9
|
+
"isolatedModules": true,
|
|
10
|
+
"erasableSyntaxOnly": true,
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"allowJs": true,
|
|
14
|
+
"checkJs": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
"strict": true,
|
|
17
|
+
"noImplicitAny": true,
|
|
18
|
+
"strictBuiltinIteratorReturn": true,
|
|
19
|
+
"useUnknownInCatchVariables": true,
|
|
20
|
+
"noUncheckedIndexedAccess": true,
|
|
21
|
+
"exactOptionalPropertyTypes": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
"noImplicitReturns": true,
|
|
24
|
+
"noFallthroughCasesInSwitch": true,
|
|
25
|
+
"noUnusedLocals": true,
|
|
26
|
+
"noUnusedParameters": true,
|
|
27
|
+
"allowUnreachableCode": false,
|
|
28
|
+
"allowUnusedLabels": false,
|
|
29
|
+
"noUncheckedSideEffectImports": true,
|
|
30
|
+
"libReplacement": false,
|
|
31
|
+
"stableTypeOrdering": true,
|
|
32
|
+
"forceConsistentCasingInFileNames": true,
|
|
33
|
+
"skipLibCheck": true
|
|
34
|
+
}
|
|
35
|
+
}
|