eslint-plugin-import-next 2.3.9 → 2.3.11
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/README.md +47 -0
- package/package.json +16 -12
- package/src/files/foo.js +0 -5
- package/src/files/no-default.js +0 -5
- package/src/index.d.ts +15 -2812
- package/src/index.js +5 -147
- package/src/oxlint.d.ts +17 -20
- package/src/oxlint.js +0 -18
- package/src/rules/consistent-type-specifier-style.js +0 -19
- package/src/rules/default.js +0 -7
- package/src/rules/dynamic-import-chunkname.js +0 -8
- package/src/rules/enforce-dependency-direction.js +2 -39
- package/src/rules/enforce-import-order.js +3 -33
- package/src/rules/enforce-team-boundaries.js +0 -49
- package/src/rules/export.js +0 -9
- package/src/rules/exports-last.js +0 -10
- package/src/rules/extensions.js +2 -11
- package/src/rules/first.js +0 -6
- package/src/rules/group-exports.js +0 -13
- package/src/rules/max-dependencies.js +0 -16
- package/src/rules/named.js +1 -10
- package/src/rules/namespace.js +1 -11
- package/src/rules/newline-after-import.js +2 -13
- package/src/rules/no-absolute-path.js +0 -7
- package/src/rules/no-amd.js +1 -18
- package/src/rules/no-anonymous-default-export.js +0 -13
- package/src/rules/no-barrel-file.js +0 -32
- package/src/rules/no-barrel-import.js +0 -25
- package/src/rules/no-commonjs.js +0 -18
- package/src/rules/no-cross-domain-imports.js +2 -47
- package/src/rules/no-cycle.js +2 -135
- package/src/rules/no-default-export.js +0 -28
- package/src/rules/no-deprecated.js +0 -32
- package/src/rules/no-duplicates.js +2 -10
- package/src/rules/no-dynamic-require.js +0 -6
- package/src/rules/no-empty-named-blocks.js +1 -17
- package/src/rules/no-extraneous-dependencies.js +0 -38
- package/src/rules/no-full-package-import.js +0 -19
- package/src/rules/no-import-module-exports.js +0 -8
- package/src/rules/no-internal-modules.js +0 -40
- package/src/rules/no-legacy-imports.js +1 -11
- package/src/rules/no-mutable-exports.js +0 -14
- package/src/rules/no-named-as-default-member.js +0 -11
- package/src/rules/no-named-as-default.js +0 -17
- package/src/rules/no-named-default.js +0 -5
- package/src/rules/no-named-export.js +1 -22
- package/src/rules/no-namespace.js +0 -10
- package/src/rules/no-nodejs-modules.js +0 -15
- package/src/rules/no-relative-packages.js +0 -15
- package/src/rules/no-relative-parent-imports.js +0 -11
- package/src/rules/no-restricted-paths.js +0 -6
- package/src/rules/no-self-import.js +0 -22
- package/src/rules/no-unassigned-import.js +0 -14
- package/src/rules/no-unresolved.js +0 -16
- package/src/rules/no-unused-modules.js +0 -7
- package/src/rules/no-useless-path-segments.js +0 -15
- package/src/rules/prefer-default-export.js +0 -18
- package/src/rules/prefer-direct-import.js +1 -21
- package/src/rules/prefer-modern-api.js +0 -21
- package/src/rules/prefer-node-protocol.js +0 -15
- package/src/rules/prefer-tree-shakeable-imports.js +0 -14
- package/src/rules/require-import-approval.js +0 -21
- package/src/rules/unambiguous.js +0 -11
- package/src/types/index.js +0 -5
- package/AGENTS.md +0 -95
- package/CHANGELOG.md +0 -170
- package/src/files/foo.d.ts +0 -7
- package/src/files/no-default.d.ts +0 -6
- package/src/rules/consistent-type-specifier-style.d.ts +0 -13
- package/src/rules/default.d.ts +0 -9
- package/src/rules/dynamic-import-chunkname.d.ts +0 -26
- package/src/rules/enforce-dependency-direction.d.ts +0 -27
- package/src/rules/enforce-import-order.d.ts +0 -29
- package/src/rules/enforce-team-boundaries.d.ts +0 -47
- package/src/rules/export.d.ts +0 -17
- package/src/rules/exports-last.d.ts +0 -15
- package/src/rules/extensions.d.ts +0 -17
- package/src/rules/first.d.ts +0 -13
- package/src/rules/group-exports.d.ts +0 -15
- package/src/rules/max-dependencies.d.ts +0 -26
- package/src/rules/named.d.ts +0 -13
- package/src/rules/namespace.d.ts +0 -13
- package/src/rules/newline-after-import.d.ts +0 -13
- package/src/rules/no-absolute-path.d.ts +0 -25
- package/src/rules/no-amd.d.ts +0 -21
- package/src/rules/no-anonymous-default-export.d.ts +0 -24
- package/src/rules/no-barrel-file.d.ts +0 -55
- package/src/rules/no-barrel-import.d.ts +0 -48
- package/src/rules/no-commonjs.d.ts +0 -28
- package/src/rules/no-cross-domain-imports.d.ts +0 -41
- package/src/rules/no-cycle.d.ts +0 -102
- package/src/rules/no-default-export.d.ts +0 -24
- package/src/rules/no-deprecated.d.ts +0 -26
- package/src/rules/no-duplicates.d.ts +0 -13
- package/src/rules/no-dynamic-require.d.ts +0 -22
- package/src/rules/no-empty-named-blocks.d.ts +0 -17
- package/src/rules/no-extraneous-dependencies.d.ts +0 -45
- package/src/rules/no-full-package-import.d.ts +0 -42
- package/src/rules/no-import-module-exports.d.ts +0 -21
- package/src/rules/no-internal-modules.d.ts +0 -28
- package/src/rules/no-legacy-imports.d.ts +0 -47
- package/src/rules/no-mutable-exports.d.ts +0 -22
- package/src/rules/no-named-as-default-member.d.ts +0 -15
- package/src/rules/no-named-as-default.d.ts +0 -15
- package/src/rules/no-named-default.d.ts +0 -15
- package/src/rules/no-named-export.d.ts +0 -26
- package/src/rules/no-namespace.d.ts +0 -21
- package/src/rules/no-nodejs-modules.d.ts +0 -24
- package/src/rules/no-relative-packages.d.ts +0 -21
- package/src/rules/no-relative-parent-imports.d.ts +0 -22
- package/src/rules/no-restricted-paths.d.ts +0 -20
- package/src/rules/no-self-import.d.ts +0 -15
- package/src/rules/no-unassigned-import.d.ts +0 -20
- package/src/rules/no-unresolved.d.ts +0 -20
- package/src/rules/no-unused-modules.d.ts +0 -19
- package/src/rules/no-useless-path-segments.d.ts +0 -23
- package/src/rules/prefer-default-export.d.ts +0 -24
- package/src/rules/prefer-direct-import.d.ts +0 -51
- package/src/rules/prefer-modern-api.d.ts +0 -47
- package/src/rules/prefer-node-protocol.d.ts +0 -19
- package/src/rules/prefer-tree-shakeable-imports.d.ts +0 -49
- package/src/rules/require-import-approval.d.ts +0 -52
- package/src/rules/unambiguous.d.ts +0 -15
package/src/rules/named.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.named = void 0;
|
|
9
4
|
const tslib_1 = require("tslib");
|
|
@@ -20,7 +15,7 @@ exports.named = (0, eslint_devkit_1.createRule)({
|
|
|
20
15
|
},
|
|
21
16
|
messages: {
|
|
22
17
|
named: (0, eslint_devkit_2.formatLLMMessage)({
|
|
23
|
-
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
18
|
+
icon: eslint_devkit_2.MessageIcons.SECURITY,
|
|
24
19
|
issueName: 'Missing Named Export',
|
|
25
20
|
description: 'Named export not found in module',
|
|
26
21
|
severity: 'HIGH',
|
|
@@ -43,22 +38,18 @@ exports.named = (0, eslint_devkit_1.createRule)({
|
|
|
43
38
|
return;
|
|
44
39
|
const tsNode = services.esTreeNodeToTSNodeMap.get(node.imported);
|
|
45
40
|
let symbol = checker?.getSymbolAtLocation?.(tsNode);
|
|
46
|
-
// Resolve alias if needed
|
|
47
41
|
if (symbol && (symbol.flags & typescript_1.default.SymbolFlags.Alias)) {
|
|
48
42
|
try {
|
|
49
43
|
symbol = checker?.getAliasedSymbol?.(symbol);
|
|
50
44
|
}
|
|
51
45
|
catch {
|
|
52
|
-
// If resolving alias fails, symbol implies broken import
|
|
53
46
|
symbol = undefined;
|
|
54
47
|
}
|
|
55
48
|
}
|
|
56
|
-
// Check if symbol is "unknown" or broken
|
|
57
49
|
if (symbol && symbol.escapedName === 'unknown') {
|
|
58
50
|
symbol = undefined;
|
|
59
51
|
}
|
|
60
52
|
if (!symbol) {
|
|
61
|
-
// Check if module itself resolves
|
|
62
53
|
const source = node.parent.source;
|
|
63
54
|
if (!source)
|
|
64
55
|
return;
|
package/src/rules/namespace.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.namespace = void 0;
|
|
9
4
|
const tslib_1 = require("tslib");
|
|
@@ -38,7 +33,6 @@ exports.namespace = (0, eslint_devkit_1.createRule)({
|
|
|
38
33
|
const checker = services.program?.getTypeChecker?.();
|
|
39
34
|
return {
|
|
40
35
|
MemberExpression(node) {
|
|
41
|
-
// Check if object is a namespace import
|
|
42
36
|
const object = node.object;
|
|
43
37
|
if (object.type !== 'Identifier')
|
|
44
38
|
return;
|
|
@@ -47,17 +41,13 @@ exports.namespace = (0, eslint_devkit_1.createRule)({
|
|
|
47
41
|
if (symbol && symbol.declarations && symbol.declarations.length > 0) {
|
|
48
42
|
const declaration = symbol.declarations[0];
|
|
49
43
|
if (declaration.kind === typescript_1.default.SyntaxKind.NamespaceImport) {
|
|
50
|
-
// If we have a namespace import, the symbol should refer to the module.
|
|
51
|
-
// We need to check if the property being accessed exists on the module exports.
|
|
52
44
|
if (node.property.type !== 'Identifier')
|
|
53
|
-
return;
|
|
45
|
+
return;
|
|
54
46
|
const propertyName = node.property.name;
|
|
55
|
-
// This is a bit simplified; we really need to check the type of the symbol
|
|
56
47
|
const type = checker?.getTypeAtLocation?.(tsNode);
|
|
57
48
|
if (!type)
|
|
58
49
|
return;
|
|
59
50
|
const propertySymbol = checker?.getPropertyOfType?.(type, propertyName);
|
|
60
|
-
// Removed erroneous early return here
|
|
61
51
|
if (!propertySymbol) {
|
|
62
52
|
context.report({
|
|
63
53
|
node: node.property,
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.newlineAfterImport = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -36,13 +31,8 @@ exports.newlineAfterImport = (0, eslint_devkit_1.createRule)({
|
|
|
36
31
|
const sourceCode = context.sourceCode;
|
|
37
32
|
const nextToken = sourceCode.getTokenAfter(node);
|
|
38
33
|
if (!nextToken)
|
|
39
|
-
return;
|
|
40
|
-
// If the next token is on the same line, it's an error (unless it's a comment, but usually imports are on own line)
|
|
34
|
+
return;
|
|
41
35
|
if (nextToken.loc.start.line === node.loc.end.line) {
|
|
42
|
-
// Maybe it's fine if it's another import?
|
|
43
|
-
// Wait, logic is: after the *last* import in a block or any import?
|
|
44
|
-
// "Enforce a newline after import statements" usually means after the *group* of imports.
|
|
45
|
-
// But checking every import: if next node is NOT an import, there should be a blank line.
|
|
46
36
|
}
|
|
47
37
|
const nextNode = sourceCode.getNodeByRangeIndex(nextToken.range[0]);
|
|
48
38
|
if (nextNode &&
|
|
@@ -50,14 +40,13 @@ exports.newlineAfterImport = (0, eslint_devkit_1.createRule)({
|
|
|
50
40
|
nextNode.type === 'TSImportEqualsDeclaration')) {
|
|
51
41
|
return;
|
|
52
42
|
}
|
|
53
|
-
// Check lines between
|
|
54
43
|
if (nextToken.loc.start.line - node.loc.end.line < 2) {
|
|
55
44
|
context.report({
|
|
56
45
|
node,
|
|
57
46
|
messageId: 'newlineAfterImport',
|
|
58
47
|
fix(fixer) {
|
|
59
48
|
const linesBetween = nextToken.loc.start.line - node.loc.end.line;
|
|
60
|
-
const newlinesToAdd = 2 - linesBetween;
|
|
49
|
+
const newlinesToAdd = 2 - linesBetween;
|
|
61
50
|
return fixer.insertTextAfter(node, '\n'.repeat(newlinesToAdd));
|
|
62
51
|
},
|
|
63
52
|
});
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noAbsolutePath = void 0;
|
|
9
4
|
const tslib_1 = require("tslib");
|
|
@@ -93,14 +88,12 @@ exports.noAbsolutePath = (0, eslint_devkit_1.createRule)({
|
|
|
93
88
|
if (node.callee.type !== 'Identifier')
|
|
94
89
|
return;
|
|
95
90
|
const calleeName = node.callee.name;
|
|
96
|
-
// CommonJS require
|
|
97
91
|
if (commonjs &&
|
|
98
92
|
calleeName === 'require' &&
|
|
99
93
|
node.arguments.length === 1 &&
|
|
100
94
|
node.arguments[0].type === 'Literal') {
|
|
101
95
|
checkImport(node, node.arguments[0]);
|
|
102
96
|
}
|
|
103
|
-
// AMD define/require
|
|
104
97
|
if (amd && (calleeName === 'define' || calleeName === 'require')) {
|
|
105
98
|
node.arguments.forEach((arg) => {
|
|
106
99
|
if (arg.type === 'Literal') {
|
package/src/rules/no-amd.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noAmd = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -56,35 +51,27 @@ exports.noAmd = (0, eslint_devkit_1.createRule)({
|
|
|
56
51
|
],
|
|
57
52
|
create(context) {
|
|
58
53
|
const [options] = context.options;
|
|
59
|
-
const { allow = [],
|
|
60
|
-
// suggestES6 = true // Reserved for future use when hasSuggestions is enabled
|
|
61
|
-
} = options || {};
|
|
54
|
+
const { allow = [], } = options || {};
|
|
62
55
|
const filename = context.filename;
|
|
63
56
|
function shouldAllow() {
|
|
64
|
-
// Check if the call is in an allowed pattern
|
|
65
57
|
return allow.some((pattern) => {
|
|
66
58
|
if (!filename)
|
|
67
59
|
return false;
|
|
68
|
-
// Support glob patterns like **/legacy/**
|
|
69
60
|
if (pattern.includes('**')) {
|
|
70
|
-
// Simple glob matching: ** matches any path segment, * matches any name segment
|
|
71
61
|
const regexPattern = pattern
|
|
72
62
|
.replace(/\*\*/g, '.*')
|
|
73
63
|
.replace(/\*/g, '[^/]*');
|
|
74
64
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
75
65
|
return regex.test(filename);
|
|
76
66
|
}
|
|
77
|
-
// Simple string matching for non-glob patterns
|
|
78
67
|
return filename.includes(pattern);
|
|
79
68
|
});
|
|
80
69
|
}
|
|
81
|
-
// Note: ES6 suggestion generation could be added here when hasSuggestions is enabled
|
|
82
70
|
return {
|
|
83
71
|
CallExpression(node) {
|
|
84
72
|
if (shouldAllow()) {
|
|
85
73
|
return;
|
|
86
74
|
}
|
|
87
|
-
// Check for define() calls
|
|
88
75
|
if (node.callee.type === 'Identifier' &&
|
|
89
76
|
node.callee.name === 'define') {
|
|
90
77
|
context.report({
|
|
@@ -97,16 +84,12 @@ exports.noAmd = (0, eslint_devkit_1.createRule)({
|
|
|
97
84
|
},
|
|
98
85
|
});
|
|
99
86
|
}
|
|
100
|
-
// Check for AMD-style require() calls (not CommonJS)
|
|
101
87
|
else if (node.callee.type === 'Identifier' &&
|
|
102
88
|
node.callee.name === 'require' &&
|
|
103
89
|
node.arguments.length > 0) {
|
|
104
90
|
const firstArg = node.arguments[0];
|
|
105
|
-
// AMD require typically has a callback function as second argument
|
|
106
|
-
// or is part of a define() call
|
|
107
91
|
const hasCallback = node.arguments.length > 1 &&
|
|
108
92
|
node.arguments[1]?.type === 'FunctionExpression';
|
|
109
|
-
// Check if this looks like AMD require (array of deps + callback)
|
|
110
93
|
if (firstArg.type === 'ArrayExpression' && hasCallback) {
|
|
111
94
|
context.report({
|
|
112
95
|
node: node.callee,
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noAnonymousDefaultExport = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -94,28 +89,20 @@ exports.noAnonymousDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
94
89
|
case 'FunctionExpression':
|
|
95
90
|
return !allowFunctionExpression;
|
|
96
91
|
case 'FunctionDeclaration':
|
|
97
|
-
// Function declarations in default exports are anonymous if they have no name
|
|
98
|
-
// (e.g., export default function() {}), and should be treated like function expressions
|
|
99
92
|
return declaration.id ? false : !allowFunctionExpression;
|
|
100
93
|
case 'ClassDeclaration':
|
|
101
|
-
// Class declarations in default exports are anonymous if they have no name
|
|
102
|
-
// (e.g., export default class {}), and should be treated like class expressions
|
|
103
94
|
return declaration.id ? false : !allowClassExpression;
|
|
104
95
|
case 'CallExpression':
|
|
105
|
-
// Allow calls like React.forwardRef(() => ...)
|
|
106
|
-
// Allow calls like withRouter(Component)
|
|
107
96
|
return false;
|
|
108
97
|
case 'Identifier':
|
|
109
98
|
case 'Literal':
|
|
110
99
|
case 'ObjectExpression':
|
|
111
100
|
case 'ArrayExpression':
|
|
112
|
-
// These are not anonymous - they're named references or literals
|
|
113
101
|
return false;
|
|
114
102
|
default:
|
|
115
103
|
return true;
|
|
116
104
|
}
|
|
117
105
|
}
|
|
118
|
-
// oxlint-disable-next-line consistent-function-scoping
|
|
119
106
|
function getSuggestionText(node) {
|
|
120
107
|
const declaration = node.declaration;
|
|
121
108
|
switch (declaration.type) {
|
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noBarrelFile = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
// Default barrel patterns - index files in various extensions
|
|
11
5
|
const DEFAULT_BARREL_PATTERNS = [
|
|
12
6
|
'.*[/\\\\]index\\.(ts|tsx|js|jsx|mts|mjs)$',
|
|
13
7
|
];
|
|
14
|
-
/**
|
|
15
|
-
* Check if a path matches any of the regex patterns
|
|
16
|
-
*/
|
|
17
8
|
function matchesPattern(filePath, patterns) {
|
|
18
9
|
return patterns.some((pattern) => {
|
|
19
10
|
try {
|
|
@@ -21,14 +12,10 @@ function matchesPattern(filePath, patterns) {
|
|
|
21
12
|
return regex.test(filePath);
|
|
22
13
|
}
|
|
23
14
|
catch {
|
|
24
|
-
// Invalid regex, try simple includes
|
|
25
15
|
return filePath.includes(pattern);
|
|
26
16
|
}
|
|
27
17
|
});
|
|
28
18
|
}
|
|
29
|
-
/**
|
|
30
|
-
* Check if a node is a re-export statement
|
|
31
|
-
*/
|
|
32
19
|
function isReexport(node) {
|
|
33
20
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.ExportAllDeclaration) {
|
|
34
21
|
return true;
|
|
@@ -39,12 +26,8 @@ function isReexport(node) {
|
|
|
39
26
|
}
|
|
40
27
|
return false;
|
|
41
28
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Check if a node is a local export (not re-exporting from another module)
|
|
44
|
-
*/
|
|
45
29
|
function isLocalExport(node) {
|
|
46
30
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.ExportNamedDeclaration) {
|
|
47
|
-
// Has a declaration (export const x = ...) or no source (export { x })
|
|
48
31
|
return node.source === null && node.declaration !== null;
|
|
49
32
|
}
|
|
50
33
|
if (node.type === eslint_devkit_1.AST_NODE_TYPES.ExportDefaultDeclaration) {
|
|
@@ -52,9 +35,6 @@ function isLocalExport(node) {
|
|
|
52
35
|
}
|
|
53
36
|
return false;
|
|
54
37
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Count the number of modules being re-exported
|
|
57
|
-
*/
|
|
58
38
|
function countReexportSources(reexports, namedReexports) {
|
|
59
39
|
const sources = new Set();
|
|
60
40
|
for (const node of reexports) {
|
|
@@ -150,15 +130,12 @@ exports.noBarrelFile = (0, eslint_devkit_1.createRule)({
|
|
|
150
130
|
create(context, [options = {}]) {
|
|
151
131
|
const { threshold = 3, allowedPaths = [], barrelPatterns = DEFAULT_BARREL_PATTERNS, allowWithLocalExports = false, reexportRatio = 0.8, } = options || {};
|
|
152
132
|
const filename = context.filename;
|
|
153
|
-
// Check if file matches barrel patterns
|
|
154
133
|
if (!matchesPattern(filename, barrelPatterns)) {
|
|
155
134
|
return {};
|
|
156
135
|
}
|
|
157
|
-
// Check if file is in allowed paths
|
|
158
136
|
if (allowedPaths.length > 0 && matchesPattern(filename, allowedPaths)) {
|
|
159
137
|
return {};
|
|
160
138
|
}
|
|
161
|
-
// Collect all exports
|
|
162
139
|
const exportAllDeclarations = [];
|
|
163
140
|
const namedReexports = [];
|
|
164
141
|
const localExports = [];
|
|
@@ -182,23 +159,16 @@ exports.noBarrelFile = (0, eslint_devkit_1.createRule)({
|
|
|
182
159
|
'Program:exit'(node) {
|
|
183
160
|
const totalReexports = exportAllDeclarations.length + namedReexports.length;
|
|
184
161
|
const totalExports = totalReexports + localExports.length;
|
|
185
|
-
// No exports = not a barrel file
|
|
186
162
|
if (totalExports === 0) {
|
|
187
163
|
return;
|
|
188
164
|
}
|
|
189
|
-
// Count unique source modules
|
|
190
165
|
const sourceCount = countReexportSources(exportAllDeclarations, namedReexports);
|
|
191
|
-
// Check if file has local exports
|
|
192
166
|
const hasLocalExports = localExports.length > 0;
|
|
193
|
-
// Skip if allows local exports and has them
|
|
194
167
|
if (allowWithLocalExports && hasLocalExports) {
|
|
195
168
|
return;
|
|
196
169
|
}
|
|
197
|
-
// Calculate re-export ratio
|
|
198
170
|
const ratio = totalReexports / totalExports;
|
|
199
|
-
// Check if this is a barrel file
|
|
200
171
|
if (sourceCount >= threshold && !hasLocalExports) {
|
|
201
|
-
// Pure barrel file - definitely flag
|
|
202
172
|
context.report({
|
|
203
173
|
node,
|
|
204
174
|
messageId: 'barrelFileDetected',
|
|
@@ -210,8 +180,6 @@ exports.noBarrelFile = (0, eslint_devkit_1.createRule)({
|
|
|
210
180
|
else if (hasLocalExports &&
|
|
211
181
|
sourceCount >= threshold &&
|
|
212
182
|
ratio >= reexportRatio) {
|
|
213
|
-
// Mixed file with high re-export ratio - suggest improvement
|
|
214
|
-
// Only applies when there ARE local exports (mixed barrels)
|
|
215
183
|
context.report({
|
|
216
184
|
node,
|
|
217
185
|
messageId: 'considerDirectExports',
|
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noBarrelImport = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
/**
|
|
11
|
-
* Check if an import path matches any of the patterns
|
|
12
|
-
*/
|
|
13
5
|
function matchesPattern(importPath, patterns) {
|
|
14
6
|
return patterns.some((pattern) => {
|
|
15
7
|
try {
|
|
@@ -21,23 +13,13 @@ function matchesPattern(importPath, patterns) {
|
|
|
21
13
|
}
|
|
22
14
|
});
|
|
23
15
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Check if import path looks like it's from node_modules
|
|
26
|
-
*/
|
|
27
16
|
function isNodeModulesImport(importPath) {
|
|
28
|
-
// Starts with package name (not relative or absolute)
|
|
29
17
|
if (importPath.startsWith('.') || importPath.startsWith('/')) {
|
|
30
18
|
return false;
|
|
31
19
|
}
|
|
32
|
-
// Could be a scoped or regular package
|
|
33
20
|
return true;
|
|
34
21
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Check if import path explicitly references /index
|
|
37
|
-
* This is a safe heuristic - explicit index imports are clearly barrel imports
|
|
38
|
-
*/
|
|
39
22
|
function endsWithIndex(importPath) {
|
|
40
|
-
// Matches: /index, /index.ts, /index.tsx, /index.js, /index.jsx, /index.mjs
|
|
41
23
|
return /\/index(\.[mc]?[jt]sx?)?$/.test(importPath);
|
|
42
24
|
}
|
|
43
25
|
exports.noBarrelImport = (0, eslint_devkit_1.createRule)({
|
|
@@ -99,18 +81,14 @@ exports.noBarrelImport = (0, eslint_devkit_1.createRule)({
|
|
|
99
81
|
create(context, [options = {}]) {
|
|
100
82
|
const { knownBarrels = [], ignoreNodeModules = true, ignoredPackages = [], } = options || {};
|
|
101
83
|
function checkImportPath(node, importPath) {
|
|
102
|
-
// Skip node_modules if configured
|
|
103
84
|
if (ignoreNodeModules && isNodeModulesImport(importPath)) {
|
|
104
|
-
// Check if it's an ignored package
|
|
105
85
|
if (ignoredPackages.length > 0 && matchesPattern(importPath, ignoredPackages)) {
|
|
106
86
|
return;
|
|
107
87
|
}
|
|
108
|
-
// For node_modules, only flag if explicitly in knownBarrels
|
|
109
88
|
if (knownBarrels.length === 0) {
|
|
110
89
|
return;
|
|
111
90
|
}
|
|
112
91
|
}
|
|
113
|
-
// Check against known barrels first (explicit configuration)
|
|
114
92
|
if (knownBarrels.length > 0 && matchesPattern(importPath, knownBarrels)) {
|
|
115
93
|
context.report({
|
|
116
94
|
node,
|
|
@@ -121,8 +99,6 @@ exports.noBarrelImport = (0, eslint_devkit_1.createRule)({
|
|
|
121
99
|
});
|
|
122
100
|
return;
|
|
123
101
|
}
|
|
124
|
-
// Safe heuristic: only flag explicit /index imports (not directory imports)
|
|
125
|
-
// We can't distinguish './utils' (directory) from './utils' (file) without FS access
|
|
126
102
|
if (endsWithIndex(importPath)) {
|
|
127
103
|
context.report({
|
|
128
104
|
node,
|
|
@@ -140,7 +116,6 @@ exports.noBarrelImport = (0, eslint_devkit_1.createRule)({
|
|
|
140
116
|
checkImportPath(node, importPath);
|
|
141
117
|
}
|
|
142
118
|
},
|
|
143
|
-
// Also check re-exports that import from barrels
|
|
144
119
|
ExportAllDeclaration(node) {
|
|
145
120
|
const importPath = node.source.value;
|
|
146
121
|
if (typeof importPath === 'string') {
|
package/src/rules/no-commonjs.js
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Copyright (c) 2025 Ofri Peretz
|
|
4
|
-
* Licensed under the MIT License. Use of this source code is governed by the
|
|
5
|
-
* MIT license that can be found in the LICENSE file.
|
|
6
|
-
*/
|
|
7
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
3
|
exports.noCommonjs = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -104,7 +99,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
104
99
|
if (!filename) {
|
|
105
100
|
return false;
|
|
106
101
|
}
|
|
107
|
-
// Check if file is in allowed list
|
|
108
102
|
return allowInFiles.some((pattern) => {
|
|
109
103
|
if (pattern.includes('*')) {
|
|
110
104
|
const regex = new RegExp(pattern.replace(/\*/g, '.*'));
|
|
@@ -114,11 +108,9 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
114
108
|
});
|
|
115
109
|
}
|
|
116
110
|
function generateES6Suggestion(node) {
|
|
117
|
-
// Try to generate ES6 equivalent based on the CommonJS pattern
|
|
118
111
|
if (node.type === 'CallExpression' &&
|
|
119
112
|
node.callee.type === 'Identifier' &&
|
|
120
113
|
node.callee.name === 'require') {
|
|
121
|
-
// require('module')
|
|
122
114
|
const arg = node.arguments[0];
|
|
123
115
|
if (arg?.type === 'Literal' && typeof arg.value === 'string') {
|
|
124
116
|
return `// Convert to: import * as moduleName from '${arg.value}';`;
|
|
@@ -127,7 +119,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
127
119
|
if (node.type === 'AssignmentExpression') {
|
|
128
120
|
const left = node.left;
|
|
129
121
|
const right = node.right;
|
|
130
|
-
// module.exports = ...
|
|
131
122
|
if (left.type === 'MemberExpression' &&
|
|
132
123
|
left.object.type === 'Identifier' &&
|
|
133
124
|
left.object.name === 'module' &&
|
|
@@ -140,7 +131,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
140
131
|
return `// Convert to: export default ${context.sourceCode.getText(right)};`;
|
|
141
132
|
}
|
|
142
133
|
}
|
|
143
|
-
// exports.something = ...
|
|
144
134
|
if (left.type === 'MemberExpression' &&
|
|
145
135
|
left.object.type === 'Identifier' &&
|
|
146
136
|
left.object.name === 'exports' &&
|
|
@@ -161,7 +151,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
161
151
|
if (shouldAllow() || allowRequire) {
|
|
162
152
|
return;
|
|
163
153
|
}
|
|
164
|
-
// Check for require() calls
|
|
165
154
|
if (node.callee.type === 'Identifier' &&
|
|
166
155
|
node.callee.name === 'require') {
|
|
167
156
|
context.report({
|
|
@@ -191,7 +180,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
191
180
|
return;
|
|
192
181
|
}
|
|
193
182
|
const left = node.left;
|
|
194
|
-
// Check for module.exports = ...
|
|
195
183
|
if (left.type === 'MemberExpression' &&
|
|
196
184
|
left.object.type === 'Identifier' &&
|
|
197
185
|
left.object.name === 'module' &&
|
|
@@ -219,7 +207,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
219
207
|
: undefined,
|
|
220
208
|
});
|
|
221
209
|
}
|
|
222
|
-
// Check for module.exports.property = ... (nested)
|
|
223
210
|
else if (left.type === 'MemberExpression' &&
|
|
224
211
|
left.object.type === 'MemberExpression' &&
|
|
225
212
|
left.object.object.type === 'Identifier' &&
|
|
@@ -247,7 +234,6 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
247
234
|
: undefined,
|
|
248
235
|
});
|
|
249
236
|
}
|
|
250
|
-
// Check for exports.* = ...
|
|
251
237
|
else if (left.type === 'MemberExpression' &&
|
|
252
238
|
left.object.type === 'Identifier' &&
|
|
253
239
|
left.object.name === 'exports' &&
|
|
@@ -274,12 +260,10 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
274
260
|
});
|
|
275
261
|
}
|
|
276
262
|
},
|
|
277
|
-
// Check for TypeScript import = require() syntax
|
|
278
263
|
TSImportEqualsDeclaration(node) {
|
|
279
264
|
if (shouldAllow() || allowRequire) {
|
|
280
265
|
return;
|
|
281
266
|
}
|
|
282
|
-
// Check if it's import x = require('module')
|
|
283
267
|
if (node.moduleReference.type === 'TSExternalModuleReference') {
|
|
284
268
|
context.report({
|
|
285
269
|
node,
|
|
@@ -307,13 +291,11 @@ exports.noCommonjs = (0, eslint_devkit_1.createRule)({
|
|
|
307
291
|
});
|
|
308
292
|
}
|
|
309
293
|
},
|
|
310
|
-
// Also check for __dirname, __filename which are CommonJS-specific
|
|
311
294
|
Identifier(node) {
|
|
312
295
|
if (shouldAllow()) {
|
|
313
296
|
return;
|
|
314
297
|
}
|
|
315
298
|
if (node.name === '__dirname' || node.name === '__filename') {
|
|
316
|
-
// These are CommonJS globals that don't work in ES modules
|
|
317
299
|
context.report({
|
|
318
300
|
node,
|
|
319
301
|
messageId: 'preferES6',
|