@tsrx/oxc 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import { resolvePackageBinary } from "./package-binary.js";
2
1
  import { runCaptured, runPassthrough } from "./process.js";
3
- import { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, isViteConfigPath, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeCommand } from "./runtime.js";
2
+ import { resolvePackageBinary } from "./package-binary.js";
3
+ import { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, isViteConfigPath, pathArguments, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeCommand } from "./runtime.js";
4
4
  import { VALUE_OPTIONS, parseOxfmtInvocation, parseOxfmtOption } from "./format-invocation.js";
5
5
  import { isAbsolute, relative } from "node:path";
6
6
  import { readFileSync } from "node:fs";
@@ -231,7 +231,7 @@ async function runCli(args, options = {}) {
231
231
  }
232
232
  }
233
233
  const positions = invocation.positionals;
234
- const files = await discoverTsrxFiles(positions, cwd);
234
+ const files = await discoverTsrxFiles(positions, cwd, "format");
235
235
  if (files.length > 0 || hasTsrxPositional(positions)) {
236
236
  const unknown = unknownCanonicalOption(args);
237
237
  if (unknown !== null) {
@@ -242,13 +242,15 @@ async function runCli(args, options = {}) {
242
242
  const explicitConfig = argumentValue(args, /* @__PURE__ */ new Set(["-c", "--config"]));
243
243
  const bridgeViteConfig = explicitConfig === null || isViteConfigPath(explicitConfig);
244
244
  const viteConfig = files.length > 0 && bridgeViteConfig ? await prepareVitePlusConfig("fmt", cwd, isViteConfigPath(explicitConfig) ? explicitConfig : null) : null;
245
+ let nativePaths = null;
245
246
  try {
246
247
  const stripped = removeExplicitTsrx(args, VALUE_OPTIONS);
247
248
  const shouldRunUpstream = !stripped.hadPositionals || stripped.remainingPositionals > 0;
248
249
  const upstream = resolvePackageBinary("oxfmt-current", "oxfmt", import.meta.url);
249
250
  const useMaterializedUpstreamConfig = Boolean(viteConfig && !viteConfig.requiresAuthoredBase);
250
251
  const upstreamArgs = useMaterializedUpstreamConfig ? replaceConfigArgument(stripped.args, viteConfig.path) : stripped.args;
251
- const nativeArgs = files.length > 0 ? nativeArguments(args, withCwdRelativePaths(files, cwd), viteConfig) : null;
252
+ nativePaths = files.length > 0 ? await pathArguments(withCwdRelativePaths(files, cwd)) : null;
253
+ const nativeArgs = nativePaths ? nativeArguments(args, nativePaths.args, viteConfig) : null;
252
254
  const nativeCommand = nativeArgs ? resolveNativeCommand("format", nativeArgs) : null;
253
255
  const [upstreamResult, nativeResult] = await Promise.all([shouldRunUpstream ? runCaptured(process.execPath, [upstream, ...upstreamArgs], {
254
256
  cwd,
@@ -269,6 +271,7 @@ async function runCli(args, options = {}) {
269
271
  process.stderr.write(attributeNativeErrors(mergeFormatStderr(upstreamResult, nativeResult, stdout)));
270
272
  return Math.max(upstreamResult.status, nativeResult.status);
271
273
  } finally {
274
+ await nativePaths?.cleanup();
272
275
  await viteConfig?.cleanup();
273
276
  }
274
277
  }
package/dist/lint-cli.js CHANGED
@@ -1,6 +1,6 @@
1
- import { resolvePackageBinary } from "./package-binary.js";
2
1
  import { runCaptured, runPassthrough } from "./process.js";
3
- import { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, ensureSupportedOutput, isViteConfigPath, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeCommand } from "./runtime.js";
2
+ import { resolvePackageBinary } from "./package-binary.js";
3
+ import { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, ensureSupportedOutput, isViteConfigPath, pathArguments, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeCommand } from "./runtime.js";
4
4
  import { DELEGATE_ONLY, VALUE_OPTIONS, parseOxlintInvocation, parseOxlintOption, withOxlintOutputFormat } from "./lint-invocation.js";
5
5
  import { jsPluginUnmappedNote, preparePluginLane } from "./lint-js-plugins.js";
6
6
  import { readFile } from "node:fs/promises";
@@ -379,6 +379,7 @@ async function runCli(args, options = {}) {
379
379
  }
380
380
  const pluginLaneActive = pluginLane?.status === "active";
381
381
  if (pluginLaneActive && !args.includes("--silent")) process.stderr.write(`${pluginLane.notice}\n`);
382
+ let nativePaths = null;
382
383
  try {
383
384
  const stripped = removeExplicitTsrx(args, VALUE_OPTIONS);
384
385
  const shouldRunUpstream = !stripped.hadPositionals || stripped.remainingPositionals > 0;
@@ -396,7 +397,8 @@ async function runCli(args, options = {}) {
396
397
  let upstreamArgs = withOxlintOutputFormat(stripped.args, "json");
397
398
  if (useMaterializedUpstreamConfig) upstreamArgs = replaceConfigArgument(upstreamArgs, viteConfig.path);
398
399
  const nativeResolvedConfig = pluginLane?.nativeConfig ?? viteConfig;
399
- const nativeArgs = files.length > 0 ? nativeArguments(args, files, nativeResolvedConfig) : null;
400
+ nativePaths = files.length > 0 ? await pathArguments(files) : null;
401
+ const nativeArgs = nativePaths ? nativeArguments(args, nativePaths.args, nativeResolvedConfig) : null;
400
402
  const nativeCommand = nativeArgs ? resolveNativeCommand("lint", nativeArgs) : null;
401
403
  let upstreamPromise;
402
404
  if (!shouldRunUpstream) upstreamPromise = Promise.resolve({
@@ -480,6 +482,7 @@ async function runCli(args, options = {}) {
480
482
  return Math.max(upstreamResult.status, nativeResult.status, denyWarnings && warnings > 0 ? 1 : 0, exceedsMaximum ? 1 : 0, pluginErrors ? 1 : 0);
481
483
  } finally {
482
484
  await pluginLane?.cleanup?.();
485
+ await nativePaths?.cleanup();
483
486
  await viteConfig?.cleanup();
484
487
  }
485
488
  }
@@ -1,6 +1,6 @@
1
- import { resolvePackageBinary } from "./package-binary.js";
2
1
  import { runCaptured } from "./process.js";
3
- import { resolveNativeCommand } from "./runtime.js";
2
+ import { resolvePackageBinary } from "./package-binary.js";
3
+ import { pathArguments, resolveNativeCommand } from "./runtime.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
6
6
  import { dirname, isAbsolute, join, parse, relative, resolve, sep } from "node:path";
@@ -434,8 +434,14 @@ async function preparePluginLane({ cwd, files, viteConfig, explicitConfig }) {
434
434
  async function emitProjections(cwd, files, nativeConfig) {
435
435
  const args = ["--emit-plugin-projection"];
436
436
  if (nativeConfig) args.push("--config", nativeConfig.path, "--config-base", nativeConfig.base);
437
- const command = resolveNativeCommand("lint", [...args, ...files]);
438
- const result = await runCaptured(command.executable, command.args, { cwd });
437
+ const paths = await pathArguments(files);
438
+ let result;
439
+ try {
440
+ const command = resolveNativeCommand("lint", [...args, ...paths.args]);
441
+ result = await runCaptured(command.executable, command.args, { cwd });
442
+ } finally {
443
+ await paths.cleanup();
444
+ }
439
445
  if (result.status !== 0) throw new Error(`the native TSRX projection needed for JS plugins failed:\n${result.stderr || result.stdout}`);
440
446
  let parsed;
441
447
  try {
@@ -1,5 +1,5 @@
1
- import { resolvePackageBinary } from "./package-binary.js";
2
1
  import { runCaptured } from "./process.js";
2
+ import { resolvePackageBinary } from "./package-binary.js";
3
3
  //#region src/lint-prestart.ts
4
4
  function startCanonicalOxlint(args, cwd = process.cwd(), env = process.env) {
5
5
  const binary = resolvePackageBinary("oxlint-current", "oxlint", import.meta.url);
package/dist/parser.js CHANGED
@@ -3,7 +3,7 @@ import { isTsrxBinaryProgram, parseTrustedTsrxProgram, parseTsrxProgram } from "
3
3
  import { createRequire } from "node:module";
4
4
  //#region src/parser.ts
5
5
  const require = createRequire(import.meta.url);
6
- const PACKAGE_VERSION = "0.10.0";
6
+ const PACKAGE_VERSION = "0.12.0";
7
7
  const parserManifest = Object.freeze({
8
8
  name: "@tsrx/oxc",
9
9
  version: PACKAGE_VERSION,
package/dist/runtime.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { nativePackageName, nativeTargetForHost } from "./native-targets.js";
2
- import { resolvePackageBinary } from "./package-binary.js";
3
2
  import { runCaptured, runPassthrough } from "./process.js";
3
+ import { resolvePackageBinary } from "./package-binary.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises";
6
6
  import { dirname, isAbsolute, join, parse, resolve, sep } from "node:path";
@@ -254,7 +254,7 @@ function slash(path) {
254
254
  function hasMagic(path) {
255
255
  return /[*?[\]{}()!]/u.test(path);
256
256
  }
257
- async function classifyPattern(raw, cwd, positives, patterns) {
257
+ async function classifyPattern(raw, cwd, positives, patterns, directories) {
258
258
  const negative = raw.startsWith("!");
259
259
  const value = negative ? raw.slice(1) : raw;
260
260
  const absolute = isAbsolute(value) ? value : resolve(cwd, value);
@@ -266,31 +266,93 @@ async function classifyPattern(raw, cwd, positives, patterns) {
266
266
  return;
267
267
  }
268
268
  if (metadata.isDirectory()) {
269
- patterns.push(`${negative ? "!" : ""}${slash(join(absolute, "**/*.tsrx"))}`);
269
+ if (negative) patterns.push(`!${slash(join(absolute, "**/*.tsrx"))}`);
270
+ else directories.push(absolute);
270
271
  return;
271
272
  }
272
273
  } catch {}
273
274
  patterns.push(`${negative ? "!" : ""}${slash(value)}`);
274
275
  }
275
- async function classifyPatterns(inputs, cwd, positives, patterns) {
276
+ async function classifyPatterns(inputs, cwd, positives, patterns, directories) {
276
277
  const classified = await Promise.all(inputs.map(async (input) => {
277
278
  const entryPositives = /* @__PURE__ */ new Set();
278
279
  const entryPatterns = [];
279
- await classifyPattern(input, cwd, entryPositives, entryPatterns);
280
+ const entryDirectories = [];
281
+ await classifyPattern(input, cwd, entryPositives, entryPatterns, entryDirectories);
280
282
  return {
281
283
  entryPositives,
282
- entryPatterns
284
+ entryPatterns,
285
+ entryDirectories
283
286
  };
284
287
  }));
285
- for (const { entryPositives, entryPatterns } of classified) {
288
+ for (const { entryPositives, entryPatterns, entryDirectories } of classified) {
286
289
  for (const positive of entryPositives) positives.add(positive);
287
290
  for (const pattern of entryPatterns) patterns.push(pattern);
291
+ for (const directory of entryDirectories) directories.push(directory);
292
+ }
293
+ }
294
+ /**
295
+ * A file list as arguments the native leaf accepts. A short list travels on the
296
+ * command line as before. A long one is written to a temporary file and named
297
+ * with `--paths-file`, because a host's argument limit is reached by a real
298
+ * repository (E2BIG past about a megabyte on macOS and Linux, a 32 KiB command
299
+ * line on Windows, which a few hundred paths fill). The caller disposes of it.
300
+ */
301
+ async function pathArguments(files, budget = 24e3) {
302
+ if (files.reduce((total, file) => total + Buffer.byteLength(file) + 1, 0) <= budget) return {
303
+ args: [...files],
304
+ cleanup: async () => {}
305
+ };
306
+ const directory = await mkdtemp(join(tmpdir(), "oxc-tsrx-paths-"));
307
+ const path = join(directory, "paths.txt");
308
+ await writeFile(path, `${files.join("\n")}\n`);
309
+ return {
310
+ args: ["--paths-file", path],
311
+ cleanup: () => rm(directory, {
312
+ recursive: true,
313
+ force: true
314
+ })
315
+ };
316
+ }
317
+ /**
318
+ * Directories are walked by the native leaf, on the same `ignore` crate
319
+ * canonical Oxlint walks with, so `.gitignore` and `.ignore` files are honoured
320
+ * and `node_modules` and `.git` are never entered. Without that, a monorepo
321
+ * that keeps gitignored copies of itself handed every one of them to the leaf.
322
+ * Returns null when no native package is installed, and the caller falls back
323
+ * to the plain glob so the run can still reach the error that names the missing
324
+ * package.
325
+ */
326
+ async function walkWithNativeLeaf(directories, cwd, kind) {
327
+ let command;
328
+ try {
329
+ command = resolveNativeCommand(kind, ["--discover"]);
330
+ } catch {
331
+ return null;
332
+ }
333
+ const paths = await pathArguments(directories);
334
+ try {
335
+ const result = await runCaptured(command.executable, [...command.args, ...paths.args], { cwd });
336
+ if (result.status !== 0) throw new Error(`.tsrx discovery failed: ${(result.stderr || result.stdout).trim()}`);
337
+ const report = JSON.parse(result.stdout);
338
+ if (!Array.isArray(report?.files)) throw new Error(".tsrx discovery returned no file list");
339
+ return report.files.map((file) => resolve(file));
340
+ } finally {
341
+ await paths.cleanup();
288
342
  }
289
343
  }
290
- async function discoverTsrxFiles(positionals, cwd = process.cwd()) {
344
+ /**
345
+ * `kind` names the leaf that walks directories, `lint` or `format`: both
346
+ * answer `--discover` identically, and each command resolves its own binary.
347
+ */
348
+ async function discoverTsrxFiles(positionals, cwd = process.cwd(), kind = "lint") {
291
349
  const positives = /* @__PURE__ */ new Set();
292
350
  const patterns = [];
293
- await classifyPatterns(positionals.length === 0 ? ["."] : positionals, cwd, positives, patterns);
351
+ const directories = [];
352
+ await classifyPatterns(positionals.length === 0 ? ["."] : positionals, cwd, positives, patterns, directories);
353
+ const walked = directories.length > 0 && !patterns.some((pattern) => pattern.startsWith("!")) ? await walkWithNativeLeaf(directories, cwd, kind) : null;
354
+ if (walked === null) for (const directory of directories) patterns.push(slash(join(directory, "**/*.tsrx")));
355
+ else for (const file of walked) positives.add(file);
294
356
  if (patterns.length > 0) {
295
357
  const { glob } = await import("tinyglobby");
296
358
  const matches = await glob(patterns, {
@@ -320,4 +382,4 @@ function ensureSupportedOutput(format, files) {
320
382
  if (files.length > 0 && format !== "default" && format !== "json") throw new Error(`OXC for TSRX currently combines default and json lint output; ${format} is unavailable for mixed .tsrx runs`);
321
383
  }
322
384
  //#endregion
323
- export { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, ensureSupportedOutput, isViteConfigPath, platformPackage, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeBinary, resolveNativeCommand, resolvePackageBinary, runCaptured, runPassthrough };
385
+ export { argumentValue, canonicalToolEnvironment, discoverTsrxFiles, ensureSupportedOutput, isViteConfigPath, pathArguments, platformPackage, prepareVitePlusConfig, removeExplicitTsrx, replaceConfigArgument, resolveNativeBinary, resolveNativeCommand, resolvePackageBinary, runCaptured, runPassthrough };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsrx/oxc",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "The official OXC integration for TSRX — Rust-native Oxlint and Oxfmt for .tsrx, JavaScript, TypeScript, and JSX",
5
5
  "keywords": [
6
6
  "formatter",
@@ -128,14 +128,14 @@
128
128
  "tinyglobby": "0.2.17"
129
129
  },
130
130
  "optionalDependencies": {
131
- "@tsrx/oxc-darwin-arm64": "0.10.0",
132
- "@tsrx/oxc-darwin-x64": "0.10.0",
133
- "@tsrx/oxc-linux-arm64-gnu": "0.10.0",
134
- "@tsrx/oxc-linux-arm64-musl": "0.10.0",
135
- "@tsrx/oxc-linux-x64-gnu": "0.10.0",
136
- "@tsrx/oxc-linux-x64-musl": "0.10.0",
137
- "@tsrx/oxc-win32-arm64-msvc": "0.10.0",
138
- "@tsrx/oxc-win32-x64-msvc": "0.10.0"
131
+ "@tsrx/oxc-darwin-arm64": "0.12.0",
132
+ "@tsrx/oxc-darwin-x64": "0.12.0",
133
+ "@tsrx/oxc-linux-arm64-gnu": "0.12.0",
134
+ "@tsrx/oxc-linux-arm64-musl": "0.12.0",
135
+ "@tsrx/oxc-linux-x64-gnu": "0.12.0",
136
+ "@tsrx/oxc-linux-x64-musl": "0.12.0",
137
+ "@tsrx/oxc-win32-arm64-msvc": "0.12.0",
138
+ "@tsrx/oxc-win32-x64-msvc": "0.12.0"
139
139
  },
140
140
  "engines": {
141
141
  "node": "^20.19.0 || >=22.12.0"