@yuu1111/quality-check 0.11.0 → 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.
- package/README.ja.md +13 -12
- package/README.md +13 -12
- package/dist/cli.js +119 -12
- package/package.json +2 -2
- package/src/config.ts +125 -23
- package/src/engines.ts +80 -10
package/README.ja.md
CHANGED
|
@@ -42,15 +42,11 @@ export default defineConfig({
|
|
|
42
42
|
},
|
|
43
43
|
config: {
|
|
44
44
|
"comment-check": {
|
|
45
|
-
enable: ["japanese-period"],
|
|
46
45
|
ignore: ["another-project"],
|
|
46
|
+
rules: { "japanese-period": "on" },
|
|
47
47
|
},
|
|
48
|
-
"document-style-check": {
|
|
49
|
-
|
|
50
|
-
},
|
|
51
|
-
"tsdoc-check": {
|
|
52
|
-
error: ["missing-doc"],
|
|
53
|
-
},
|
|
48
|
+
"document-style-check": { enable: true },
|
|
49
|
+
"tsdoc-check": { error: true },
|
|
54
50
|
},
|
|
55
51
|
});
|
|
56
52
|
```
|
|
@@ -91,9 +87,9 @@ engineは `biome` → `typecheck` → `knip` → `code-style-check` → `comment
|
|
|
91
87
|
| `typecheck` | `tsc --noEmit` | `args`、`projects` 設定は `tsconfig.json` が持つ |
|
|
92
88
|
| `knip` | `knip` | `args` 設定は `knip.ts` が持つ |
|
|
93
89
|
| `code-style-check` | `code-style-check --json` | `ignore`、`targets`、`args` |
|
|
94
|
-
| `comment-check` | `comment-check --json` | `ignore`、`targets`、`args`、`enable
|
|
95
|
-
| `document-style-check` | `document-style-check lint --json` | `ignore`、`targets`、`args`、`enable
|
|
96
|
-
| `tsdoc-check` | `tsdoc-check --json` | `ignore`、`targets`、`args`、`enable
|
|
90
|
+
| `comment-check` | `comment-check --json` | `ignore`、`targets`、`args`、`enable`、`rules` |
|
|
91
|
+
| `document-style-check` | `document-style-check lint --json` | `ignore`、`targets`、`args`、`enable`、`rules` |
|
|
92
|
+
| `tsdoc-check` | `tsdoc-check --json` | `ignore`、`targets`、`args`、`enable`、`error`、`rules` |
|
|
97
93
|
|
|
98
94
|
`args` はengineの既定引数の後ろへ足す
|
|
99
95
|
設定fileで表せない起動条件や、engineの引数が変わったときの逃げ道として使う
|
|
@@ -105,8 +101,13 @@ engineが受け取らない条件は渡さず、その旨をそのengineのsecti
|
|
|
105
101
|
biome: ignore skipped (biome.json holds its settings)
|
|
106
102
|
```
|
|
107
103
|
|
|
108
|
-
`enable`
|
|
109
|
-
|
|
104
|
+
`enable` と `error` はruleをまとめて選び、`rules` はruleを1つずつ選ぶ
|
|
105
|
+
`enable: true` はengineが既定で無効にしているruleを全て有効にする
|
|
106
|
+
`error: true` は `tsdoc-check` の全ruleを違反として扱い、opt-inのruleは先に有効にする 違反へ上げられるのはこのengineだけ
|
|
107
|
+
`rules` はrule名をkeyにして `off`、`on`、`error` のいずれかを渡す `on` はengineの既定のまま、`error` はそのruleだけpresetと同じ扱いにする
|
|
108
|
+
keyがrule名そのものなので導入済みengineのunionで型付けし、engineが知らない名前は起動時の失敗ではなく型errorになる
|
|
109
|
+
`error` を取れるのは `tsdoc-check` だけ、`off` を取れるのは既定で無効のruleだけで、既定で有効なruleを無効にする引数をengineは持たない
|
|
110
|
+
選んだruleは `--enable <rule>` になり、`tsdoc-check` では `--error <rule>` にもなる 他のengineはこれらのoptionを拒否する
|
|
110
111
|
|
|
111
112
|
`comment-check` はbaseline差分を無効化する未作成のpathを渡して起動する
|
|
112
113
|
新規と解消済みの判定はengineごとではなく統合CLIが1つのbaseline fileで行うため、既存の `comment-baseline.json` がある場合は `--update-baseline` で移す
|
package/README.md
CHANGED
|
@@ -43,15 +43,11 @@ export default defineConfig({
|
|
|
43
43
|
},
|
|
44
44
|
config: {
|
|
45
45
|
"comment-check": {
|
|
46
|
-
enable: ["japanese-period"],
|
|
47
46
|
ignore: ["another-project"],
|
|
47
|
+
rules: { "japanese-period": "on" },
|
|
48
48
|
},
|
|
49
|
-
"document-style-check": {
|
|
50
|
-
|
|
51
|
-
},
|
|
52
|
-
"tsdoc-check": {
|
|
53
|
-
error: ["missing-doc"],
|
|
54
|
-
},
|
|
49
|
+
"document-style-check": { enable: true },
|
|
50
|
+
"tsdoc-check": { error: true },
|
|
55
51
|
},
|
|
56
52
|
});
|
|
57
53
|
```
|
|
@@ -94,9 +90,9 @@ Each engine runs:
|
|
|
94
90
|
| `typecheck` | `tsc --noEmit` | `args`, `projects`; `tsconfig.json` holds the settings |
|
|
95
91
|
| `knip` | `knip` | `args`; `knip.ts` holds the settings |
|
|
96
92
|
| `code-style-check` | `code-style-check --json` | `ignore`, `targets`, `args` |
|
|
97
|
-
| `comment-check` | `comment-check --json` | `ignore`, `targets`, `args`, `enable`
|
|
98
|
-
| `document-style-check` | `document-style-check lint --json` | `ignore`, `targets`, `args`, `enable`
|
|
99
|
-
| `tsdoc-check` | `tsdoc-check --json` | `ignore`, `targets`, `args`, `enable
|
|
93
|
+
| `comment-check` | `comment-check --json` | `ignore`, `targets`, `args`, `enable`, `rules` |
|
|
94
|
+
| `document-style-check` | `document-style-check lint --json` | `ignore`, `targets`, `args`, `enable`, `rules` |
|
|
95
|
+
| `tsdoc-check` | `tsdoc-check --json` | `ignore`, `targets`, `args`, `enable`, `error`, `rules` |
|
|
100
96
|
|
|
101
97
|
`args` is appended after the engine defaults, for conditions the config cannot express and for the case where an engine changes its arguments.
|
|
102
98
|
|
|
@@ -107,8 +103,13 @@ A condition that an engine does not take is not passed on, and the section says
|
|
|
107
103
|
biome: ignore skipped (biome.json holds its settings)
|
|
108
104
|
```
|
|
109
105
|
|
|
110
|
-
`enable`
|
|
111
|
-
|
|
106
|
+
`enable` and `error` pick rules in bulk, and `rules` picks one rule at a time.
|
|
107
|
+
`enable: true` turns on every rule the engine keeps off by default.
|
|
108
|
+
`error: true` turns every rule of `tsdoc-check` into an error, enabling the opt-in ones first; it is the only condition that raises a rule.
|
|
109
|
+
A `rules` entry names one rule and gives it `off`, `on`, or `error`, where `on` keeps the engine default and `error` means the same as the `error` preset for that rule.
|
|
110
|
+
The `rules` key is the rule name itself, so the installed engine's union types it and a name that engine does not know is a type error rather than a start-up failure.
|
|
111
|
+
Only `tsdoc-check` takes `error` in `rules`, and only rules that are off by default take `off`, because no engine can turn off a rule that is on by default.
|
|
112
|
+
Each selected rule becomes `--enable <rule>` and, on `tsdoc-check`, `--error <rule>`; the other engines reject the fields.
|
|
112
113
|
|
|
113
114
|
`comment-check` runs with an unwritten baseline path so that it reports every finding.
|
|
114
115
|
The new-and-resolved diff is done by this CLI from a single baseline file, so an existing `comment-baseline.json` is moved over with `--update-baseline`.
|
package/dist/cli.js
CHANGED
|
@@ -194,6 +194,18 @@ function colorEnabled(stream, env) {
|
|
|
194
194
|
import { existsSync as existsSync2 } from "fs";
|
|
195
195
|
import { resolve } from "path";
|
|
196
196
|
import { pathToFileURL } from "url";
|
|
197
|
+
import {
|
|
198
|
+
OPT_IN_RULE_IDS as COMMENT_CHECK_OPT_IN_RULE_IDS,
|
|
199
|
+
RULE_IDS as COMMENT_CHECK_RULE_IDS
|
|
200
|
+
} from "@yuu1111/comment-check/rule-ids";
|
|
201
|
+
import {
|
|
202
|
+
OPT_IN_RULE_IDS as DOCUMENT_STYLE_CHECK_OPT_IN_RULE_IDS,
|
|
203
|
+
RULE_IDS as DOCUMENT_STYLE_CHECK_RULE_IDS
|
|
204
|
+
} from "@yuu1111/document-style-check/rule-ids";
|
|
205
|
+
import {
|
|
206
|
+
OPT_IN_RULE_IDS as TSDOC_CHECK_OPT_IN_RULE_IDS,
|
|
207
|
+
KNOWN_RULE_NAMES as TSDOC_CHECK_RULE_NAMES
|
|
208
|
+
} from "@yuu1111/tsdoc-check/rule-ids";
|
|
197
209
|
var ENGINE_NAMES = [
|
|
198
210
|
"biome",
|
|
199
211
|
"typecheck",
|
|
@@ -203,6 +215,27 @@ var ENGINE_NAMES = [
|
|
|
203
215
|
"document-style-check",
|
|
204
216
|
"tsdoc-check"
|
|
205
217
|
];
|
|
218
|
+
var RULE_VOCABULARY = {
|
|
219
|
+
biome: { all: [], optIn: [], promotes: false },
|
|
220
|
+
typecheck: { all: [], optIn: [], promotes: false },
|
|
221
|
+
knip: { all: [], optIn: [], promotes: false },
|
|
222
|
+
"code-style-check": { all: [], optIn: [], promotes: false },
|
|
223
|
+
"comment-check": {
|
|
224
|
+
all: COMMENT_CHECK_RULE_IDS,
|
|
225
|
+
optIn: COMMENT_CHECK_OPT_IN_RULE_IDS,
|
|
226
|
+
promotes: false
|
|
227
|
+
},
|
|
228
|
+
"document-style-check": {
|
|
229
|
+
all: DOCUMENT_STYLE_CHECK_RULE_IDS,
|
|
230
|
+
optIn: DOCUMENT_STYLE_CHECK_OPT_IN_RULE_IDS,
|
|
231
|
+
promotes: false
|
|
232
|
+
},
|
|
233
|
+
"tsdoc-check": {
|
|
234
|
+
all: TSDOC_CHECK_RULE_NAMES,
|
|
235
|
+
optIn: TSDOC_CHECK_OPT_IN_RULE_IDS,
|
|
236
|
+
promotes: true
|
|
237
|
+
}
|
|
238
|
+
};
|
|
206
239
|
var DEFAULT_CONFIG_FILES = [
|
|
207
240
|
"quality.config.ts",
|
|
208
241
|
"quality.config.mts",
|
|
@@ -221,9 +254,9 @@ var ENGINE_OPTION_KEYS = {
|
|
|
221
254
|
typecheck: ["args", "ignore", "projects", "targets"],
|
|
222
255
|
knip: ["args", "ignore", "targets"],
|
|
223
256
|
"code-style-check": ["args", "ignore", "targets"],
|
|
224
|
-
"comment-check": ["args", "enable", "ignore", "targets"],
|
|
225
|
-
"document-style-check": ["args", "enable", "ignore", "targets"],
|
|
226
|
-
"tsdoc-check": ["args", "enable", "error", "ignore", "targets"]
|
|
257
|
+
"comment-check": ["args", "enable", "ignore", "rules", "targets"],
|
|
258
|
+
"document-style-check": ["args", "enable", "ignore", "rules", "targets"],
|
|
259
|
+
"tsdoc-check": ["args", "enable", "error", "ignore", "rules", "targets"]
|
|
227
260
|
};
|
|
228
261
|
function readStringArray(value, field) {
|
|
229
262
|
if (value === undefined) {
|
|
@@ -234,6 +267,41 @@ function readStringArray(value, field) {
|
|
|
234
267
|
}
|
|
235
268
|
return [...value];
|
|
236
269
|
}
|
|
270
|
+
function readBoolean(value, field) {
|
|
271
|
+
if (value === undefined) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (typeof value !== "boolean") {
|
|
275
|
+
throw new Error(`${field} must be a boolean`);
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
}
|
|
279
|
+
function readRuleStates(value, field, name) {
|
|
280
|
+
if (value === undefined) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
if (!isJsonObject2(value)) {
|
|
284
|
+
throw new Error(`${field} must be an object`);
|
|
285
|
+
}
|
|
286
|
+
const vocabulary = RULE_VOCABULARY[name];
|
|
287
|
+
const states = {};
|
|
288
|
+
for (const [rule, state] of Object.entries(value)) {
|
|
289
|
+
if (!vocabulary.all.includes(rule)) {
|
|
290
|
+
throw new Error(`${field} has an unknown rule: ${rule}`);
|
|
291
|
+
}
|
|
292
|
+
if (state !== "off" && state !== "on" && state !== "error") {
|
|
293
|
+
throw new Error(`${field}.${rule} must be "off", "on" or "error"`);
|
|
294
|
+
}
|
|
295
|
+
if (state === "error" && !vocabulary.promotes) {
|
|
296
|
+
throw new Error(`${field}.${rule}: ${name} cannot treat a rule as an error`);
|
|
297
|
+
}
|
|
298
|
+
if (state === "off" && !vocabulary.optIn.includes(rule)) {
|
|
299
|
+
throw new Error(`${field}.${rule}: ${name} cannot turn off a rule that is on by default`);
|
|
300
|
+
}
|
|
301
|
+
states[rule] = state;
|
|
302
|
+
}
|
|
303
|
+
return states;
|
|
304
|
+
}
|
|
237
305
|
function readBaseline2(value, source) {
|
|
238
306
|
if (value === undefined || value === false) {
|
|
239
307
|
return value;
|
|
@@ -265,13 +333,17 @@ function parseEngines(value, source) {
|
|
|
265
333
|
function parseEngineExtras(value, source, name) {
|
|
266
334
|
const extras = {};
|
|
267
335
|
if (name === "comment-check" || name === "document-style-check" || name === "tsdoc-check") {
|
|
268
|
-
const enable =
|
|
336
|
+
const enable = readBoolean(value.enable, `${source}: config.${name}.enable`);
|
|
269
337
|
if (enable !== undefined) {
|
|
270
338
|
extras.enable = enable;
|
|
271
339
|
}
|
|
340
|
+
const rules = readRuleStates(value.rules, `${source}: config.${name}.rules`, name);
|
|
341
|
+
if (rules !== undefined) {
|
|
342
|
+
extras.rules = rules;
|
|
343
|
+
}
|
|
272
344
|
}
|
|
273
345
|
if (name === "tsdoc-check") {
|
|
274
|
-
const error =
|
|
346
|
+
const error = readBoolean(value.error, `${source}: config.${name}.error`);
|
|
275
347
|
if (error !== undefined) {
|
|
276
348
|
extras.error = error;
|
|
277
349
|
}
|
|
@@ -460,19 +532,54 @@ function buildTypecheckCommand(executable, context, project) {
|
|
|
460
532
|
...options.args ?? []
|
|
461
533
|
];
|
|
462
534
|
}
|
|
463
|
-
function
|
|
464
|
-
|
|
535
|
+
function applyRuleState(vocabulary, selected, rule, state) {
|
|
536
|
+
if (state === "off") {
|
|
537
|
+
selected.enable.delete(rule);
|
|
538
|
+
selected.error.delete(rule);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
if (state === "on") {
|
|
542
|
+
selected.error.delete(rule);
|
|
543
|
+
} else {
|
|
544
|
+
selected.error.add(rule);
|
|
545
|
+
}
|
|
546
|
+
if (vocabulary.optIn.includes(rule)) {
|
|
547
|
+
selected.enable.add(rule);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function selectRules(name, options) {
|
|
551
|
+
const selection = options ?? {};
|
|
552
|
+
const vocabulary = RULE_VOCABULARY[name];
|
|
553
|
+
const selected = { enable: new Set, error: new Set };
|
|
554
|
+
if (selection.enable === true) {
|
|
555
|
+
for (const rule of vocabulary.optIn) {
|
|
556
|
+
selected.enable.add(rule);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (selection.error === true) {
|
|
560
|
+
for (const rule of vocabulary.all) {
|
|
561
|
+
applyRuleState(vocabulary, selected, rule, "error");
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
for (const [rule, state] of Object.entries(selection.rules ?? {})) {
|
|
565
|
+
applyRuleState(vocabulary, selected, rule, state);
|
|
566
|
+
}
|
|
567
|
+
return { enable: [...selected.enable], error: [...selected.error] };
|
|
465
568
|
}
|
|
466
569
|
function buildEngineCommand(name, executable, context) {
|
|
467
570
|
const options = engineConfig(context.config, name) ?? {};
|
|
468
571
|
const limits = ENGINE_LIMITS[name];
|
|
572
|
+
const selection = selectRules(name, options);
|
|
573
|
+
const enableArguments = selection.enable.flatMap((rule) => [
|
|
574
|
+
"--enable",
|
|
575
|
+
rule
|
|
576
|
+
]);
|
|
577
|
+
const errorArguments = selection.error.flatMap((rule) => ["--error", rule]);
|
|
469
578
|
const extra = options.args ?? [];
|
|
470
579
|
const ignores = limits.ignore === undefined ? [...options.ignore ?? [], ...context.overrides.ignore] : [];
|
|
471
580
|
const requested = context.overrides.targets.length > 0 ? context.overrides.targets : options.targets ?? ["."];
|
|
472
581
|
const targets = limits.targets === undefined ? requested : [];
|
|
473
582
|
const ignoreArguments = ignores.flatMap((ignore) => ["--ignore", ignore]);
|
|
474
|
-
const rules = engineConfig(context.config, "tsdoc-check")?.error ?? [];
|
|
475
|
-
const errorArguments = rules.flatMap((rule) => ["--error", rule]);
|
|
476
583
|
if (name === "biome") {
|
|
477
584
|
return [
|
|
478
585
|
executable,
|
|
@@ -494,7 +601,7 @@ function buildEngineCommand(name, executable, context) {
|
|
|
494
601
|
"--json",
|
|
495
602
|
"--baseline",
|
|
496
603
|
context.rawBaseline,
|
|
497
|
-
...enableArguments
|
|
604
|
+
...enableArguments,
|
|
498
605
|
...targets,
|
|
499
606
|
...ignoreArguments,
|
|
500
607
|
...extra
|
|
@@ -505,7 +612,7 @@ function buildEngineCommand(name, executable, context) {
|
|
|
505
612
|
executable,
|
|
506
613
|
"lint",
|
|
507
614
|
"--json",
|
|
508
|
-
...enableArguments
|
|
615
|
+
...enableArguments,
|
|
509
616
|
...targets,
|
|
510
617
|
...ignoreArguments,
|
|
511
618
|
...extra
|
|
@@ -517,7 +624,7 @@ function buildEngineCommand(name, executable, context) {
|
|
|
517
624
|
return [
|
|
518
625
|
executable,
|
|
519
626
|
"--json",
|
|
520
|
-
...enableArguments
|
|
627
|
+
...enableArguments,
|
|
521
628
|
...errorArguments,
|
|
522
629
|
...targets,
|
|
523
630
|
...ignoreArguments,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yuu1111/quality-check",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Integrated quality check runner",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"dist"
|
|
24
24
|
],
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "bun build src/cli.ts --target=bun --outdir=dist"
|
|
26
|
+
"build": "bun build src/cli.ts --target=bun --outdir=dist --external @yuu1111/comment-check/rule-ids --external @yuu1111/document-style-check/rule-ids --external @yuu1111/tsdoc-check/rule-ids"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"quality",
|
package/src/config.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
OptInRuleId as
|
|
8
|
-
|
|
4
|
+
import {
|
|
5
|
+
OPT_IN_RULE_IDS as COMMENT_CHECK_OPT_IN_RULE_IDS,
|
|
6
|
+
RULE_IDS as COMMENT_CHECK_RULE_IDS,
|
|
7
|
+
type OptInRuleId as CommentCheckRuleName,
|
|
8
|
+
} from "@yuu1111/comment-check/rule-ids";
|
|
9
|
+
import {
|
|
10
|
+
OPT_IN_RULE_IDS as DOCUMENT_STYLE_CHECK_OPT_IN_RULE_IDS,
|
|
11
|
+
RULE_IDS as DOCUMENT_STYLE_CHECK_RULE_IDS,
|
|
12
|
+
type OptInRuleId as DocumentStyleCheckRuleName,
|
|
13
|
+
} from "@yuu1111/document-style-check/rule-ids";
|
|
14
|
+
import {
|
|
15
|
+
OPT_IN_RULE_IDS as TSDOC_CHECK_OPT_IN_RULE_IDS,
|
|
16
|
+
KNOWN_RULE_NAMES as TSDOC_CHECK_RULE_NAMES,
|
|
17
|
+
type TsdocRule,
|
|
9
18
|
} from "@yuu1111/tsdoc-check/rule-ids";
|
|
10
19
|
|
|
11
20
|
/**
|
|
@@ -42,26 +51,32 @@ export interface EngineOptions {
|
|
|
42
51
|
* comment-checkへ渡す起動条件
|
|
43
52
|
*/
|
|
44
53
|
export interface CommentCheckOptions extends EngineOptions {
|
|
45
|
-
/** 既定で無効のopt-in rule
|
|
46
|
-
enable?:
|
|
54
|
+
/** 既定で無効のopt-in ruleを全て有効にする */
|
|
55
|
+
enable?: boolean;
|
|
56
|
+
/** rule名ごとの状態 offで無効 onで有効 省略したruleはengineの既定に従う */
|
|
57
|
+
rules?: Partial<Record<CommentCheckRuleName, "off" | "on">>;
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
/**
|
|
50
61
|
* document-style-checkへ渡す起動条件
|
|
51
62
|
*/
|
|
52
63
|
export interface DocumentStyleCheckOptions extends EngineOptions {
|
|
53
|
-
/** 既定で無効のopt-in rule
|
|
54
|
-
enable?:
|
|
64
|
+
/** 既定で無効のopt-in ruleを全て有効にする */
|
|
65
|
+
enable?: boolean;
|
|
66
|
+
/** rule名ごとの状態 offで無効 onで有効 省略したruleはengineの既定に従う */
|
|
67
|
+
rules?: Partial<Record<DocumentStyleCheckRuleName, "off" | "on">>;
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
71
|
* TSDoc検査へ渡す起動条件
|
|
59
72
|
*/
|
|
60
73
|
export interface TsdocCheckOptions extends EngineOptions {
|
|
61
|
-
/** 既定で無効のopt-in rule
|
|
62
|
-
enable?:
|
|
63
|
-
/**
|
|
64
|
-
error?:
|
|
74
|
+
/** 既定で無効のopt-in ruleを全て有効にする */
|
|
75
|
+
enable?: boolean;
|
|
76
|
+
/** 全てのruleを違反として扱う opt-in ruleは有効にしてから上げる */
|
|
77
|
+
error?: boolean;
|
|
78
|
+
/** rule名ごとの状態 offで無効 onで既定のseverity errorで違反として扱う */
|
|
79
|
+
rules?: Partial<Record<TsdocRule, "off" | "on" | "error">>;
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
/**
|
|
@@ -85,6 +100,39 @@ export interface EngineConfigMap {
|
|
|
85
100
|
"tsdoc-check": TsdocCheckOptions;
|
|
86
101
|
}
|
|
87
102
|
|
|
103
|
+
/**
|
|
104
|
+
* rule名ごとの状態
|
|
105
|
+
*/
|
|
106
|
+
export type RuleState = "off" | "on" | "error";
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* engineが公開するrule語彙 全ruleと既定で無効のopt-in ruleを持つ
|
|
110
|
+
*/
|
|
111
|
+
export const RULE_VOCABULARY: Record<
|
|
112
|
+
EngineName,
|
|
113
|
+
{ all: readonly string[]; optIn: readonly string[]; promotes: boolean }
|
|
114
|
+
> = {
|
|
115
|
+
biome: { all: [], optIn: [], promotes: false },
|
|
116
|
+
typecheck: { all: [], optIn: [], promotes: false },
|
|
117
|
+
knip: { all: [], optIn: [], promotes: false },
|
|
118
|
+
"code-style-check": { all: [], optIn: [], promotes: false },
|
|
119
|
+
"comment-check": {
|
|
120
|
+
all: COMMENT_CHECK_RULE_IDS,
|
|
121
|
+
optIn: COMMENT_CHECK_OPT_IN_RULE_IDS,
|
|
122
|
+
promotes: false,
|
|
123
|
+
},
|
|
124
|
+
"document-style-check": {
|
|
125
|
+
all: DOCUMENT_STYLE_CHECK_RULE_IDS,
|
|
126
|
+
optIn: DOCUMENT_STYLE_CHECK_OPT_IN_RULE_IDS,
|
|
127
|
+
promotes: false,
|
|
128
|
+
},
|
|
129
|
+
"tsdoc-check": {
|
|
130
|
+
all: TSDOC_CHECK_RULE_NAMES,
|
|
131
|
+
optIn: TSDOC_CHECK_OPT_IN_RULE_IDS,
|
|
132
|
+
promotes: true,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
88
136
|
/**
|
|
89
137
|
* quality.config.tsが受け付ける統合検査の設定
|
|
90
138
|
*/
|
|
@@ -137,9 +185,9 @@ const ENGINE_OPTION_KEYS: Record<EngineName, readonly string[]> = {
|
|
|
137
185
|
typecheck: ["args", "ignore", "projects", "targets"],
|
|
138
186
|
knip: ["args", "ignore", "targets"],
|
|
139
187
|
"code-style-check": ["args", "ignore", "targets"],
|
|
140
|
-
"comment-check": ["args", "enable", "ignore", "targets"],
|
|
141
|
-
"document-style-check": ["args", "enable", "ignore", "targets"],
|
|
142
|
-
"tsdoc-check": ["args", "enable", "error", "ignore", "targets"],
|
|
188
|
+
"comment-check": ["args", "enable", "ignore", "rules", "targets"],
|
|
189
|
+
"document-style-check": ["args", "enable", "ignore", "rules", "targets"],
|
|
190
|
+
"tsdoc-check": ["args", "enable", "error", "ignore", "rules", "targets"],
|
|
143
191
|
};
|
|
144
192
|
|
|
145
193
|
function readStringArray(value: unknown, field: string): string[] | undefined {
|
|
@@ -155,6 +203,54 @@ function readStringArray(value: unknown, field: string): string[] | undefined {
|
|
|
155
203
|
return [...value] as string[];
|
|
156
204
|
}
|
|
157
205
|
|
|
206
|
+
function readBoolean(value: unknown, field: string): boolean | undefined {
|
|
207
|
+
if (value === undefined) {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
if (typeof value !== "boolean") {
|
|
211
|
+
throw new Error(`${field} must be a boolean`);
|
|
212
|
+
}
|
|
213
|
+
return value;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* rule名ごとの状態を読み取る engineが公開する語彙とengineが受け付ける状態で検証する
|
|
218
|
+
*/
|
|
219
|
+
function readRuleStates(
|
|
220
|
+
value: unknown,
|
|
221
|
+
field: string,
|
|
222
|
+
name: EngineName,
|
|
223
|
+
): Record<string, RuleState> | undefined {
|
|
224
|
+
if (value === undefined) {
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
if (!isJsonObject(value)) {
|
|
228
|
+
throw new Error(`${field} must be an object`);
|
|
229
|
+
}
|
|
230
|
+
const vocabulary = RULE_VOCABULARY[name];
|
|
231
|
+
const states: Record<string, RuleState> = {};
|
|
232
|
+
for (const [rule, state] of Object.entries(value)) {
|
|
233
|
+
if (!vocabulary.all.includes(rule)) {
|
|
234
|
+
throw new Error(`${field} has an unknown rule: ${rule}`);
|
|
235
|
+
}
|
|
236
|
+
if (state !== "off" && state !== "on" && state !== "error") {
|
|
237
|
+
throw new Error(`${field}.${rule} must be "off", "on" or "error"`);
|
|
238
|
+
}
|
|
239
|
+
if (state === "error" && !vocabulary.promotes) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`${field}.${rule}: ${name} cannot treat a rule as an error`,
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (state === "off" && !vocabulary.optIn.includes(rule)) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`${field}.${rule}: ${name} cannot turn off a rule that is on by default`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
states[rule] = state;
|
|
250
|
+
}
|
|
251
|
+
return states;
|
|
252
|
+
}
|
|
253
|
+
|
|
158
254
|
function readBaseline(
|
|
159
255
|
value: unknown,
|
|
160
256
|
source: string,
|
|
@@ -194,9 +290,10 @@ function parseEngines(
|
|
|
194
290
|
}
|
|
195
291
|
|
|
196
292
|
type ParsedEngineOptions = EngineOptions & {
|
|
197
|
-
enable?:
|
|
198
|
-
error?:
|
|
293
|
+
enable?: boolean;
|
|
294
|
+
error?: boolean;
|
|
199
295
|
projects?: string[];
|
|
296
|
+
rules?: Record<string, RuleState>;
|
|
200
297
|
};
|
|
201
298
|
|
|
202
299
|
/**
|
|
@@ -213,19 +310,24 @@ function parseEngineExtras(
|
|
|
213
310
|
name === "document-style-check" ||
|
|
214
311
|
name === "tsdoc-check"
|
|
215
312
|
) {
|
|
216
|
-
const enable =
|
|
313
|
+
const enable = readBoolean(
|
|
217
314
|
value.enable,
|
|
218
315
|
`${source}: config.${name}.enable`,
|
|
219
316
|
);
|
|
220
317
|
if (enable !== undefined) {
|
|
221
318
|
extras.enable = enable;
|
|
222
319
|
}
|
|
320
|
+
const rules = readRuleStates(
|
|
321
|
+
value.rules,
|
|
322
|
+
`${source}: config.${name}.rules`,
|
|
323
|
+
name,
|
|
324
|
+
);
|
|
325
|
+
if (rules !== undefined) {
|
|
326
|
+
extras.rules = rules;
|
|
327
|
+
}
|
|
223
328
|
}
|
|
224
329
|
if (name === "tsdoc-check") {
|
|
225
|
-
const error =
|
|
226
|
-
value.error,
|
|
227
|
-
`${source}: config.${name}.error`,
|
|
228
|
-
);
|
|
330
|
+
const error = readBoolean(value.error, `${source}: config.${name}.error`);
|
|
229
331
|
if (error !== undefined) {
|
|
230
332
|
extras.error = error;
|
|
231
333
|
}
|
package/src/engines.ts
CHANGED
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
type EngineOptions,
|
|
6
6
|
engineConfig,
|
|
7
7
|
type QualityConfig,
|
|
8
|
+
RULE_VOCABULARY,
|
|
9
|
+
type RuleState,
|
|
8
10
|
} from "./config";
|
|
9
11
|
|
|
10
12
|
/**
|
|
@@ -194,12 +196,76 @@ function buildTypecheckCommand(
|
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
/**
|
|
197
|
-
*
|
|
199
|
+
* 設定fileが持つruleの指定
|
|
198
200
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
201
|
+
interface RuleSelection {
|
|
202
|
+
enable?: boolean;
|
|
203
|
+
error?: boolean;
|
|
204
|
+
rules?: Record<string, RuleState>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* engineが公開するrule語彙
|
|
209
|
+
*/
|
|
210
|
+
type RuleVocabulary = (typeof RULE_VOCABULARY)[EngineName];
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 選んだruleを有効の一覧と違反の一覧へ反映する
|
|
214
|
+
*
|
|
215
|
+
* @param vocabulary - 反映先engineのrule語彙
|
|
216
|
+
* @param selected - 反映先のrule名の集合
|
|
217
|
+
* @param rule - 反映するrule名
|
|
218
|
+
* @param state - 反映する状態
|
|
219
|
+
*/
|
|
220
|
+
function applyRuleState(
|
|
221
|
+
vocabulary: RuleVocabulary,
|
|
222
|
+
selected: { enable: Set<string>; error: Set<string> },
|
|
223
|
+
rule: string,
|
|
224
|
+
state: RuleState,
|
|
225
|
+
): void {
|
|
226
|
+
if (state === "off") {
|
|
227
|
+
selected.enable.delete(rule);
|
|
228
|
+
selected.error.delete(rule);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (state === "on") {
|
|
232
|
+
selected.error.delete(rule);
|
|
233
|
+
} else {
|
|
234
|
+
selected.error.add(rule);
|
|
235
|
+
}
|
|
236
|
+
if (vocabulary.optIn.includes(rule)) {
|
|
237
|
+
selected.enable.add(rule);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* ruleの一括指定と個別指定をengineへ渡すruleの一覧へ展開する
|
|
243
|
+
*
|
|
244
|
+
* @param name - 展開するengine名
|
|
245
|
+
* @param options - engineへ渡す起動条件
|
|
246
|
+
* @returns --enableへ渡すrule名と--errorへ渡すrule名の組
|
|
247
|
+
*/
|
|
248
|
+
function selectRules(
|
|
249
|
+
name: EngineName,
|
|
250
|
+
options: EngineOptions | null | undefined,
|
|
251
|
+
): { enable: string[]; error: string[] } {
|
|
252
|
+
const selection = (options ?? {}) as RuleSelection;
|
|
253
|
+
const vocabulary = RULE_VOCABULARY[name];
|
|
254
|
+
const selected = { enable: new Set<string>(), error: new Set<string>() };
|
|
255
|
+
if (selection.enable === true) {
|
|
256
|
+
for (const rule of vocabulary.optIn) {
|
|
257
|
+
selected.enable.add(rule);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (selection.error === true) {
|
|
261
|
+
for (const rule of vocabulary.all) {
|
|
262
|
+
applyRuleState(vocabulary, selected, rule, "error");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
for (const [rule, state] of Object.entries(selection.rules ?? {})) {
|
|
266
|
+
applyRuleState(vocabulary, selected, rule, state);
|
|
267
|
+
}
|
|
268
|
+
return { enable: [...selected.enable], error: [...selected.error] };
|
|
203
269
|
}
|
|
204
270
|
|
|
205
271
|
/**
|
|
@@ -217,6 +283,12 @@ export function buildEngineCommand(
|
|
|
217
283
|
): string[] {
|
|
218
284
|
const options: EngineOptions = engineConfig(context.config, name) ?? {};
|
|
219
285
|
const limits = ENGINE_LIMITS[name];
|
|
286
|
+
const selection = selectRules(name, options);
|
|
287
|
+
const enableArguments = selection.enable.flatMap((rule) => [
|
|
288
|
+
"--enable",
|
|
289
|
+
rule,
|
|
290
|
+
]);
|
|
291
|
+
const errorArguments = selection.error.flatMap((rule) => ["--error", rule]);
|
|
220
292
|
const extra = options.args ?? [];
|
|
221
293
|
const ignores =
|
|
222
294
|
limits.ignore === undefined
|
|
@@ -228,8 +300,6 @@ export function buildEngineCommand(
|
|
|
228
300
|
: (options.targets ?? ["."]);
|
|
229
301
|
const targets = limits.targets === undefined ? requested : [];
|
|
230
302
|
const ignoreArguments = ignores.flatMap((ignore) => ["--ignore", ignore]);
|
|
231
|
-
const rules = engineConfig(context.config, "tsdoc-check")?.error ?? [];
|
|
232
|
-
const errorArguments = rules.flatMap((rule) => ["--error", rule]);
|
|
233
303
|
if (name === "biome") {
|
|
234
304
|
return [
|
|
235
305
|
executable,
|
|
@@ -251,7 +321,7 @@ export function buildEngineCommand(
|
|
|
251
321
|
"--json",
|
|
252
322
|
"--baseline",
|
|
253
323
|
context.rawBaseline,
|
|
254
|
-
...enableArguments
|
|
324
|
+
...enableArguments,
|
|
255
325
|
...targets,
|
|
256
326
|
...ignoreArguments,
|
|
257
327
|
...extra,
|
|
@@ -262,7 +332,7 @@ export function buildEngineCommand(
|
|
|
262
332
|
executable,
|
|
263
333
|
"lint",
|
|
264
334
|
"--json",
|
|
265
|
-
...enableArguments
|
|
335
|
+
...enableArguments,
|
|
266
336
|
...targets,
|
|
267
337
|
...ignoreArguments,
|
|
268
338
|
...extra,
|
|
@@ -274,7 +344,7 @@ export function buildEngineCommand(
|
|
|
274
344
|
return [
|
|
275
345
|
executable,
|
|
276
346
|
"--json",
|
|
277
|
-
...enableArguments
|
|
347
|
+
...enableArguments,
|
|
278
348
|
...errorArguments,
|
|
279
349
|
...targets,
|
|
280
350
|
...ignoreArguments,
|