Skip to content

Commit f4e73c8

Browse files
committed
feat: add concurrency
1 parent 8025020 commit f4e73c8

File tree

5 files changed

+114
-78
lines changed

5 files changed

+114
-78
lines changed

Diff for: bun.lockb

756 Bytes
Binary file not shown.

Diff for: package.json

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@
5959
"dependencies": {
6060
"@biomejs/js-api": "^0.6.2",
6161
"eslint": "^9.11.0",
62+
"fast-glob": "^3.3.2",
63+
"p-limit": "^6.1.0",
6264
"yargs": "^17.7.2"
6365
}
6466
}

Diff for: src/biome.ts

+74-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
import { Biome, Distribution } from "@biomejs/js-api";
2+
import { readFileSync, existsSync } from "node:fs";
3+
import { readFile, writeFile } from "node:fs/promises";
4+
import fg from "fast-glob";
5+
import fs from "node:fs";
16
import path from "node:path";
2-
import { readFileSync, existsSync, writeFileSync } from "node:fs";
3-
import type { Biome, Configuration, LintResult } from "@biomejs/js-api";
7+
import os from "node:os";
8+
import type { Configuration, LintResult } from "@biomejs/js-api";
49
import type { ESLint } from "eslint";
10+
import pLimit from "p-limit";
511

