@rustwrap/eslint 1.0.1 → 1.0.3
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.
- package/README.md +32 -2
- package/bin/{oxpack.js → rustwrap-eslint.js} +9 -7
- package/lib/config.js +49 -9
- package/lib/index.js +14 -13
- package/lib/runner.js +2 -2
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -22,6 +22,32 @@ dependency at `@rustwrap/eslint` and lint **~50–80× faster**.
|
|
|
22
22
|
No script changes needed — `eslint …`, `pcf-scripts lint`, and tools using the ESLint Node API keep
|
|
23
23
|
working. `@rustwrap/eslint` ships the `eslint` bin.
|
|
24
24
|
|
|
25
|
+
## Requirements
|
|
26
|
+
|
|
27
|
+
**Node.js `^20.19.0 || ^22.13.0 || >=24`** (enforced via the package's `engines` field).
|
|
28
|
+
|
|
29
|
+
This is **not** an arbitrary floor — it is the exact intersection of the engine requirements of the
|
|
30
|
+
Rust toolchain this package is built on:
|
|
31
|
+
|
|
32
|
+
| Dependency | Requires | Why |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `oxlint` (+ native binding) | `^20.19.0 \|\| >=22.12.0` | The N-API/V8 features the Rust binary uses were backported into each LTS line at Node **20.19.0** and **22.12.0**. |
|
|
35
|
+
| `eslint-scope` | `^20.19.0 \|\| ^22.13.0 \|\| >=24` | Follows ESLint's policy: active LTS lines only, skipping odd non-LTS majors (21.x, 23.x). |
|
|
36
|
+
|
|
37
|
+
Taking the **strictest** clause on each line yields the declared range. Reading it:
|
|
38
|
+
|
|
39
|
+
- `^20.19.0` → the **Node 20 LTS** line, from patch **.19** up (`>=20.19.0 <21`). Earlier 20.x patches
|
|
40
|
+
lack the backported native feature.
|
|
41
|
+
- `^22.13.0` → the **Node 22 LTS** line, from patch **.13** up (`>=22.13.0 <23`). Note this is one
|
|
42
|
+
patch higher than oxlint's own `22.12.0` floor, because `eslint-scope` requires `22.13.0`.
|
|
43
|
+
- `>=24` → **Node 24+** (the next even LTS line and beyond).
|
|
44
|
+
- **Excluded:** Node ≤16 (EOL), 18.x, 21.x, 22.0–22.12, and 23.x — none satisfy every dependency.
|
|
45
|
+
|
|
46
|
+
> **Node 16 / 18 are not supported.** oxlint 1.x and Rolldown 1.x dropped them; the native Rust
|
|
47
|
+
> binaries will not run there. The `engines` field makes this an **immediate, named `EBADENGINE`
|
|
48
|
+
> warning** at install (or a hard failure under `engine-strict=true`/CI) instead of a cryptic deep
|
|
49
|
+
> crash inside the native module.
|
|
50
|
+
|
|
25
51
|
## What it honors (config & ignore)
|
|
26
52
|
- **Legacy eslintrc**: `.eslintrc.json`, `.eslintrc`, `.eslintrc.js`, `.eslintrc.cjs`,
|
|
27
53
|
`.eslintrc.yaml`/`.yml`, and `package.json#eslintConfig`. Auto-discovered up the directory tree;
|
|
@@ -37,14 +63,18 @@ working. `@rustwrap/eslint` ships the `eslint` bin.
|
|
|
37
63
|
doesn't implement are dropped automatically (it would otherwise reject the config).
|
|
38
64
|
- **`env`, `globals`, `settings`, `overrides`, `ignorePatterns`** — translated (incl. normalizing
|
|
39
65
|
`settings.react.version: "detect"` to a concrete version).
|
|
40
|
-
- **`parser` / `parserOptions`** —
|
|
66
|
+
- **`parser` / `parserOptions`** — TS/JSX is auto-detected by extension. `parserOptions.project` is
|
|
67
|
+
honored for **tsconfig resolution**: oxlint auto-discovers the nearest `tsconfig.json` per file, and
|
|
68
|
+
if your config points `project` at a non-standard tsconfig (e.g. `tsconfig.eslint.json`) it's passed
|
|
69
|
+
through via `--tsconfig`. An explicit `--tsconfig <file>` CLI flag (and `tsconfig` Node API option)
|
|
70
|
+
overrides discovery.
|
|
41
71
|
- **`.eslintignore`** + `--ignore-path` + `--ignore-pattern` + `--no-ignore`.
|
|
42
72
|
|
|
43
73
|
## CLI
|
|
44
74
|
ESLint-compatible flags: file/dir/**glob** args (incl. `src/**/*.{ts,tsx}` brace expansion — `@rustwrap/eslint`
|
|
45
75
|
expands globs since oxlint doesn't), `--fix`, `--quiet`, `--max-warnings <n>`, `-c/--config`,
|
|
46
76
|
`--no-eslintrc`, `--ext`, `-f/--format <stylish|json|compact|unix|summary>`, `-o/--output-file`,
|
|
47
|
-
`--ignore-path`, `--ignore-pattern`, `--no-ignore`, `--color/--no-color`, `--stdin`/`--stdin-filename`.
|
|
77
|
+
`--ignore-path`, `--ignore-pattern`, `--no-ignore`, `--tsconfig <file>`, `--color/--no-color`, `--stdin`/`--stdin-filename`.
|
|
48
78
|
Other ESLint flags are accepted and ignored for drop-in tolerance.
|
|
49
79
|
|
|
50
80
|
**Exit codes** match ESLint: `0` clean (or warnings under threshold), `1` lint errors or
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
/*
|
|
4
|
-
*
|
|
4
|
+
* @rustwrap/eslint CLI — an `eslint`-compatible command backed by oxlint. Parses the common ESLint flags,
|
|
5
5
|
* expands globs (ESLint expands internally; oxlint does not), runs oxlint, renders an ESLint-style
|
|
6
6
|
* report, and exits with ESLint semantics (0 = clean / warnings under threshold, 1 = lint errors or
|
|
7
7
|
* --max-warnings exceeded, 2 = fatal).
|
|
@@ -34,13 +34,15 @@ function parse(argv) {
|
|
|
34
34
|
else if (a === "--ignore-path") o.ignorePath = next();
|
|
35
35
|
else if (a.startsWith("--ignore-path=")) o.ignorePath = a.split("=")[1];
|
|
36
36
|
else if (a === "--ignore-pattern") o.ignorePattern.push(next());
|
|
37
|
+
else if (a === "--tsconfig") o.tsconfig = next();
|
|
38
|
+
else if (a.startsWith("--tsconfig=")) o.tsconfig = a.split("=")[1];
|
|
37
39
|
else if (a === "--no-ignore") o.noIgnore = true;
|
|
38
40
|
else if (a === "--no-color") process.env.NO_COLOR = "1";
|
|
39
41
|
else if (a === "--color") process.env.FORCE_COLOR = "1";
|
|
40
42
|
else if (a === "--report-unused-disable-directives") o.reportUnused = true;
|
|
41
43
|
else if (a === "--rulesdir" || a === "--resolve-plugins-relative-to" || a === "--parser" || a === "--parser-options" || a === "--rule" || a === "--env" || a === "--global" || a === "--cache-location" || a === "--cache-strategy") { next(); /* accepted, ignored */ }
|
|
42
44
|
else if (a === "--cache" || a === "--no-cache" || a === "--stdin" || a === "--stdin-filename" || a === "--init" || a === "--debug" || a === "--exit-on-fatal-error") { if (a === "--stdin-filename") o.stdinFilename = next(); else if (a === "--stdin") o.stdin = true; }
|
|
43
|
-
else if (a === "-v" || a === "--version") { console.log(require("../package.json").version + " (
|
|
45
|
+
else if (a === "-v" || a === "--version") { console.log(require("../package.json").version + " (@rustwrap/eslint, eslint-compatible)"); process.exit(0); }
|
|
44
46
|
else if (a === "-h" || a === "--help") { printHelp(); process.exit(0); }
|
|
45
47
|
else if (a.startsWith("-")) { /* unknown flag: ignore for drop-in tolerance */ }
|
|
46
48
|
else o.patterns.push(a);
|
|
@@ -49,7 +51,7 @@ function parse(argv) {
|
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
function printHelp() {
|
|
52
|
-
console.log("
|
|
54
|
+
console.log("@rustwrap/eslint — eslint-compatible CLI backed by oxlint\n\nUsage: eslint [options] [file|dir|glob]*\n\nCommon options: --fix --quiet --max-warnings <n> -c/--config <file> --no-eslintrc\n --ext <.ts,.tsx> -f/--format <stylish|json|compact|unix|summary> -o/--output-file <file>\n --ignore-path <file> --ignore-pattern <glob> --no-ignore --tsconfig <file> --color/--no-color");
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
async function main() {
|
|
@@ -66,12 +68,12 @@ async function main() {
|
|
|
66
68
|
|
|
67
69
|
const files = expandPatterns(opts.patterns.length ? opts.patterns : ["."], cwd, opts.exts);
|
|
68
70
|
if (!files.length) {
|
|
69
|
-
if (opts.patterns.length) process.stderr.write("
|
|
71
|
+
if (opts.patterns.length) process.stderr.write("@rustwrap/eslint: no files matched the provided patterns\n");
|
|
70
72
|
process.exit(0);
|
|
71
73
|
}
|
|
72
|
-
const { oxConfig } = buildOxlintConfig({ cwd, configFile: opts.config, noEslintrc: opts.noEslintrc });
|
|
74
|
+
const { oxConfig, tsconfig } = buildOxlintConfig({ cwd, configFile: opts.config, noEslintrc: opts.noEslintrc, tsconfig: opts.tsconfig });
|
|
73
75
|
const { results, internalError } = runOxlint(files, oxConfig, {
|
|
74
|
-
cwd, fix: !!opts.fix, quiet: !!opts.quiet, ignorePath: opts.ignorePath, ignorePattern: opts.ignorePattern, noIgnore: opts.noIgnore,
|
|
76
|
+
cwd, fix: !!opts.fix, quiet: !!opts.quiet, ignorePath: opts.ignorePath, ignorePattern: opts.ignorePattern, noIgnore: opts.noIgnore, tsconfig,
|
|
75
77
|
});
|
|
76
78
|
if (internalError) { process.stderr.write(internalError + "\n"); process.exit(2); }
|
|
77
79
|
// ESLint reports clean files too (count only); for output we only need ones with messages.
|
|
@@ -89,7 +91,7 @@ function finish(results, opts) {
|
|
|
89
91
|
// ESLint exit semantics.
|
|
90
92
|
if (errorCount > 0) process.exit(1);
|
|
91
93
|
if (opts.maxWarnings >= 0 && warningCount > opts.maxWarnings) {
|
|
92
|
-
process.stderr.write(
|
|
94
|
+
process.stderr.write(`@rustwrap/eslint: too many warnings (${warningCount}). Maximum allowed is ${opts.maxWarnings}.\n`);
|
|
93
95
|
process.exit(1);
|
|
94
96
|
}
|
|
95
97
|
process.exit(0);
|
package/lib/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
*
|
|
3
|
+
* @rustwrap/eslint config layer — discovers an ESLint configuration (eslintrc legacy or flat), and translates
|
|
4
4
|
* it into the `.oxlintrc.json` shape oxlint consumes (oxlint already targets ESLint-v8 config
|
|
5
5
|
* compatibility, so most of `rules`/`env`/`globals`/`settings`/`overrides` pass straight through;
|
|
6
6
|
* `plugins`/`extends`/`parser` need mapping).
|
|
@@ -103,6 +103,8 @@ function loadEslintrc(file, inline, seen) {
|
|
|
103
103
|
rules: cfg.rules || {}, env: cfg.env || {}, globals: cfg.globals || {}, settings: cfg.settings || {},
|
|
104
104
|
overrides: cfg.overrides || [], ignorePatterns: [].concat(cfg.ignorePatterns || []),
|
|
105
105
|
});
|
|
106
|
+
const po = cfg.parserOptions || {};
|
|
107
|
+
if (po.project) merged._project = resolveProjectRef(po.project, baseDir);
|
|
106
108
|
return merged;
|
|
107
109
|
}
|
|
108
110
|
|
|
@@ -114,6 +116,38 @@ function mergeInto(target, src) {
|
|
|
114
116
|
if (src.overrides) target.overrides.push(...src.overrides);
|
|
115
117
|
if (src.ignorePatterns) target.ignorePatterns.push(...src.ignorePatterns);
|
|
116
118
|
if (src._pluginIds) for (const p of src._pluginIds) target._pluginIds.add(p);
|
|
119
|
+
if (src._project && !target._project) target._project = src._project;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Resolve an ESLint `parserOptions.project` value (string | string[] | true) to a single tsconfig
|
|
123
|
+
// path relative to the config file's directory. `true` means "nearest tsconfig" — left for discovery.
|
|
124
|
+
function resolveProjectRef(project, baseDir) {
|
|
125
|
+
if (project === true) return true;
|
|
126
|
+
const first = Array.isArray(project) ? project[0] : project;
|
|
127
|
+
if (typeof first !== "string") return true;
|
|
128
|
+
return path.resolve(baseDir, first);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Walk up from `dir` to find the nearest tsconfig.json (like tsc/webpack resolution).
|
|
132
|
+
function findTsconfig(dir) {
|
|
133
|
+
for (let i = 0; i < 12 && dir; i++) {
|
|
134
|
+
const f = path.join(dir, "tsconfig.json");
|
|
135
|
+
if (fs.existsSync(f)) return f;
|
|
136
|
+
const up = path.dirname(dir);
|
|
137
|
+
if (up === dir) break;
|
|
138
|
+
dir = up;
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Decide which tsconfig (if any) to *override* oxlint with. oxlint already auto-discovers the
|
|
144
|
+
// nearest tsconfig.json per file, so we only pass --tsconfig when the user is explicit: an explicit
|
|
145
|
+
// option/CLI flag, or `parserOptions.project` (which can point at a non-standard name/path oxlint
|
|
146
|
+
// wouldn't find on its own). When project===true or unset, return undefined and let oxlint discover.
|
|
147
|
+
function resolveTsconfig(opts, project, configDir, cwd) {
|
|
148
|
+
if (opts && opts.tsconfig) { const p = path.resolve(cwd, opts.tsconfig); return fs.existsSync(p) ? p : undefined; }
|
|
149
|
+
if (project && project !== true) return fs.existsSync(project) ? project : undefined;
|
|
150
|
+
return undefined;
|
|
117
151
|
}
|
|
118
152
|
|
|
119
153
|
// Load the set of rule names oxlint actually implements from its bundled JSON schema, so we can
|
|
@@ -275,19 +309,23 @@ function sanitizeGlobals(globals) {
|
|
|
275
309
|
|
|
276
310
|
// Returns { oxConfig, pluginFlags, source } or null when no config found / --no-eslintrc.
|
|
277
311
|
function buildOxlintConfig(opts) {
|
|
278
|
-
|
|
312
|
+
opts = opts || {};
|
|
313
|
+
const cwd = opts.cwd || process.cwd();
|
|
314
|
+
const defaults = { plugins: ["typescript", "unicorn", "oxc"], categories: { correctness: "warn" } };
|
|
315
|
+
if (opts.noEslintrc) return { oxConfig: defaults, source: null, tsconfig: resolveTsconfig(opts, null, cwd, cwd) };
|
|
279
316
|
let found;
|
|
280
|
-
if (opts
|
|
281
|
-
else found = discoverConfig(
|
|
282
|
-
if (!found) return { oxConfig:
|
|
317
|
+
if (opts.configFile) found = { type: opts.configFile.endsWith(".js") || opts.configFile.endsWith(".mjs") || opts.configFile.endsWith(".cjs") ? "flat" : "eslintrc", file: path.resolve(opts.configFile) };
|
|
318
|
+
else found = discoverConfig(cwd);
|
|
319
|
+
if (!found) return { oxConfig: defaults, source: null, tsconfig: resolveTsconfig(opts, null, cwd, cwd) };
|
|
320
|
+
const configDir = found.file ? path.dirname(found.file) : cwd;
|
|
283
321
|
if (found.type === "flat") {
|
|
284
322
|
// Flat config: we can read `rules`/`plugins` heuristically but cannot fully evaluate it; enable
|
|
285
323
|
// common plugins and let oxlint use its own discovery. Pass-through with defaults.
|
|
286
324
|
const flat = loadFlat(found.file);
|
|
287
|
-
return { oxConfig: toOxlintConfig(flat), source: found.file };
|
|
325
|
+
return { oxConfig: toOxlintConfig(flat), source: found.file, tsconfig: resolveTsconfig(opts, flat._project, configDir, cwd) };
|
|
288
326
|
}
|
|
289
|
-
const merged = loadEslintrc(found.
|
|
290
|
-
return { oxConfig: toOxlintConfig(merged), source: found.file };
|
|
327
|
+
const merged = loadEslintrc(found.file, found.inline, new Set());
|
|
328
|
+
return { oxConfig: toOxlintConfig(merged), source: found.file, tsconfig: resolveTsconfig(opts, merged._project, configDir, cwd) };
|
|
291
329
|
}
|
|
292
330
|
|
|
293
331
|
// Best-effort flat-config reader: merges `rules`/`plugins` across array entries.
|
|
@@ -302,8 +340,10 @@ function loadFlat(file) {
|
|
|
302
340
|
if (block.languageOptions && block.languageOptions.globals) Object.assign(merged.globals, block.languageOptions.globals);
|
|
303
341
|
for (const name of Object.keys(block.plugins || {})) { const id = PLUGIN_MAP[name] || PLUGIN_MAP[name.replace(/^eslint-plugin-/, "")]; if (id) merged._pluginIds.add(id); }
|
|
304
342
|
if (block.ignores) merged.ignorePatterns.push(...block.ignores);
|
|
343
|
+
const po = block.languageOptions && block.languageOptions.parserOptions;
|
|
344
|
+
if (po && po.project && !merged._project) merged._project = resolveProjectRef(po.project, path.dirname(file));
|
|
305
345
|
}
|
|
306
346
|
return merged;
|
|
307
347
|
}
|
|
308
348
|
|
|
309
|
-
module.exports = { discoverConfig, buildOxlintConfig, toOxlintConfig, loadEslintrc, normalizeRules, PLUGIN_MAP };
|
|
349
|
+
module.exports = { discoverConfig, buildOxlintConfig, toOxlintConfig, loadEslintrc, normalizeRules, PLUGIN_MAP, findTsconfig };
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
*
|
|
3
|
+
* @rustwrap/eslint — a drop-in ESLint Node API + CLI backed by oxlint.
|
|
4
4
|
*
|
|
5
5
|
* Exposes the modern `ESLint` class (lintFiles/lintText/loadFormatter/outputFixes/…), the legacy
|
|
6
6
|
* `CLIEngine`, `Linter`, and `loadESLint`, all delegating to oxlint (Rust). Config is discovered
|
|
@@ -52,11 +52,12 @@ class ESLint {
|
|
|
52
52
|
const files = expandPatterns(patterns, cwd, extensions);
|
|
53
53
|
if (!files.length) return [];
|
|
54
54
|
// Discover/translate config relative to the first file's directory.
|
|
55
|
-
const
|
|
55
|
+
const tsOpt = o.tsconfig || (o.overrideConfig && o.overrideConfig.parserOptions && o.overrideConfig.parserOptions.project);
|
|
56
|
+
const { oxConfig, tsconfig } = buildOxlintConfig({ cwd, configFile: typeof overrideConfigFile === "string" ? overrideConfigFile : undefined, noEslintrc, tsconfig: tsOpt });
|
|
56
57
|
applyOverrides(oxConfig, o.overrideConfig);
|
|
57
58
|
const { results, internalError } = runOxlint(files, oxConfig, {
|
|
58
59
|
cwd, fix: !!o.fix, quiet: !!o.quiet, ignorePath: o.ignorePath, noIgnore: o.ignore === false,
|
|
59
|
-
ignorePattern: o.overrideConfig && o.overrideConfig.ignorePatterns,
|
|
60
|
+
ignorePattern: o.overrideConfig && o.overrideConfig.ignorePatterns, tsconfig,
|
|
60
61
|
});
|
|
61
62
|
if (internalError) { const e = new Error(internalError); throw e; }
|
|
62
63
|
// Ensure every linted file has a result entry (ESLint returns clean files too).
|
|
@@ -67,11 +68,11 @@ class ESLint {
|
|
|
67
68
|
options = options || {};
|
|
68
69
|
const cwd = this.cwd;
|
|
69
70
|
const filePath = options.filePath || path.join(cwd, "__stdin__.ts");
|
|
70
|
-
const tmp = path.join(require("os").tmpdir(), `
|
|
71
|
+
const tmp = path.join(require("os").tmpdir(), `rustwrap-stdin-${process.pid}-${Date.now()}${path.extname(filePath) || ".ts"}`);
|
|
71
72
|
fs.writeFileSync(tmp, code);
|
|
72
73
|
try {
|
|
73
|
-
const { oxConfig } = buildOxlintConfig({ cwd, noEslintrc: this.options.useEslintrc === false });
|
|
74
|
-
const { results } = runOxlint([tmp], oxConfig, { cwd, quiet: !!this.options.quiet });
|
|
74
|
+
const { oxConfig, tsconfig } = buildOxlintConfig({ cwd, noEslintrc: this.options.useEslintrc === false, tsconfig: this.options.tsconfig });
|
|
75
|
+
const { results } = runOxlint([tmp], oxConfig, { cwd, quiet: !!this.options.quiet, tsconfig });
|
|
75
76
|
const r = results[0] || { filePath: tmp, messages: [], errorCount: 0, warningCount: 0, fatalErrorCount: 0, fixableErrorCount: 0, fixableWarningCount: 0, suppressedMessages: [], usedDeprecatedRules: [] };
|
|
76
77
|
r.filePath = path.resolve(filePath);
|
|
77
78
|
r.source = code;
|
|
@@ -114,7 +115,7 @@ class ESLint {
|
|
|
114
115
|
return out;
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
static get version() { return "8.57.0-
|
|
118
|
+
static get version() { return "8.57.0-rustwrap"; }
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
function applyOverrides(oxConfig, override) {
|
|
@@ -137,18 +138,18 @@ class CLIEngine {
|
|
|
137
138
|
// CLIEngine is sync; run oxlint synchronously via the same path.
|
|
138
139
|
const cwd = this.options.cwd || process.cwd();
|
|
139
140
|
const files = expandPatterns(patterns, cwd, this.options.extensions);
|
|
140
|
-
const { oxConfig } = buildOxlintConfig({ cwd, noEslintrc: this.options.useEslintrc === false });
|
|
141
|
-
const { results } = runOxlint(files, oxConfig, { cwd, fix: !!this.options.fix, quiet: !!this.options.quiet });
|
|
141
|
+
const { oxConfig, tsconfig } = buildOxlintConfig({ cwd, noEslintrc: this.options.useEslintrc === false, tsconfig: this.options.tsconfig });
|
|
142
|
+
const { results } = runOxlint(files, oxConfig, { cwd, fix: !!this.options.fix, quiet: !!this.options.quiet, tsconfig });
|
|
142
143
|
const filled = fillMissing(results, files);
|
|
143
144
|
return makeReport(filled);
|
|
144
145
|
}
|
|
145
146
|
executeOnText(text, filename) {
|
|
146
147
|
const cwd = this.options.cwd || process.cwd();
|
|
147
|
-
const tmp = path.join(require("os").tmpdir(), `
|
|
148
|
+
const tmp = path.join(require("os").tmpdir(), `rustwrap-cli-${Date.now()}${path.extname(filename || ".ts") || ".ts"}`);
|
|
148
149
|
fs.writeFileSync(tmp, text);
|
|
149
150
|
try {
|
|
150
|
-
const { oxConfig } = buildOxlintConfig({ cwd });
|
|
151
|
-
const { results } = runOxlint([tmp], oxConfig, { cwd });
|
|
151
|
+
const { oxConfig, tsconfig } = buildOxlintConfig({ cwd, tsconfig: this.options.tsconfig });
|
|
152
|
+
const { results } = runOxlint([tmp], oxConfig, { cwd, tsconfig });
|
|
152
153
|
if (results[0]) results[0].filePath = filename ? path.resolve(filename) : "<text>";
|
|
153
154
|
return makeReport(results.length ? results : [{ filePath: filename || "<text>", messages: [], errorCount: 0, warningCount: 0, fatalErrorCount: 0, fixableErrorCount: 0, fixableWarningCount: 0 }]);
|
|
154
155
|
} finally { try { fs.unlinkSync(tmp); } catch (_) {} }
|
|
@@ -174,7 +175,7 @@ class Linter {
|
|
|
174
175
|
constructor() {}
|
|
175
176
|
verify(code, _config, options) {
|
|
176
177
|
const filename = (typeof options === "string" ? options : options && options.filename) || "input.ts";
|
|
177
|
-
const tmp = path.join(require("os").tmpdir(), `
|
|
178
|
+
const tmp = path.join(require("os").tmpdir(), `rustwrap-linter-${Date.now()}${path.extname(filename) || ".ts"}`);
|
|
178
179
|
fs.writeFileSync(tmp, code);
|
|
179
180
|
try { const { results } = runOxlint([tmp], null, { cwd: process.cwd() }); return (results[0] && results[0].messages) || []; }
|
|
180
181
|
finally { try { fs.unlinkSync(tmp); } catch (_) {} }
|
package/lib/runner.js
CHANGED
|
@@ -70,7 +70,7 @@ function runOxlint(paths, oxConfigObj, opts) {
|
|
|
70
70
|
}
|
|
71
71
|
return { results: groupResults((res.parsed && res.parsed.diagnostics) || [], opts.cwd || process.cwd()), raw: res.parsed };
|
|
72
72
|
}
|
|
73
|
-
return { results: [], internalError: "
|
|
73
|
+
return { results: [], internalError: "@rustwrap/eslint: could not produce a valid oxlint config after stripping unknown rules/options" };
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function hasRuleOptions(cfg) {
|
|
@@ -90,7 +90,7 @@ function invoke(paths, cfg, opts) {
|
|
|
90
90
|
const args = [];
|
|
91
91
|
let tmpCfg;
|
|
92
92
|
if (cfg) {
|
|
93
|
-
tmpCfg = path.join(os.tmpdir(), `
|
|
93
|
+
tmpCfg = path.join(os.tmpdir(), `rustwrap-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}.oxlintrc.json`);
|
|
94
94
|
fs.writeFileSync(tmpCfg, JSON.stringify(cfg));
|
|
95
95
|
args.push("-c", tmpCfg);
|
|
96
96
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rustwrap/eslint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "A drop-in ESLint replacement (CLI + Node API) backed by the Rust-based oxlint for very fast linting. Honors .eslintrc(.json/.js/.yml), package.json#eslintConfig, flat eslint.config.js, and .eslintignore.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"test": "node test/run.js"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
13
|
-
"eslint": "bin/
|
|
14
|
-
"
|
|
13
|
+
"eslint": "bin/rustwrap-eslint.js",
|
|
14
|
+
"rustwrap-eslint": "bin/rustwrap-eslint.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"lib/",
|
|
@@ -30,5 +30,8 @@
|
|
|
30
30
|
"oxc",
|
|
31
31
|
"pcf"
|
|
32
32
|
],
|
|
33
|
-
"license": "MIT"
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
36
|
+
}
|
|
34
37
|
}
|