@yuu1111/quality-check 0.1.0 → 0.3.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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @yuu1111/quality-check
4
4
 
5
- Projectごとのscriptから個別に呼んでいたBiome、Knip、comment-check、TSDoc checkerを1つのCLIへまとめる baselineの差分判定もここで行う
5
+ Projectごとのscriptから個別に呼んでいたBiome、Knip、comment-check、document-style-check、TSDoc checkerを1つのCLIへまとめる baselineの差分判定もここで行う
6
6
 
7
7
  ## Install
8
8
 
@@ -12,7 +12,7 @@ bun add -D @yuu1111/quality-check
12
12
 
13
13
  ## Usage
14
14
 
15
- `quality.config.ts` engineと除外pathを指定し、scriptから起動する
15
+ `quality.config.ts` で起動するengineとengineごとの起動条件を指定し、scriptから起動する
16
16
 
17
17
  ```json
18
18
  {
@@ -26,13 +26,17 @@ bun add -D @yuu1111/quality-check
26
26
  import { defineConfig } from "@yuu1111/quality-check";
27
27
 
28
28
  export default defineConfig({
29
- engines: {
30
- biome: true,
31
- knip: true,
32
- "comment-check": true,
33
- "tsdoc-check": { args: ["--error", "missing-doc"] },
34
- },
35
- ignore: ["FFXIVReplayAnalyzer"],
29
+ engines: {
30
+ biome: true,
31
+ knip: true,
32
+ "comment-check": true,
33
+ "document-style-check": true,
34
+ "tsdoc-check": true,
35
+ },
36
+ config: {
37
+ "comment-check": { ignore: ["FFXIVReplayAnalyzer"] },
38
+ "tsdoc-check": { error: ["missing-doc"] },
39
+ },
36
40
  });
37
41
  ```
38
42
 
@@ -56,13 +60,23 @@ quality-check: 1 of 3 engines failed
56
60
 
57
61
  | Field | Description |
58
62
  |-------|-------------|
59
- | `engines` | 起動するengine 値は `true` または `{ args }` |
60
- | `ignore` | file走査engineが検査から外すpath |
63
+ | `engines` | 起動するengine 値は `true` または `false` |
64
+ | `config` | engineごとの起動条件 |
61
65
  | `baseline` | baseline fileのpath `false` なら差分判定を行わない |
62
- | `targets` | file走査engineへ渡す対象path |
63
66
 
64
- engineは `biome` → `knip` → `comment-check` → `tsdoc-check` の順に実行する
65
- `args` はengineの既定引数の後ろへ足すため、`tsdoc-check` の `--error` のようなengine固有の指定はここへ置く
67
+ engineは `biome` → `knip` → `comment-check` → `document-style-check` → `tsdoc-check` の順に実行する
68
+
69
+ `engines` は起動の委任だけを表し、起動条件は `config` のengineの下へ置く engineが受け取る条件は次のとおり
70
+
71
+ | engine | 受け取る条件 |
72
+ |--------|--------------|
73
+ | `biome` | `targets`、`args` 除外pathは `biome.json` が持つ |
74
+ | `knip` | `args` 設定は `knip.ts` が持つ |
75
+ | `comment-check` | `ignore`、`targets`、`args` |
76
+ | `document-style-check` | `ignore`、`targets`、`args` |
77
+ | `tsdoc-check` | `ignore`、`targets`、`args`、`error`(違反として扱うrule名) |
78
+
79
+ `args` はengineの既定引数の後ろへ足す 設定fileで表せない起動条件や、engineの引数が変わったときの逃げ道として使う
66
80
 
67
81
  ## Options
68
82
 
@@ -74,11 +88,20 @@ engineは `biome` → `knip` → `comment-check` → `tsdoc-check` の順に実
74
88
  | `--update-baseline` | 現在の検出でbaselineを置き換える |
75
89
  | `--json` | engineごとの結果をJSONで出力する |
76
90
 
