mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-12 02:19:43 +00:00
chore: Enforce extraneous dependencies in Oxlint (no-changelog) (#39281)
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Oxlint migration blockers
|
||||
|
||||
Last reviewed: 2026-09-18
|
||||
Last reviewed: 2026-09-22
|
||||
Oxlint version: 1.78.0
|
||||
|
||||
This file is the working backlog for the ESLint to Oxlint migration. It focuses on rules that block an Oxlint-only lint command for many packages. `oxlint-gap.json` is the machine-readable source of truth for shared-layer parity.
|
||||
@@ -21,7 +21,6 @@ These rules come from the shared base or backend layers. Resolve these first bec
|
||||
|
||||
| Priority | Rule | Blocker | Suggested next action |
|
||||
| --- | --- | --- | --- |
|
||||
| P0 | `import-x/no-extraneous-dependencies` | Oxlint reserves the `import-x` plugin name. The JS plugin bridge has not been validated with an alias. | Test `eslint-plugin-import-x` under an alias. If that is unstable, implement a native package-manifest check. |
|
||||
| P1 | `no-restricted-syntax` | Oxlint has no AST-selector rule. The base layer uses it for the raw-enum restriction. | Add a purpose-built syntax rule for each active selector. Start with the raw-enum rule. |
|
||||
| P1 | `typescript/consistent-type-imports` | Oxlint does not honor the `emitDecoratorMetadata` exception. Its fixer can remove imports that DI needs at runtime. | Wait for upstream support or add a tested shim that skips decorated files. Do not enable the current fixer. |
|
||||
| P1 | `typescript/prefer-optional-chain` | The native nursery rule changes guarded undeclared globals incorrectly. | Re-test after the rule leaves nursery or after the upstream fixer issue is resolved. |
|
||||
@@ -150,13 +149,12 @@ The main exceptions are:
|
||||
|
||||
## Work order
|
||||
|
||||
1. Resolve or isolate `import-x/no-extraneous-dependencies`.
|
||||
2. Replace active `no-restricted-syntax` selectors with focused rules.
|
||||
3. Resolve decorator-safe `consistent-type-imports` behavior.
|
||||
4. Audit and reduce `naming-convention` package overrides.
|
||||
5. Re-test the two nursery rules.
|
||||
6. Run a JS-plugin bridge spike for `n8n-nodes-base`.
|
||||
7. Keep a template-only ESLint pass for Vue until native template support exists.
|
||||
1. Replace active `no-restricted-syntax` selectors with focused rules.
|
||||
2. Resolve decorator-safe `consistent-type-imports` behavior.
|
||||
3. Audit and reduce `naming-convention` package overrides.
|
||||
4. Re-test the two nursery rules.
|
||||
5. Run a JS-plugin bridge spike for `n8n-nodes-base`.
|
||||
6. Keep a template-only ESLint pass for Vue until native template support exists.
|
||||
|
||||
## Validation commands
|
||||
|
||||
|
||||
@@ -21,13 +21,6 @@
|
||||
"impact": "Near zero.",
|
||||
"replacement": "No action unless non-module source becomes supported."
|
||||
},
|
||||
"import-x/no-extraneous-dependencies": {
|
||||
"layer": "base",
|
||||
"native": null,
|
||||
"reason": "`import-x` is a reserved plugin name in oxlint, so `eslint-plugin-import-x` cannot load as a jsPlugin under its own name (`Plugin name 'import-x' is reserved`). An alias would permanently change the rule ids, and these rules are the slowest in ESLint and unvalidated through the alpha bridge.",
|
||||
"impact": "A package can import a dependency it does not declare. Left out of the spike deliberately.",
|
||||
"replacement": "Validate eslint-plugin-import-x with an alias, or replace the dependency check with a native package-manifest rule."
|
||||
},
|
||||
"typescript/prefer-optional-chain": {
|
||||
"layer": "base",
|
||||
"native": "typescript/prefer-optional-chain",
|
||||
|
||||
@@ -61,6 +61,7 @@ const SCOPE_BY_NAMESPACE = {
|
||||
/** Namespaces oxlint can only reach through a jsPlugin, so ids stay as ESLint wrote them. */
|
||||
const JS_PLUGIN_NAMESPACES = new Set([
|
||||
'@stylistic',
|
||||
'import-x-alias',
|
||||
'lodash',
|
||||
'unused-imports',
|
||||
'n8n-local-rules',
|
||||
@@ -77,13 +78,17 @@ function oxlintRuleIds() {
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 32 * 1024 * 1024,
|
||||
});
|
||||
const start = out.stdout.indexOf('[');
|
||||
const arrayLine = out.stdout.lastIndexOf('\n[');
|
||||
const start = arrayLine === -1 ? out.stdout.indexOf('[') : arrayLine + 1;
|
||||
if (start === -1) throw new Error(`oxlint --rules failed: ${(out.stderr || out.stdout).trim()}`);
|
||||
return new Set(JSON.parse(out.stdout.slice(start)).map((r) => `${r.scope}/${r.value}`));
|
||||
}
|
||||
|
||||
/** ESLint id -> the oxlint id we would write in a config, or null if oxlint has no such rule. */
|
||||
function toOxlintId(eslintId, native) {
|
||||
if (eslintId === 'import-x/no-extraneous-dependencies') {
|
||||
return 'import-x-alias/no-extraneous-dependencies';
|
||||
}
|
||||
const [ns, name] = splitId(eslintId);
|
||||
if (JS_PLUGIN_NAMESPACES.has(ns)) return eslintId;
|
||||
if (ns === '') return native.has(`eslint/${name}`) ? name : null;
|
||||
|
||||
Reference in New Issue
Block a user