Skip to content

Commit 0caa08d

Browse files
committed
feat: add concurrency settings
1 parent 197d6be commit 0caa08d

File tree

4 files changed

+98
-51
lines changed

4 files changed

+98
-51
lines changed

Diff for: src/biome.ts

+15-41
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { Biome, Distribution } from "@biomejs/js-api";
2+
import pLimit from "p-limit";
23
import { readFileSync, existsSync } from "node:fs";
34
import { readFile, writeFile } from "node:fs/promises";
4-
import fg from "fast-glob";
5-
import fs from "node:fs";
65
import path from "node:path";
76
import os from "node:os";
7+
import { performance } from "node:perf_hooks";
88
import type { Configuration, LintResult } from "@biomejs/js-api";
99
import type { ESLint } from "eslint";
10-
import pLimit from "p-limit";
1110

1211
const getSeverity = (severity: LintResult["diagnostics"][0]["severity"]) => {
1312
switch (severity) {
@@ -130,9 +129,13 @@ const biomeLintFile = async (biome: Biome, filePath: string, fix = true) => {
130129
return convertBiomeResult(result, filePath, result.content);
131130
};
132131

133-
const biomeLintFiles = async (biome: Biome, files: string[], fix = true) => {
134-
const limit = pLimit(os.cpus().length);
135-
132+
const biomeLintFiles = async (
133+
biome: Biome,
134+
files: string[],
135+
fix = true,
136+
concurrency: number = os.cpus().length,
137+
) => {
138+
const limit = pLimit(concurrency);
136139
const results = await Promise.all(
137140
files.map((file) =>
138141
limit(async () => await biomeLintFile(biome, file, fix)),
@@ -222,51 +225,22 @@ const getBiomeConfig = (): Configuration => {
222225
};
223226

224227
export const lintWithBiome = async (
225-
eslint: ESLint,
226-
patterns: string[],
228+
files: string[],
229+
concurrency: number = os.cpus().length,
227230
fix = true,
228231
debug = false,
229232
) => {
230-
const globPatterns = patterns.flatMap((pattern) => {
231-
if (!fs.existsSync(pattern)) {
232-
return pattern;
233-
}
234-
235-
const stats = fs.lstatSync(pattern);
236-
237-
if (stats.isDirectory()) {
238-
return path.join(pattern, "**/*.{js,jsx,ts,tsx}");
239-
}
240-
241-
if (stats.isFile()) {
242-
return pattern;
243-
}
244-
245-
return [];
246-
});
247-
248-
const files = await fg(globPatterns, { dot: true, absolute: true });
233+
if (debug) {
234+
performance.mark("biome-start");
235+
}
249236

250237
const biome = await Biome.create({
251238
distribution: Distribution.NODE,
252239
});
253240

254241
biome.applyConfiguration(getBiomeConfig());
255242

256-
const allFiles: string[] = (
257-
await Promise.all(
258-
files.map(async (file) => {
259-
const isIgnored = await eslint.isPathIgnored(file);
260-
return !isIgnored ? file : null;
261-
}),
262-
)
263-
).filter(Boolean) as string[];
264-
265-
if (debug) {
266-
performance.mark("biome-start");
267-
}
268-
269-
const biomeResults = await biomeLintFiles(biome, allFiles, fix);
243+
const biomeResults = await biomeLintFiles(biome, files, fix, concurrency);
270244

271245
if (debug) {
272246
performance.mark("biome-end");

Diff for: src/eslint.ts

+20-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
import { ESLint } from "eslint";
2-
import type { Linter } from "eslint";
2+
import os from "node:os";
33
import { performance } from "node:perf_hooks";
4+
import pLimit from "p-limit";
5+
import type { Linter } from "eslint";
46

57
export const lintWithEslint = async (
68
eslint: ESLint,
7-
patterns: string[],
9+
files: string[],
10+
concurrency: number = os.cpus().length,
811
fix = true,
912
debug = false,
1013
) => {
1114
if (debug) {
1215
performance.mark("eslint-start");
1316
}
1417

15-
const eslintResults = await eslint.lintFiles(patterns);
16-
17-
if (fix && eslintResults.length > 0) {
18-
await ESLint.outputFixes(eslintResults);
19-
}
18+
const limit = pLimit(concurrency);
19+
20+
const eslintResults = (
21+
await Promise.all(
22+
files.map((file) =>
23+
limit(async () => {
24+
const results = await eslint.lintFiles([file]);
25+
if (fix && results.length > 0) {
26+
await ESLint.outputFixes(results);
27+
}
28+
return results;
29+
}),
30+
),
31+
)
32+
).flat();
2033

2134
if (debug) {
2235
performance.mark("eslint-end");

Diff for: src/files.ts

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import path from "node:path";
2+
import fs from "node:fs";
3+
import os from "node:os";
4+
import fg from "fast-glob";
5+
import type { ESLint } from "eslint";
6+
import pLimit from "p-limit";
7+
8+
export const getFilesToLint = async (
9+
eslint: ESLint,
10+
patterns: string[],
11+
12+
concurrency: number = os.cpus().length,
13+
) => {
14+
const globPatterns = patterns.flatMap((pattern) => {
15+
if (!fs.existsSync(pattern)) {
16+
return pattern;
17+
}
18+
19+
const stats = fs.lstatSync(pattern);
20+
21+
if (stats.isDirectory()) {
22+
return path.join(pattern, "**/*.{js,jsx,ts,tsx}");
23+
}
24+
25+
if (stats.isFile()) {
26+
return pattern;
27+
}
28+
29+
return [];
30+
});
31+
32+
const files = await fg(globPatterns, { dot: true, absolute: true });
33+
34+
await eslint.isPathIgnored(files[0]);
35+
36+
const limit = pLimit(concurrency);
37+
38+
const results = (
39+
await Promise.all(
40+
files.map(async (file) =>
41+
limit(async () => {
42+
const isIgnored = await eslint.isPathIgnored(file);
43+
return !isIgnored ? file : null;
44+
}),
45+
),
46+
)
47+
).filter(Boolean) as string[];
48+
49+
return results;
50+
};

Diff for: src/index.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#!/usr/bin/env node
22

33
import { ESLint } from "eslint";
4+
import { getFilesToLint } from "./files";
45
import { lintWithBiome } from "./biome";
56
import { lintWithEslint, mergeResults, overrideConfig } from "./eslint";
67
import pkgJson from "../package.json" assert { type: "json" };
78
import yargs from "yargs";
89
import { hideBin } from "yargs/helpers";
910
import { performance } from "node:perf_hooks";
11+
import os from "node:os";
1012

1113
const instance = yargs(hideBin(process.argv))
1214
.scriptName("@nivalis/linter")
@@ -35,10 +37,16 @@ const instance = yargs(hideBin(process.argv))
3537
default: false,
3638
description: "Run in debug mode",
3739
})
40+
.option("concurrency", {
41+
type: "number",
42+
default: os.cpus().length,
43+
description:
44+
"Number of concurrent linting processes (default: number of CPU cores)",
45+
})
3846
.help(),
3947
async (args) => {
4048
try {
41-
const { files: files_, fix, debug } = args;
49+
const { files: files_, fix, debug, concurrency } = args;
4250
const patterns = Array.isArray(files_) ? files_ : [files_];
4351

4452
const eslint = new ESLint({
@@ -48,9 +56,11 @@ const instance = yargs(hideBin(process.argv))
4856
});
4957

5058
const formatter = await eslint.loadFormatter("stylish");
59+
const files = await getFilesToLint(eslint, patterns, concurrency);
60+
5161
const [eslntResults, biomeResults] = await Promise.all([
52-
lintWithEslint(eslint, patterns, fix, debug),
53-
lintWithBiome(eslint, patterns, fix, debug),
62+
lintWithEslint(eslint, files, concurrency, fix, debug),
63+
lintWithBiome(files, concurrency, fix, debug),
5464
]);
5565

5666
const resultText = await formatter.format(

0 commit comments

Comments
 (0)