612
const getSeverity = (severity: LintResult["diagnostics"][0]["severity"]) => {
713
switch (severity) {
@@ -103,8 +109,8 @@ const convertBiomeResult = (
103109
};
104110
};
105111

106-
const biomeLintFile = (biome: Biome, filePath: string, fix = true) => {
107-
const initialContent = readFileSync(filePath, "utf8");
112+
const biomeLintFile = async (biome: Biome, filePath: string, fix = true) => {
113+
const initialContent = await readFile(filePath, "utf8");
108114

109115
const result = biome.lintContent(initialContent, {
110116
filePath,
@@ -117,21 +123,21 @@ const biomeLintFile = (biome: Biome, filePath: string, fix = true) => {
117123
});
118124

119125
if (formatted.content !== result.content) {
120-
writeFileSync(filePath, formatted.content);
126+
await writeFile(filePath, formatted.content);
121127
}
122128
}
123129

124130
return convertBiomeResult(result, filePath, result.content);
125131
};
126132

127-
export const biomeLintFiles = (biome: Biome, files: string[], fix = true) => {
128-
const results = [];
133+
const biomeLintFiles = async (biome: Biome, files: string[], fix = true) => {
134+
const limit = pLimit(os.cpus().length);
129135

130-
for (const file of files) {
131-
const result = biomeLintFile(biome, file, fix);
132-
133-
results.push(result);
134-
}
136+
const results = await Promise.all(
137+
files.map((file) =>
138+
limit(async () => await biomeLintFile(biome, file, fix)),
139+
),
140+
);
135141

136142
return results;
137143
};
@@ -198,7 +204,7 @@ const defaultConfig: Configuration = {
198204
},
199205
};
200206

201-
export const getBiomeConfig = (): Configuration => {
207+
const getBiomeConfig = (): Configuration => {
202208
try {
203209
let config = defaultConfig;
204210
const biomeConfigPath = findNearestBiomeConfig();
@@ -214,3 +220,58 @@ export const getBiomeConfig = (): Configuration => {
214220
return defaultConfig;
215221
}
216222
};
223+
224+
export const lintWithBiome = async (
225+
eslint: ESLint,
226+
patterns: string[],
227+
fix = true,
228+
debug = false,
229+
) => {
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 });
249+
250+
const biome = await Biome.create({
251+
distribution: Distribution.NODE,
252+
});
253+
254+
biome.applyConfiguration(getBiomeConfig());
255+
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);
270+
271+
if (debug) {
272+
performance.mark("biome-end");
273+
performance.measure("biome", "biome-start", "biome-end");
274+
}
275+
276+
return biomeResults;
277+
};

Diff for: src/eslint.ts

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,30 @@
1-
import type { ESLint, Linter } from "eslint";
1+
import { ESLint } from "eslint";
2+
import type { Linter } from "eslint";
3+
import { performance } from "node:perf_hooks";
4+
5+
export const lintWithEslint = async (
6+
eslint: ESLint,
7+
patterns: string[],
8+
fix = true,
9+
debug = false,
10+
) => {
11+
if (debug) {
12+
performance.mark("eslint-start");
13+
}
14+
15+
const eslintResults = await eslint.lintFiles(patterns);
16+
17+
if (fix && eslintResults.length > 0) {
18+
await ESLint.outputFixes(eslintResults);
19+
}
20+
21+
if (debug) {
22+
performance.mark("eslint-end");
23+
performance.measure("eslint", "eslint-start", "eslint-end");
24+
}
25+
26+
return eslintResults;
27+
};
228

329
export const mergeResults = (
430
results: ESLint.LintResult[],

Diff for: src/index.ts

+11-64
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
#!/usr/bin/env node
22

3-
import { Biome, Distribution } from "@biomejs/js-api";
43
import { ESLint } from "eslint";
5-
import { biomeLintFiles, getBiomeConfig } from "./biome";
6-
import { mergeResults, overrideConfig } from "./eslint";
4+
import { lintWithBiome } from "./biome";
5+
import { lintWithEslint, mergeResults, overrideConfig } from "./eslint";
76
import pkgJson from "../package.json" assert { type: "json" };
87
import yargs from "yargs";
98
import { hideBin } from "yargs/helpers";
@@ -31,10 +30,6 @@ const instance = yargs(hideBin(process.argv))
3130
default: true,
3231
description: "Automatically fix linting errors",
3332
})
34-
.option("only", {
35-
choices: ["eslint"],
36-
description: "Only run ESLint",
37-
})
3833
.option("debug", {
3934
type: "boolean",
4035
default: false,
@@ -43,79 +38,31 @@ const instance = yargs(hideBin(process.argv))
4338
.help(),
4439
async (args) => {
4540
try {
46-
const { files: files_, fix, only, debug } = args;
47-
const files = Array.isArray(files_) ? files_ : [files_];
48-
const eslintOnly = only === "eslint";
49-
50-
if (files.length === 0) {
51-
throw new Error("No files provided");
52-
}
41+
const { files: files_, fix, debug } = args;
42+
const patterns = Array.isArray(files_) ? files_ : [files_];
5343

5444
const eslint = new ESLint({
5545
fix,
56-
stats: debug,
57-
cache: true,
58-
overrideConfig: eslintOnly ? [] : overrideConfig,
46+
cache: false,
47+
overrideConfig: overrideConfig,
5948
});
6049

61-
if (debug) {
62-
performance.mark("eslint-start");
63-
}
64-
const eslintResults = await eslint.lintFiles(files);
65-
66-
if (debug) {
67-
performance.mark("eslint-end");
68-
performance.measure("eslint", "eslint-start", "eslint-end");
69-
}
70-
71-
if (fix && eslintResults.length > 0) {
72-
await ESLint.outputFixes(eslintResults);
73-
}
74-
7550
const formatter = await eslint.loadFormatter("stylish");
76-
77-
if (eslintOnly) {
78-
console.warn("Running only ESLint");
79-
const resultText = await formatter.format(eslintResults);
80-
81-
console.log(resultText ? resultText : "No issues found");
82-
83-
return;
84-
}
85-
86-
const allFiles: string[] = eslintResults.map(
87-
(result) => result.filePath,
88-
);
89-
90-
const biome = await Biome.create({
91-
distribution: Distribution.NODE,
92-
});
93-
94-
biome.applyConfiguration(getBiomeConfig());
95-
96-
if (debug) {
97-
performance.mark("biome-start");
98-
}
99-
100-
const biomeResults = biomeLintFiles(biome, allFiles, fix);
101-
102-
if (debug) {
103-
performance.mark("biome-end");
104-
performance.measure("biome", "biome-start", "biome-end");
105-
}
51+
const eslntResults = await lintWithEslint(eslint, patterns, fix, debug);
52+
const biomeResults = await lintWithBiome(eslint, patterns, fix, debug);
10653

10754
const resultText = await formatter.format(
108-
mergeResults([...biomeResults, ...eslintResults]),
55+
mergeResults([...biomeResults, ...eslntResults]),
10956
);
11057

58+
console.log(resultText ? resultText : "No issues found");
59+
11160
if (debug) {
11261
const measurements = performance.getEntriesByType("measure");
11362
for (const measurement of measurements) {
11463
console.log(`${measurement.name}: ${measurement.duration}ms`);
11564
}
11665
}
117-
118-
console.log(resultText ? resultText : "No issues found");
11966
} catch (error) {
12067
console.error(error);
12168
process.exit(1);

0 commit comments

Comments
 (0)