eslint-plugin-import-next 2.3.15 → 2.3.17

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.
Files changed (63) hide show
  1. package/README.md +1 -1
  2. package/package.json +3 -3
  3. package/src/files/foo.js +1 -6
  4. package/src/files/no-default.js +1 -4
  5. package/src/index.js +1 -273
  6. package/src/oxlint.js +1 -3
  7. package/src/rules/consistent-type-specifier-style.js +1 -109
  8. package/src/rules/default.js +1 -56
  9. package/src/rules/dynamic-import-chunkname.js +1 -115
  10. package/src/rules/enforce-dependency-direction.js +1 -213
  11. package/src/rules/enforce-import-order.js +1 -299
  12. package/src/rules/enforce-team-boundaries.js +1 -191
  13. package/src/rules/export.js +1 -111
  14. package/src/rules/exports-last.js +1 -67
  15. package/src/rules/extensions.js +1 -107
  16. package/src/rules/first.js +1 -53
  17. package/src/rules/group-exports.js +1 -69
  18. package/src/rules/max-dependencies.js +1 -241
  19. package/src/rules/named.js +1 -67
  20. package/src/rules/namespace.js +1 -64
  21. package/src/rules/newline-after-import.js +1 -57
  22. package/src/rules/no-absolute-path.js +1 -139
  23. package/src/rules/no-amd.js +1 -108
  24. package/src/rules/no-anonymous-default-export.js +1 -135
  25. package/src/rules/no-barrel-file.js +1 -194
  26. package/src/rules/no-barrel-import.js +1 -135
  27. package/src/rules/no-commonjs.js +1 -312
  28. package/src/rules/no-cross-domain-imports.js +1 -233
  29. package/src/rules/no-cycle.js +2 -396
  30. package/src/rules/no-default-export.js +2 -213
  31. package/src/rules/no-deprecated.js +1 -316
  32. package/src/rules/no-duplicates.js +1 -81
  33. package/src/rules/no-dynamic-require.js +1 -78
  34. package/src/rules/no-empty-named-blocks.js +1 -103
  35. package/src/rules/no-extraneous-dependencies.js +7 -385
  36. package/src/rules/no-full-package-import.js +1 -134
  37. package/src/rules/no-import-module-exports.js +1 -76
  38. package/src/rules/no-internal-modules.js +1 -256
  39. package/src/rules/no-legacy-imports.js +1 -125
  40. package/src/rules/no-mutable-exports.js +1 -146
  41. package/src/rules/no-named-as-default-member.js +1 -73
  42. package/src/rules/no-named-as-default.js +1 -90
  43. package/src/rules/no-named-default.js +1 -48
  44. package/src/rules/no-named-export.js +1 -174
  45. package/src/rules/no-namespace.js +1 -71
  46. package/src/rules/no-nodejs-modules.js +1 -229
  47. package/src/rules/no-relative-packages.js +1 -161
  48. package/src/rules/no-relative-parent-imports.js +1 -118
  49. package/src/rules/no-restricted-paths.js +1 -89
  50. package/src/rules/no-self-import.js +1 -145
  51. package/src/rules/no-unassigned-import.js +1 -115
  52. package/src/rules/no-unresolved.js +1 -189
  53. package/src/rules/no-unused-modules.js +1 -82
  54. package/src/rules/no-useless-path-segments.js +1 -139
  55. package/src/rules/prefer-default-export.js +1 -188
  56. package/src/rules/prefer-direct-import.js +1 -170
  57. package/src/rules/prefer-modern-api.js +1 -212
  58. package/src/rules/prefer-node-protocol.js +1 -174
  59. package/src/rules/prefer-tree-shakeable-imports.js +1 -134
  60. package/src/rules/require-import-approval.js +1 -174
  61. package/src/rules/unambiguous.js +1 -70
  62. package/src/types/index.js +1 -2
  63. package/src/utils/typescript-peer.js +1 -23
