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.
Files changed (123) hide show
  1. package/README.md +47 -0
  2. package/package.json +16 -12
  3. package/src/files/foo.js +0 -5
  4. package/src/files/no-default.js +0 -5
  5. package/src/index.d.ts +15 -2812
  6. package/src/index.js +5 -147
  7. package/src/oxlint.d.ts +17 -20
  8. package/src/oxlint.js +0 -18
  9. package/src/rules/consistent-type-specifier-style.js +0 -19
  10. package/src/rules/default.js +0 -7
  11. package/src/rules/dynamic-import-chunkname.js +0 -8
  12. package/src/rules/enforce-dependency-direction.js +2 -39
  13. package/src/rules/enforce-import-order.js +3 -33
  14. package/src/rules/enforce-team-boundaries.js +0 -49
  15. package/src/rules/export.js +0 -9
  16. package/src/rules/exports-last.js +0 -10
  17. package/src/rules/extensions.js +2 -11
  18. package/src/rules/first.js +0 -6
  19. package/src/rules/group-exports.js +0 -13
  20. package/src/rules/max-dependencies.js +0 -16
  21. package/src/rules/named.js +1 -10
  22. package/src/rules/namespace.js +1 -11
  23. package/src/rules/newline-after-import.js +2 -13
  24. package/src/rules/no-absolute-path.js +0 -7
  25. package/src/rules/no-amd.js +1 -18
  26. package/src/rules/no-anonymous-default-export.js +0 -13
  27. package/src/rules/no-barrel-file.js +0 -32
  28. package/src/rules/no-barrel-import.js +0 -25
  29. package/src/rules/no-commonjs.js +0 -18
  30. package/src/rules/no-cross-domain-imports.js +2 -47
  31. package/src/rules/no-cycle.js +2 -135
  32. package/src/rules/no-default-export.js +0 -28
  33. package/src/rules/no-deprecated.js +0 -32
  34. package/src/rules/no-duplicates.js +2 -10
  35. package/src/rules/no-dynamic-require.js +0 -6
  36. package/src/rules/no-empty-named-blocks.js +1 -17
  37. package/src/rules/no-extraneous-dependencies.js +0 -38
  38. package/src/rules/no-full-package-import.js +0 -19
  39. package/src/rules/no-import-module-exports.js +0 -8
  40. package/src/rules/no-internal-modules.js +0 -40
  41. package/src/rules/no-legacy-imports.js +1 -11
  42. package/src/rules/no-mutable-exports.js +0 -14
  43. package/src/rules/no-named-as-default-member.js +0 -11
  44. package/src/rules/no-named-as-default.js +0 -17
  45. package/src/rules/no-named-default.js +0 -5
  46. package/src/rules/no-named-export.js +1 -22
  47. package/src/rules/no-namespace.js +0 -10
  48. package/src/rules/no-nodejs-modules.js +0 -15
  49. package/src/rules/no-relative-packages.js +0 -15
  50. package/src/rules/no-relative-parent-imports.js +0 -11
  51. package/src/rules/no-restricted-paths.js +0 -6
  52. package/src/rules/no-self-import.js +0 -22
  53. package/src/rules/no-unassigned-import.js +0 -14
  54. package/src/rules/no-unresolved.js +0 -16
  55. package/src/rules/no-unused-modules.js +0 -7
  56. package/src/rules/no-useless-path-segments.js +0 -15
  57. package/src/rules/prefer-default-export.js +0 -18
  58. package/src/rules/prefer-direct-import.js +1 -21
  59. package/src/rules/prefer-modern-api.js +0 -21
  60. package/src/rules/prefer-node-protocol.js +0 -15
  61. package/src/rules/prefer-tree-shakeable-imports.js +0 -14
  62. package/src/rules/require-import-approval.js +0 -21
  63. package/src/rules/unambiguous.js +0 -11
  64. package/src/types/index.js +0 -5
  65. package/AGENTS.md +0 -95
  66. package/CHANGELOG.md +0 -170
  67. package/src/files/foo.d.ts +0 -7
  68. package/src/files/no-default.d.ts +0 -6
  69. package/src/rules/consistent-type-specifier-style.d.ts +0 -13
  70. package/src/rules/default.d.ts +0 -9
  71. package/src/rules/dynamic-import-chunkname.d.ts +0 -26
  72. package/src/rules/enforce-dependency-direction.d.ts +0 -27
  73. package/src/rules/enforce-import-order.d.ts +0 -29
  74. package/src/rules/enforce-team-boundaries.d.ts +0 -47
  75. package/src/rules/export.d.ts +0 -17
  76. package/src/rules/exports-last.d.ts +0 -15
  77. package/src/rules/extensions.d.ts +0 -17
  78. package/src/rules/first.d.ts +0 -13
  79. package/src/rules/group-exports.d.ts +0 -15
  80. package/src/rules/max-dependencies.d.ts +0 -26
  81. package/src/rules/named.d.ts +0 -13
  82. package/src/rules/namespace.d.ts +0 -13
  83. package/src/rules/newline-after-import.d.ts +0 -13
  84. package/src/rules/no-absolute-path.d.ts +0 -25
  85. package/src/rules/no-amd.d.ts +0 -21
  86. package/src/rules/no-anonymous-default-export.d.ts +0 -24
  87. package/src/rules/no-barrel-file.d.ts +0 -55
  88. package/src/rules/no-barrel-import.d.ts +0 -48
  89. package/src/rules/no-commonjs.d.ts +0 -28
  90. package/src/rules/no-cross-domain-imports.d.ts +0 -41
  91. package/src/rules/no-cycle.d.ts +0 -102
  92. package/src/rules/no-default-export.d.ts +0 -24
  93. package/src/rules/no-deprecated.d.ts +0 -26
  94. package/src/rules/no-duplicates.d.ts +0 -13
  95. package/src/rules/no-dynamic-require.d.ts +0 -22
  96. package/src/rules/no-empty-named-blocks.d.ts +0 -17
  97. package/src/rules/no-extraneous-dependencies.d.ts +0 -45
  98. package/src/rules/no-full-package-import.d.ts +0 -42
  99. package/src/rules/no-import-module-exports.d.ts +0 -21
  100. package/src/rules/no-internal-modules.d.ts +0 -28
  101. package/src/rules/no-legacy-imports.d.ts +0 -47
  102. package/src/rules/no-mutable-exports.d.ts +0 -22
  103. package/src/rules/no-named-as-default-member.d.ts +0 -15
  104. package/src/rules/no-named-as-default.d.ts +0 -15
  105. package/src/rules/no-named-default.d.ts +0 -15
  106. package/src/rules/no-named-export.d.ts +0 -26
  107. package/src/rules/no-namespace.d.ts +0 -21
  108. package/src/rules/no-nodejs-modules.d.ts +0 -24
  109. package/src/rules/no-relative-packages.d.ts +0 -21
  110. package/src/rules/no-relative-parent-imports.d.ts +0 -22
  111. package/src/rules/no-restricted-paths.d.ts +0 -20
  112. package/src/rules/no-self-import.d.ts +0 -15
  113. package/src/rules/no-unassigned-import.d.ts +0 -20
  114. package/src/rules/no-unresolved.d.ts +0 -20
  115. package/src/rules/no-unused-modules.d.ts +0 -19
  116. package/src/rules/no-useless-path-segments.d.ts +0 -23
  117. package/src/rules/prefer-default-export.d.ts +0 -24
  118. package/src/rules/prefer-direct-import.d.ts +0 -51
  119. package/src/rules/prefer-modern-api.d.ts +0 -47
  120. package/src/rules/prefer-node-protocol.d.ts +0 -19
  121. package/src/rules/prefer-tree-shakeable-imports.d.ts +0 -49
  122. package/src/rules/require-import-approval.d.ts +0 -52
  123. 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, // Manual fix required for multi-import
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',
@@ -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({
@@ -1,7 +1,2 @@
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 });