mirror of
https://github.com/biomejs/biome.git
synced 2025-12-23 08:21:13 +00:00
249 lines
6.9 KiB
JavaScript
249 lines
6.9 KiB
JavaScript
#!/usr/bin/node
|
|
|
|
import { execSync } from "node:child_process";
|
|
import * as fs from "node:fs";
|
|
import * as path from "node:path";
|
|
import * as process from "node:process";
|
|
import * as util from "node:util";
|
|
|
|
const REPOSITORIES = {
|
|
eslint: {
|
|
repository: "https://github.com/eslint/eslint.git",
|
|
lintedDirs: ["lib", "messages", "tests/lib", "tests/performance", "tools"],
|
|
},
|
|
prettier: {
|
|
repository: "https://github.com/prettier/prettier.git",
|
|
formattedDirs: ["src", "scripts"],
|
|
},
|
|
webpack: {
|
|
repository: "https://github.com/webpack/webpack.git",
|
|
formattedDirs: ["lib", "examples", "benchmark"],
|
|
lintedDirs: ["lib"],
|
|
},
|
|
};
|
|
|
|
const TMP_DIR = path.resolve("./target");
|
|
|
|
function benchmarkFormatter(biomeBin, options) {
|
|
// Run Dprint once to run the installer
|
|
execSync("npx dprint --version");
|
|
|
|
for (const [name, config] of Object.entries(REPOSITORIES)) {
|
|
if (
|
|
!config.formattedDirs ||
|
|
("repository" in options && options.repository !== name)
|
|
) {
|
|
continue;
|
|
}
|
|
console.info(`\n⌛ repository: ${name}`);
|
|
const projectDirectory = cloneProject(
|
|
name,
|
|
config.repository,
|
|
config.formattedDirs,
|
|
);
|
|
console.info("");
|
|
|
|
const dirs = config.formattedDirs.join(" ");
|
|
const dirGlobs = config.formattedDirs.map((dir) => `"${dir}/**"`).join(" ");
|
|
const biomeCommand = `${biomeBin} format --config-path=../../ --write --max-diagnostics=0 ${dirs}`;
|
|
const benchCommands = {
|
|
prettier: `../../node_modules/.bin/prettier --config=../../.prettierrc.json --ignore-path=../../.prettierignore --write --log-level=error ${dirs}`,
|
|
// FIXME: Parallel Prettier is crashing on Node 22
|
|
// "parallel-prettier": `../../node_modules/.bin/pprettier --write --concurrency ${os.cpus().length} ${dirGlobs}`,
|
|
dprint: `../../node_modules/dprint/dprint fmt --config=../../dprint.json ${dirGlobs}`,
|
|
biome: biomeCommand,
|
|
"biome-1-thread": withEnvVariable("RAYON_NUM_THREADS", "1", biomeCommand),
|
|
};
|
|
|
|
let suite = "";
|
|
for (const benchName of Object.keys(benchCommands)) {
|
|
if ("bench" in options && !options.bench.includes(benchName)) {
|
|
continue;
|
|
}
|
|
suite += ` -n "${benchName}" '${benchCommands[benchName]}'`;
|
|
}
|
|
if (suite.length === 0) {
|
|
console.error(`Benchmark '${options.bench}' doesn't exist.`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Run 2 warmups to make sure the files are formatted correctly
|
|
let hyperfineCommand = `hyperfine --warmup 2 --shell=${shellOption()} ${suite}`;
|
|
if (options.verbose) {
|
|
hyperfineCommand += " --show-output";
|
|
console.info(`${hyperfineCommand}\n`);
|
|
}
|
|
|
|
execSync(hyperfineCommand, {
|
|
cwd: projectDirectory,
|
|
stdio: "inherit",
|
|
});
|
|
}
|
|
}
|
|
|
|
function benchmarkLinter(biomeBin, options) {
|
|
for (const [name, config] of Object.entries(REPOSITORIES)) {
|
|
if (
|
|
!config.lintedDirs ||
|
|
("repository" in options && options.repository !== name)
|
|
) {
|
|
continue;
|
|
}
|
|
console.info(`\n⌛ repository: ${name}`);
|
|
const projectDirectory = cloneProject(
|
|
name,
|
|
config.repository,
|
|
config.formattedDirs,
|
|
);
|
|
console.info("");
|
|
|
|
const dirs = config.lintedDirs.map((dir) => `"${dir}"`).join(" ");
|
|
const biomeCmd = `"${biomeBin}" lint --config-path=../../ --max-diagnostics=0 ${dirs}`;
|
|
const benchCommands = {
|
|
eslint: `../../node_modules/.bin/eslint --quiet --config=../../eslint.config.js --no-ignore ${dirs}`,
|
|
"ts-eslint": `../../node_modules/.bin/eslint --quiet --config=../../ts-eslint.config.js --no-ignore ${dirs}`,
|
|
biome: biomeCmd,
|
|
"biome-1-thread": withEnvVariable("RAYON_NUM_THREADS", "1", biomeCmd),
|
|
"ts-biome": `"${biomeBin}" lint --config-path=../../ts-biome.json --max-diagnostics=0 ${dirs}`,
|
|
};
|
|
|
|
let suite = "";
|
|
for (const benchName of Object.keys(benchCommands)) {
|
|
if ("bench" in options && !options.bench.includes(benchName)) {
|
|
continue;
|
|
}
|
|
suite += ` -n "${benchName}" '${benchCommands[benchName]}'`;
|
|
}
|
|
if (suite.length === 0) {
|
|
console.error(`Benchmark '${options.bench}' doesn't exist.`);
|
|
process.exit(1);
|
|
}
|
|
|
|
let hyperfineCommand = `hyperfine --ignore-failure --shell=${shellOption()} ${suite}`;
|
|
if (options.verbose) {
|
|
hyperfineCommand += " --show-output";
|
|
console.info(`${hyperfineCommand}\n`);
|
|
}
|
|
|
|
execSync(hyperfineCommand, {
|
|
cwd: projectDirectory,
|
|
stdio: "inherit",
|
|
});
|
|
}
|
|
}
|
|
|
|
function shellOption() {
|
|
if (process.platform === "win32") {
|
|
// Use Powershell so that it is possible to set an environment variable for a single command (ugh!)
|
|
return "powershell";
|
|
}
|
|
return "default";
|
|
}
|
|
|
|
function withEnvVariable(name, value, command) {
|
|
switch (process.platform) {
|
|
case "win32": {
|
|
return `$Env:${name}=${value}; ${command}`;
|
|
}
|
|
default:
|
|
return `${name}="${value}" ${command}`;
|
|
}
|
|
}
|
|
|
|
function withDirectory(cwd) {
|
|
return {
|
|
run(command, options) {
|
|
execSync(command, {
|
|
cwd,
|
|
...options,
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
function cloneProject(name, repository, dirs = []) {
|
|
const projectDirectory = path.join(TMP_DIR, name);
|
|
|
|
const inProjectDirectory = withDirectory(projectDirectory);
|
|
|
|
if (fs.existsSync(projectDirectory)) {
|
|
inProjectDirectory.run("git reset --hard @{u}");
|
|
inProjectDirectory.run("git clean -df");
|
|
inProjectDirectory.run("git pull --quiet --depth=1 --ff-only");
|
|
} else {
|
|
withDirectory(TMP_DIR).run(
|
|
`git clone --quiet --depth=1 ${dirs.length > 0 ? "--sparse" : ""} ${repository}`,
|
|
{
|
|
stdio: "inherit",
|
|
},
|
|
);
|
|
}
|
|
|
|
if (dirs.length > 0) {
|
|
console.info(
|
|
`Adding directories ${dirs.join()} to sparse checkout in ${projectDirectory}`,
|
|
);
|
|
inProjectDirectory.run(`git sparse-checkout add ${dirs.join(" ")}`);
|
|
}
|
|
|
|
return projectDirectory;
|
|
}
|
|
|
|
function buildBiome() {
|
|
console.info("Building Biome...");
|
|
execSync(
|
|
withEnvVariable(
|
|
"BIOME_VERSION",
|
|
"0.0.0",
|
|
"cargo build --bin biome --release",
|
|
),
|
|
{
|
|
stdio: "inherit",
|
|
},
|
|
);
|
|
return path.resolve("../target/release/biome");
|
|
}
|
|
|
|
function run({ positionals, values: options }) {
|
|
fs.mkdirSync(TMP_DIR, { recursive: true });
|
|
let biomeBinPath;
|
|
if ("biome" in options) {
|
|
biomeBinPath = options.biome;
|
|
} else {
|
|
biomeBinPath = buildBiome();
|
|
}
|
|
switch (positionals[0]) {
|
|
case "formatter":
|
|
benchmarkFormatter(biomeBinPath, options);
|
|
break;
|
|
case "linter":
|
|
benchmarkLinter(biomeBinPath, options);
|
|
break;
|
|
default:
|
|
console.error(
|
|
`A positional argument among 'formatter' and 'linter' must be passed.`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
run(
|
|
util.parseArgs({
|
|
allowPositionals: true,
|
|
options: {
|
|
bench: {
|
|
multiple: true,
|
|
type: "string",
|
|
},
|
|
biome: {
|
|
type: "string",
|
|
},
|
|
repository: {
|
|
type: "string",
|
|
},
|
|
verbose: {
|
|
type: "boolean",
|
|
},
|
|
},
|
|
}),
|
|
);
|