eslint-plugin-import-next 2.8.2 → 2.8.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-import-next",
3
- "version": "2.8.2",
3
+ "version": "2.8.4",
4
4
  "description": "ESLint plugin for imports and module boundaries — drop-in replacement for eslint-plugin-import, 3.1x faster end-to-end, zero-config migration.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -76,7 +76,7 @@
76
76
  "typescript": "^4.8.4 || ^5.0.0 || ^6.0.0"
77
77
  },
78
78
  "dependencies": {
79
- "@interlace/eslint-devkit": "^1.19.2",
79
+ "@interlace/eslint-devkit": "^1.19.5",
80
80
  "oxc-resolver": "^11.24.2"
81
81
  },
82
82
  "funding": {
package/src/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.clearCircularDependencyCache=exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const no_cycle_1=require("./rules/no-cycle");Object.defineProperty(exports,"clearCircularDependencyCache",{enumerable:true,get:function(){return no_cycle_1.clearCircularDependencyCache}});exports.rules={get"no-duplicates"(){return require("./rules/no-duplicates").noDuplicates},get named(){return require("./rules/named").named},get default(){return require("./rules/default").defaultRule},get namespace(){return require("./rules/namespace").namespace},get extensions(){return require("./rules/extensions").extensions},get"no-self-import"(){return require("./rules/no-self-import").noSelfImport},get"no-unresolved"(){return require("./rules/no-unresolved").noUnresolved},get"no-absolute-path"(){return require("./rules/no-absolute-path").noAbsolutePath},get"no-dynamic-require"(){return require("./rules/no-dynamic-require").noDynamicRequire},get"no-relative-packages"(){return require("./rules/no-relative-packages").noRelativePackages},get"no-useless-path-segments"(){return require("./rules/no-useless-path-segments").noUselessPathSegments},get"no-amd"(){return require("./rules/no-amd").noAmd},get"no-commonjs"(){return require("./rules/no-commonjs").noCommonjs},get"no-nodejs-modules"(){return require("./rules/no-nodejs-modules").noNodejsModules},get"no-import-module-exports"(){return require("./rules/no-import-module-exports").noImportModuleExports},get unambiguous(){return require("./rules/unambiguous").unambiguous},get"no-cycle"(){return require("./rules/no-cycle").noCycle},get"no-internal-modules"(){return require("./rules/no-internal-modules").noInternalModules},get"no-cross-domain-imports"(){return require("./rules/no-cross-domain-imports").noCrossDomainImports},get"enforce-dependency-direction"(){return require("./rules/enforce-dependency-direction").enforceDependencyDirection},get"no-restricted-paths"(){return require("./rules/no-restricted-paths").noRestrictedPaths},get"no-relative-parent-imports"(){return require("./rules/no-relative-parent-imports").noRelativeParentImports},get export(){return require("./rules/export").exportRule},get"no-default-export"(){return require("./rules/no-default-export").noDefaultExport},get"no-named-export"(){return require("./rules/no-named-export").noNamedExport},get"prefer-default-export"(){return require("./rules/prefer-default-export").preferDefaultExport},get"no-anonymous-default-export"(){return require("./rules/no-anonymous-default-export").noAnonymousDefaultExport},get"no-mutable-exports"(){return require("./rules/no-mutable-exports").noMutableExports},get"no-deprecated"(){return require("./rules/no-deprecated").noDeprecated},get"exports-last"(){return require("./rules/exports-last").exportsLast},get"group-exports"(){return require("./rules/group-exports").groupExports},get"enforce-import-order"(){return require("./rules/enforce-import-order").enforceImportOrder},get order(){return require("./rules/enforce-import-order").enforceImportOrder},get"no-unassigned-import"(){return require("./rules/no-unassigned-import").noUnassignedImport},get first(){return require("./rules/first").first},get"newline-after-import"(){return require("./rules/newline-after-import").newlineAfterImport},get"no-empty-named-blocks"(){return require("./rules/no-empty-named-blocks").noEmptyNamedBlocks},get"no-named-as-default"(){return require("./rules/no-named-as-default").noNamedAsDefault},get"no-named-as-default-member"(){return require("./rules/no-named-as-default-member").noNamedAsDefaultMember},get"no-named-default"(){return require("./rules/no-named-default").noNamedDefault},get"no-namespace"(){return require("./rules/no-namespace").noNamespace},get"consistent-type-specifier-style"(){return require("./rules/consistent-type-specifier-style").consistentTypeSpecifierStyle},get"dynamic-import-chunkname"(){return require("./rules/dynamic-import-chunkname").dynamicImportChunkname},get"no-extraneous-dependencies"(){return require("./rules/no-extraneous-dependencies").noExtraneousDependencies},get"no-unused-modules"(){return require("./rules/no-unused-modules").noUnusedModules},get"max-dependencies"(){return require("./rules/max-dependencies").maxDependencies},get"prefer-node-protocol"(){return require("./rules/prefer-node-protocol").preferNodeProtocol},get"no-barrel-file"(){return require("./rules/no-barrel-file").noBarrelFile},get"no-barrel-import"(){return require("./rules/no-barrel-import").noBarrelImport},get"prefer-tree-shakeable-imports"(){return require("./rules/prefer-tree-shakeable-imports").preferTreeShakeableImports},get"prefer-direct-import"(){return require("./rules/prefer-direct-import").preferDirectImport},get"no-full-package-import"(){return require("./rules/no-full-package-import").noFullPackageImport},get"enforce-team-boundaries"(){return require("./rules/enforce-team-boundaries").enforceTeamBoundaries},get"no-legacy-imports"(){return require("./rules/no-legacy-imports").noLegacyImports},get"require-import-approval"(){return require("./rules/require-import-approval").requireImportApproval},get"prefer-modern-api"(){return require("./rules/prefer-modern-api").preferModernApi}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-import-next",exports.rules);exports.plugin={meta:{name:"eslint-plugin-import-next",version:"2.8.2"},rules:exports.rules};exports.configs={flagship:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-cycle":"error"}},recommended:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"warn","import-next/no-duplicates":"error","import-next/export":"error","import-next/no-cycle":"error","import-next/no-self-import":"error","import-next/no-named-as-default":"warn","import-next/no-named-as-default-member":"warn","import-next/no-amd":"warn","import-next/no-empty-named-blocks":"warn","import-next/no-extraneous-dependencies":"warn"}},strict:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/extensions":"error","import-next/no-self-import":"error","import-next/no-duplicates":"error","import-next/no-absolute-path":"error","import-next/no-dynamic-require":"error","import-next/no-useless-path-segments":"error","import-next/export":"error","import-next/no-amd":"error","import-next/no-commonjs":"error","import-next/no-nodejs-modules":"error","import-next/no-import-module-exports":"error","import-next/unambiguous":"error","import-next/no-cycle":"error","import-next/no-internal-modules":"error","import-next/no-cross-domain-imports":"error","import-next/enforce-dependency-direction":"error","import-next/no-restricted-paths":"error","import-next/no-relative-parent-imports":"error","import-next/no-relative-packages":"error","import-next/no-anonymous-default-export":"error","import-next/no-mutable-exports":"error","import-next/no-deprecated":"error","import-next/exports-last":"error","import-next/group-exports":"error","import-next/order":"error","import-next/no-unassigned-import":"error","import-next/first":"error","import-next/newline-after-import":"error","import-next/no-empty-named-blocks":"error","import-next/no-named-as-default":"error","import-next/no-named-as-default-member":"error","import-next/no-named-default":"error","import-next/no-namespace":"error","import-next/consistent-type-specifier-style":"error","import-next/no-extraneous-dependencies":"error","import-next/no-unused-modules":"error","import-next/max-dependencies":"error","import-next/prefer-node-protocol":"error"}},typescript:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"off","import-next/default":"error","import-next/namespace":"error","import-next/export":"error","import-next/no-cycle":"error","import-next/no-duplicates":"error","import-next/order":"warn","import-next/first":"warn","import-next/newline-after-import":"warn","import-next/consistent-type-specifier-style":["warn","prefer-inline"]}},"module-resolution":{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/extensions":"warn","import-next/no-self-import":"error","import-next/no-duplicates":"error","import-next/no-absolute-path":"error","import-next/no-useless-path-segments":"warn"}},"import-style":{plugins:{"import-next":exports.plugin},rules:{"import-next/order":"error","import-next/first":"error","import-next/newline-after-import":"error","import-next/no-duplicates":"error","import-next/no-unassigned-import":"warn","import-next/no-empty-named-blocks":"error","import-next/no-namespace":"warn"}},esm:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-amd":"error","import-next/no-commonjs":"error","import-next/no-import-module-exports":"error","import-next/unambiguous":"error","import-next/prefer-node-protocol":"error"}},architecture:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-cycle":"error","import-next/no-internal-modules":"error","import-next/no-cross-domain-imports":"error","import-next/enforce-dependency-direction":"error","import-next/no-restricted-paths":"error","import-next/no-relative-parent-imports":"warn","import-next/no-relative-packages":"error"}},errors:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/export":"error"}},warnings:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-named-as-default":"warn","import-next/no-named-as-default-member":"warn","import-next/no-duplicates":"warn"}},performance:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-barrel-file":"error","import-next/no-barrel-import":"warn","import-next/prefer-tree-shakeable-imports":"warn","import-next/prefer-direct-import":"warn","import-next/no-full-package-import":"warn","import-next/no-cycle":"error"}},enterprise:{plugins:{"import-next":exports.plugin},rules:{"import-next/enforce-team-boundaries":"off","import-next/no-legacy-imports":"off","import-next/no-cross-domain-imports":"warn","import-next/enforce-dependency-direction":"warn","import-next/no-internal-modules":"warn"}}};exports.default=exports.plugin;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.clearCircularDependencyCache=exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const no_cycle_1=require("./rules/no-cycle");Object.defineProperty(exports,"clearCircularDependencyCache",{enumerable:true,get:function(){return no_cycle_1.clearCircularDependencyCache}});exports.rules={get"no-duplicates"(){return require("./rules/no-duplicates").noDuplicates},get named(){return require("./rules/named").named},get default(){return require("./rules/default").defaultRule},get namespace(){return require("./rules/namespace").namespace},get extensions(){return require("./rules/extensions").extensions},get"no-self-import"(){return require("./rules/no-self-import").noSelfImport},get"no-unresolved"(){return require("./rules/no-unresolved").noUnresolved},get"no-absolute-path"(){return require("./rules/no-absolute-path").noAbsolutePath},get"no-dynamic-require"(){return require("./rules/no-dynamic-require").noDynamicRequire},get"no-relative-packages"(){return require("./rules/no-relative-packages").noRelativePackages},get"no-useless-path-segments"(){return require("./rules/no-useless-path-segments").noUselessPathSegments},get"no-amd"(){return require("./rules/no-amd").noAmd},get"no-commonjs"(){return require("./rules/no-commonjs").noCommonjs},get"no-nodejs-modules"(){return require("./rules/no-nodejs-modules").noNodejsModules},get"no-import-module-exports"(){return require("./rules/no-import-module-exports").noImportModuleExports},get unambiguous(){return require("./rules/unambiguous").unambiguous},get"no-cycle"(){return require("./rules/no-cycle").noCycle},get"no-internal-modules"(){return require("./rules/no-internal-modules").noInternalModules},get"no-cross-domain-imports"(){return require("./rules/no-cross-domain-imports").noCrossDomainImports},get"enforce-dependency-direction"(){return require("./rules/enforce-dependency-direction").enforceDependencyDirection},get"no-restricted-paths"(){return require("./rules/no-restricted-paths").noRestrictedPaths},get"no-relative-parent-imports"(){return require("./rules/no-relative-parent-imports").noRelativeParentImports},get export(){return require("./rules/export").exportRule},get"no-default-export"(){return require("./rules/no-default-export").noDefaultExport},get"no-named-export"(){return require("./rules/no-named-export").noNamedExport},get"prefer-default-export"(){return require("./rules/prefer-default-export").preferDefaultExport},get"no-anonymous-default-export"(){return require("./rules/no-anonymous-default-export").noAnonymousDefaultExport},get"no-mutable-exports"(){return require("./rules/no-mutable-exports").noMutableExports},get"no-deprecated"(){return require("./rules/no-deprecated").noDeprecated},get"exports-last"(){return require("./rules/exports-last").exportsLast},get"group-exports"(){return require("./rules/group-exports").groupExports},get"enforce-import-order"(){return require("./rules/enforce-import-order").enforceImportOrder},get order(){return require("./rules/enforce-import-order").enforceImportOrder},get"no-unassigned-import"(){return require("./rules/no-unassigned-import").noUnassignedImport},get first(){return require("./rules/first").first},get"newline-after-import"(){return require("./rules/newline-after-import").newlineAfterImport},get"no-empty-named-blocks"(){return require("./rules/no-empty-named-blocks").noEmptyNamedBlocks},get"no-named-as-default"(){return require("./rules/no-named-as-default").noNamedAsDefault},get"no-named-as-default-member"(){return require("./rules/no-named-as-default-member").noNamedAsDefaultMember},get"no-named-default"(){return require("./rules/no-named-default").noNamedDefault},get"no-namespace"(){return require("./rules/no-namespace").noNamespace},get"consistent-type-specifier-style"(){return require("./rules/consistent-type-specifier-style").consistentTypeSpecifierStyle},get"dynamic-import-chunkname"(){return require("./rules/dynamic-import-chunkname").dynamicImportChunkname},get"no-extraneous-dependencies"(){return require("./rules/no-extraneous-dependencies").noExtraneousDependencies},get"no-unused-modules"(){return require("./rules/no-unused-modules").noUnusedModules},get"max-dependencies"(){return require("./rules/max-dependencies").maxDependencies},get"prefer-node-protocol"(){return require("./rules/prefer-node-protocol").preferNodeProtocol},get"no-barrel-file"(){return require("./rules/no-barrel-file").noBarrelFile},get"no-barrel-import"(){return require("./rules/no-barrel-import").noBarrelImport},get"prefer-tree-shakeable-imports"(){return require("./rules/prefer-tree-shakeable-imports").preferTreeShakeableImports},get"prefer-direct-import"(){return require("./rules/prefer-direct-import").preferDirectImport},get"no-full-package-import"(){return require("./rules/no-full-package-import").noFullPackageImport},get"enforce-team-boundaries"(){return require("./rules/enforce-team-boundaries").enforceTeamBoundaries},get"no-legacy-imports"(){return require("./rules/no-legacy-imports").noLegacyImports},get"require-import-approval"(){return require("./rules/require-import-approval").requireImportApproval},get"prefer-modern-api"(){return require("./rules/prefer-modern-api").preferModernApi}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-import-next",exports.rules);exports.plugin={meta:{name:"eslint-plugin-import-next",version:"2.8.4"},rules:exports.rules};exports.configs={flagship:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-cycle":"error"}},recommended:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"warn","import-next/no-duplicates":"error","import-next/export":"error","import-next/no-cycle":"error","import-next/no-self-import":"error","import-next/no-named-as-default":"warn","import-next/no-named-as-default-member":"warn","import-next/no-amd":"warn","import-next/no-empty-named-blocks":"warn","import-next/no-extraneous-dependencies":"warn"}},strict:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/extensions":"error","import-next/no-self-import":"error","import-next/no-duplicates":"error","import-next/no-absolute-path":"error","import-next/no-dynamic-require":"error","import-next/no-useless-path-segments":"error","import-next/export":"error","import-next/no-amd":"error","import-next/no-commonjs":"error","import-next/no-nodejs-modules":"error","import-next/no-import-module-exports":"error","import-next/unambiguous":"error","import-next/no-cycle":"error","import-next/no-internal-modules":"error","import-next/no-cross-domain-imports":"error","import-next/enforce-dependency-direction":"error","import-next/no-restricted-paths":"error","import-next/no-relative-parent-imports":"error","import-next/no-relative-packages":"error","import-next/no-anonymous-default-export":"error","import-next/no-mutable-exports":"error","import-next/no-deprecated":"error","import-next/exports-last":"error","import-next/group-exports":"error","import-next/order":"error","import-next/no-unassigned-import":"error","import-next/first":"error","import-next/newline-after-import":"error","import-next/no-empty-named-blocks":"error","import-next/no-named-as-default":"error","import-next/no-named-as-default-member":"error","import-next/no-named-default":"error","import-next/no-namespace":"error","import-next/consistent-type-specifier-style":"error","import-next/no-extraneous-dependencies":"error","import-next/no-unused-modules":"error","import-next/max-dependencies":"error","import-next/prefer-node-protocol":"error"}},typescript:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"off","import-next/default":"error","import-next/namespace":"error","import-next/export":"error","import-next/no-cycle":"error","import-next/no-duplicates":"error","import-next/order":"warn","import-next/first":"warn","import-next/newline-after-import":"warn","import-next/consistent-type-specifier-style":["warn","prefer-inline"]}},"module-resolution":{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/extensions":"warn","import-next/no-self-import":"error","import-next/no-duplicates":"error","import-next/no-absolute-path":"error","import-next/no-useless-path-segments":"warn"}},"import-style":{plugins:{"import-next":exports.plugin},rules:{"import-next/order":"error","import-next/first":"error","import-next/newline-after-import":"error","import-next/no-duplicates":"error","import-next/no-unassigned-import":"warn","import-next/no-empty-named-blocks":"error","import-next/no-namespace":"warn"}},esm:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-amd":"error","import-next/no-commonjs":"error","import-next/no-import-module-exports":"error","import-next/unambiguous":"error","import-next/prefer-node-protocol":"error"}},architecture:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-cycle":"error","import-next/no-internal-modules":"error","import-next/no-cross-domain-imports":"error","import-next/enforce-dependency-direction":"error","import-next/no-restricted-paths":"error","import-next/no-relative-parent-imports":"warn","import-next/no-relative-packages":"error"}},errors:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-unresolved":"error","import-next/named":"error","import-next/default":"error","import-next/namespace":"error","import-next/export":"error"}},warnings:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-named-as-default":"warn","import-next/no-named-as-default-member":"warn","import-next/no-duplicates":"warn"}},performance:{plugins:{"import-next":exports.plugin},rules:{"import-next/no-barrel-file":"error","import-next/no-barrel-import":"warn","import-next/prefer-tree-shakeable-imports":"warn","import-next/prefer-direct-import":"warn","import-next/no-full-package-import":"warn","import-next/no-cycle":"error"}},enterprise:{plugins:{"import-next":exports.plugin},rules:{"import-next/enforce-team-boundaries":"off","import-next/no-legacy-imports":"off","import-next/no-cross-domain-imports":"warn","import-next/enforce-dependency-direction":"warn","import-next/no-internal-modules":"warn"}}};exports.default=exports.plugin;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.exportsLast=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.exportsLast=(0,eslint_devkit_1.createRule)({name:"exports-last",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/exports-last.md",description:"Ensure all exports appear after other statements",cwe:"CWE-1078",cvss:2.5},messages:{exportNotLast:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Export Not Last",cwe:"CWE-1078",description:"Export statements should appear at the end of the file",severity:"LOW",fix:"Move this export to the end of the file",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/exports-last.md"})},schema:[]},defaultOptions:[],create(context){return{"Program:exit"(node){const body=node.body;let lastNonExportIndex=-1;const exportIndices=[];const nonExportIndices=[];body.forEach((statement,index)=>{const isExport=statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration||statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration||statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportAllDeclaration;if(isExport){if(statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration&&statement.declaration){nonExportIndices.push(index)}else{exportIndices.push(index)}}else{nonExportIndices.push(index)}});if(nonExportIndices.length>0){lastNonExportIndex=Math.max(...nonExportIndices)}for(const exportIndex of exportIndices){if(exportIndex<lastNonExportIndex){context.report({node:body[exportIndex],messageId:"exportNotLast"})}}}}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.exportsLast=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.exportsLast=(0,eslint_devkit_1.createRule)({name:"exports-last",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/exports-last.md",description:"Ensure all exports appear after other statements",cwe:"CWE-1078",cvss:2.5},messages:{exportNotLast:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Export Not Last",cwe:"CWE-1078",description:"Export statements should appear at the end of the file",severity:"LOW",fix:"Move this export to the end of the file",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/exports-last.md"})},schema:[]},defaultOptions:[],create(context){return{"Program:exit"(node){const body=node.body;let lastNonExportIndex=-1;const exportIndices=[];const nonExportIndices=[];body.forEach((statement,index)=>{const isExport=statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration||statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration||statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportAllDeclaration;if(isExport){if(statement.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration&&statement.declaration){}else{exportIndices.push(index)}}else{nonExportIndices.push(index)}});if(nonExportIndices.length>0){lastNonExportIndex=Math.max(...nonExportIndices)}for(const exportIndex of exportIndices){if(exportIndex<lastNonExportIndex){context.report({node:body[exportIndex],messageId:"exportNotLast"})}}}}}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noBarrelFile=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const DEFAULT_BARREL_PATTERNS=[".*[/\\\\]index\\.(ts|tsx|js|jsx|mts|mjs)$"];function matchesPattern(filePath,patterns){return patterns.some(pattern=>{try{const regex=new RegExp(pattern);return regex.test(filePath)}catch{return filePath.includes(pattern)}})}function isReexport(node){if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportAllDeclaration){return true}if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration&&node.source!==null){return true}return false}function isLocalExport(node){if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration){return node.source===null&&node.declaration!==null}if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration){return true}return false}function countReexportSources(reexports,namedReexports){const sources=new Set;for(const node of reexports){if(node.source?.value){sources.add(String(node.source.value))}}for(const node of namedReexports){if(node.source?.value){sources.add(String(node.source.value))}}return sources.size}exports.noBarrelFile=(0,eslint_devkit_1.createRule)({name:"no-barrel-file",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md",description:"Disallow barrel files that harm build performance and tree-shaking efficiency"},messages:{barrelFileDetected:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Barrel File Detected",description:"This file re-exports {{reexportCount}} modules without adding local logic. Barrel files severely impact build performance and prevent effective tree-shaking.",severity:"MEDIUM",fix:"Replace barrel pattern with direct imports. Instead of: import { Button } from '@/components'; Use: import { Button } from '@/components/Button';",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md"}),considerDirectExports:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Consider Direct Exports",description:"This file has a high ratio of re-exports ({{ratio}}%). Consider using direct imports for better tree-shaking.",severity:"LOW",fix:"Evaluate if consumers can import directly from source modules instead of through this barrel file.",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md"})},schema:[{type:"object",properties:{threshold:{type:"number",minimum:1,default:3,description:"Minimum number of re-exports to consider a file a barrel"},allowedPaths:{type:"array",items:{type:"string"},default:[],description:"Regex patterns for paths where barrel files are allowed"},barrelPatterns:{type:"array",items:{type:"string"},default:DEFAULT_BARREL_PATTERNS,description:"File patterns considered barrel candidates"},allowWithLocalExports:{type:"boolean",default:false,description:"Allow barrel files that also export local declarations"},reexportRatio:{type:"number",minimum:0,maximum:1,default:.8,description:"Maximum allowed ratio of re-exports to total exports"}},additionalProperties:false}]},defaultOptions:[{threshold:3,allowedPaths:[],barrelPatterns:DEFAULT_BARREL_PATTERNS,allowWithLocalExports:false,reexportRatio:.8}],create(context,[options={}]){const{threshold=3,allowedPaths=[],barrelPatterns=DEFAULT_BARREL_PATTERNS,allowWithLocalExports=false,reexportRatio=.8}=options||{};const filename=context.filename;if(!matchesPattern(filename,barrelPatterns)){return{}}if(allowedPaths.length>0&&matchesPattern(filename,allowedPaths)){return{}}const exportAllDeclarations=[];const namedReexports=[];const localExports=[];return{ExportAllDeclaration(node){exportAllDeclarations.push(node)},ExportNamedDeclaration(node){if(isReexport(node)){namedReexports.push(node)}else if(isLocalExport(node)){localExports.push(node)}},ExportDefaultDeclaration(node){if(isLocalExport(node)){localExports.push(node)}},"Program:exit"(node){const totalReexports=exportAllDeclarations.length+namedReexports.length;const totalExports=totalReexports+localExports.length;if(totalExports===0){return}const sourceCount=countReexportSources(exportAllDeclarations,namedReexports);const hasLocalExports=localExports.length>0;if(allowWithLocalExports&&hasLocalExports){return}const ratio=totalReexports/totalExports;if(sourceCount>=threshold&&!hasLocalExports){context.report({node,messageId:"barrelFileDetected",data:{reexportCount:String(sourceCount)}})}else if(hasLocalExports&&sourceCount>=threshold&&ratio>=reexportRatio){context.report({node,messageId:"considerDirectExports",data:{ratio:String(Math.round(ratio*100))}})}}}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noBarrelFile=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const DEFAULT_BARREL_PATTERNS=[".*[/\\\\]index\\.(ts|tsx|js|jsx|mts|mjs)$"];function matchesPattern(filePath,patterns){return patterns.some(pattern=>{try{const regex=new RegExp(pattern);return regex.test(filePath)}catch{return filePath.includes(pattern)}})}function isReexport(node){if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportAllDeclaration){return true}if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration&&node.source!==null){return true}return false}function splitSpecifierClause(node,importSourceByLocalName){const reexportSources=[];let hasLocalExport=false;for(const specifier of node.specifiers){if(specifier.exportKind==="type"||node.exportKind==="type"){continue}const localName=specifier.local.name;const source=importSourceByLocalName.get(localName);if(source===void 0){hasLocalExport=true}else{reexportSources.push(source)}}return{reexportSources,hasLocalExport}}function isLocalExport(node){if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration){return node.source===null&&node.declaration!==null}if(node.type===eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration){return true}return false}function collectReexportSources(reexports,namedReexports){const sources=new Set;for(const node of[...reexports,...namedReexports]){if(node.source?.value){sources.add(String(node.source.value))}}return sources}exports.noBarrelFile=(0,eslint_devkit_1.createRule)({name:"no-barrel-file",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md",description:"Disallow barrel files that harm build performance and tree-shaking efficiency"},messages:{barrelFileDetected:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Barrel File Detected",description:"This file re-exports {{reexportCount}} modules without adding local logic. Barrel files severely impact build performance and prevent effective tree-shaking.",severity:"MEDIUM",fix:"Replace barrel pattern with direct imports. Instead of: import { Button } from '@/components'; Use: import { Button } from '@/components/Button';",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md"}),considerDirectExports:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Consider Direct Exports",description:"This file has a high ratio of re-exports ({{ratio}}%). Consider using direct imports for better tree-shaking.",severity:"LOW",fix:"Evaluate if consumers can import directly from source modules instead of through this barrel file.",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-barrel-file.md"})},schema:[{type:"object",properties:{threshold:{type:"number",minimum:1,default:3,description:"Minimum number of re-exports to consider a file a barrel"},allowedPaths:{type:"array",items:{type:"string"},default:[],description:"Regex patterns for paths where barrel files are allowed"},barrelPatterns:{type:"array",items:{type:"string"},default:DEFAULT_BARREL_PATTERNS,description:"File patterns considered barrel candidates"},allowWithLocalExports:{type:"boolean",default:false,description:"Allow barrel files that also export local declarations"},reexportRatio:{type:"number",minimum:0,maximum:1,default:.8,description:"Maximum allowed ratio of re-exports to total exports"}},additionalProperties:false}]},defaultOptions:[{threshold:3,allowedPaths:[],barrelPatterns:DEFAULT_BARREL_PATTERNS,allowWithLocalExports:false,reexportRatio:.8}],create(context,[options={}]){const{threshold=3,allowedPaths=[],barrelPatterns=DEFAULT_BARREL_PATTERNS,allowWithLocalExports=false,reexportRatio=.8}=options||{};const filename=context.filename;if(!matchesPattern(filename,barrelPatterns)){return{}}if(allowedPaths.length>0&&matchesPattern(filename,allowedPaths)){return{}}const exportAllDeclarations=[];const namedReexports=[];const localExports=[];const importSourceByLocalName=new Map;const indirectReexportSources=new Set;return{ImportDeclaration(node){if(node.importKind==="type")return;for(const specifier of node.specifiers){if(specifier.type===eslint_devkit_1.AST_NODE_TYPES.ImportSpecifier&&specifier.importKind==="type"){continue}importSourceByLocalName.set(specifier.local.name,String(node.source.value))}},ExportAllDeclaration(node){exportAllDeclarations.push(node)},ExportNamedDeclaration(node){if(isReexport(node)){namedReexports.push(node)}else if(isLocalExport(node)){localExports.push(node)}else{const{reexportSources,hasLocalExport}=splitSpecifierClause(node,importSourceByLocalName);for(const source of reexportSources){indirectReexportSources.add(source)}if(reexportSources.length>0){namedReexports.push(node)}if(hasLocalExport){localExports.push(node)}}},ExportDefaultDeclaration(node){if(isLocalExport(node)){localExports.push(node)}},"Program:exit"(node){const totalReexports=exportAllDeclarations.length+namedReexports.length;const totalExports=totalReexports+localExports.length;if(totalExports===0){return}const sources=new Set(indirectReexportSources);for(const source of collectReexportSources(exportAllDeclarations,namedReexports)){sources.add(source)}const sourceCount=sources.size;const hasLocalExports=localExports.length>0;if(allowWithLocalExports&&hasLocalExports){return}const ratio=totalReexports/totalExports;if(sourceCount>=threshold&&!hasLocalExports){context.report({node,messageId:"barrelFileDetected",data:{reexportCount:String(sourceCount)}})}else if(hasLocalExports&&sourceCount>=threshold&&ratio>=reexportRatio){context.report({node,messageId:"considerDirectExports",data:{ratio:String(Math.round(ratio*100))}})}}}}});
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCycle=void 0;exports.clearCircularDependencyCache=clearCircularDependencyCache;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");const node_fs_1=require("node:fs");const eslint_devkit_4=require("@interlace/eslint-devkit");const sharedCache=(0,eslint_devkit_4.createFileSystemCache)();function clearCircularDependencyCache(){(0,eslint_devkit_4.clearCache)(sharedCache);exportKindCache.clear()}const exportKindCache=new Map;function exportKindsOf(target){const hit=exportKindCache.get(target);if(hit)return hit;const kinds=new Map;let source;try{source=(0,node_fs_1.readFileSync)(target,"utf-8")}catch{exportKindCache.set(target,kinds);return kinds}for(const m of source.matchAll(/export\s+(?:declare\s+)?(?:abstract\s+)?(?:const|let|var|function|class|enum|namespace|module)\s+([A-Za-z_$][\w$]*)/g)){kinds.set(m[1],"value")}for(const m of source.matchAll(/export\s+(?:declare\s+)?(?:interface|type)\s+([A-Za-z_$][\w$]*)/g)){if(!kinds.has(m[1]))kinds.set(m[1],"type")}exportKindCache.set(target,kinds);return kinds}function importsOnlyTypes(node,target){const specifiers=node.specifiers??[];if(!specifiers.length)return false;const kinds=exportKindsOf(target);return specifiers.every(spec=>{if(spec.type!=="ImportSpecifier")return false;if(spec.importKind==="type")return true;const name=spec.imported.name;return kinds.get(name)==="type"})}exports.noCycle=(0,eslint_devkit_1.createRule)({name:"no-cycle",skipGeneratedFiles:true,meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-cycle.md",description:"Detect circular dependencies that cause bundle memory bloat and initialization issues",cwe:"CWE-1047",confidence:"high"},messages:{moduleSplit:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Split {{moduleToSplit}} into .{{coreFile}} and .{{extendedFile}}",documentationLink:"https://en.wikipedia.org/wiki/Circular_dependency"}),directImport:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"{{newImport}} (direct imports preferred over barrel exports)",documentationLink:"https://en.wikipedia.org/wiki/Circular_dependency"}),extractShared:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Extract shared types to {{exports}} file",documentationLink:"https://en.wikipedia.org/wiki/Dependency_inversion_principle"}),dependencyInjection:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Use dependency injection pattern to break cycle",documentationLink:"https://en.wikipedia.org/wiki/Dependency_injection"})},schema:[{type:"object",properties:{maxDepth:{type:"number",default:Number.MAX_SAFE_INTEGER,description:"Maximum depth to traverse when detecting cycles. Default: unlimited (matches eslint-plugin-import and oxlint). Lower values are a performance escape hatch \u2014 but with our nonCyclicFiles cache, traversal cost is amortized, and a low cap silently misses cycles deeper than the limit. Set to a finite number only on huge graphs where the bench latency hurts you."},ignorePatterns:{type:"array",items:{type:"string"},default:["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/*.stories.tsx","**/__tests__/**","**/__mocks__/**"],description:"File patterns to ignore (glob patterns)"},barrelExports:{type:"array",items:{type:"string"},default:["index.ts","index.tsx","index.js","index.jsx"],description:"Files considered barrel exports"},reportAllCycles:{type:"boolean",default:true,description:"Report all circular dependencies found (not just the first one)"},fixStrategy:{type:"string",enum:["module-split","direct-import","extract-shared","dependency-injection","auto"],default:"auto",description:"Strategy for fixing circular dependencies (auto = smart detection)"},moduleNamingConvention:{type:"string",enum:["semantic","numbered"],default:"semantic",description:"Naming convention for split modules (semantic: .core, .api | numbered: .1, .2)"},coreModuleSuffix:{type:"string",default:"core",description:'Suffix for core module when splitting (e.g., "core", "base", "main")'},extendedModuleSuffix:{type:"string",default:"extended",description:'Suffix for extended module when splitting (e.g., "extended", "api", "helpers")'}},additionalProperties:false}],fixable:void 0},defaultOptions:[{maxDepth:Infinity,ignorePatterns:[],barrelExports:["index.ts","index.tsx","index.js","index.jsx"],reportAllCycles:true,fixStrategy:"auto",moduleNamingConvention:"semantic",coreModuleSuffix:"core",extendedModuleSuffix:"extended"}],create(context){const options=context.options[0]||{};const maxDepth=options.maxDepth??Infinity;const ignorePatterns=options.ignorePatterns??["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/*.stories.tsx","**/__tests__/**","**/__mocks__/**"];const barrelExports=options.barrelExports??["index.ts","index.tsx","index.js","index.jsx"];const _reportAllCycles=options.reportAllCycles??true;const fixStrategy=options.fixStrategy??"auto";const moduleNamingConvention=options.moduleNamingConvention??"semantic";const coreModuleSuffix=options.coreModuleSuffix??"core";const extendedModuleSuffix=options.extendedModuleSuffix??"extended";const filename=context.filename;const normalizedFilename=(()=>{try{return(0,node_fs_1.realpathSync)(filename)}catch{return filename}})();const workspaceRoot=context.cwd;const settings=context.settings;const resolverSettings=settings?.["import/resolver"]||settings?.["import-next/resolver"];if((0,eslint_devkit_3.shouldIgnoreFile)(filename,ignorePatterns,sharedCache.compiledPatterns)){return{}}sharedCache.pendingCycleReports.clear();const reportedImportNodes=new Set;function selectFixStrategy(cycle,userStrategy){if(userStrategy!=="auto"){return userStrategy}const hasBarrel=cycle.some(file=>(0,eslint_devkit_3.isBarrelExport)(file,barrelExports));const typesOnly=(0,eslint_devkit_4.hasOnlyTypeImports)(cycle,sharedCache);const cycleSize=cycle.length;if(hasBarrel&&cycleSize===2){return"direct-import"}if(typesOnly){return"extract-shared"}return"module-split"}function generateModuleSplitMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[module1,module2]=moduleNames;const moduleToSplit=module1;const suffix1=moduleNamingConvention==="semantic"?`.${coreModuleSuffix}`:".1";const suffix2=moduleNamingConvention==="semantic"?`.${extendedModuleSuffix}`:".2";return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),moduleToSplit,coreFile:coreModuleSuffix,extendedFile:extendedModuleSuffix,splitCount:"2",fileStructure:`\u251C\u2500 ${moduleToSplit}/${moduleToSplit}${suffix1}.ts (\u2192 ${module2} \u2713)
2
- \u2514\u2500 ${moduleToSplit}/${moduleToSplit}${suffix2}.ts (\u2192 ${suffix1} + ${module2} \u2713)`,result:`${suffix1} \u2192 ${module2} \u2192 ${suffix2} (no cycle)`}}function generateDirectImportMessage(cycle,sourceImport){const currentFile=(0,eslint_devkit_3.getBasename)(context.filename);const targetFile=cycle[1];const relativeImport=(0,eslint_devkit_3.getRelativeImportPath)(context.filename,targetFile);return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),currentFile,oldImport:`import { ... } from '${sourceImport.source}'`,newImport:`import { ... } from '${relativeImport}'`}}function generateExtractSharedMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[module1,module2]=moduleNames;const exports2=[`- export type ${module1}Id, ${module2}Id`,`- export interface ${module1}Summary, ${module2}Summary`].join("\n");return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),exports:exports2,result:`shared/types \u2190 ${module1}, ${module2} (no cycle)`}}function generateDependencyInjectionMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[service1,service2]=moduleNames;const steps=[`1. Create interfaces/I${service1}.ts, interfaces/I${service2}.ts`,`2. Both services implement their interface`,`3. Inject via constructor: constructor(private dep?: IDep)`,`4. Wire in container.ts`].join("\n");return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),steps}}function generateMessageData(cycle,strategy,sourceImport){switch(strategy){case"direct-import":return{messageId:"directImport",data:generateDirectImportMessage(cycle,sourceImport)};case"extract-shared":return{messageId:"extractShared",data:generateExtractSharedMessage(cycle)};case"dependency-injection":return{messageId:"dependencyInjection",data:generateDependencyInjectionMessage(cycle)};default:return{messageId:"moduleSplit",data:generateModuleSplitMessage(cycle)}}}return{"Program"(){},ImportDeclaration(node){if(node.importKind==="type")return;if(reportedImportNodes.has(node))return;const importSource=node.source.value;const resolved=(0,eslint_devkit_4.resolveImportPath)(importSource,{fromFile:normalizedFilename,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!resolved)return;if(importsOnlyTypes(node,resolved))return;if(sharedCache.nonCyclicFiles.has(resolved))return;let tgtSCC=sharedCache.sccIndex.get(resolved);if(tgtSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(resolved,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});tgtSCC=sharedCache.sccIndex.get(resolved)}let srcSCC=sharedCache.sccIndex.get(normalizedFilename);if(srcSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(normalizedFilename,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});srcSCC=sharedCache.sccIndex.get(normalizedFilename)}if(srcSCC===void 0||tgtSCC===void 0||srcSCC!==tgtSCC){return}const cyclePath=(0,eslint_devkit_4.findShortestCyclePath)(normalizedFilename,resolved,{maxDepth,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!cyclePath)return;reportedImportNodes.add(node);const cycleStart=cyclePath.indexOf(normalizedFilename);const relevantCycle=cycleStart>=0?[...cyclePath.slice(cycleStart),...cyclePath.slice(0,cycleStart)]:cyclePath;const strategy=selectFixStrategy(relevantCycle,fixStrategy);const sourceImport={path:resolved,source:importSource};const{messageId,data}=generateMessageData(relevantCycle,strategy,sourceImport);context.report({node,messageId,data})},ExportNamedDeclaration(node){if(!node.source)return;if(reportedImportNodes.has(node))return;const importSource=node.source.value;const resolved=(0,eslint_devkit_4.resolveImportPath)(importSource,{fromFile:normalizedFilename,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!resolved)return;if(sharedCache.nonCyclicFiles.has(resolved))return;let tgtSCC=sharedCache.sccIndex.get(resolved);if(tgtSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(resolved,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});tgtSCC=sharedCache.sccIndex.get(resolved)}const srcSCC=sharedCache.sccIndex.get(normalizedFilename);if(srcSCC===void 0||tgtSCC===void 0||srcSCC!==tgtSCC)return;const cyclePath=(0,eslint_devkit_4.findShortestCyclePath)(normalizedFilename,resolved,{maxDepth,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!cyclePath)return;reportedImportNodes.add(node);const cycleStart=cyclePath.indexOf(normalizedFilename);const relevantCycle=cycleStart>=0?[...cyclePath.slice(cycleStart),...cyclePath.slice(0,cycleStart)]:cyclePath;const strategy=selectFixStrategy(relevantCycle,fixStrategy);const sourceImport={path:resolved,source:importSource};const{messageId,data}=generateMessageData(relevantCycle,strategy,sourceImport);context.report({node,messageId,data})}}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCycle=void 0;exports.clearCircularDependencyCache=clearCircularDependencyCache;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");const node_fs_1=require("node:fs");const eslint_devkit_4=require("@interlace/eslint-devkit");const sharedCache=(0,eslint_devkit_4.createFileSystemCache)();function clearCircularDependencyCache(){(0,eslint_devkit_4.clearCache)(sharedCache);exportKindCache.clear()}const exportKindCache=new Map;function exportKindsOf(target){const hit=exportKindCache.get(target);if(hit)return hit;const kinds=new Map;let source;try{source=(0,node_fs_1.readFileSync)(target,"utf-8")}catch{exportKindCache.set(target,kinds);return kinds}for(const m of source.matchAll(/export\s+(?:declare\s+)?(?:abstract\s+)?(?:const|let|var|function|class|enum|namespace|module)\s+([A-Za-z_$][\w$]*)/g)){kinds.set(m[1],"value")}for(const m of source.matchAll(/export\s+(?:declare\s+)?(?:interface|type)\s+([A-Za-z_$][\w$]*)/g)){if(!kinds.has(m[1]))kinds.set(m[1],"type")}exportKindCache.set(target,kinds);return kinds}function importsOnlyTypes(node,target,verbatimModuleSyntax){const specifiers=node.specifiers??[];if(!specifiers.length)return false;const kinds=exportKindsOf(target);return specifiers.every(spec=>{if(spec.type!=="ImportSpecifier")return false;if(spec.importKind==="type")return!verbatimModuleSyntax;const name=spec.imported.name;return kinds.get(name)==="type"})}exports.noCycle=(0,eslint_devkit_1.createRule)({name:"no-cycle",skipGeneratedFiles:true,meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-cycle.md",description:"Detect circular dependencies that cause bundle memory bloat and initialization issues",cwe:"CWE-1047",confidence:"high"},messages:{moduleSplit:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Split {{moduleToSplit}} into .{{coreFile}} and .{{extendedFile}}",documentationLink:"https://en.wikipedia.org/wiki/Circular_dependency"}),directImport:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"{{newImport}} (direct imports preferred over barrel exports)",documentationLink:"https://en.wikipedia.org/wiki/Circular_dependency"}),extractShared:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Extract shared types to {{exports}} file",documentationLink:"https://en.wikipedia.org/wiki/Dependency_inversion_principle"}),dependencyInjection:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Circular dependency",cwe:"CWE-1047",description:"Circular dependency detected",severity:"MEDIUM",fix:"Use dependency injection pattern to break cycle",documentationLink:"https://en.wikipedia.org/wiki/Dependency_injection"})},schema:[{type:"object",properties:{maxDepth:{type:"number",default:Number.MAX_SAFE_INTEGER,description:"Maximum depth to traverse when detecting cycles. Default: unlimited (matches eslint-plugin-import and oxlint). Lower values are a performance escape hatch \u2014 but with our nonCyclicFiles cache, traversal cost is amortized, and a low cap silently misses cycles deeper than the limit. Set to a finite number only on huge graphs where the bench latency hurts you."},ignorePatterns:{type:"array",items:{type:"string"},default:["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/*.stories.tsx","**/__tests__/**","**/__mocks__/**"],description:"File patterns to ignore (glob patterns)"},barrelExports:{type:"array",items:{type:"string"},default:["index.ts","index.tsx","index.js","index.jsx"],description:"Files considered barrel exports"},reportAllCycles:{type:"boolean",default:true,description:"Report all circular dependencies found (not just the first one)"},verbatimModuleSyntax:{type:"boolean",default:false,description:"Treat an inline `import { type Foo }` specifier as a runtime edge. Set this when the project compiles with TypeScript's `verbatimModuleSyntax`, under which the inline form is emitted as `import {} from './foo.js'` rather than erased \u2014 so the target module is still evaluated and the cycle is real. A statement-level `import type` is erased under every setting and stays skipped either way."},fixStrategy:{type:"string",enum:["module-split","direct-import","extract-shared","dependency-injection","auto"],default:"auto",description:"Strategy for fixing circular dependencies (auto = smart detection)"},moduleNamingConvention:{type:"string",enum:["semantic","numbered"],default:"semantic",description:"Naming convention for split modules (semantic: .core, .api | numbered: .1, .2)"},coreModuleSuffix:{type:"string",default:"core",description:'Suffix for core module when splitting (e.g., "core", "base", "main")'},extendedModuleSuffix:{type:"string",default:"extended",description:'Suffix for extended module when splitting (e.g., "extended", "api", "helpers")'}},additionalProperties:false}],fixable:void 0},defaultOptions:[{maxDepth:Infinity,ignorePatterns:[],barrelExports:["index.ts","index.tsx","index.js","index.jsx"],reportAllCycles:true,verbatimModuleSyntax:false,fixStrategy:"auto",moduleNamingConvention:"semantic",coreModuleSuffix:"core",extendedModuleSuffix:"extended"}],create(context){const options=context.options[0]||{};const maxDepth=options.maxDepth??Infinity;const verbatimModuleSyntax=options.verbatimModuleSyntax??false;const ignorePatterns=options.ignorePatterns??["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/*.stories.tsx","**/__tests__/**","**/__mocks__/**"];const barrelExports=options.barrelExports??["index.ts","index.tsx","index.js","index.jsx"];const _reportAllCycles=options.reportAllCycles??true;const fixStrategy=options.fixStrategy??"auto";const moduleNamingConvention=options.moduleNamingConvention??"semantic";const coreModuleSuffix=options.coreModuleSuffix??"core";const extendedModuleSuffix=options.extendedModuleSuffix??"extended";const filename=context.filename;const normalizedFilename=(()=>{try{return(0,node_fs_1.realpathSync)(filename)}catch{return filename}})();const workspaceRoot=context.cwd;const settings=context.settings;const resolverSettings=settings?.["import/resolver"]||settings?.["import-next/resolver"];if((0,eslint_devkit_3.shouldIgnoreFile)(filename,ignorePatterns,sharedCache.compiledPatterns)){return{}}sharedCache.pendingCycleReports.clear();const reportedImportNodes=new Set;function selectFixStrategy(cycle,userStrategy){if(userStrategy!=="auto"){return userStrategy}const hasBarrel=cycle.some(file=>(0,eslint_devkit_3.isBarrelExport)(file,barrelExports));const typesOnly=(0,eslint_devkit_4.hasOnlyTypeImports)(cycle,sharedCache);const cycleSize=cycle.length;if(hasBarrel&&cycleSize===2){return"direct-import"}if(typesOnly){return"extract-shared"}return"module-split"}function generateModuleSplitMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[module1,module2]=moduleNames;const moduleToSplit=module1;const suffix1=moduleNamingConvention==="semantic"?`.${coreModuleSuffix}`:".1";const suffix2=moduleNamingConvention==="semantic"?`.${extendedModuleSuffix}`:".2";return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),moduleToSplit,coreFile:coreModuleSuffix,extendedFile:extendedModuleSuffix,splitCount:"2",fileStructure:`\u251C\u2500 ${moduleToSplit}/${moduleToSplit}${suffix1}.ts (\u2192 ${module2} \u2713)
2
+ \u2514\u2500 ${moduleToSplit}/${moduleToSplit}${suffix2}.ts (\u2192 ${suffix1} + ${module2} \u2713)`,result:`${suffix1} \u2192 ${module2} \u2192 ${suffix2} (no cycle)`}}function generateDirectImportMessage(cycle,sourceImport){const currentFile=(0,eslint_devkit_3.getBasename)(context.filename);const targetFile=cycle[1];const relativeImport=(0,eslint_devkit_3.getRelativeImportPath)(context.filename,targetFile);return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),currentFile,oldImport:`import { ... } from '${sourceImport.source}'`,newImport:`import { ... } from '${relativeImport}'`}}function generateExtractSharedMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[module1,module2]=moduleNames;const exports2=[`- export type ${module1}Id, ${module2}Id`,`- export interface ${module1}Summary, ${module2}Summary`].join("\n");return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),exports:exports2,result:`shared/types \u2190 ${module1}, ${module2} (no cycle)`}}function generateDependencyInjectionMessage(cycle){const moduleNames=(0,eslint_devkit_3.getModuleNames)(cycle,workspaceRoot);const[service1,service2]=moduleNames;const steps=[`1. Create interfaces/I${service1}.ts, interfaces/I${service2}.ts`,`2. Both services implement their interface`,`3. Inject via constructor: constructor(private dep?: IDep)`,`4. Wire in container.ts`].join("\n");return{cycle:(0,eslint_devkit_3.formatCycleDisplay)(cycle,workspaceRoot),steps}}function generateMessageData(cycle,strategy,sourceImport){switch(strategy){case"direct-import":return{messageId:"directImport",data:generateDirectImportMessage(cycle,sourceImport)};case"extract-shared":return{messageId:"extractShared",data:generateExtractSharedMessage(cycle)};case"dependency-injection":return{messageId:"dependencyInjection",data:generateDependencyInjectionMessage(cycle)};default:return{messageId:"moduleSplit",data:generateModuleSplitMessage(cycle)}}}return{"Program"(){},ImportDeclaration(node){if(node.importKind==="type")return;if(reportedImportNodes.has(node))return;const importSource=node.source.value;const resolved=(0,eslint_devkit_4.resolveImportPath)(importSource,{fromFile:normalizedFilename,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!resolved)return;if(importsOnlyTypes(node,resolved,verbatimModuleSyntax))return;if(sharedCache.nonCyclicFiles.has(resolved))return;let tgtSCC=sharedCache.sccIndex.get(resolved);if(tgtSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(resolved,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});tgtSCC=sharedCache.sccIndex.get(resolved)}let srcSCC=sharedCache.sccIndex.get(normalizedFilename);if(srcSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(normalizedFilename,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});srcSCC=sharedCache.sccIndex.get(normalizedFilename)}if(srcSCC===void 0||tgtSCC===void 0||srcSCC!==tgtSCC){return}const cyclePath=(0,eslint_devkit_4.findShortestCyclePath)(normalizedFilename,resolved,{maxDepth,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!cyclePath)return;reportedImportNodes.add(node);const cycleStart=cyclePath.indexOf(normalizedFilename);const relevantCycle=cycleStart>=0?[...cyclePath.slice(cycleStart),...cyclePath.slice(0,cycleStart)]:cyclePath;const strategy=selectFixStrategy(relevantCycle,fixStrategy);const sourceImport={path:resolved,source:importSource};const{messageId,data}=generateMessageData(relevantCycle,strategy,sourceImport);context.report({node,messageId,data})},ExportNamedDeclaration(node){if(!node.source)return;if(reportedImportNodes.has(node))return;const importSource=node.source.value;const resolved=(0,eslint_devkit_4.resolveImportPath)(importSource,{fromFile:normalizedFilename,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!resolved)return;if(sharedCache.nonCyclicFiles.has(resolved))return;let tgtSCC=sharedCache.sccIndex.get(resolved);if(tgtSCC===void 0){(0,eslint_devkit_4.computeSCCsFromFile)(resolved,{maxDepth:Infinity,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});tgtSCC=sharedCache.sccIndex.get(resolved)}const srcSCC=sharedCache.sccIndex.get(normalizedFilename);if(srcSCC===void 0||tgtSCC===void 0||srcSCC!==tgtSCC)return;const cyclePath=(0,eslint_devkit_4.findShortestCyclePath)(normalizedFilename,resolved,{maxDepth,workspaceRoot,barrelExports,cache:sharedCache,resolverSettings});if(!cyclePath)return;reportedImportNodes.add(node);const cycleStart=cyclePath.indexOf(normalizedFilename);const relevantCycle=cycleStart>=0?[...cyclePath.slice(cycleStart),...cyclePath.slice(0,cycleStart)]:cyclePath;const strategy=selectFixStrategy(relevantCycle,fixStrategy);const sourceImport={path:resolved,source:importSource};const{messageId,data}=generateMessageData(relevantCycle,strategy,sourceImport);context.report({node,messageId,data})}}}});
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noExtraneousDependencies=void 0;const node_module_1=require("node:module");const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");const eslint_devkit_4=require("@interlace/eslint-devkit");exports.noExtraneousDependencies=(0,eslint_devkit_1.createRule)({name:"no-extraneous-dependencies",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-extraneous-dependencies.md",description:"Forbid the use of extraneous packages not listed in package.json"},hasSuggestions:true,messages:{extraneousDependency:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Extraneous Dependency",description:"Package not listed in package.json dependencies",severity:"HIGH",fix:"Add package to package.json or remove the import",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),missingDependency:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Missing Dependency",description:"Package used but not in package.json",severity:"HIGH",fix:"Add package to appropriate section in package.json",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),devDependencyInProduction:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Dev Dependency in Production",description:"Dev dependency used in production code",severity:"MEDIUM",fix:"Move to dependencies or ensure this is only used in development",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),addToDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Add to Dependencies",description:"Add package to dependencies in package.json",severity:"HIGH",fix:"Run: npm install <package>",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),addToDevDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Add to Dev Dependencies",description:"Add package to devDependencies in package.json",severity:"HIGH",fix:"Run: npm install --save-dev <package>",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),moveToDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Move to Dependencies",description:"Move package from devDependencies to dependencies",severity:"MEDIUM",fix:"Move package from devDependencies to dependencies in package.json",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"})},schema:[{type:"object",properties:{devDependencies:{type:"boolean",default:true,description:"Allow imports from devDependencies."},optionalDependencies:{type:"boolean",default:true,description:"Allow imports from optionalDependencies."},peerDependencies:{type:"boolean",default:true,description:"Allow imports from peerDependencies."},bundledDependencies:{type:"boolean",default:true,description:"Allow imports from bundledDependencies."},packageJsonPath:{type:"string",description:"Path to package.json file to use."},packageJson:{type:"object",description:"Direct package.json content for testing."},resolutionStrategy:{type:"string",enum:["strict","workspace","monorepo"],default:"strict",description:"Dependency resolution strategy: strict (exact match), workspace (allow workspace packages), monorepo (cross-package resolution)."},allowPatterns:{type:"array",items:{type:"string"},description:"Regex patterns for packages to allow even if not in package.json."},ignore:{type:"array",items:{type:"string"},description:"Specific package names to ignore (don't report as missing)."}},additionalProperties:false}]},defaultOptions:[{devDependencies:true,optionalDependencies:true,peerDependencies:true,bundledDependencies:true,resolutionStrategy:"strict",allowPatterns:[]}],create(context){const[options]=context.options;const{devDependencies=true,optionalDependencies=true,peerDependencies=true,bundledDependencies=true,packageJsonPath,packageJson,resolutionStrategy="strict",allowPatterns=[]}=options||{};const filename=context.filename;if(!filename){return{}}let resolvedPackageJson=null;if(packageJson){resolvedPackageJson=packageJson}else if(packageJsonPath){resolvedPackageJson=(0,eslint_devkit_3.readJsonFileSync)(packageJsonPath);if(!resolvedPackageJson){return{}}}else{const packageJsonFile=(0,eslint_devkit_3.findFileUpward)("package.json",(0,eslint_devkit_4.getDirname)(filename));if(!packageJsonFile){return{}}resolvedPackageJson=(0,eslint_devkit_3.readJsonFileSync)(packageJsonFile);if(!resolvedPackageJson){return{}}}const allowedPackages=new Set;if(resolvedPackageJson?.dependencies){Object.keys(resolvedPackageJson.dependencies).forEach(pkg=>allowedPackages.add(pkg))}if(devDependencies&&resolvedPackageJson?.devDependencies){Object.keys(resolvedPackageJson.devDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(optionalDependencies&&resolvedPackageJson?.optionalDependencies){Object.keys(resolvedPackageJson.optionalDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(peerDependencies&&resolvedPackageJson?.peerDependencies){Object.keys(resolvedPackageJson.peerDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(bundledDependencies&&resolvedPackageJson?.bundledDependencies){resolvedPackageJson.bundledDependencies.forEach(pkg=>allowedPackages.add(pkg))}function isExternalPackage(importPath){if(/^\.\.?(\/|$)/.test(importPath)){return null}if(importPath.startsWith("/")){return null}if(importPath.startsWith("#")){return null}if(importPath.startsWith("node:")||node_module_1.builtinModules.includes(importPath)){return null}if(/^[a-zA-Z][a-zA-Z0-9+\-.]+:/.test(importPath)){return null}const packageName=importPath.startsWith("@")?importPath.split("/").slice(0,2).join("/"):importPath.split("/")[0];return packageName}function isWorkspacePackage(packageName){return packageName.startsWith("@workspace/")||packageName.startsWith("@company/")}function checkImport(importPath,node){const packageName=isExternalPackage(importPath);if(!packageName){return}const isAllowedByPattern=allowPatterns.some(pattern=>{try{const regex=new RegExp(pattern);return regex.test(packageName)}catch{return false}});if(isAllowedByPattern){return}const shouldCheckDependency=()=>{switch(resolutionStrategy){case"workspace":return!allowedPackages.has(packageName)&&!isWorkspacePackage(packageName);case"monorepo":return!allowedPackages.has(packageName)&&!isWorkspacePackage(packageName);case"strict":default:return!allowedPackages.has(packageName)}};if(shouldCheckDependency()){const isInDevDeps=resolvedPackageJson?.devDependencies&&resolvedPackageJson.devDependencies[packageName];if(isInDevDeps&&!devDependencies){context.report({node,messageId:"devDependencyInProduction",data:{packageName,importPath,suggestion:"Move to dependencies if used in production, or ensure this code is only executed in development"},suggest:[{messageId:"moveToDependencies",fix(fixer){let parentStatement=node;while(parentStatement&&parentStatement.type!=="ImportDeclaration"&&parentStatement.type!=="VariableDeclaration"&&parentStatement.type!=="ExpressionStatement"){parentStatement=parentStatement.parent}if(parentStatement){return fixer.insertTextBefore(parentStatement,`// TODO: Move ${packageName} from devDependencies to dependencies in package.json
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noExtraneousDependencies=void 0;const node_module_1=require("node:module");const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");const eslint_devkit_4=require("@interlace/eslint-devkit");exports.noExtraneousDependencies=(0,eslint_devkit_1.createRule)({name:"no-extraneous-dependencies",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-extraneous-dependencies.md",description:"Forbid the use of extraneous packages not listed in package.json"},hasSuggestions:true,messages:{extraneousDependency:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Extraneous Dependency",description:"Package not listed in package.json dependencies",severity:"HIGH",fix:"Add package to package.json or remove the import",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),missingDependency:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Missing Dependency",description:"Package used but not in package.json",severity:"HIGH",fix:"Add package to appropriate section in package.json",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),devDependencyInProduction:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.WARNING,issueName:"Dev Dependency in Production",description:"Dev dependency used in production code",severity:"MEDIUM",fix:"Move to dependencies or ensure this is only used in development",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),addToDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Add to Dependencies",description:"Add package to dependencies in package.json",severity:"HIGH",fix:"Run: npm install <package>",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),addToDevDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Add to Dev Dependencies",description:"Add package to devDependencies in package.json",severity:"HIGH",fix:"Run: npm install --save-dev <package>",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"}),moveToDependencies:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Move to Dependencies",description:"Move package from devDependencies to dependencies",severity:"MEDIUM",fix:"Move package from devDependencies to dependencies in package.json",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md"})},schema:[{type:"object",properties:{devDependencies:{type:"boolean",default:true,description:"Allow imports from devDependencies."},optionalDependencies:{type:"boolean",default:true,description:"Allow imports from optionalDependencies."},peerDependencies:{type:"boolean",default:true,description:"Allow imports from peerDependencies."},bundledDependencies:{type:"boolean",default:true,description:"Allow imports from bundledDependencies."},packageJsonPath:{type:"string",description:"Path to package.json file to use."},packageJson:{type:"object",description:"Direct package.json content for testing."},resolutionStrategy:{type:"string",enum:["strict","workspace","monorepo"],default:"strict",description:"Dependency resolution strategy. 'strict' allows only packages declared in the nearest package.json. 'workspace' and 'monorepo' are aliases of each other: they additionally allow the literal '@workspace/' and '@company/' scopes, and do NOT read workspace-root or sibling manifests; for real monorepo scopes use allowPatterns."},allowPatterns:{type:"array",items:{type:"string"},description:"Regex patterns for packages to allow even if not in package.json."},ignore:{type:"array",items:{type:"string"},description:"Specific package names to ignore (don't report as missing)."}},additionalProperties:false}]},defaultOptions:[{devDependencies:true,optionalDependencies:true,peerDependencies:true,bundledDependencies:true,resolutionStrategy:"strict",allowPatterns:[]}],create(context){const[options]=context.options;const{devDependencies=true,optionalDependencies=true,peerDependencies=true,bundledDependencies=true,packageJsonPath,packageJson,resolutionStrategy="strict",allowPatterns=[],ignore=[]}=options||{};const filename=context.filename;if(!filename){return{}}let resolvedPackageJson=null;if(packageJson){resolvedPackageJson=packageJson}else if(packageJsonPath){resolvedPackageJson=(0,eslint_devkit_3.readJsonFileSync)(packageJsonPath);if(!resolvedPackageJson){return{}}}else{const packageJsonFile=(0,eslint_devkit_3.findFileUpward)("package.json",(0,eslint_devkit_4.getDirname)(filename));if(!packageJsonFile){return{}}resolvedPackageJson=(0,eslint_devkit_3.readJsonFileSync)(packageJsonFile);if(!resolvedPackageJson){return{}}}const allowedPackages=new Set;if(resolvedPackageJson?.dependencies){Object.keys(resolvedPackageJson.dependencies).forEach(pkg=>allowedPackages.add(pkg))}if(devDependencies&&resolvedPackageJson?.devDependencies){Object.keys(resolvedPackageJson.devDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(optionalDependencies&&resolvedPackageJson?.optionalDependencies){Object.keys(resolvedPackageJson.optionalDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(peerDependencies&&resolvedPackageJson?.peerDependencies){Object.keys(resolvedPackageJson.peerDependencies).forEach(pkg=>allowedPackages.add(pkg))}if(bundledDependencies&&resolvedPackageJson?.bundledDependencies){resolvedPackageJson.bundledDependencies.forEach(pkg=>allowedPackages.add(pkg))}function isExternalPackage(importPath){if(/^\.\.?(\/|$)/.test(importPath)){return null}if(importPath.startsWith("/")){return null}if(importPath.startsWith("#")){return null}if(importPath.startsWith("node:")||node_module_1.builtinModules.includes(importPath)){return null}if(/^[a-zA-Z][a-zA-Z0-9+\-.]+:/.test(importPath)){return null}const packageName=importPath.startsWith("@")?importPath.split("/").slice(0,2).join("/"):importPath.split("/")[0];return packageName}function isWorkspacePackage(packageName){return packageName.startsWith("@workspace/")||packageName.startsWith("@company/")}function checkImport(importPath,node){const packageName=isExternalPackage(importPath);if(!packageName){return}const isAllowedByPattern=allowPatterns.some(pattern=>{try{const regex=new RegExp(pattern);return regex.test(packageName)}catch{return false}});if(isAllowedByPattern){return}if(ignore.includes(packageName)){return}const shouldCheckDependency=()=>{switch(resolutionStrategy){case"workspace":return!allowedPackages.has(packageName)&&!isWorkspacePackage(packageName);case"monorepo":return!allowedPackages.has(packageName)&&!isWorkspacePackage(packageName);case"strict":default:return!allowedPackages.has(packageName)}};if(shouldCheckDependency()){const isInDevDeps=resolvedPackageJson?.devDependencies&&resolvedPackageJson.devDependencies[packageName];if(isInDevDeps&&!devDependencies){context.report({node,messageId:"devDependencyInProduction",data:{packageName,importPath,suggestion:"Move to dependencies if used in production, or ensure this code is only executed in development"},suggest:[{messageId:"moveToDependencies",fix(fixer){let parentStatement=node;while(parentStatement&&parentStatement.type!=="ImportDeclaration"&&parentStatement.type!=="VariableDeclaration"&&parentStatement.type!=="ExpressionStatement"){parentStatement=parentStatement.parent}if(parentStatement){return fixer.insertTextBefore(parentStatement,`// TODO: Move ${packageName} from devDependencies to dependencies in package.json
2
2
  `)}return fixer.insertTextBefore(node,`// TODO: Move ${packageName} from devDependencies to dependencies in package.json
3
3
  `)}}]})}else{context.report({node,messageId:"missingDependency",data:{packageName,importPath,allowedPackages:Array.from(allowedPackages).slice(0,5).join(", ")+(allowedPackages.size>5?"...":""),suggestion:`Add "${packageName}" to package.json dependencies`},suggest:[{messageId:"addToDependencies",fix(fixer){let parentStatement=node;while(parentStatement&&parentStatement.type!=="ImportDeclaration"&&parentStatement.type!=="VariableDeclaration"&&parentStatement.type!=="ExpressionStatement"){parentStatement=parentStatement.parent}if(parentStatement){return fixer.insertTextBefore(parentStatement,`// TODO: Run: npm install ${packageName}
4
4
  `)}return fixer.insertTextBefore(node,`// TODO: Run: npm install ${packageName}