diff --git a/packages/eslint-config-basic/index.js b/packages/eslint-config-basic/index.js index 075863c630..b881295034 100644 --- a/packages/eslint-config-basic/index.js +++ b/packages/eslint-config-basic/index.js @@ -396,6 +396,7 @@ module.exports = { 'yml/no-empty-document': 'off', // antfu + 'antfu/no-import-node-modules-by-path': 'error', 'antfu/if-newline': 'error', 'antfu/import-dedupe': 'error', 'antfu/top-level-function': 'error', diff --git a/packages/eslint-plugin-antfu/src/index.ts b/packages/eslint-plugin-antfu/src/index.ts index 8522a6fcbd..d4b5830240 100644 --- a/packages/eslint-plugin-antfu/src/index.ts +++ b/packages/eslint-plugin-antfu/src/index.ts @@ -3,6 +3,7 @@ import ifNewline from './rules/if-newline' import importDedupe from './rules/import-dedupe' import preferInlineTypeImport from './rules/prefer-inline-type-import' import topLevelFunction from './rules/top-level-function' +import noImportNodeModulesByPath from './rules/no-import-node-modules-by-path' import noTsExportEqual from './rules/no-ts-export-equal' import noCjsExports from './rules/no-cjs-exports' import noConstEnum from './rules/no-const-enum' @@ -15,6 +16,7 @@ export default { 'prefer-inline-type-import': preferInlineTypeImport, 'generic-spacing': genericSpacing, 'top-level-function': topLevelFunction, + 'no-import-node-modules-by-path': noImportNodeModulesByPath, 'no-cjs-exports': noCjsExports, 'no-ts-export-equal': noTsExportEqual, 'no-const-enum': noConstEnum, diff --git a/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.test.ts b/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.test.ts new file mode 100644 index 0000000000..4d4e5cb599 --- /dev/null +++ b/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.test.ts @@ -0,0 +1,31 @@ +import { RuleTester } from '@typescript-eslint/utils/dist/ts-eslint' +import { it } from 'vitest' +import rule, { RULE_NAME } from './no-import-node-modules-by-path' + +const valids = [ + 'import xxx from "a"', + 'import "b"', + 'const c = require("c")', + 'require("d")', +] + +const invalids = [ + 'import a from "../node_modules/a"', + 'import "../node_modules/b"', + 'const c = require("../node_modules/c")', + 'require("../node_modules/d")', +] + +it('runs', () => { + const ruleTester: RuleTester = new RuleTester({ + parser: require.resolve('@typescript-eslint/parser'), + }) + + ruleTester.run(RULE_NAME, rule, { + valid: valids, + invalid: invalids.map(i => ({ + code: i, + errors: [{ messageId: 'noImportNodeModulesByPath' }], + })), + }) +}) diff --git a/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.ts b/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.ts new file mode 100644 index 0000000000..0c9f4ebf78 --- /dev/null +++ b/packages/eslint-plugin-antfu/src/rules/no-import-node-modules-by-path.ts @@ -0,0 +1,42 @@ +import { createEslintRule } from '../utils' + +export const RULE_NAME = 'no-import-node-modules-by-path' +export type MessageIds = 'noImportNodeModulesByPath' +export type Options = [] + +export default createEslintRule({ + name: RULE_NAME, + meta: { + type: 'problem', + docs: { + description: 'Prevent importing modules in `node_modules` folder by relative or absolute path', + recommended: 'error', + }, + schema: [], + messages: { + noImportNodeModulesByPath: 'Do not import modules in `node_modules` folder by path', + }, + }, + defaultOptions: [], + create: (context) => { + return { + 'ImportDeclaration': (node) => { + if (node.source.value.includes('/node_modules/')) { + context.report({ + node, + messageId: 'noImportNodeModulesByPath', + }) + } + }, + 'CallExpression[callee.name="require"]': (node: any) => { + const value = node.arguments[0]?.value + if (typeof value === 'string' && value.includes('/node_modules/')) { + context.report({ + node, + messageId: 'noImportNodeModulesByPath', + }) + } + }, + } + }, +})