












@@ -1,84 +1,182 @@
11import { spawn, spawnSync } from "node:child_process";
2+import fs from "node:fs";
23import path from "node:path";
34import {
45acquireLocalHeavyCheckLockSync,
56resolveLocalHeavyCheckEnv,
67shouldAcquireLocalHeavyCheckLockForOxlint,
78} from "./lib/local-heavy-check-runtime.mjs";
899-const extraArgs = process.argv.slice(2);
10-const runner = path.resolve("scripts", "run-oxlint.mjs");
11-const env = resolveLocalHeavyCheckEnv(process.env);
12-const hasMetadataOnlyFlag = extraArgs.some((arg) =>
13-["--help", "-h", "--version", "-V", "--rules", "--print-config", "--init"].includes(arg),
14-);
15-const shouldAcquireParentLock =
16-!hasMetadataOnlyFlag ||
17-shouldAcquireLocalHeavyCheckLockForOxlint(extraArgs, {
10+const DEFAULT_WINDOWS_EXTENSION_CHUNK_SIZE = 8;
11+const EXTENSION_TS_CONFIG = "config/tsconfig/oxlint.extensions.json";
12+const EXTENSIONS_DIR = "extensions";
13+const OXLINT_SOURCE_FILE_PATTERN = /\.[cm]?[jt]sx?$/;
14+15+const CORE_SHARD = {
16+name: "core",
17+args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "src", "ui", "packages"],
18+};
19+const EXTENSIONS_SHARD = {
20+name: "extensions",
21+args: ["--tsconfig", EXTENSION_TS_CONFIG, EXTENSIONS_DIR],
22+};
23+const SCRIPTS_SHARD = {
24+name: "scripts",
25+args: ["--tsconfig", "config/tsconfig/oxlint.scripts.json", "scripts"],
26+};
27+28+export function createOxlintShards({
29+ cwd = process.cwd(),
30+ env = process.env,
31+ platform = process.platform,
32+ readDir = fs.readdirSync,
33+} = {}) {
34+const extensionShards =
35+platform === "win32"
36+ ? createWindowsExtensionShards({ cwd, env, readDir })
37+ : [EXTENSIONS_SHARD];
38+39+return [CORE_SHARD, ...extensionShards, SCRIPTS_SHARD];
40+}
41+42+export function createWindowsExtensionShards({
43+ cwd = process.cwd(),
44+ env = process.env,
45+ readDir = fs.readdirSync,
46+} = {}) {
47+const entries = listExtensionEntries({ cwd, readDir });
48+if (entries.dirs.length === 0 && entries.rootFiles.length === 0) {
49+return [EXTENSIONS_SHARD];
50+}
51+52+const chunkSize = resolveWindowsExtensionChunkSize(env);
53+const shards = [];
54+55+if (entries.rootFiles.length > 0) {
56+shards.push({
57+name: "extensions:root",
58+args: ["--tsconfig", EXTENSION_TS_CONFIG, ...entries.rootFiles],
59+});
60+}
61+62+for (let index = 0; index < entries.dirs.length; index += chunkSize) {
63+const chunk = entries.dirs.slice(index, index + chunkSize);
64+const chunkNumber = String(index / chunkSize + 1).padStart(2, "0");
65+shards.push({
66+name: `extensions:${chunkNumber}`,
67+args: ["--tsconfig", EXTENSION_TS_CONFIG, ...chunk],
68+});
69+}
70+return shards;
71+}
72+73+export function resolveWindowsExtensionChunkSize(env = process.env) {
74+const rawValue = env.OPENCLAW_OXLINT_WINDOWS_EXTENSION_CHUNK_SIZE;
75+if (rawValue === undefined) {
76+return DEFAULT_WINDOWS_EXTENSION_CHUNK_SIZE;
77+}
78+79+const parsedValue = Number.parseInt(rawValue, 10);
80+return Number.isFinite(parsedValue) && parsedValue > 0
81+ ? parsedValue
82+ : DEFAULT_WINDOWS_EXTENSION_CHUNK_SIZE;
83+}
84+85+function listExtensionEntries({ cwd, readDir }) {
86+let entries;
87+try {
88+entries = readDir(path.join(cwd, EXTENSIONS_DIR), { withFileTypes: true });
89+} catch {
90+return {
91+dirs: [],
92+rootFiles: [],
93+};
94+}
95+96+const dirs = entries
97+.filter((entry) => entry.isDirectory())
98+.map((entry) => `${EXTENSIONS_DIR}/${entry.name}`)
99+.toSorted((left, right) => left.localeCompare(right));
100+const rootFiles = entries
101+.filter((entry) => entry.isFile() && OXLINT_SOURCE_FILE_PATTERN.test(entry.name))
102+.map((entry) => `${EXTENSIONS_DIR}/${entry.name}`)
103+.toSorted((left, right) => left.localeCompare(right));
104+105+return {
106+ dirs,
107+ rootFiles,
108+};
109+}
110+111+export async function main(extraArgs = process.argv.slice(2), runtimeEnv = process.env) {
112+const runner = path.resolve("scripts", "run-oxlint.mjs");
113+const env = resolveLocalHeavyCheckEnv(runtimeEnv);
114+const hasMetadataOnlyFlag = extraArgs.some((arg) =>
115+["--help", "-h", "--version", "-V", "--rules", "--print-config", "--init"].includes(arg),
116+);
117+const shouldAcquireParentLock =
118+!hasMetadataOnlyFlag ||
119+shouldAcquireLocalHeavyCheckLockForOxlint(extraArgs, {
120+cwd: process.cwd(),
121+ env,
122+});
123+const releaseLock =
124+env.OPENCLAW_OXLINT_SKIP_LOCK === "1"
125+ ? () => {}
126+ : shouldAcquireParentLock
127+ ? acquireLocalHeavyCheckLockSync({
128+cwd: process.cwd(),
129+ env,
130+toolName: "oxlint shards",
131+})
132+ : () => {};
133+134+const shards = createOxlintShards({
18135cwd: process.cwd(),
19136 env,
137+platform: process.platform,
20138});
21-const releaseLock =
22-env.OPENCLAW_OXLINT_SKIP_LOCK === "1"
23- ? () => {}
24- : shouldAcquireParentLock
25- ? acquireLocalHeavyCheckLockSync({
26-cwd: process.cwd(),
27- env,
28-toolName: "oxlint shards",
29-})
30- : () => {};
31-32-const shards = [
33-{
34-name: "core",
35-args: ["--tsconfig", "config/tsconfig/oxlint.core.json", "src", "ui", "packages"],
36-},
37-{
38-name: "extensions",
39-args: ["--tsconfig", "config/tsconfig/oxlint.extensions.json", "extensions"],
40-},
41-{
42-name: "scripts",
43-args: ["--tsconfig", "config/tsconfig/oxlint.scripts.json", "scripts"],
44-},
45-];
46-47-try {
48-const prepareResult = spawnSync(
49-process.execPath,
50-[path.resolve("scripts", "prepare-extension-package-boundary-artifacts.mjs")],
51-{
52-stdio: "inherit",
53- env,
54-},
55-);
5613957-if (prepareResult.error) {
58-throw prepareResult.error;
59-}
60-if ((prepareResult.status ?? 1) !== 0) {
61-process.exitCode = prepareResult.status ?? 1;
62-} else {
63-const runSerial = env.OPENCLAW_OXLINT_SHARDS_SERIAL === "1";
64-const results = runSerial
65- ? await runShardsSerial(shards)
66- : await Promise.all(shards.map((shard) => runShard(shard)));
67-process.exitCode = results.find((status) => status !== 0) ?? 0;
140+try {
141+const prepareResult = spawnSync(
142+process.execPath,
143+[path.resolve("scripts", "prepare-extension-package-boundary-artifacts.mjs")],
144+{
145+stdio: "inherit",
146+ env,
147+},
148+);
149+150+if (prepareResult.error) {
151+throw prepareResult.error;
152+}
153+if ((prepareResult.status ?? 1) !== 0) {
154+process.exitCode = prepareResult.status ?? 1;
155+} else {
156+const runSerial = env.OPENCLAW_OXLINT_SHARDS_SERIAL === "1" || process.platform === "win32";
157+const results = runSerial
158+ ? await runShardsSerial({ entries: shards, env, extraArgs, runner })
159+ : await Promise.all(shards.map((shard) => runShard({ env, extraArgs, runner, shard })));
160+process.exitCode = results.find((status) => status !== 0) ?? 0;
161+}
162+} finally {
163+releaseLock();
68164}
69-} finally {
70-releaseLock();
71165}
7216673-async function runShardsSerial(entries) {
167+if (import.meta.main) {
168+await main();
169+}
170+171+async function runShardsSerial({ entries, env, extraArgs, runner }) {
74172const results = [];
75173for (const shard of entries) {
76-results.push(await runShard(shard));
174+results.push(await runShard({ env, extraArgs, runner, shard }));
77175}
78176return results;
79177}
8017881-async function runShard(shard) {
179+async function runShard({ env, extraArgs, runner, shard }) {
82180console.error(`[oxlint:${shard.name}] starting`);
83181const child = spawn(process.execPath, [runner, ...shard.args, ...extraArgs], {
84182stdio: "inherit",
此內容由慣性聚合(RSS閱讀器)自動聚合整理,僅供閱讀參考。 原文來自 — 版權歸原作者所有。