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

@@ -36,6 +36,7 @@ export {
type InsightsByWorkflow,
type InsightsByTime,
type InsightsDateRange,
type RestrictedInsightsByTime,
} from './schemas/insights.schema';
export {

View File

@@ -37,9 +37,9 @@ import { WorkflowsConfig } from './configs/workflows.config';
import { Config, Env, Nested } from './decorators';
export { Config, Env, Nested } from './decorators';
export { DatabaseConfig } from './configs/database.config';
export { DatabaseConfig, SqliteConfig } from './configs/database.config';
export { InstanceSettingsConfig } from './configs/instance-settings-config';
export { TaskRunnersConfig } from './configs/runners.config';
export { TaskRunnersConfig, TaskRunnerMode } from './configs/runners.config';
export { SecurityConfig } from './configs/security.config';
export { ExecutionsConfig } from './configs/executions.config';
export { LOG_SCOPES } from './configs/logging.config';

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 },
});
},
};
},
});

View File

@@ -1,6 +1,6 @@
import { mockInstance } from '@n8n/backend-test-utils';
import { GlobalConfig } from '@n8n/config';
import type { SqliteConfig } from '@n8n/config/src/configs/database.config';
import type { SqliteConfig } from '@n8n/config';
import type { IExecutionResponse } from '@n8n/db';
import { ExecutionEntity, ExecutionRepository } from '@n8n/db';
import { Container } from '@n8n/di';

View File

@@ -1,6 +1,10 @@
import { InsightsDateFilterDto, ListInsightsWorkflowQueryDto } from '@n8n/api-types';
import type { InsightsSummary, InsightsByTime, InsightsByWorkflow } from '@n8n/api-types';
import type { RestrictedInsightsByTime } from '@n8n/api-types/src/schemas/insights.schema';
import type {
RestrictedInsightsByTime,
InsightsSummary,
InsightsByTime,
InsightsByWorkflow,
} from '@n8n/api-types';
import { AuthenticatedRequest } from '@n8n/db';
import { Get, GlobalScope, Licensed, Query, RestController } from '@n8n/decorators';
import type { UserError } from 'n8n-workflow';

View File

@@ -1,4 +1,4 @@
import type { TaskRunnerMode } from '@n8n/config/src/configs/runners.config';
import type { TaskRunnerMode } from '@n8n/config';
import { OperationalError } from 'n8n-workflow';
export class TaskRunnerExecutionTimeoutError extends OperationalError {

View File

@@ -4,6 +4,7 @@ import { frontendConfig } from '@n8n/eslint-config/frontend';
export default defineConfig(frontendConfig, {
rules: {
// TODO: Remove these
'n8n-local-rules/no-internal-package-import': 'warn',
'@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }],
'id-denylist': 'warn',
'no-case-declarations': 'warn',