91
+ `--ignore` と位置引数の対象pathは、その条件を受け取るengineへだけ渡す
92
+
77
93
  ## Notes
78
94
 
79
95
  終了codeは0が全engine成功、1が失敗したengineあり、2が設定またはengine起動の失敗
80
96
 
81
- BiomeとKnipは除外pathを自分のconfig(`biome.json`、`knip.ts`)で持つ `ignore` はfile走査engineへ `--ignore` として渡し、BiomeとKnipには渡さない
97
+ engineが受け取らない条件を書いた場合は渡さず、その旨をそのengineのsectionへ出す
98
+
99
+ ```text
100
+ == biome ==
101
+ biome: ignore skipped (biome.json holds its settings)
102
+ ```
103
+
104
+ BiomeとKnipの除外pathは `biome.json` と `knip.ts` が持つ このCLIは同じfileからengineの起動と結果の集約だけを行う
82
105
 
83
106
  `comment-check` はbaseline差分を無効化する未作成のpathを渡して起動する 新規と解消済みの判定はengineごとではなく統合CLIが1つのbaseline fileで行うため、既存の `comment-baseline.json` がある場合は `--update-baseline` で移す
84
107
 
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  # @yuu1111/quality-check
4
4
 
5
- Runs Biome, Knip, comment-check, and the TSDoc checker from one CLI instead of
6
- one script per project. The baseline diff lives here too.
5
+ Runs Biome, Knip, comment-check, document-style-check, and the TSDoc checker
6
+ from one CLI instead of one script per project. The baseline diff lives here too.
7
7
 
8
8
  ## Install
9
9
 
@@ -13,8 +13,8 @@ bun add -D @yuu1111/quality-check
13
13
 
14
14
  ## Usage
15
15
 
16
- Declare the engines and the excluded paths in `quality.config.ts`, then call the
17
- CLI from a script:
16
+ Declare the engines to run and the conditions of each engine in
17
+ `quality.config.ts`, then call the CLI from a script:
18
18
 
19
19
  ```json
20
20
  {
@@ -28,13 +28,17 @@ CLI from a script:
28
28
  import { defineConfig } from "@yuu1111/quality-check";
29
29
 
30
30
  export default defineConfig({
31
- engines: {
32
- biome: true,
33
- knip: true,
34
- "comment-check": true,
35
- "tsdoc-check": { args: ["--error", "missing-doc"] },
36
- },
37
- ignore: ["FFXIVReplayAnalyzer"],
31
+ engines: {
32
+ biome: true,
33
+ knip: true,
34
+ "comment-check": true,
35
+ "document-style-check": true,
36
+ "tsdoc-check": true,
37
+ },
38
+ config: {
39
+ "comment-check": { ignore: ["FFXIVReplayAnalyzer"] },
40
+ "tsdoc-check": { error: ["missing-doc"] },
41
+ },
38
42
  });
39
43
  ```
40
44
 
@@ -59,14 +63,26 @@ quality-check: 1 of 3 engines failed
59
63
 
60
64
  | Field | Description |
61
65
  |-------|-------------|
62
- | `engines` | Engines to run, as `true` or `{ args }` |
63
- | `ignore` | Paths that the file-scanning engines leave out |
66
+ | `engines` | Engines to run, as `true` or `false` |
67
+ | `config` | Conditions of each engine |
64
68
  | `baseline` | Baseline file path; `false` disables the diff |
65
- | `targets` | Targets passed to the file-scanning engines |
66
69
 
