refactor(core): Add lint rule no-internal-package-import (#18724)

This commit is contained in:
Iván Ovejero
2025-08-26 10:03:32 +02:00
committed by GitHub
parent 8df258dd7a
commit aa0c8fac83
11 changed files with 88 additions and 6 deletions

View File

@@ -38,6 +38,9 @@ export const frontendConfig = tseslint.config(
rules: {
'import-x/no-extraneous-dependencies': 'warn',
'vue/one-component-per-file': 'off',
// TODO: remove these
'n8n-local-rules/no-internal-package-import': 'warn',
},
},
{
@@ -98,6 +101,7 @@ export const frontendConfig = tseslint.config(
'vue/no-side-effects-in-computed-properties': 'warn',
'vue/no-v-text-v-html-on-component': 'warn',
'vue/return-in-computed-property': 'warn',
'n8n-local-rules/no-internal-package-import': 'warn',
},
},
eslintConfigPrettier,

View File

@@ -24,6 +24,7 @@ export const localRulesPlugin = {
'n8n-local-rules/no-interpolation-in-regular-string': 'error',
'n8n-local-rules/no-unused-param-in-catch-clause': 'error',
'n8n-local-rules/no-useless-catch-throw': 'error',
'n8n-local-rules/no-internal-package-import': 'error',
},
},
},

View File

@@ -14,6 +14,7 @@ import { NoTopLevelRelativeImportsInBackendModuleRule } from './no-top-level-rel
import { NoConstructorInBackendModuleRule } from './no-constructor-in-backend-module.js';
import type { AnyRuleModule } from '@typescript-eslint/utils/ts-eslint';
import { NoArgumentSpreadRule } from './no-argument-spread.js';
import { NoInternalPackageImportRule } from './no-internal-package-import.js';
export const rules = {
'no-uncaught-json-parse': NoUncaughtJsonParseRule,
@@ -31,4 +32,5 @@ export const rules = {
'no-top-level-relative-imports-in-backend-module': NoTopLevelRelativeImportsInBackendModuleRule,
'no-constructor-in-backend-module': NoConstructorInBackendModuleRule,
'no-argument-spread': NoArgumentSpreadRule,
'no-internal-package-import': NoInternalPackageImportRule,
} satisfies Record<string, AnyRuleModule>;

View File

@@ -0,0 +1,30 @@
import { RuleTester } from '@typescript-eslint/rule-tester';
import { NoInternalPackageImportRule } from './no-internal-package-import.js';
const ruleTester = new RuleTester();
ruleTester.run('no-internal-package-import', NoInternalPackageImportRule, {
valid: [
{ code: 'import { SomeDto } from "@n8n/api-types"' },
{ code: 'import { Logger } from "@n8n/backend-common"' },
{ code: 'import { NodeHelpers } from "@n8n/workflow"' },
{ code: 'import lodash from "lodash"' },
{ code: 'import { helper } from "./local-file"' },
{ code: 'import { utils } from "../utils"' },
{ code: 'import express from "express"' },
{ code: 'import { something } from "@other-org/package/src/file"' },
],
invalid: [
{
code: 'import { UpdateDataStoreDto } from "@n8n/api-types/src/dto/data-store/update-data-store.dto"',
output: 'import { UpdateDataStoreDto } from "@n8n/api-types"',
errors: [{ messageId: 'noInternalPackageImport' }],
},
{
code: 'import { helper } from "@n8n/backend-common/src/utils/helper"',
output: 'import { helper } from "@n8n/backend-common"',
errors: [{ messageId: 'noInternalPackageImport' }],
},
],
});

View File

@@ -0,0 +1,39 @@
import { ESLintUtils } from '@typescript-eslint/utils';
export const NoInternalPackageImportRule = ESLintUtils.RuleCreator.withoutDocs({
meta: {
type: 'problem',
docs: {
description: 'Disallow imports from internal package paths (e.g. `@n8n/pkg/src/...`).',
},
messages: {
noInternalPackageImport:
'Import from "{{ packageRoot }}", not from the internal `/src/` path.',
},
fixable: 'code',
schema: [],
},
defaultOptions: [],
create(context) {
const INTERNAL_IMPORT_REGEX = /^(?<packageRoot>@n8n\/[^/]+)\/src\//;
return {
ImportDeclaration(node) {
if (typeof node.source.type !== 'string') return;
const match = node.source.value.match(INTERNAL_IMPORT_REGEX);
if (!match?.groups) return;
const { packageRoot } = match.groups;
context.report({
node: node.source,
messageId: 'noInternalPackageImport',
fix: (fixer) => fixer.replaceText(node.source, `"${packageRoot}"`),
data: { packageRoot },
});
},
};
},
});