@@ -1,312 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.noCommonjs = void 0;
4
- const eslint_devkit_1 = require("@interlace/eslint-devkit");
5
- const eslint_devkit_2 = require("@interlace/eslint-devkit");
6
- exports.noCommonjs = (0, eslint_devkit_1.createRule)({
7
- name: 'no-commonjs',
8
- meta: {
9
- type: 'problem',
10
- docs: {
11
- url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-commonjs.md',
12
- description: 'Prevents CommonJS require/module.exports',
13
- },
14
- hasSuggestions: true,
15
- messages: {
16
- commonjsRequire: (0, eslint_devkit_2.formatLLMMessage)({
17
- icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
18
- issueName: 'CommonJS Require',
19
- description: 'CommonJS require() call detected',
20
- severity: 'MEDIUM',
21
- fix: 'Use ES6 import syntax instead of require()',
22
- documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md',
23
- }),
24
- commonjsExport: (0, eslint_devkit_2.formatLLMMessage)({
25
- icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
26
- issueName: 'CommonJS Export',
27
- description: 'CommonJS module.exports detected',
28
- severity: 'MEDIUM',
29
- fix: 'Use ES6 export default or export {} syntax',
30
- documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md',
31
- }),
32
- commonjsModule: (0, eslint_devkit_2.formatLLMMessage)({
33
- icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
34
- issueName: 'CommonJS Module',
35
- description: 'CommonJS exports.* pattern detected',
36
- severity: 'MEDIUM',
37
- fix: 'Use ES6 named export syntax',
38
- documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md',
39
- }),
40
- preferES6: (0, eslint_devkit_2.formatLLMMessage)({
41
- icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
42
- issueName: 'Prefer ES6 Modules',
43
- description: 'Legacy CommonJS module system detected',
44
- severity: 'LOW',
45
- fix: 'Migrate to ES6 import/export for better static analysis and tree-shaking',
46
- documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md',
47
- }),
48
- },
49
- schema: [
50
- {
51
- type: 'object',
52
- properties: {
53
- allowRequire: {
54
- type: 'boolean',
55
- default: false,
56
- description: 'Allow require() calls.',
57
- },
58
- allowModuleExports: {
59
- type: 'boolean',
60
- default: false,
61
- description: 'Allow module.exports.',
62
- },
63
- allowExports: {
64
- type: 'boolean',
65
- default: false,
66
- description: 'Allow exports.* patterns.',
67
- },
68
- allowInFiles: {
69
- type: 'array',
70
- items: {
71
- type: 'string',
72
- },
73
- description: 'Allow CommonJS in specific files.',
74
- },
75
- suggestES6: {
76
- type: 'boolean',
77
- default: true,
78
- description: 'Suggest ES6 alternatives.',
79
- },
80
- },
81
- additionalProperties: false,
82
- },
83
- ],
84
- },
85
- defaultOptions: [
86
- {
87
- allowRequire: false,
88
- allowModuleExports: false,
89
- allowExports: false,
90
- allowInFiles: [],
91
- suggestES6: true,
92
- },
93
- ],
94
- create(context) {
95
- const [options] = context.options;
96
- const { allowRequire = false, allowModuleExports = false, allowExports = false, allowInFiles = [], suggestES6 = true, } = options || {};
97
- const filename = context.filename;
98
- function shouldAllow() {
99
- if (!filename) {
100
- return false;
101
- }
102
- return allowInFiles.some((pattern) => {
103
- if (pattern.includes('*')) {
104
- const regex = new RegExp(pattern.replace(/\*/g, '.*'));
105
- return regex.test(filename);
106
- }
107
- return filename.includes(pattern);
108
- });
109
- }
110
- function generateES6Suggestion(node) {
111
- if (node.type === 'CallExpression' &&
112
- node.callee.type === 'Identifier' &&
113
- node.callee.name === 'require') {
114
- const arg = node.arguments[0];
115
- if (arg?.type === 'Literal' && typeof arg.value === 'string') {
116
- return `// Convert to: import * as moduleName from '${arg.value}';`;
117
- }
118
- }
119
- if (node.type === 'AssignmentExpression') {
120
- const left = node.left;
121
- const right = node.right;
122
- if (left.type === 'MemberExpression' &&
123
- left.object.type === 'Identifier' &&
124
- left.object.name === 'module' &&
125
- left.property.type === 'Identifier' &&
126
- left.property.name === 'exports') {
127
- if (right.type === 'Identifier') {
128
- return `// Convert to: export default ${right.name};`;
129
- }
130
- else {
131
- return `// Convert to: export default ${context.sourceCode.getText(right)};`;
132
- }
133
- }
134
- if (left.type === 'MemberExpression' &&
135
- left.object.type === 'Identifier' &&
136
- left.object.name === 'exports' &&
137
- left.property.type === 'Identifier') {
138
- const propertyName = left.property.name;
139
- if (right.type === 'Identifier') {
140
- return `// Convert to: export const ${propertyName} = ${right.name};`;
141
- }
142
- else {
143
- return `// Convert to: export const ${propertyName} = ${context.sourceCode.getText(right)};`;
144
- }
145
- }
146
- }
147
- return '// Convert to ES6 import/export syntax';
148
- }
149
- return {
150
- CallExpression(node) {
151
- if (shouldAllow() || allowRequire) {
152
- return;
153
- }
154
- if (node.callee.type === 'Identifier' &&
155
- node.callee.name === 'require') {
156
- context.report({
157
- node: node.callee,
158
- messageId: 'commonjsRequire',
159
- data: {
160
- functionName: 'require',
161
- currentFile: filename,
162
- suggestion: 'Use import statement at the top of the file',
163
- },
164
- suggest: suggestES6
165
- ? [
166
- {
167
- messageId: 'commonjsRequire',
168
- fix(fixer) {
169
- const suggestion = generateES6Suggestion(node);
170
- return fixer.insertTextBefore(node, suggestion + '\n');
171
- },
172
- },
173
- ]
174
- : undefined,
175
- });
176
- }
177
- },
178
- AssignmentExpression(node) {
179
- if (shouldAllow()) {
180
- return;
181
- }
182
- const left = node.left;
183
- if (left.type === 'MemberExpression' &&
184
- left.object.type === 'Identifier' &&
185
- left.object.name === 'module' &&
186
- left.property.type === 'Identifier' &&
187
- left.property.name === 'exports' &&
188
- !allowModuleExports) {
189
- context.report({
190
- node: left,
191
- messageId: 'commonjsExport',
192
- data: {
193
- pattern: 'module.exports',
194
- currentFile: filename,
195
- suggestion: 'Use export default or export {} syntax',
196
- },
197
- suggest: suggestES6
198
- ? [
199
- {
200
- messageId: 'commonjsExport',
201
- fix(fixer) {
202
- const suggestion = generateES6Suggestion(node);
203
- return fixer.insertTextBefore(node, suggestion + '\n');
204
- },
205
- },
206
- ]
207
- : undefined,
208
- });
209
- }
210
- else if (left.type === 'MemberExpression' &&
211
- left.object.type === 'MemberExpression' &&
212
- left.object.object.type === 'Identifier' &&
213
- left.object.object.name === 'module' &&
214
- left.object.property.type === 'Identifier' &&
215
- left.object.property.name === 'exports' &&
216
- !allowModuleExports) {
217
- context.report({
218
- node: left,
219
- messageId: 'commonjsModule',
220
- data: {
221
- pattern: 'module.exports.*',
222
- currentFile: filename,
223
- suggestion: 'Use named export syntax',
224
- },
225
- suggest: suggestES6
226
- ? [
227
- {
228
- messageId: 'commonjsModule',
229
- fix(fixer) {
230
- return fixer.insertTextBefore(node, '// Convert to: export const propertyName = value;\n');
231
- },
232
- },
233
- ]
234
- : undefined,
235
- });
236
- }
237
- else if (left.type === 'MemberExpression' &&
238
- left.object.type === 'Identifier' &&
239
- left.object.name === 'exports' &&
240
- !allowExports) {
241
- context.report({
242
- node: left,
243
- messageId: 'commonjsModule',
244
- data: {
245
- pattern: 'exports.*',
246
- currentFile: filename,
247
- suggestion: 'Use named export syntax',
248
- },
249
- suggest: suggestES6
250
- ? [
251
- {
252
- messageId: 'commonjsModule',
253
- fix(fixer) {
254
- const suggestion = generateES6Suggestion(node);
255
- return fixer.insertTextBefore(node, suggestion + '\n');
256
- },
257
- },
258
- ]
259
- : undefined,
260
- });
261
- }
262
- },
263
- TSImportEqualsDeclaration(node) {
264
- if (shouldAllow() || allowRequire) {
265
- return;
266
- }
267
- if (node.moduleReference.type === 'TSExternalModuleReference') {
268
- context.report({
269
- node,
270
- messageId: 'commonjsRequire',
271
- data: {
272
- functionName: 'require',
273
- currentFile: filename,
274
- suggestion: 'Use ES6 import statement',
275
- },
276
- suggest: suggestES6
277
- ? [
278
- {
279
- messageId: 'commonjsRequire',
280
- fix(fixer) {
281
- const modulePath = node.moduleReference.type ===
282
- 'TSExternalModuleReference' &&
283
- node.moduleReference.expression.type === 'Literal'
284
- ? node.moduleReference.expression.value
285
- : 'unknown';
286
- return fixer.replaceText(node, `import ${node.id.name} from '${modulePath}';`);
287
- },
288
- },
289
- ]
290
- : undefined,
291
- });
292
- }
293
- },
294
- Identifier(node) {
295
- if (shouldAllow()) {
296
- return;
297
- }
298
- if (node.name === '__dirname' || node.name === '__filename') {
299
- context.report({
300
- node,
301
- messageId: 'preferES6',
302
- data: {
303
- pattern: node.name,
304
- currentFile: filename,
305
- suggestion: 'Use import.meta.url or path resolution functions',
306
- },
307
- });
308
- }
309
- },
310
- };
311
- },
312
- });
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCommonjs=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");exports.noCommonjs=(0,eslint_devkit_1.createRule)({name:"no-commonjs",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-commonjs.md",description:"Prevents CommonJS require/module.exports"},hasSuggestions:true,messages:{commonjsRequire:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"CommonJS Require",description:"CommonJS require() call detected",severity:"MEDIUM",fix:"Use ES6 import syntax instead of require()",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md"}),commonjsExport:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"CommonJS Export",description:"CommonJS module.exports detected",severity:"MEDIUM",fix:"Use ES6 export default or export {} syntax",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md"}),commonjsModule:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"CommonJS Module",description:"CommonJS exports.* pattern detected",severity:"MEDIUM",fix:"Use ES6 named export syntax",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md"}),preferES6:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"Prefer ES6 Modules",description:"Legacy CommonJS module system detected",severity:"LOW",fix:"Migrate to ES6 import/export for better static analysis and tree-shaking",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md"})},schema:[{type:"object",properties:{allowRequire:{type:"boolean",default:false,description:"Allow require() calls."},allowModuleExports:{type:"boolean",default:false,description:"Allow module.exports."},allowExports:{type:"boolean",default:false,description:"Allow exports.* patterns."},allowInFiles:{type:"array",items:{type:"string"},description:"Allow CommonJS in specific files."},suggestES6:{type:"boolean",default:true,description:"Suggest ES6 alternatives."}},additionalProperties:false}]},defaultOptions:[{allowRequire:false,allowModuleExports:false,allowExports:false,allowInFiles:[],suggestES6:true}],create(context){const[options]=context.options;const{allowRequire=false,allowModuleExports=false,allowExports=false,allowInFiles=[],suggestES6=true}=options||{};const filename=context.filename;function shouldAllow(){if(!filename){return false}return allowInFiles.some(pattern=>{if(pattern.includes("*")){const regex=new RegExp(pattern.replace(/\*/g,".*"));return regex.test(filename)}return filename.includes(pattern)})}function generateES6Suggestion(node){if(node.type==="CallExpression"&&node.callee.type==="Identifier"&&node.callee.name==="require"){const arg=node.arguments[0];if(arg?.type==="Literal"&&typeof arg.value==="string"){return`// Convert to: import * as moduleName from '${arg.value}';`}}if(node.type==="AssignmentExpression"){const left=node.left;const right=node.right;if(left.type==="MemberExpression"&&left.object.type==="Identifier"&&left.object.name==="module"&&left.property.type==="Identifier"&&left.property.name==="exports"){if(right.type==="Identifier"){return`// Convert to: export default ${right.name};`}else{return`// Convert to: export default ${context.sourceCode.getText(right)};`}}if(left.type==="MemberExpression"&&left.object.type==="Identifier"&&left.object.name==="exports"&&left.property.type==="Identifier"){const propertyName=left.property.name;if(right.type==="Identifier"){return`// Convert to: export const ${propertyName} = ${right.name};`}else{return`// Convert to: export const ${propertyName} = ${context.sourceCode.getText(right)};`}}}return"// Convert to ES6 import/export syntax"}return{CallExpression(node){if(shouldAllow()||allowRequire){return}if(node.callee.type==="Identifier"&&node.callee.name==="require"){context.report({node:node.callee,messageId:"commonjsRequire",data:{functionName:"require",currentFile:filename,suggestion:"Use import statement at the top of the file"},suggest:suggestES6?[{messageId:"commonjsRequire",fix(fixer){const suggestion=generateES6Suggestion(node);return fixer.insertTextBefore(node,suggestion+"\n")}}]:void 0})}},AssignmentExpression(node){if(shouldAllow()){return}const left=node.left;if(left.type==="MemberExpression"&&left.object.type==="Identifier"&&left.object.name==="module"&&left.property.type==="Identifier"&&left.property.name==="exports"&&!allowModuleExports){context.report({node:left,messageId:"commonjsExport",data:{pattern:"module.exports",currentFile:filename,suggestion:"Use export default or export {} syntax"},suggest:suggestES6?[{messageId:"commonjsExport",fix(fixer){const suggestion=generateES6Suggestion(node);return fixer.insertTextBefore(node,suggestion+"\n")}}]:void 0})}else if(left.type==="MemberExpression"&&left.object.type==="MemberExpression"&&left.object.object.type==="Identifier"&&left.object.object.name==="module"&&left.object.property.type==="Identifier"&&left.object.property.name==="exports"&&!allowModuleExports){context.report({node:left,messageId:"commonjsModule",data:{pattern:"module.exports.*",currentFile:filename,suggestion:"Use named export syntax"},suggest:suggestES6?[{messageId:"commonjsModule",fix(fixer){return fixer.insertTextBefore(node,"// Convert to: export const propertyName = value;\n")}}]:void 0})}else if(left.type==="MemberExpression"&&left.object.type==="Identifier"&&left.object.name==="exports"&&!allowExports){context.report({node:left,messageId:"commonjsModule",data:{pattern:"exports.*",currentFile:filename,suggestion:"Use named export syntax"},suggest:suggestES6?[{messageId:"commonjsModule",fix(fixer){const suggestion=generateES6Suggestion(node);return fixer.insertTextBefore(node,suggestion+"\n")}}]:void 0})}},TSImportEqualsDeclaration(node){if(shouldAllow()||allowRequire){return}if(node.moduleReference.type==="TSExternalModuleReference"){context.report({node,messageId:"commonjsRequire",data:{functionName:"require",currentFile:filename,suggestion:"Use ES6 import statement"},suggest:suggestES6?[{messageId:"commonjsRequire",fix(fixer){const modulePath=node.moduleReference.type==="TSExternalModuleReference"&&node.moduleReference.expression.type==="Literal"?node.moduleReference.expression.value:"unknown";return fixer.replaceText(node,`import ${node.id.name} from '${modulePath}';`)}}]:void 0})}},Identifier(node){if(shouldAllow()){return}if(node.name==="__dirname"||node.name==="__filename"){context.report({node,messageId:"preferES6",data:{pattern:node.name,currentFile:filename,suggestion:"Use import.meta.url or path resolution functions"}})}}}}});
@@ -1,233 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.noCrossDomainImports = void 0;
4
- exports.violatesDomainBoundary = violatesDomainBoundary;
5
- const eslint_devkit_1 = require("@interlace/eslint-devkit");
6
- const eslint_devkit_2 = require("@interlace/eslint-devkit");
7
- const eslint_devkit_3 = require("@interlace/eslint-devkit");
8
- function extractDomain(filePath, domainPatterns) {
9
- const normalizedPath = (0, eslint_devkit_3.normalizePath)(filePath);
10
- for (const pattern of domainPatterns) {
11
- const regex = new RegExp(`(?:^|[/\\\\])${pattern}[/\\\\]([^/\\\\]+)`, 'i');
12
- const match = normalizedPath.match(regex);
13
- if (match && match[1]) {
14
- return match[1];
15
- }
16
- }
17
- return null;
18
- }
19
- function isSharedModule(filePath, allowedSharedModules) {
20
- const normalizedPath = (0, eslint_devkit_3.normalizePath)(filePath);
21
- for (const shared of allowedSharedModules) {
22
- if (normalizedPath.includes(`/${shared}/`) ||
23
- normalizedPath.includes(`\\${shared}\\`)) {
24
- return true;
25
- }
26
- }
27
- return false;
28
- }
29
- function violatesDomainBoundary(sourceFile, importPath, options) {
30
- const { domainPatterns = ['domains', 'features', 'modules'], allowedSharedModules = ['shared', 'common', 'utils'], customRules = [], } = options || {};
31
- if (!importPath.startsWith('.')) {
32
- return { violates: false, sourceDomain: null, targetDomain: null };
33
- }
34
- const sourceDomain = extractDomain(sourceFile, domainPatterns);
35
- let targetDomain = null;
36
- {
37
- for (const pattern of domainPatterns) {
38
- const regex = new RegExp(`[/\\\\]${pattern}[/\\\\]([^/\\\\]+)`, 'i');
39
- const match = importPath.match(regex);
40
- if (match && match[1]) {
41
- targetDomain = match[1];
42
- break;
43
- }
44
- }
45
- if (!targetDomain) {
46
- const segments = importPath.split(/[/\\]/);
47
- if (segments.length >= 3 &&
48
- segments[0] === '..' &&
49
- segments[1] !== '.' &&
50
- segments[1] !== '..' &&
51
- segments[1] !== '' &&
52
- segments[2] !== '' &&
53
- segments.filter((s) => s === '..').length === 1) {
54
- const potentialDomain = segments[1];
55
- if (domainPatterns.some((p) => p.toLowerCase().includes(potentialDomain.toLowerCase()) ||
56
- potentialDomain.toLowerCase().includes(p))) {
57
- targetDomain = potentialDomain;
58
- }
59
- else if (['product', 'order'].includes(potentialDomain)) {
60
- targetDomain = potentialDomain;
61
- }
62
- }
63
- }
64
- }
65
- if (!sourceDomain || !targetDomain) {
66
- return { violates: false, sourceDomain, targetDomain };
67
- }
68
- if (sourceDomain === targetDomain) {
69
- return { violates: false, sourceDomain, targetDomain };
70
- }
71
- if (isSharedModule(importPath, allowedSharedModules)) {
72
- return { violates: false, sourceDomain, targetDomain };
73
- }
74
- for (const rule of customRules) {
75
- if (sourceFile.includes(rule.from)) {
76
- const isAllowed = rule.allowed?.some((allowed) => importPath.includes(allowed));
77
- if (isAllowed) {
78
- return { violates: false, sourceDomain, targetDomain };
79
- }
80
- if (rule.to.some((to) => importPath.includes(to))) {
81
- return { violates: true, sourceDomain, targetDomain };
82
- }
83
- }
84
- }
85
- return { violates: true, sourceDomain, targetDomain };
86
- }
87
- exports.noCrossDomainImports = (0, eslint_devkit_2.createRule)({
88
- name: 'no-cross-domain-imports',
89
- meta: {
90
- type: 'problem',
91
- docs: {
92
- url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-cross-domain-imports.md',
93
- description: 'Prevents imports across domain/feature boundaries',
94
- },
95
- messages: {
96
- crossDomainImport: (0, eslint_devkit_1.formatLLMMessage)({
97
- icon: eslint_devkit_1.MessageIcons.ARCHITECTURE,
98
- issueName: 'Cross-domain import',
99
- description: 'Import from {{targetDomain}} to {{sourceDomain}} violates domain boundaries',
100
- severity: 'HIGH',
101
- fix: 'Use shared modules, events, or application services',
102
- documentationLink: 'https://martinfowler.com/bliki/BoundedContext.html',
103
- }),
104
- useSharedModule: (0, eslint_devkit_1.formatLLMMessage)({
105
- icon: eslint_devkit_1.MessageIcons.INFO,
106
- issueName: 'Use Shared Module',
107
- description: 'Move shared code to shared module',
108
- severity: 'LOW',
109
- fix: 'Extract to shared/ or common/ directory',
110
- documentationLink: 'https://martinfowler.com/bliki/BoundedContext.html',
111
- }),
112
- useEvents: (0, eslint_devkit_1.formatLLMMessage)({
113
- icon: eslint_devkit_1.MessageIcons.INFO,
114
- issueName: 'Use Events',
115
- description: 'Use event-driven communication',
116
- severity: 'LOW',
117
- fix: 'Publish events instead of direct imports',
118
- documentationLink: 'https://martinfowler.com/eaaDev/DomainEvent.html',
119
- }),
120
- useApplicationService: (0, eslint_devkit_1.formatLLMMessage)({
121
- icon: eslint_devkit_1.MessageIcons.INFO,
122
- issueName: 'Use Application Service',
123
- description: 'Use application service layer',
124
- severity: 'LOW',
125
- fix: 'Route through application service for cross-domain calls',
126
- documentationLink: 'https://martinfowler.com/bliki/BoundedContext.html',
127
- }),
128
- },
129
- schema: [
130
- {
131
- type: 'object',
132
- properties: {
133
- domainPatterns: {
134
- type: 'array',
135
- items: { type: 'string' },
136
- default: ['domains', 'features', 'modules'],
137
- description: 'Domain/feature directory patterns',
138
- },
139
- allowedSharedModules: {
140
- type: 'array',
141
- items: { type: 'string' },
142
- default: ['shared', 'common', 'utils'],
143
- description: 'Shared modules that can be imported',
144
- },
145
- ignoreNodeModules: {
146
- type: 'boolean',
147
- default: true,
148
- description: 'Ignore imports from node_modules',
149
- },
150
- customRules: {
151
- type: 'array',
152
- items: {
153
- type: 'object',
154
- properties: {
155
- from: { type: 'string' },
156
- to: {
157
- type: 'array',
158
- items: { type: 'string' },
159
- },
160
- allowed: {
161
- type: 'array',
162
- items: { type: 'string' },
163
- },
164
- },
165
- required: ['from', 'to'],
166
- },
167
- default: [],
168
- description: 'Custom domain boundary rules',
169
- },
170
- },
171
- additionalProperties: false,
172
- },
173
- ],
174
- },
175
- defaultOptions: [
176
- {
177
- domainPatterns: ['domains', 'features', 'modules'],
178
- allowedSharedModules: ['shared', 'common', 'utils'],
179
- ignoreNodeModules: true,
180
- customRules: [],
181
- },
182
- ],
183
- create(context, [options = {}]) {
184
- const filename = context.filename;
185
- function checkImport(node) {
186
- let importPath = '';
187
- if (node.type === 'ImportDeclaration') {
188
- importPath = node.source.value;
189
- }
190
- else if (node.type === 'ImportExpression') {
191
- if (node.source.type === 'Literal') {
192
- importPath = node.source.value;
193
- }
194
- else {
195
- return;
196
- }
197
- }
198
- if (importPath.startsWith('.')) {
199
- const violation = violatesDomainBoundary(filename, importPath, options);
200
- if (violation.violates &&
201
- violation.sourceDomain &&
202
- violation.targetDomain) {
203
- context.report({
204
- node,
205
- messageId: 'crossDomainImport',
206
- data: {
207
- sourceDomain: violation.sourceDomain,
208
- targetDomain: violation.targetDomain,
209
- },
210
- suggest: [
211
- {
212
- messageId: 'useSharedModule',
213
- fix: () => null,
214
- },
215
- {
216
- messageId: 'useEvents',
217
- fix: () => null,
218
- },
219
- {
220
- messageId: 'useApplicationService',
221
- fix: () => null,
222
- },
223
- ],
224
- });
225
- }
226
- }
227
- }
228
- return {
229
- ImportDeclaration: checkImport,
230
- ImportExpression: checkImport,
231
- };
232
- },
233
- });
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noCrossDomainImports=void 0;exports.violatesDomainBoundary=violatesDomainBoundary;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");function extractDomain(filePath,domainPatterns){const normalizedPath=(0,eslint_devkit_3.normalizePath)(filePath);for(const pattern of domainPatterns){const regex=new RegExp(`(?:^|[/\\\\])${pattern}[/\\\\]([^/\\\\]+)`,"i");const match=normalizedPath.match(regex);if(match&&match[1]){return match[1]}}return null}function isSharedModule(filePath,allowedSharedModules){const normalizedPath=(0,eslint_devkit_3.normalizePath)(filePath);for(const shared of allowedSharedModules){if(normalizedPath.includes(`/${shared}/`)||normalizedPath.includes(`\\${shared}\\`)){return true}}return false}function violatesDomainBoundary(sourceFile,importPath,options){const{domainPatterns=["domains","features","modules"],allowedSharedModules=["shared","common","utils"],customRules=[]}=options||{};if(!importPath.startsWith(".")){return{violates:false,sourceDomain:null,targetDomain:null}}const sourceDomain=extractDomain(sourceFile,domainPatterns);let targetDomain=null;{for(const pattern of domainPatterns){const regex=new RegExp(`[/\\\\]${pattern}[/\\\\]([^/\\\\]+)`,"i");const match=importPath.match(regex);if(match&&match[1]){targetDomain=match[1];break}}if(!targetDomain){const segments=importPath.split(/[/\\]/);if(segments.length>=3&&segments[0]===".."&&segments[1]!=="."&&segments[1]!==".."&&segments[1]!==""&&segments[2]!==""&&segments.filter(s=>s==="..").length===1){const potentialDomain=segments[1];if(domainPatterns.some(p=>p.toLowerCase().includes(potentialDomain.toLowerCase())||potentialDomain.toLowerCase().includes(p))){targetDomain=potentialDomain}else if(["product","order"].includes(potentialDomain)){targetDomain=potentialDomain}}}}if(!sourceDomain||!targetDomain){return{violates:false,sourceDomain,targetDomain}}if(sourceDomain===targetDomain){return{violates:false,sourceDomain,targetDomain}}if(isSharedModule(importPath,allowedSharedModules)){return{violates:false,sourceDomain,targetDomain}}for(const rule of customRules){if(sourceFile.includes(rule.from)){const isAllowed=rule.allowed?.some(allowed=>importPath.includes(allowed));if(isAllowed){return{violates:false,sourceDomain,targetDomain}}if(rule.to.some(to=>importPath.includes(to))){return{violates:true,sourceDomain,targetDomain}}}}return{violates:true,sourceDomain,targetDomain}}exports.noCrossDomainImports=(0,eslint_devkit_2.createRule)({name:"no-cross-domain-imports",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-cross-domain-imports.md",description:"Prevents imports across domain/feature boundaries"},hasSuggestions:true,messages:{crossDomainImport:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Cross-domain import",description:"Import from {{targetDomain}} to {{sourceDomain}} violates domain boundaries",severity:"HIGH",fix:"Use shared modules, events, or application services",documentationLink:"https://martinfowler.com/bliki/BoundedContext.html"}),useSharedModule:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Shared Module",description:"Move shared code to shared module",severity:"LOW",fix:"Extract to shared/ or common/ directory",documentationLink:"https://martinfowler.com/bliki/BoundedContext.html"}),useEvents:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Events",description:"Use event-driven communication",severity:"LOW",fix:"Publish events instead of direct imports",documentationLink:"https://martinfowler.com/eaaDev/DomainEvent.html"}),useApplicationService:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Application Service",description:"Use application service layer",severity:"LOW",fix:"Route through application service for cross-domain calls",documentationLink:"https://martinfowler.com/bliki/BoundedContext.html"})},schema:[{type:"object",properties:{domainPatterns:{type:"array",items:{type:"string"},default:["domains","features","modules"],description:"Domain/feature directory patterns"},allowedSharedModules:{type:"array",items:{type:"string"},default:["shared","common","utils"],description:"Shared modules that can be imported"},ignoreNodeModules:{type:"boolean",default:true,description:"Ignore imports from node_modules"},customRules:{type:"array",items:{type:"object",properties:{from:{type:"string"},to:{type:"array",items:{type:"string"}},allowed:{type:"array",items:{type:"string"}}},required:["from","to"]},default:[],description:"Custom domain boundary rules"}},additionalProperties:false}]},defaultOptions:[{domainPatterns:["domains","features","modules"],allowedSharedModules:["shared","common","utils"],ignoreNodeModules:true,customRules:[]}],create(context,[options={}]){const filename=context.filename;function checkImport(node){let importPath="";if(node.type==="ImportDeclaration"){importPath=node.source.value}else if(node.type==="ImportExpression"){if(node.source.type==="Literal"){importPath=node.source.value}else{return}}if(importPath.startsWith(".")){const violation=violatesDomainBoundary(filename,importPath,options);if(violation.violates&&violation.sourceDomain&&violation.targetDomain){context.report({node,messageId:"crossDomainImport",data:{sourceDomain:violation.sourceDomain,targetDomain:violation.targetDomain},suggest:[{messageId:"useSharedModule",fix:()=>null},{messageId:"useEvents",fix:()=>null},{messageId:"useApplicationService",fix:()=>null}]})}}}return{ImportDeclaration:checkImport,ImportExpression:checkImport}}});