67
- Engines run in the order `biome`, `knip`, `comment-check`, `tsdoc-check`.
68
- `args` is appended after the engine defaults, so engine-specific flags such as
69
- `--error` for `tsdoc-check` belong there.
70
+ Engines run in the order `biome`, `knip`, `comment-check`,
71
+ `document-style-check`, `tsdoc-check`.
72
+
73
+ `engines` only delegates the start-up, and the conditions belong under the
74
+ engine in `config`. Each engine takes:
75
+
76
+ | Engine | Conditions |
77
+ |--------|------------|
78
+ | `biome` | `targets`, `args`; `biome.json` holds the excluded paths |
79
+ | `knip` | `args`; `knip.ts` holds the settings |
80
+ | `comment-check` | `ignore`, `targets`, `args` |
81
+ | `document-style-check` | `ignore`, `targets`, `args` |
82
+ | `tsdoc-check` | `ignore`, `targets`, `args`, `error` (rule names to fail on) |
83
+
84
+ `args` is appended after the engine defaults, for conditions the config cannot
85
+ express and for the case where an engine changes its arguments.
70
86
 
71
87
  ## Options
72
88
 
@@ -78,14 +94,23 @@ Engines run in the order `biome`, `knip`, `comment-check`, `tsdoc-check`.
78
94
  | `--update-baseline` | Replace the baseline with the current findings |
79
95
  | `--json` | Print the per-engine results as JSON |
80
96
 
97
+ `--ignore` and the positional targets reach only the engines that take them.
98
+
81
99
  ## Notes
82
100
 
83
101
  Exit code 0 means every engine passed, 1 that at least one failed, and 2 that the
84
102
  configuration or an engine could not start.
85
103
 
86
- Biome and Knip keep their excluded paths in their own config (`biome.json`,
87
- `knip.ts`). `ignore` reaches the file-scanning engines as `--ignore` and is not
88
- passed to Biome or Knip.
104
+ A condition that an engine does not take is not passed on, and the section says
105
+ so:
106
+
107
+ ```text
108
+ == biome ==
109
+ biome: ignore skipped (biome.json holds its settings)
110
+ ```
111
+
112
+ Biome and Knip keep their excluded paths in `biome.json` and `knip.ts`. This
113
+ CLI starts the engines from one file and aggregates the results.
89
114
 
90
115
  `comment-check` runs with an unwritten baseline path so that it reports every
91
116
  finding. The new-and-resolved diff is done by this CLI from a single baseline
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuu1111/quality-check",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Integrated quality check runner",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/cli.ts CHANGED
@@ -98,13 +98,6 @@ function parseArguments(argv: string[]): Options {
98
98
  return options;
99
99
  }
100
100
 
