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
|
@@ -1,15 +1,6 @@
|
|
|
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.noUnresolved = void 0;
|
|
9
|
-
/**
|
|
10
|
-
* ESLint Rule: no-unresolved
|
|
11
|
-
* Ensures imports point to resolvable modules (eslint-plugin-import inspired)
|
|
12
|
-
*/
|
|
13
4
|
const node_module_1 = require("node:module");
|
|
14
5
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
15
6
|
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
@@ -95,7 +86,6 @@ exports.noUnresolved = (0, eslint_devkit_1.createRule)({
|
|
|
95
86
|
create(context) {
|
|
96
87
|
const [options] = context.options;
|
|
97
88
|
const { ignore = [], allowUnresolved = false } = options || {};
|
|
98
|
-
// If allowUnresolved is true, don't check anything
|
|
99
89
|
if (allowUnresolved) {
|
|
100
90
|
return {};
|
|
101
91
|
}
|
|
@@ -109,11 +99,9 @@ exports.noUnresolved = (0, eslint_devkit_1.createRule)({
|
|
|
109
99
|
});
|
|
110
100
|
}
|
|
111
101
|
function checkImport(importPath, node) {
|
|
112
|
-
// Skip if ignored
|
|
113
102
|
if (shouldIgnore(importPath)) {
|
|
114
103
|
return;
|
|
115
104
|
}
|
|
116
|
-
// Skip built-in modules
|
|
117
105
|
if (importPath.startsWith('node:') ||
|
|
118
106
|
node_module_1.builtinModules.includes(importPath)) {
|
|
119
107
|
return;
|
|
@@ -134,7 +122,6 @@ exports.noUnresolved = (0, eslint_devkit_1.createRule)({
|
|
|
134
122
|
{
|
|
135
123
|
messageId: 'addIgnoreComment',
|
|
136
124
|
fix(fixer) {
|
|
137
|
-
// Find the statement that contains this import
|
|
138
125
|
let statement = node;
|
|
139
126
|
while (statement.parent &&
|
|
140
127
|
statement.parent.type !== 'Program') {
|
|
@@ -175,7 +162,6 @@ exports.noUnresolved = (0, eslint_devkit_1.createRule)({
|
|
|
175
162
|
}
|
|
176
163
|
},
|
|
177
164
|
CallExpression(node) {
|
|
178
|
-
// Check require() calls
|
|
179
165
|
if (node.callee.type === 'Identifier' &&
|
|
180
166
|
node.callee.name === 'require' &&
|
|
181
167
|
node.arguments.length === 1) {
|
|
@@ -186,14 +172,12 @@ exports.noUnresolved = (0, eslint_devkit_1.createRule)({
|
|
|
186
172
|
}
|
|
187
173
|
},
|
|
188
174
|
ImportExpression(node) {
|
|
189
|
-
// Handle dynamic imports: import("module")
|
|
190
175
|
if (node.source.type === 'Literal' &&
|
|
191
176
|
typeof node.source.value === 'string') {
|
|
192
177
|
checkImport(node.source.value, node.source);
|
|
193
178
|
}
|
|
194
179
|
},
|
|
195
180
|
TSImportEqualsDeclaration(node) {
|
|
196
|
-
// Handle TypeScript import = require() syntax
|
|
197
181
|
if (node.moduleReference.type === 'TSExternalModuleReference' &&
|
|
198
182
|
node.moduleReference.expression.type === 'Literal' &&
|
|
199
183
|
typeof node.moduleReference.expression.value === 'string') {
|
|
@@ -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.noUnusedModules = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -61,7 +56,6 @@ exports.noUnusedModules = (0, eslint_devkit_1.createRule)({
|
|
|
61
56
|
hasExports = true;
|
|
62
57
|
},
|
|
63
58
|
AssignmentExpression(node) {
|
|
64
|
-
// Check for CommonJS exports
|
|
65
59
|
if (node.left.type === 'MemberExpression' &&
|
|
66
60
|
node.left.object.type === 'Identifier' &&
|
|
67
61
|
node.left.object.name === 'module' &&
|
|
@@ -69,7 +63,6 @@ exports.noUnusedModules = (0, eslint_devkit_1.createRule)({
|
|
|
69
63
|
node.left.property.name === 'exports') {
|
|
70
64
|
hasExports = true;
|
|
71
65
|
}
|
|
72
|
-
// Check for exports.xxx = ...
|
|
73
66
|
if (node.left.type === 'MemberExpression' &&
|
|
74
67
|
node.left.object.type === 'Identifier' &&
|
|
75
68
|
node.left.object.name === 'exports') {
|
|
@@ -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.noUselessPathSegments = void 0;
|
|
9
4
|
const tslib_1 = require("tslib");
|
|
@@ -47,32 +42,22 @@ exports.noUselessPathSegments = (0, eslint_devkit_1.createRule)({
|
|
|
47
42
|
const options = context.options[0] || {};
|
|
48
43
|
const { noUselessIndex = false, commonjs = true } = options;
|
|
49
44
|
function simplifyPath(importPath) {
|
|
50
|
-
// Only process relative paths
|
|
51
45
|
if (!importPath.startsWith('./') && !importPath.startsWith('../')) {
|
|
52
46
|
return null;
|
|
53
47
|
}
|
|
54
48
|
const normalized = path.posix.normalize(importPath);
|
|
55
|
-
// Check for useless ./
|
|
56
|
-
// ./foo -> foo (but we keep it as relative)
|
|
57
|
-
// ./a/../b -> ./b
|
|
58
|
-
// ./a/./b -> ./a/b
|
|
59
|
-
// Normalize the path
|
|
60
49
|
let simplified = normalized;
|
|
61
|
-
// Remove trailing /index if noUselessIndex is enabled
|
|
62
50
|
if (noUselessIndex) {
|
|
63
51
|
simplified = simplified.replace(/\/index$/, '');
|
|
64
|
-
// Handle ./index -> .
|
|
65
52
|
if (simplified === './index' || simplified === 'index') {
|
|
66
53
|
simplified = '.';
|
|
67
54
|
}
|
|
68
55
|
}
|
|
69
|
-
// Ensure relative paths start with ./
|
|
70
56
|
if (!simplified.startsWith('./') &&
|
|
71
57
|
!simplified.startsWith('../') &&
|
|
72
58
|
!simplified.startsWith('.')) {
|
|
73
59
|
simplified = './' + simplified;
|
|
74
60
|
}
|
|
75
|
-
// If nothing changed, return null
|
|
76
61
|
if (simplified === importPath) {
|
|
77
62
|
return null;
|
|
78
63
|
}
|
|
@@ -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.preferDefaultExport = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -88,7 +83,6 @@ exports.preferDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
88
83
|
if (shouldIgnoreFile() || allowNamedExports) {
|
|
89
84
|
return {};
|
|
90
85
|
}
|
|
91
|
-
// Track exports in this module with their nodes
|
|
92
86
|
const namedExports = new Map();
|
|
93
87
|
let defaultExportNode = null;
|
|
94
88
|
function addNamedExport(name, exportNode) {
|
|
@@ -98,9 +92,7 @@ exports.preferDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
98
92
|
if (target === 'single' &&
|
|
99
93
|
namedExports.size === 1 &&
|
|
100
94
|
!defaultExportNode) {
|
|
101
|
-
// Find the export node to report on
|
|
102
95
|
const [exportName, exportNode] = Array.from(namedExports.entries())[0];
|
|
103
|
-
// Report on the single named export
|
|
104
96
|
context.report({
|
|
105
97
|
node: exportNode,
|
|
106
98
|
messageId: 'preferDefaultExport',
|
|
@@ -123,29 +115,22 @@ exports.preferDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
123
115
|
}
|
|
124
116
|
return {
|
|
125
117
|
ExportNamedDeclaration(node) {
|
|
126
|
-
// Check if this is a re-export of 'default' (export { default } from "./other")
|
|
127
118
|
if (node.source && node.specifiers) {
|
|
128
119
|
const hasDefaultReExport = node.specifiers.some((specifier) => specifier.exported.type === 'Identifier' &&
|
|
129
120
|
specifier.exported.name === 'default');
|
|
130
121
|
if (hasDefaultReExport) {
|
|
131
|
-
// Treat re-export of default as a default export
|
|
132
122
|
defaultExportNode =
|
|
133
123
|
node;
|
|
134
124
|
}
|
|
135
|
-
// Skip all other re-exports
|
|
136
125
|
return;
|
|
137
126
|
}
|
|
138
|
-
// Skip re-exports (exports from another module)
|
|
139
127
|
if (node.source) {
|
|
140
128
|
return;
|
|
141
129
|
}
|
|
142
|
-
// Skip TypeScript type-only exports
|
|
143
130
|
if (node.exportKind === 'type') {
|
|
144
131
|
return;
|
|
145
132
|
}
|
|
146
|
-
// Track named exports
|
|
147
133
|
if (node.declaration) {
|
|
148
|
-
// Skip TypeScript interface and type declarations
|
|
149
134
|
if (node.declaration.type === 'TSInterfaceDeclaration' ||
|
|
150
135
|
node.declaration.type === 'TSTypeAliasDeclaration') {
|
|
151
136
|
return;
|
|
@@ -166,10 +151,8 @@ exports.preferDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
166
151
|
addNamedExport(node.declaration.id.name, node);
|
|
167
152
|
}
|
|
168
153
|
}
|
|
169
|
-
// Handle export specifiers (but not type specifiers)
|
|
170
154
|
if (node.specifiers) {
|
|
171
155
|
node.specifiers.forEach((specifier) => {
|
|
172
|
-
// Skip type-only export specifiers
|
|
173
156
|
if (specifier.exportKind === 'type') {
|
|
174
157
|
return;
|
|
175
158
|
}
|
|
@@ -182,7 +165,6 @@ exports.preferDefaultExport = (0, eslint_devkit_1.createRule)({
|
|
|
182
165
|
ExportDefaultDeclaration(node) {
|
|
183
166
|
defaultExportNode = node;
|
|
184
167
|
},
|
|
185
|
-
// At the end of the file, analyze the export pattern
|
|
186
168
|
'Program:exit'(node) {
|
|
187
169
|
if (target === 'always' &&
|
|
188
170
|
namedExports.size > 0 &&
|
|
@@ -1,15 +1,8 @@
|
|
|
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.preferDirectImport = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
// Common barrel-to-direct mappings
|
|
11
5
|
const DEFAULT_MAPPINGS = [
|
|
12
|
-
// React component libraries commonly use this pattern
|
|
13
6
|
{ barrel: '^@/components$', directPath: '@/components/{name}' },
|
|
14
7
|
{ barrel: '^@/hooks$', directPath: '@/hooks/{name}' },
|
|
15
8
|
{ barrel: '^@/utils$', directPath: '@/utils/{name}' },
|
|
@@ -17,9 +10,6 @@ const DEFAULT_MAPPINGS = [
|
|
|
17
10
|
{ barrel: '^~/components$', directPath: '~/components/{name}' },
|
|
18
11
|
{ barrel: '^~/hooks$', directPath: '~/hooks/{name}' },
|
|
19
12
|
];
|
|
20
|
-
/**
|
|
21
|
-
* Find a matching mapping for an import path
|
|
22
|
-
*/
|
|
23
13
|
function findMapping(importPath, mappings) {
|
|
24
14
|
for (const mapping of mappings) {
|
|
25
15
|
try {
|
|
@@ -36,9 +26,6 @@ function findMapping(importPath, mappings) {
|
|
|
36
26
|
}
|
|
37
27
|
return null;
|
|
38
28
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Generate direct import path from mapping template
|
|
41
|
-
*/
|
|
42
29
|
function generateDirectPath(template, importedName) {
|
|
43
30
|
return template.replace('{name}', importedName);
|
|
44
31
|
}
|
|
@@ -106,18 +93,14 @@ exports.preferDirectImport = (0, eslint_devkit_1.createRule)({
|
|
|
106
93
|
const importPath = node.source.value;
|
|
107
94
|
if (typeof importPath !== 'string')
|
|
108
95
|
return;
|
|
109
|
-
// Skip type-only imports (they don't affect bundle size)
|
|
110
96
|
if (node.importKind === 'type')
|
|
111
97
|
return;
|
|
112
|
-
// Find matching barrel mapping
|
|
113
98
|
const mapping = findMapping(importPath, mappings);
|
|
114
99
|
if (!mapping)
|
|
115
100
|
return;
|
|
116
|
-
// Only process named imports (not default or namespace)
|
|
117
101
|
const namedImports = node.specifiers.filter((spec) => spec.type === 'ImportSpecifier');
|
|
118
102
|
if (namedImports.length === 0)
|
|
119
103
|
return;
|
|
120
|
-
// For single named import, we can suggest/fix the direct path
|
|
121
104
|
if (namedImports.length === 1) {
|
|
122
105
|
const importedName = namedImports[0].imported.type === 'Identifier'
|
|
123
106
|
? namedImports[0].imported.name
|
|
@@ -133,7 +116,6 @@ exports.preferDirectImport = (0, eslint_devkit_1.createRule)({
|
|
|
133
116
|
},
|
|
134
117
|
fix: autoFix
|
|
135
118
|
? (fixer) => {
|
|
136
|
-
// Replace the import path
|
|
137
119
|
return fixer.replaceText(node.source, `'${suggestedPath}'`);
|
|
138
120
|
}
|
|
139
121
|
: undefined,
|
|
@@ -155,7 +137,6 @@ exports.preferDirectImport = (0, eslint_devkit_1.createRule)({
|
|
|
155
137
|
});
|
|
156
138
|
}
|
|
157
139
|
else {
|
|
158
|
-
// Multiple named imports - suggest splitting them
|
|
159
140
|
for (const spec of namedImports) {
|
|
160
141
|
const importedName = spec.imported.type === 'Identifier'
|
|
161
142
|
? spec.imported.name
|
|
@@ -169,7 +150,6 @@ exports.preferDirectImport = (0, eslint_devkit_1.createRule)({
|
|
|
169
150
|
suggestedPath,
|
|
170
151
|
barrelPath: importPath,
|
|
171
152
|
},
|
|
172
|
-
// Don't auto-fix multiple imports as it requires splitting the statement
|
|
173
153
|
suggest: [
|
|
174
154
|
{
|
|
175
155
|
messageId: 'preferDirectImport',
|
|
@@ -178,7 +158,7 @@ exports.preferDirectImport = (0, eslint_devkit_1.createRule)({
|
|
|
178
158
|
suggestedPath,
|
|
179
159
|
barrelPath: importPath,
|
|
180
160
|
},
|
|
181
|
-
fix: () => null,
|
|
161
|
+
fix: () => null,
|
|
182
162
|
},
|
|
183
163
|
],
|
|
184
164
|
});
|
|
@@ -1,15 +1,8 @@
|
|
|
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.preferModernApi = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
// Built-in mappings for common outdated packages
|
|
11
5
|
const BUILT_IN_MAPPINGS = [
|
|
12
|
-
// Date/Time
|
|
13
6
|
{
|
|
14
7
|
deprecated: 'moment',
|
|
15
8
|
modern: 'date-fns or dayjs',
|
|
@@ -23,7 +16,6 @@ const BUILT_IN_MAPPINGS = [
|
|
|
23
16
|
reason: 'Maintenance mode. date-fns-tz is smaller and tree-shakeable.',
|
|
24
17
|
difficulty: 'medium',
|
|
25
18
|
},
|
|
26
|
-
// HTTP Clients
|
|
27
19
|
{
|
|
28
20
|
deprecated: 'request',
|
|
29
21
|
modern: 'node-fetch, axios, or undici',
|
|
@@ -36,14 +28,12 @@ const BUILT_IN_MAPPINGS = [
|
|
|
36
28
|
reason: 'Deprecated with the request package.',
|
|
37
29
|
difficulty: 'easy',
|
|
38
30
|
},
|
|
39
|
-
// Utility Libraries (full imports)
|
|
40
31
|
{
|
|
41
32
|
deprecated: 'underscore',
|
|
42
33
|
modern: 'lodash-es or native methods',
|
|
43
34
|
reason: 'Underscore is outdated. Modern JS has most utilities built-in.',
|
|
44
35
|
difficulty: 'medium',
|
|
45
36
|
},
|
|
46
|
-
// Testing
|
|
47
37
|
{
|
|
48
38
|
deprecated: 'mocha',
|
|
49
39
|
modern: 'vitest or jest',
|
|
@@ -56,7 +46,6 @@ const BUILT_IN_MAPPINGS = [
|
|
|
56
46
|
reason: 'Modern test runners have built-in assertions.',
|
|
57
47
|
difficulty: 'medium',
|
|
58
48
|
},
|
|
59
|
-
// Build Tools
|
|
60
49
|
{
|
|
61
50
|
deprecated: 'gulp',
|
|
62
51
|
modern: 'npm scripts or vite',
|
|
@@ -69,42 +58,36 @@ const BUILT_IN_MAPPINGS = [
|
|
|
69
58
|
reason: 'Grunt is largely obsolete. Use modern build tools.',
|
|
70
59
|
difficulty: 'hard',
|
|
71
60
|
},
|
|
72
|
-
// CSS
|
|
73
61
|
{
|
|
74
62
|
deprecated: 'node-sass',
|
|
75
63
|
modern: 'sass (dart-sass)',
|
|
76
64
|
reason: 'node-sass is deprecated. dart-sass is the official implementation.',
|
|
77
65
|
difficulty: 'easy',
|
|
78
66
|
},
|
|
79
|
-
// Crypto
|
|
80
67
|
{
|
|
81
68
|
deprecated: 'bcrypt-nodejs',
|
|
82
69
|
modern: 'bcrypt or bcryptjs',
|
|
83
70
|
reason: 'bcrypt-nodejs is unmaintained and has security issues.',
|
|
84
71
|
difficulty: 'easy',
|
|
85
72
|
},
|
|
86
|
-
// UUID
|
|
87
73
|
{
|
|
88
74
|
deprecated: 'uuid/v4',
|
|
89
75
|
modern: 'crypto.randomUUID() or uuid',
|
|
90
76
|
reason: 'Node.js 16+ has built-in crypto.randomUUID().',
|
|
91
77
|
difficulty: 'easy',
|
|
92
78
|
},
|
|
93
|
-
// State Management
|
|
94
79
|
{
|
|
95
80
|
deprecated: 'redux',
|
|
96
81
|
modern: 'zustand, jotai, or redux-toolkit',
|
|
97
82
|
reason: 'Modern state libraries have less boilerplate.',
|
|
98
83
|
difficulty: 'hard',
|
|
99
84
|
},
|
|
100
|
-
// Validation
|
|
101
85
|
{
|
|
102
86
|
deprecated: 'joi',
|
|
103
87
|
modern: 'zod or yup',
|
|
104
88
|
reason: 'Zod has better TypeScript integration and smaller bundle.',
|
|
105
89
|
difficulty: 'medium',
|
|
106
90
|
},
|
|
107
|
-
// Bundlers
|
|
108
91
|
{
|
|
109
92
|
deprecated: 'webpack',
|
|
110
93
|
modern: 'vite, esbuild, or rspack',
|
|
@@ -112,9 +95,6 @@ const BUILT_IN_MAPPINGS = [
|
|
|
112
95
|
difficulty: 'hard',
|
|
113
96
|
},
|
|
114
97
|
];
|
|
115
|
-
/**
|
|
116
|
-
* Match package name against pattern
|
|
117
|
-
*/
|
|
118
98
|
function matchPackage(importPath, deprecated) {
|
|
119
99
|
const packageName = importPath.startsWith('@')
|
|
120
100
|
? importPath.split('/').slice(0, 2).join('/')
|
|
@@ -180,7 +160,6 @@ exports.preferModernApi = (0, eslint_devkit_1.createRule)({
|
|
|
180
160
|
? customMappings
|
|
181
161
|
: [...BUILT_IN_MAPPINGS, ...customMappings];
|
|
182
162
|
function checkImport(importPath, node) {
|
|
183
|
-
// Only check package imports
|
|
184
163
|
if (importPath.startsWith('.') || importPath.startsWith('/'))
|
|
185
164
|
return;
|
|
186
165
|
for (const mapping of allMappings) {
|
|
@@ -1,14 +1,8 @@
|
|
|
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.preferNodeProtocol = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
5
|
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
11
|
-
// Node.js built-in modules that should use node: protocol
|
|
12
6
|
const NODE_BUILT_INS = new Set([
|
|
13
7
|
'assert',
|
|
14
8
|
'async_hooks',
|
|
@@ -95,7 +89,6 @@ exports.preferNodeProtocol = (0, eslint_devkit_1.createRule)({
|
|
|
95
89
|
...additionalModules,
|
|
96
90
|
]);
|
|
97
91
|
return {
|
|
98
|
-
// Check import declarations
|
|
99
92
|
ImportDeclaration(node) {
|
|
100
93
|
const moduleName = node.source.value;
|
|
101
94
|
if (typeof moduleName === 'string' &&
|
|
@@ -114,7 +107,6 @@ exports.preferNodeProtocol = (0, eslint_devkit_1.createRule)({
|
|
|
114
107
|
});
|
|
115
108
|
}
|
|
116
109
|
},
|
|
117
|
-
// Check require() calls
|
|
118
110
|
CallExpression(node) {
|
|
119
111
|
if (node.callee.type === 'Identifier' &&
|
|
120
112
|
node.callee.name === 'require' &&
|
|
@@ -139,7 +131,6 @@ exports.preferNodeProtocol = (0, eslint_devkit_1.createRule)({
|
|
|
139
131
|
}
|
|
140
132
|
}
|
|
141
133
|
},
|
|
142
|
-
// Check dynamic import() calls
|
|
143
134
|
ImportExpression(node) {
|
|
144
135
|
if (node.source.type === 'Literal' &&
|
|
145
136
|
typeof node.source.value === 'string') {
|
|
@@ -161,27 +152,21 @@ exports.preferNodeProtocol = (0, eslint_devkit_1.createRule)({
|
|
|
161
152
|
}
|
|
162
153
|
},
|
|
163
154
|
};
|
|
164
|
-
// oxlint-disable-next-line consistent-function-scoping
|
|
165
155
|
function isBuiltInModule(moduleName, modulesToCheck) {
|
|
166
|
-
// Skip if already using node: protocol
|
|
167
156
|
if (moduleName.startsWith('node:')) {
|
|
168
157
|
return false;
|
|
169
158
|
}
|
|
170
|
-
// Check exact match first
|
|
171
159
|
if (modulesToCheck.has(moduleName)) {
|
|
172
160
|
return true;
|
|
173
161
|
}
|
|
174
|
-
// Check case-insensitive match
|
|
175
162
|
const lowerCaseModule = moduleName.toLowerCase();
|
|
176
163
|
if (modulesToCheck.has(lowerCaseModule)) {
|
|
177
164
|
return true;
|
|
178
165
|
}
|
|
179
|
-
// Check for sub-path imports like 'fs/promises', 'path/posix', etc.
|
|
180
166
|
const baseModule = moduleName.split('/')[0];
|
|
181
167
|
if (modulesToCheck.has(baseModule)) {
|
|
182
168
|
return true;
|
|
183
169
|
}
|
|
184
|
-
// Check case-insensitive for base module
|
|
185
170
|
const lowerCaseBaseModule = baseModule.toLowerCase();
|
|
186
171
|
return modulesToCheck.has(lowerCaseBaseModule);
|
|
187
172
|
}
|
|
@@ -1,13 +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.preferTreeShakeableImports = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
// Known large packages that benefit from subpath/named imports
|
|
11
5
|
const KNOWN_LARGE_PACKAGES = [
|
|
12
6
|
{ name: 'lodash', subpathPattern: 'lodash/{method}', preferNamed: false },
|
|
13
7
|
{ name: '@mui/material', subpathPattern: '@mui/material/{Component}', preferNamed: true },
|
|
@@ -22,12 +16,8 @@ const KNOWN_LARGE_PACKAGES = [
|
|
|
22
16
|
{ name: 'antd', preferNamed: true },
|
|
23
17
|
{ name: '@ant-design/icons', preferNamed: true },
|
|
24
18
|
];
|
|
25
|
-
/**
|
|
26
|
-
* Check if import is from a target package
|
|
27
|
-
*/
|
|
28
19
|
function matchesPackage(importPath, packages) {
|
|
29
20
|
for (const pkg of packages) {
|
|
30
|
-
// Exact match or scoped package match
|
|
31
21
|
if (importPath === pkg.name || importPath.startsWith(`${pkg.name}/`)) {
|
|
32
22
|
return pkg;
|
|
33
23
|
}
|
|
@@ -109,11 +99,9 @@ exports.preferTreeShakeableImports = (0, eslint_devkit_1.createRule)({
|
|
|
109
99
|
const importPath = node.source.value;
|
|
110
100
|
if (typeof importPath !== 'string')
|
|
111
101
|
return;
|
|
112
|
-
// Check for namespace imports
|
|
113
102
|
const namespaceSpecifier = node.specifiers.find((spec) => spec.type === eslint_devkit_1.AST_NODE_TYPES.ImportNamespaceSpecifier);
|
|
114
103
|
if (namespaceSpecifier) {
|
|
115
104
|
const matchedPackage = matchesPackage(importPath, targetPackages);
|
|
116
|
-
// Flag namespace imports from target packages
|
|
117
105
|
if (matchedPackage || blockAllNamespaceImports) {
|
|
118
106
|
context.report({
|
|
119
107
|
node,
|
|
@@ -126,11 +114,9 @@ exports.preferTreeShakeableImports = (0, eslint_devkit_1.createRule)({
|
|
|
126
114
|
return;
|
|
127
115
|
}
|
|
128
116
|
}
|
|
129
|
-
// Check for default imports from large packages
|
|
130
117
|
const defaultSpecifier = node.specifiers.find((spec) => spec.type === eslint_devkit_1.AST_NODE_TYPES.ImportDefaultSpecifier);
|
|
131
118
|
if (defaultSpecifier) {
|
|
132
119
|
const matchedPackage = matchesPackage(importPath, targetPackages);
|
|
133
|
-
// Only flag if importing from root of package (not subpath)
|
|
134
120
|
if (matchedPackage && importPath === matchedPackage.name) {
|
|
135
121
|
context.report({
|
|
136
122
|
node,
|
|
@@ -1,17 +1,8 @@
|
|
|
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.requireImportApproval = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
10
|
-
/**
|
|
11
|
-
* Match package name against pattern
|
|
12
|
-
*/
|
|
13
5
|
function matchPackage(packageName, pattern) {
|
|
14
|
-
// Support glob-like patterns
|
|
15
6
|
if (pattern.endsWith('/*')) {
|
|
16
7
|
const prefix = pattern.slice(0, -2);
|
|
17
8
|
return packageName.startsWith(prefix + '/') || packageName === prefix;
|
|
@@ -21,22 +12,14 @@ function matchPackage(packageName, pattern) {
|
|
|
21
12
|
}
|
|
22
13
|
return packageName === pattern;
|
|
23
14
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Check if import path is a package (not relative)
|
|
26
|
-
*/
|
|
27
15
|
function isPackageImport(importPath) {
|
|
28
16
|
return !importPath.startsWith('.') && !importPath.startsWith('/');
|
|
29
17
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Extract package name from import path
|
|
32
|
-
*/
|
|
33
18
|
function getPackageName(importPath) {
|
|
34
|
-
// Scoped packages: @org/package/path -> @org/package
|
|
35
19
|
if (importPath.startsWith('@')) {
|
|
36
20
|
const parts = importPath.split('/');
|
|
37
21
|
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importPath;
|
|
38
22
|
}
|
|
39
|
-
// Regular packages: package/path -> package
|
|
40
23
|
return importPath.split('/')[0];
|
|
41
24
|
}
|
|
42
25
|
exports.requireImportApproval = (0, eslint_devkit_1.createRule)({
|
|
@@ -119,12 +102,10 @@ exports.requireImportApproval = (0, eslint_devkit_1.createRule)({
|
|
|
119
102
|
if (!isPackageImport(importPath))
|
|
120
103
|
return;
|
|
121
104
|
const packageName = getPackageName(importPath);
|
|
122
|
-
// Check ignore patterns
|
|
123
105
|
for (const pattern of ignorePatterns) {
|
|
124
106
|
if (matchPackage(packageName, pattern))
|
|
125
107
|
return;
|
|
126
108
|
}
|
|
127
|
-
// Find matching policy
|
|
128
109
|
const policy = packages.find(p => matchPackage(packageName, p.package));
|
|
129
110
|
if (policy) {
|
|
130
111
|
if (policy.status === 'blocked') {
|
|
@@ -149,10 +130,8 @@ exports.requireImportApproval = (0, eslint_devkit_1.createRule)({
|
|
|
149
130
|
},
|
|
150
131
|
});
|
|
151
132
|
}
|
|
152
|
-
// 'approved' status - no error
|
|
153
133
|
}
|
|
154
134
|
else if (defaultPolicy === 'deny') {
|
|
155
|
-
// Package not in list and default is deny
|
|
156
135
|
context.report({
|
|
157
136
|
node,
|
|
158
137
|
messageId: 'unapprovedPackage',
|
package/src/rules/unambiguous.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.unambiguous = void 0;
|
|
9
4
|
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
@@ -38,7 +33,6 @@ exports.unambiguous = (0, eslint_devkit_1.createRule)({
|
|
|
38
33
|
hasModuleSyntax = true;
|
|
39
34
|
},
|
|
40
35
|
ImportExpression() {
|
|
41
|
-
// Dynamic import makes it a module
|
|
42
36
|
hasModuleSyntax = true;
|
|
43
37
|
},
|
|
44
38
|
ExportDefaultDeclaration() {
|
|
@@ -52,22 +46,17 @@ exports.unambiguous = (0, eslint_devkit_1.createRule)({
|
|
|
52
46
|
},
|
|
53
47
|
'Program:exit'(node) {
|
|
54
48
|
if (hasModuleSyntax) {
|
|
55
|
-
// File is unambiguously a module
|
|
56
49
|
return;
|
|
57
50
|
}
|
|
58
|
-
// Check for 'use strict' directive
|
|
59
51
|
const hasUseStrict = node.body.some((statement) => statement.type === eslint_devkit_1.AST_NODE_TYPES.ExpressionStatement &&
|
|
60
52
|
statement.expression.type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
61
53
|
statement.expression.value === 'use strict');
|
|
62
54
|
if (hasUseStrict) {
|
|
63
|
-
// While not technically making it a module, it's at least intentional
|
|
64
55
|
return;
|
|
65
56
|
}
|
|
66
|
-
// Empty files are also ambiguous but typically intentional
|
|
67
57
|
if (node.body.length === 0) {
|
|
68
58
|
return;
|
|
69
59
|
}
|
|
70
|
-
// Check if there are any actual statements (not just comments)
|
|
71
60
|
const hasStatements = node.body.some((statement) => statement.type !== eslint_devkit_1.AST_NODE_TYPES.EmptyStatement);
|
|
72
61
|
if (hasStatements) {
|
|
73
62
|
context.report({
|
package/src/types/index.js
CHANGED