@yuu1111/quality-check 1.0.0 → 4.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 +102 -46
- package/README.md +105 -49
- package/dist/cli.js +21876 -419
- package/package.json +11 -14
- package/schema.json +688 -0
- package/src/config.ts +0 -490
- package/src/engines.ts +0 -403
package/src/engines.ts
DELETED
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
type EngineName,
|
|
5
|
-
type EngineOptions,
|
|
6
|
-
engineConfig,
|
|
7
|
-
type QualityConfig,
|
|
8
|
-
RULE_VOCABULARY,
|
|
9
|
-
type RuleState,
|
|
10
|
-
} from "./config";
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 子プロセスとして起動したengineの生の結果
|
|
14
|
-
*/
|
|
15
|
-
export interface EngineProcessResult {
|
|
16
|
-
exitCode: number | null;
|
|
17
|
-
stderr: string;
|
|
18
|
-
stdout: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* engineを起動して出力を返す関数 テストでは差し替える
|
|
23
|
-
*/
|
|
24
|
-
export type EngineRunner = (
|
|
25
|
-
command: string[],
|
|
26
|
-
options: { cwd: string },
|
|
27
|
-
) => Promise<EngineProcessResult>;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* engineごとの実行file名
|
|
31
|
-
*/
|
|
32
|
-
export const ENGINE_BINS: Record<EngineName, string> = {
|
|
33
|
-
biome: "biome",
|
|
34
|
-
"code-style-check": "code-style-check",
|
|
35
|
-
"comment-check": "comment-check",
|
|
36
|
-
"document-style-check": "document-style-check",
|
|
37
|
-
knip: "knip",
|
|
38
|
-
"tsdoc-check": "tsdoc-check",
|
|
39
|
-
typecheck: "tsc",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const WINDOWS_SHIMS = [".exe", ".cmd", ".bat", ""];
|
|
43
|
-
const POSIX_SHIMS = [""];
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* コマンドラインから渡された起動条件の上書き
|
|
47
|
-
*/
|
|
48
|
-
export interface RunOverrides {
|
|
49
|
-
ignore: string[];
|
|
50
|
-
targets: string[];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* engineのコマンドを組み立てるための実行条件
|
|
55
|
-
*/
|
|
56
|
-
export interface EngineCommandContext {
|
|
57
|
-
config: QualityConfig;
|
|
58
|
-
/** engine自身の出力へ色を付けるか */
|
|
59
|
-
color: boolean;
|
|
60
|
-
/** 対応するengineへだけ足す上書き */
|
|
61
|
-
overrides: RunOverrides;
|
|
62
|
-
/** comment-checkのbaseline差分を無効化するために渡す未作成のpath */
|
|
63
|
-
rawBaseline: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* engineが受け取らない起動条件と、その設定の持ち主
|
|
68
|
-
*/
|
|
69
|
-
export const ENGINE_LIMITS: Record<
|
|
70
|
-
EngineName,
|
|
71
|
-
Partial<Record<"ignore" | "targets", string>>
|
|
72
|
-
> = {
|
|
73
|
-
biome: { ignore: "biome.json holds its settings" },
|
|
74
|
-
typecheck: {
|
|
75
|
-
ignore: "tsconfig.json holds its settings",
|
|
76
|
-
targets: "tsconfig.json and projects hold its settings",
|
|
77
|
-
},
|
|
78
|
-
knip: {
|
|
79
|
-
ignore: "knip.ts holds its settings",
|
|
80
|
-
targets: "knip analyzes the whole project",
|
|
81
|
-
},
|
|
82
|
-
"code-style-check": {},
|
|
83
|
-
"comment-check": {},
|
|
84
|
-
"document-style-check": {},
|
|
85
|
-
"tsdoc-check": {},
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* engineが受け取らないため渡さなかった起動条件を返す
|
|
90
|
-
*
|
|
91
|
-
* @param name - 受け取れない起動条件を引くengine名
|
|
92
|
-
* @param options - engineへ渡そうとした起動条件
|
|
93
|
-
* @returns 渡さなかった起動条件とその理由の一覧
|
|
94
|
-
*/
|
|
95
|
-
export function skippedEngineOptions(
|
|
96
|
-
name: EngineName,
|
|
97
|
-
options: EngineOptions | undefined,
|
|
98
|
-
): string[] {
|
|
99
|
-
if (options === undefined) {
|
|
100
|
-
return [];
|
|
101
|
-
}
|
|
102
|
-
const limits = ENGINE_LIMITS[name];
|
|
103
|
-
const skipped: string[] = [];
|
|
104
|
-
for (const key of ["ignore", "targets"] as const) {
|
|
105
|
-
const reason = limits[key];
|
|
106
|
-
if (reason !== undefined && options[key] !== undefined) {
|
|
107
|
-
skipped.push(`${key} skipped (${reason})`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return skipped;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* 検出をJSONで返すengineか
|
|
115
|
-
*
|
|
116
|
-
* @param name - 判定するengine名
|
|
117
|
-
* @returns 検出をJSONで返すengineならtrue
|
|
118
|
-
*/
|
|
119
|
-
export function isFindingEngine(name: EngineName): boolean {
|
|
120
|
-
return (
|
|
121
|
-
name === "code-style-check" ||
|
|
122
|
-
name === "comment-check" ||
|
|
123
|
-
name === "document-style-check" ||
|
|
124
|
-
name === "tsdoc-check"
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* node_modules/.binとPATHからengineの実行fileを探す
|
|
130
|
-
*
|
|
131
|
-
* @param name - 実行fileを探すengine名
|
|
132
|
-
* @param cwd - 探索を開始する作業ディレクトリのpath
|
|
133
|
-
* @returns 見つけた実行fileのpath PATHにも無ければnull
|
|
134
|
-
*/
|
|
135
|
-
export function resolveExecutable(
|
|
136
|
-
name: EngineName,
|
|
137
|
-
cwd: string,
|
|
138
|
-
): string | null {
|
|
139
|
-
const shims = process.platform === "win32" ? WINDOWS_SHIMS : POSIX_SHIMS;
|
|
140
|
-
const bin = ENGINE_BINS[name];
|
|
141
|
-
let directory = cwd;
|
|
142
|
-
for (;;) {
|
|
143
|
-
for (const shim of shims) {
|
|
144
|
-
const candidate = join(
|
|
145
|
-
directory,
|
|
146
|
-
"node_modules",
|
|
147
|
-
".bin",
|
|
148
|
-
`${bin}${shim}`,
|
|
149
|
-
);
|
|
150
|
-
if (existsSync(candidate)) {
|
|
151
|
-
return candidate;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
const parent = dirname(directory);
|
|
155
|
-
if (parent === directory) {
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
directory = parent;
|
|
159
|
-
}
|
|
160
|
-
const onPath = Bun.which(bin);
|
|
161
|
-
return onPath ?? null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* engine自身の出力へ色を付けるための引数を返す
|
|
166
|
-
*/
|
|
167
|
-
function colorArguments(name: EngineName, color: boolean): string[] {
|
|
168
|
-
if (!color) {
|
|
169
|
-
return [];
|
|
170
|
-
}
|
|
171
|
-
if (name === "biome") {
|
|
172
|
-
return ["--colors=force"];
|
|
173
|
-
}
|
|
174
|
-
if (name === "typecheck") {
|
|
175
|
-
return ["--pretty"];
|
|
176
|
-
}
|
|
177
|
-
return [];
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* 型検査のコマンドを組み立てる projectを渡すとそのtsconfigを読む
|
|
182
|
-
*/
|
|
183
|
-
function buildTypecheckCommand(
|
|
184
|
-
executable: string,
|
|
185
|
-
context: EngineCommandContext,
|
|
186
|
-
project: string | undefined,
|
|
187
|
-
): string[] {
|
|
188
|
-
const options = engineConfig(context.config, "typecheck") ?? {};
|
|
189
|
-
return [
|
|
190
|
-
executable,
|
|
191
|
-
"--noEmit",
|
|
192
|
-
...(project === undefined ? [] : ["--project", project]),
|
|
193
|
-
...colorArguments("typecheck", context.color),
|
|
194
|
-
...(options.args ?? []),
|
|
195
|
-
];
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* 設定fileが持つruleの指定
|
|
200
|
-
*/
|
|
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] };
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* engineへ渡すコマンドを組み立てる
|
|
273
|
-
*
|
|
274
|
-
* @param name - コマンドを組み立てるengine名
|
|
275
|
-
* @param executable - 起動するengineの実行fileのpath
|
|
276
|
-
* @param context - 設定と上書きを持つ実行条件
|
|
277
|
-
* @returns engineへ渡す引数を並べたコマンド
|
|
278
|
-
*/
|
|
279
|
-
export function buildEngineCommand(
|
|
280
|
-
name: EngineName,
|
|
281
|
-
executable: string,
|
|
282
|
-
context: EngineCommandContext,
|
|
283
|
-
): string[] {
|
|
284
|
-
const options: EngineOptions = engineConfig(context.config, name) ?? {};
|
|
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]);
|
|
292
|
-
const extra = options.args ?? [];
|
|
293
|
-
const ignores =
|
|
294
|
-
limits.ignore === undefined
|
|
295
|
-
? [...(options.ignore ?? []), ...context.overrides.ignore]
|
|
296
|
-
: [];
|
|
297
|
-
const requested =
|
|
298
|
-
context.overrides.targets.length > 0
|
|
299
|
-
? context.overrides.targets
|
|
300
|
-
: (options.targets ?? ["."]);
|
|
301
|
-
const targets = limits.targets === undefined ? requested : [];
|
|
302
|
-
const ignoreArguments = ignores.flatMap((ignore) => ["--ignore", ignore]);
|
|
303
|
-
if (name === "biome") {
|
|
304
|
-
return [
|
|
305
|
-
executable,
|
|
306
|
-
"check",
|
|
307
|
-
...colorArguments(name, context.color),
|
|
308
|
-
...targets,
|
|
309
|
-
...extra,
|
|
310
|
-
];
|
|
311
|
-
}
|
|
312
|
-
if (name === "typecheck") {
|
|
313
|
-
return buildTypecheckCommand(executable, context, undefined);
|
|
314
|
-
}
|
|
315
|
-
if (name === "knip") {
|
|
316
|
-
return [executable, ...extra];
|
|
317
|
-
}
|
|
318
|
-
if (name === "comment-check") {
|
|
319
|
-
return [
|
|
320
|
-
executable,
|
|
321
|
-
"--json",
|
|
322
|
-
"--baseline",
|
|
323
|
-
context.rawBaseline,
|
|
324
|
-
...enableArguments,
|
|
325
|
-
...targets,
|
|
326
|
-
...ignoreArguments,
|
|
327
|
-
...extra,
|
|
328
|
-
];
|
|
329
|
-
}
|
|
330
|
-
if (name === "document-style-check") {
|
|
331
|
-
return [
|
|
332
|
-
executable,
|
|
333
|
-
"lint",
|
|
334
|
-
"--json",
|
|
335
|
-
...enableArguments,
|
|
336
|
-
...targets,
|
|
337
|
-
...ignoreArguments,
|
|
338
|
-
...extra,
|
|
339
|
-
];
|
|
340
|
-
}
|
|
341
|
-
if (name === "code-style-check") {
|
|
342
|
-
return [executable, "--json", ...targets, ...ignoreArguments, ...extra];
|
|
343
|
-
}
|
|
344
|
-
return [
|
|
345
|
-
executable,
|
|
346
|
-
"--json",
|
|
347
|
-
...enableArguments,
|
|
348
|
-
...errorArguments,
|
|
349
|
-
...targets,
|
|
350
|
-
...ignoreArguments,
|
|
351
|
-
...extra,
|
|
352
|
-
];
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
/**
|
|
356
|
-
* engineの起動コマンドを順番に返す 型検査だけはprojectsごとに起動する
|
|
357
|
-
*
|
|
358
|
-
* @param name - コマンドを組み立てるengine名
|
|
359
|
-
* @param executable - 起動するengineの実行fileのpath
|
|
360
|
-
* @param context - 設定と上書きを持つ実行条件
|
|
361
|
-
* @returns 起動する順に並べたコマンドの配列
|
|
362
|
-
*/
|
|
363
|
-
export function buildEngineCommands(
|
|
364
|
-
name: EngineName,
|
|
365
|
-
executable: string,
|
|
366
|
-
context: EngineCommandContext,
|
|
367
|
-
): string[][] {
|
|
368
|
-
const projects =
|
|
369
|
-
name === "typecheck"
|
|
370
|
-
? (engineConfig(context.config, "typecheck")?.projects ?? [])
|
|
371
|
-
: [];
|
|
372
|
-
if (projects.length === 0) {
|
|
373
|
-
return [buildEngineCommand(name, executable, context)];
|
|
374
|
-
}
|
|
375
|
-
return projects.map((project) =>
|
|
376
|
-
buildTypecheckCommand(executable, context, project),
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* Bun.spawnでengineを起動する既定のrunner
|
|
382
|
-
*
|
|
383
|
-
* @param command - 実行fileと引数を並べたコマンド
|
|
384
|
-
* @param options - engineを起動する作業ディレクトリを持つ条件
|
|
385
|
-
* @returns 終了codeと標準出力と標準エラーを持つ結果
|
|
386
|
-
*/
|
|
387
|
-
export async function runEngineProcess(
|
|
388
|
-
command: string[],
|
|
389
|
-
options: { cwd: string },
|
|
390
|
-
): Promise<EngineProcessResult> {
|
|
391
|
-
const child = Bun.spawn({
|
|
392
|
-
cmd: command,
|
|
393
|
-
cwd: options.cwd,
|
|
394
|
-
stderr: "pipe",
|
|
395
|
-
stdout: "pipe",
|
|
396
|
-
});
|
|
397
|
-
const [stdout, stderr, exitCode] = await Promise.all([
|
|
398
|
-
new Response(child.stdout).text(),
|
|
399
|
-
new Response(child.stderr).text(),
|
|
400
|
-
child.exited,
|
|
401
|
-
]);
|
|
402
|
-
return { exitCode, stderr, stdout };
|
|
403
|
-
}
|