101
- function mergeIgnores(config: QualityConfig, ignores: string[]): QualityConfig {
102
- if (ignores.length === 0) {
103
- return config;
104
- }
105
- return { ...config, ignore: [...(config.ignore ?? []), ...ignores] };
106
- }
107
-
108
101
  function resolveBaselinePath(
109
102
  options: Options,
110
103
  config: QualityConfig,
@@ -138,7 +131,7 @@ async function main(argv: string[]): Promise<number> {
138
131
  console.error(`quality.config.ts not found in ${cwd}`);
139
132
  return 2;
140
133
  }
141
- const config = mergeIgnores(await loadConfig(configPath), options.ignores);
134
+ const config = await loadConfig(configPath);
142
135
  const baselinePath = resolveBaselinePath(options, config, cwd);
143
136
  const results = await runEngines({
144
137
  baseline:
@@ -147,9 +140,8 @@ async function main(argv: string[]): Promise<number> {
147
140
  : readBaseline(baselinePath),
148
141
  config,
149
142
  cwd,
143
+ overrides: { ignore: options.ignores, targets: options.targets },
150
144
  rawBaseline: join(tmpdir(), `quality-check-raw-${process.pid}.json`),
151
- targets:
152
- options.targets.length > 0 ? options.targets : (config.targets ?? ["."]),
153
145
  });
154
146
  if (options.update) {
155
147
  if (baselinePath === null) {
package/src/config.ts CHANGED
@@ -9,6 +9,7 @@ export const ENGINE_NAMES = [
9
9
  "biome",
10
10
  "knip",
11
11
  "comment-check",
12
+ "document-style-check",
12
13
  "tsdoc-check",
13
14
  ] as const;
14
15
 
@@ -18,25 +19,46 @@ export const ENGINE_NAMES = [
18
19
  export type EngineName = (typeof ENGINE_NAMES)[number];
19
20
 
20
21
  /**
21
- * engineのbinへ追加で渡す起動設定
22
+ * engineへ渡す起動条件
22
23
  */
23
24
  export interface EngineOptions {
25
+ /** 検査から外すpath engineが受け取れないときはreportへ出す */
26
+ ignore?: string[];
27
+ /** 検査する対象path engineが受け取れないときはreportへ出す */
28
+ targets?: string[];
24
29
  /** engineの既定引数の後ろへ足す引数 */
25
30
  args?: string[];
26
31
  }
27
32
 
33
+ /**
34
+ * TSDoc検査へ渡す起動条件
35
+ */
36
+ export interface TsdocCheckOptions extends EngineOptions {
37
+ /** 違反として扱うrule名 */
38
+ error?: string[];
39
+ }
40
+
41
+ /**
42
+ * engine名ごとの起動条件
43
+ */
44
+ export interface EngineConfigMap {
45
+ biome: EngineOptions;
46
+ knip: EngineOptions;
47
+ "comment-check": EngineOptions;
48
+ "document-style-check": EngineOptions;
49
+ "tsdoc-check": TsdocCheckOptions;
50
+ }
51
+
28
52
  /**
29
53
  * quality.config.tsが受け付ける統合検査の設定
30
54
  */
31
55
  export interface QualityConfig {
32
56
  /** 起動するengine 値がfalseまたは未指定のengineは起動しない */
33
- engines: Partial<Record<EngineName, boolean | EngineOptions>>;
34
- /** file走査engineが検査から外すpath */
35
- ignore?: string[];
57
+ engines: Partial<Record<EngineName, boolean>>;
58
+ /** engineごとの起動条件 省略したengineは既定値で起動する */
59
+ config?: Partial<EngineConfigMap>;
36
60
  /** baseline fileのpath falseなら差分判定を行わない */
37
61
  baseline?: string | false;
38
- /** file走査engineへ渡す対象path */
39
- targets?: string[];
40
62
  }
41
63
 
42
64
  /**
@@ -71,6 +93,14 @@ function isEngineName(value: string): value is EngineName {
71
93
  return (ENGINE_NAMES as readonly string[]).includes(value);
72
94
  }
73
95
 
96
+ const ENGINE_OPTION_KEYS: Record<EngineName, readonly string[]> = {
97
+ biome: ["args", "ignore", "targets"],
98
+ knip: ["args", "ignore", "targets"],
99
+ "comment-check": ["args", "ignore", "targets"],
100
+ "document-style-check": ["args", "ignore", "targets"],
101
+ "tsdoc-check": ["args", "error", "ignore", "targets"],
102
+ };
103
+
74
104
  function readStringArray(value: unknown, field: string): string[] | undefined {
75
105
  if (value === undefined) {
76
106
  return undefined;
@@ -97,27 +127,96 @@ function readBaseline(
97
127
  throw new Error(`${source}: baseline must be a path string or false`);
98
128
  }
99
129
 
100
- function parseEngineOptions(
130
+ function parseEngines(
101
131
  value: unknown,
102
132
  source: string,
103
- name: EngineName,
104
- ): boolean | EngineOptions {
105
- if (typeof value === "boolean") {
106
- return value;
107
- }
133
+ ): Partial<Record<EngineName, boolean>> {
108
134
  if (!isJsonObject(value)) {
109
- throw new Error(
110
- `${source}: engines.${name} must be a boolean or an object`,
111
- );
135
+ throw new Error(`${source} must export an engines object`);
112
136
  }
113
- const unknown = Object.keys(value).filter((key) => key !== "args");
137
+ const engines: Partial<Record<EngineName, boolean>> = {};
138
+ for (const [name, enabled] of Object.entries(value)) {
139
+ if (!isEngineName(name)) {
140
+ throw new Error(`${source}: unknown engine: ${name}`);
141
+ }
142
+ if (typeof enabled !== "boolean") {
143
+ throw new Error(
144
+ `${source}: engines.${name} must be a boolean 起動条件はconfigへ置く`,
145
+ );
146
+ }
147
+ engines[name] = enabled;
148
+ }
149
+ if (ENGINE_NAMES.every((name) => !engines[name])) {
150
+ throw new Error(`${source} must enable at least one engine`);
151
+ }
152
+ return engines;
153
+ }
154
+
155
+ function parseEngineOptions(
156
+ value: JsonObject,
157
+ source: string,
158
+ name: EngineName,
159
+ ): TsdocCheckOptions {
160
+ const unknown = Object.keys(value).filter(
161
+ (key) => !ENGINE_OPTION_KEYS[name].includes(key),
162
+ );
114
163
  if (unknown.length > 0) {
115
164
  throw new Error(
116
- `${source}: engines.${name} has an unknown option: ${unknown[0]}`,
165
+ `${source}: config.${name} has an unknown option: ${unknown[0]}`,
166
+ );
167
+ }
168
+ const options: TsdocCheckOptions = {};
169
+ const ignore = readStringArray(
170
+ value.ignore,
171
+ `${source}: config.${name}.ignore`,
172
+ );
173
+ if (ignore !== undefined) {
174
+ options.ignore = ignore;
175
+ }
176
+ const targets = readStringArray(
177
+ value.targets,
178
+ `${source}: config.${name}.targets`,
179
+ );
180
+ if (targets !== undefined) {
181
+ options.targets = targets;
182
+ }
183
+ const args = readStringArray(value.args, `${source}: config.${name}.args`);
184
+ if (args !== undefined) {
185
+ options.args = args;
186
+ }
187
+ if (name === "tsdoc-check") {
188
+ const error = readStringArray(
189
+ value.error,
190
+ `${source}: config.${name}.error`,
117
191
  );
192
+ if (error !== undefined) {
193
+ options.error = error;
194
+ }
195
+ }
196
+ return options;
197
+ }
198
+
199
+ function parseEngineConfig(
200
+ value: unknown,
201
+ source: string,
202
+ ): Partial<EngineConfigMap> | undefined {
203
+ if (value === undefined) {
204
+ return undefined;
205
+ }
206
+ if (!isJsonObject(value)) {
207
+ throw new Error(`${source}: config must be an object`);
208
+ }
209
+ const config: Partial<EngineConfigMap> = {};
210
+ for (const [name, options] of Object.entries(value)) {
211
+ if (!isEngineName(name)) {
212
+ throw new Error(`${source}: unknown engine in config: ${name}`);
213
+ }
214
+ if (!isJsonObject(options)) {
215
+ throw new Error(`${source}: config.${name} must be an object`);
216
+ }
217
+ config[name] = parseEngineOptions(options, source, name);
118
218
  }
119
- const args = readStringArray(value.args, `${source}: engines.${name}.args`);
120
- return args === undefined ? {} : { args };
219
+ return config;
121
220
  }
122
221
 
123
222
  /**
@@ -127,32 +226,17 @@ export function parseConfig(value: unknown, source: string): QualityConfig {
127
226
  if (!isJsonObject(value)) {
128
227
  throw new Error(`${source} must export a config object`);
129
228
  }
130
- if (!isJsonObject(value.engines)) {
131
- throw new Error(`${source} must export an engines object`);
132
- }
133
- const engines: Partial<Record<EngineName, boolean | EngineOptions>> = {};
134
- for (const [name, options] of Object.entries(value.engines)) {
135
- if (!isEngineName(name)) {
136
- throw new Error(`${source}: unknown engine: ${name}`);
137
- }
138
- engines[name] = parseEngineOptions(options, source, name);
229
+ const config: QualityConfig = {
230
+ engines: parseEngines(value.engines, source),
231
+ };
232
+ const engineConfig = parseEngineConfig(value.config, source);
233
+ if (engineConfig !== undefined) {
234
+ config.config = engineConfig;
139
235
  }
140
- if (ENGINE_NAMES.every((name) => !engines[name])) {
141
- throw new Error(`${source} must enable at least one engine`);
142
- }
143
- const config: QualityConfig = { engines };
144
236
  const baseline = readBaseline(value.baseline, source);
145
237
  if (baseline !== undefined) {
146
238
  config.baseline = baseline;
147
239
  }
148
- const ignore = readStringArray(value.ignore, `${source}: ignore`);
149
- if (ignore !== undefined) {
150
- config.ignore = ignore;
151
- }
152
- const targets = readStringArray(value.targets, `${source}: targets`);
153
- if (targets !== undefined) {
154
- config.targets = targets;
155
- }
156
240
  return config;
157
241
  }
158
242
 
@@ -164,17 +248,16 @@ export function enabledEngines(config: QualityConfig): EngineName[] {
164
248
  }
165
249
 
166
250
  /**
167
- * engineの起動設定を返す 無効なengineにはnullを返す
251
+ * engineの起動条件を返す 無効なengineにはnullを返す
168
252
  */
169
- export function engineOptions(
253
+ export function engineConfig<K extends EngineName>(
170
254
  config: QualityConfig,
171
- name: EngineName,
172
- ): EngineOptions | null {
173
- const value = config.engines[name];
174
- if (!value) {
255
+ name: K,
256
+ ): EngineConfigMap[K] | null {
257
+ if (!config.engines[name]) {
175
258
  return null;
176
259
  }
177
- return value === true ? {} : value;
260
+ return config.config?.[name] ?? ({} as EngineConfigMap[K]);
178
261
  }
179
262
 
180
263
  /**
package/src/engines.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
- import { type EngineName, engineOptions, type QualityConfig } from "./config";
3
+ import {
4
+ type EngineName,
5
+ type EngineOptions,
6
+ engineConfig,
7
+ type QualityConfig,
8
+ } from "./config";
4
9
 
5
10
  /**
6
11
  * 子プロセスとして起動したengineの生の結果
@@ -25,6 +30,7 @@ export type EngineRunner = (
25
30
  export const ENGINE_BINS: Record<EngineName, string> = {
26
31
  biome: "biome",
27
32
  "comment-check": "comment-check",
33
+ "document-style-check": "document-style-check",
28
34
  knip: "knip",
29
35
  "tsdoc-check": "tsdoc-check",
30
36
  };
@@ -32,22 +38,72 @@ export const ENGINE_BINS: Record<EngineName, string> = {
32
38
  const WINDOWS_SHIMS = [".exe", ".cmd", ".bat", ""];
33
39
  const POSIX_SHIMS = [""];
34
40
 
41
+ /**
42
+ * コマンドラインから渡された起動条件の上書き
43
+ */
44
+ export interface RunOverrides {
45
+ ignore: string[];
46
+ targets: string[];
47
+ }
48
+
35
49
  /**
36
50
  * engineのコマンドを組み立てるための実行条件
37
51
  */
38
52
  export interface EngineCommandContext {
39
53
  config: QualityConfig;
40
- ignores: string[];
54
+ /** 対応するengineへだけ足す上書き */
55
+ overrides: RunOverrides;
41
56
  /** comment-checkのbaseline差分を無効化するために渡す未作成のpath */
42
57
  rawBaseline: string;
43
- targets: string[];
58
+ }
59
+
60
+ /**
61
+ * engineが受け取らない起動条件と、その設定の持ち主
62
+ */
63
+ export const ENGINE_LIMITS: Record<
64
+ EngineName,
65
+ Partial<Record<"ignore" | "targets", string>>
66
+ > = {
67
+ biome: { ignore: "biome.json holds its settings" },
68
+ knip: {
69
+ ignore: "knip.ts holds its settings",
70
+ targets: "knip analyzes the whole project",
71
+ },
72
+ "comment-check": {},
73
+ "document-style-check": {},
74
+ "tsdoc-check": {},
75
+ };
76
+
77
+ /**
78
+ * engineが受け取らないため渡さなかった起動条件を返す
79
+ */
80
+ export function skippedEngineOptions(
81
+ name: EngineName,
82
+ options: EngineOptions | undefined,
83
+ ): string[] {
84
+ if (options === undefined) {
85
+ return [];
86
+ }
87
+ const limits = ENGINE_LIMITS[name];
88
+ const skipped: string[] = [];
89
+ for (const key of ["ignore", "targets"] as const) {
90
+ const reason = limits[key];
91
+ if (reason !== undefined && options[key] !== undefined) {
92
+ skipped.push(`${key} skipped (${reason})`);
93
+ }
94
+ }
95
+ return skipped;
44
96
  }
45
97
 
46
98
  /**
47
99
  * 検出をJSONで返すengineか
48
100
  */
49
101
  export function isFindingEngine(name: EngineName): boolean {
50
- return name === "comment-check" || name === "tsdoc-check";
102
+ return (
103
+ name === "comment-check" ||
104
+ name === "document-style-check" ||
105
+ name === "tsdoc-check"
106
+ );
51
107
  }
52
108
 
53
109
  /**
@@ -90,24 +146,44 @@ export function buildEngineCommand(
90
146
  executable: string,
91
147
  context: EngineCommandContext,
92
148
  ): string[] {
93
- const extra = engineOptions(context.config, name)?.args ?? [];
149
+ const options: EngineOptions = engineConfig(context.config, name) ?? {};
150
+ const limits = ENGINE_LIMITS[name];
151
+ const extra = options.args ?? [];
152
+ const ignores =
153
+ limits.ignore === undefined
154
+ ? [...(options.ignore ?? []), ...context.overrides.ignore]
155
+ : [];
156
+ const requested =
157
+ context.overrides.targets.length > 0
158
+ ? context.overrides.targets
159
+ : (options.targets ?? ["."]);
160
+ const targets = limits.targets === undefined ? requested : [];
161
+ const ignoreArguments = ignores.flatMap((ignore) => ["--ignore", ignore]);
162
+ const rules = engineConfig(context.config, "tsdoc-check")?.error ?? [];
163
+ const errorArguments = rules.flatMap((rule) => ["--error", rule]);
94
164
  if (name === "biome") {
95
- return [executable, "check", ...context.targets, ...extra];
165
+ return [executable, "check", ...targets, ...extra];
96
166
  }
97
167
  if (name === "knip") {
98
168
  return [executable, ...extra];
99
169
  }
100
- const ignoreArguments = context.ignores.flatMap((ignore) => [
101
- "--ignore",
102
- ignore,
103
- ]);
104
170
  if (name === "comment-check") {
105
171
  return [
106
172
  executable,
107
173
  "--json",
108
174
  "--baseline",
109
175
  context.rawBaseline,
110
- ...context.targets,
176
+ ...targets,
177
+ ...ignoreArguments,
178
+ ...extra,
179
+ ];
180
+ }
181
+ if (name === "document-style-check") {
182
+ return [
183
+ executable,
184
+ "lint",
185
+ "--json",
186
+ ...targets,
111
187
  ...ignoreArguments,
112
188
  ...extra,
113
189
  ];
@@ -115,7 +191,8 @@ export function buildEngineCommand(
115
191
  return [
116
192
  executable,
117
193
  "--json",
118
- ...context.targets,
194
+ ...errorArguments,
195
+ ...targets,
119
196
  ...ignoreArguments,
120
197
  ...extra,
121
198
  ];
package/src/report.ts CHANGED
@@ -25,6 +25,9 @@ function describeStatus(result: EngineResult): string {
25
25
  */
26
26
  export function formatEngineSection(result: EngineResult): string {
27
27
  const lines = [`== ${result.name} ==`];
28
+ for (const skipped of result.skipped) {
29
+ lines.push(`${result.name}: ${skipped}`);
30
+ }
28
31
  if (result.output !== "" && !isFindingEngine(result.name)) {
29
32
  lines.push(result.output);
30
33
  }
@@ -73,6 +76,7 @@ export function toJsonReport(results: EngineResult[]): unknown {
73
76
  name: result.name,
74
77
  reported: result.reported,
75
78
  resolved: result.resolved,
79
+ skipped: result.skipped,
76
80
  status: result.status,
77
81
  warnings: result.warnings,
78
82
  })),
package/src/run.ts CHANGED
@@ -7,8 +7,10 @@ import {
7
7
  type EngineProcessResult,
8
8
  type EngineRunner,
9
9
  isFindingEngine,
10
+ type RunOverrides,
10
11
  resolveExecutable,
11
12
  runEngineProcess,
13
+ skippedEngineOptions,
12
14
  } from "./engines";
13
15
  import { type NormalizedFinding, parseFindings } from "./findings";
14
16
 
@@ -30,6 +32,8 @@ export interface EngineResult {
30
32
  /** baseline適用後に残った阻害する検出 */
31
33
  reported: NormalizedFinding[];
32
34
  resolved: number;
35
+ /** engineが受け取らなかった起動条件 */
36
+ skipped: string[];
33
37
  status: EngineStatus;
34
38
  warnings: NormalizedFinding[];
35
39
  }
@@ -42,8 +46,8 @@ export interface RunOptions {
42
46
  baseline: BaselineFile | null;
43
47
  config: QualityConfig;
44
48
  cwd: string;
45
- /** file走査engineへ渡す対象path */
46
- targets: string[];
49
+ /** コマンドラインから渡された起動条件の上書き */
50
+ overrides: RunOverrides;
47
51
  /** comment-checkのbaseline差分を無効化する未作成のpath */
48
52
  rawBaseline: string;
49
53
  /** engineの実行fileを解決する関数 テストでは差し替える */
@@ -63,6 +67,7 @@ function baseResult(
63
67
  output,
64
68
  reported: [],
65
69
  resolved: 0,
70
+ skipped: [],
66
71
  warnings: [],
67
72
  };
68
73
  }
@@ -144,7 +149,7 @@ async function runProcessEngine(
144
149
  };
145
150
  }
146
151
 
147
- async function runEngine(
152
+ async function executeEngine(
148
153
  name: EngineName,
149
154
  options: RunOptions,
150
155
  context: EngineCommandContext,
@@ -164,6 +169,19 @@ async function runEngine(
164
169
  return await runProcessEngine(name, options, executable, context, runner);
165
170
  }
166
171
 
172
+ async function runEngine(
173
+ name: EngineName,
174
+ options: RunOptions,
175
+ context: EngineCommandContext,
176
+ runner: EngineRunner,
177
+ ): Promise<EngineResult> {
178
+ const result = await executeEngine(name, options, context, runner);
179
+ return {
180
+ ...result,
181
+ skipped: skippedEngineOptions(name, options.config.config?.[name]),
182
+ };
183
+ }
184
+
167
185
  /**
168
186
  * 設定で有効なengineを順に起動する
169
187
  */
@@ -171,9 +189,8 @@ export async function runEngines(options: RunOptions): Promise<EngineResult[]> {
171
189
  const runner = options.runner ?? runEngineProcess;
172
190
  const context: EngineCommandContext = {
173
191
  config: options.config,
174
- ignores: options.config.ignore ?? [],
192
+ overrides: options.overrides,
175
193
  rawBaseline: options.rawBaseline,
176
- targets: options.targets,
177
194
  };
178
195
  const results: EngineResult[] = [];
179
196
  for (const name of enabledEngines(options.config)) {