fix(lint): shard core lint checks

This commit is contained in:
Vincent Koc
2026-05-27 09:30:43 +02:00
parent 8caa44fba3
commit 1ba4448a60
3 changed files with 115 additions and 10 deletions

View File

@@ -1486,7 +1486,7 @@
"lint:apps": "pnpm lint:swift",
"lint:auth:no-pairing-store-group": "node scripts/check-no-pairing-store-group-auth.mjs",
"lint:auth:pairing-account-scope": "node scripts/check-pairing-account-scope.mjs",
"lint:core": "node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.core.json src ui packages",
"lint:core": "node scripts/run-oxlint-shards.mjs --only=core --split-core",
"lint:docker-e2e": "node scripts/check-docker-e2e-boundaries.mjs",
"lint:docs": "pnpm dlx --config.resolution-mode=highest markdownlint-cli2 --config config/markdownlint-cli2.jsonc",
"lint:docs:fix": "pnpm dlx --config.resolution-mode=highest markdownlint-cli2 --config config/markdownlint-cli2.jsonc --fix",

View File

@@ -19,6 +19,7 @@ const CORE_SHARD = {
name: "core",
args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "src", "ui", "packages"],
};
const CORE_SPLIT_TARGETS = ["src", "ui", "packages"];
const EXTENSIONS_SHARD = {
name: "extensions",
args: ["--tsconfig", EXTENSION_TS_CONFIG, EXTENSIONS_DIR],
@@ -33,11 +34,20 @@ export function createOxlintShards({
env = process.env,
platform = process.platform,
readDir = fs.readdirSync,
splitCore = false,
} = {}) {
const coreShards = splitCore ? createCoreOxlintShards() : [CORE_SHARD];
const extensionShards =
platform === "win32" ? createWindowsExtensionShards({ cwd, env, readDir }) : [EXTENSIONS_SHARD];
return [CORE_SHARD, ...extensionShards, SCRIPTS_SHARD];
return [...coreShards, ...extensionShards, SCRIPTS_SHARD];
}
export function createCoreOxlintShards() {
return CORE_SPLIT_TARGETS.map((target) => ({
name: `core:${target}`,
args: ["--tsconfig", "config/tsconfig/oxlint.core.json", target],
}));
}
export function createWindowsExtensionShards({
@@ -143,13 +153,14 @@ function listExtensionEntries({ cwd, readDir }) {
export async function main(extraArgs = process.argv.slice(2), runtimeEnv = process.env) {
const runner = path.resolve("scripts", "run-oxlint.mjs");
const shardArgs = parseShardRunnerArgs(extraArgs);
const env = resolveLocalHeavyCheckEnv(runtimeEnv);
const hasMetadataOnlyFlag = extraArgs.some((arg) =>
const hasMetadataOnlyFlag = shardArgs.oxlintArgs.some((arg) =>
["--help", "-h", "--version", "-V", "--rules", "--print-config", "--init"].includes(arg),
);
const shouldAcquireParentLock =
!hasMetadataOnlyFlag ||
shouldAcquireLocalHeavyCheckLockForOxlint(extraArgs, {
shouldAcquireLocalHeavyCheckLockForOxlint(shardArgs.oxlintArgs, {
cwd: process.cwd(),
env,
});
@@ -168,7 +179,9 @@ export async function main(extraArgs = process.argv.slice(2), runtimeEnv = proce
cwd: process.cwd(),
env,
platform: process.platform,
splitCore: shardArgs.splitCore,
});
const selectedShards = filterOxlintShards(shards, shardArgs.only);
try {
const prepareResult = spawnSync(
@@ -186,13 +199,24 @@ export async function main(extraArgs = process.argv.slice(2), runtimeEnv = proce
if ((prepareResult.status ?? 1) !== 0) {
process.exitCode = prepareResult.status ?? 1;
} else {
const runSerial = shouldRunOxlintShardsSerial({
env,
platform: process.platform,
});
const runSerial =
shardArgs.splitCore ||
shouldRunOxlintShardsSerial({
env,
platform: process.platform,
});
const results = runSerial
? await runShardsSerial({ entries: shards, env, extraArgs, runner })
: await Promise.all(shards.map((shard) => runShard({ env, extraArgs, runner, shard })));
? await runShardsSerial({
entries: selectedShards,
env,
extraArgs: shardArgs.oxlintArgs,
runner,
})
: await Promise.all(
selectedShards.map((shard) =>
runShard({ env, extraArgs: shardArgs.oxlintArgs, runner, shard }),
),
);
process.exitCode = results.find((status) => status !== 0) ?? 0;
}
} finally {
@@ -216,6 +240,46 @@ function resolveHostResources(hostResources) {
};
}
export function parseShardRunnerArgs(args) {
const only = new Set();
const oxlintArgs = [];
let splitCore = false;
for (let index = 0; index < args.length; index += 1) {
const arg = args[index];
if (arg === "--split-core") {
splitCore = true;
continue;
}
if (arg === "--only") {
const value = args[index + 1];
if (value) {
only.add(value);
index += 1;
}
continue;
}
if (arg.startsWith("--only=")) {
const value = arg.slice("--only=".length);
if (value) {
only.add(value);
}
continue;
}
oxlintArgs.push(arg);
}
return { only, oxlintArgs, splitCore };
}
export function filterOxlintShards(shards, only) {
if (only.size === 0) {
return shards;
}
return shards.filter((shard) => only.has(shard.name) || only.has(shard.name.split(":")[0]));
}
async function runShardsSerial({ entries, env, extraArgs, runner }) {
const results = [];
for (const shard of entries) {

View File

@@ -2,6 +2,8 @@ import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import {
createOxlintShards,
filterOxlintShards,
parseShardRunnerArgs,
createWindowsExtensionShards,
resolveWindowsExtensionChunkSize,
shouldRunOxlintShardsSerial,
@@ -33,6 +35,9 @@ describe("run-oxlint", () => {
expect(packageJson.scripts.check).toBe("node scripts/check.mjs");
expect(packageJson.scripts.lint).toBe("node scripts/run-oxlint-shards.mjs");
expect(packageJson.scripts["lint:core"]).toBe(
"node scripts/run-oxlint-shards.mjs --only=core --split-core",
);
expect(packageJson.scripts.check).not.toContain(
"node scripts/prepare-extension-package-boundary-artifacts.mjs",
);
@@ -168,6 +173,42 @@ describe("run-oxlint", () => {
]);
});
it("splits core oxlint shards when requested", () => {
expect(createOxlintShards({ splitCore: true }).slice(0, 3)).toEqual([
{
name: "core:src",
args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "src"],
},
{
name: "core:ui",
args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "ui"],
},
{
name: "core:packages",
args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "packages"],
},
]);
});
it("parses shard runner flags without forwarding them to oxlint", () => {
const parsed = parseShardRunnerArgs([
"--only=core",
"--split-core",
"--max-warnings",
"0",
]);
expect([...parsed.only]).toEqual(["core"]);
expect(parsed.splitCore).toBe(true);
expect(parsed.oxlintArgs).toEqual(["--max-warnings", "0"]);
});
it("filters split core shards by shard family", () => {
const shards = filterOxlintShards(createOxlintShards({ splitCore: true }), new Set(["core"]));
expect(shards.map((shard) => shard.name)).toEqual(["core:src", "core:ui", "core:packages"]);
});
it("falls back to the full extension shard when Windows extension dirs are unavailable", () => {
const shards = createWindowsExtensionShards({
cwd: "/repo",