eslint-plugin-restrict-replace-import 1.5.0 → 2.0.0
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 +35 -4
- package/dist/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +354 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +372 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +36 -22
- package/docs/rules/restrict-import.md +0 -166
- package/eslint.config.mjs +0 -43
- package/lib/index.js +0 -18
- package/lib/rules/restrict-import.js +0 -548
package/README.md
CHANGED
|
@@ -20,6 +20,33 @@ npm install eslint-plugin-restrict-replace-import --save-dev
|
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
|
+
### ESLint v9+ (Flat Config)
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
// eslint.config.js
|
|
27
|
+
import restrictReplaceImport from 'eslint-plugin-restrict-replace-import'
|
|
28
|
+
|
|
29
|
+
export default [
|
|
30
|
+
// Use the recommended config
|
|
31
|
+
restrictReplaceImport.flatConfigs.recommended,
|
|
32
|
+
|
|
33
|
+
// Or configure manually
|
|
34
|
+
{
|
|
35
|
+
plugins: {
|
|
36
|
+
'restrict-replace-import': restrictReplaceImport,
|
|
37
|
+
},
|
|
38
|
+
rules: {
|
|
39
|
+
'restrict-replace-import/restrict-import': [
|
|
40
|
+
'error',
|
|
41
|
+
['restricted-package1', 'restricted-package2'],
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### ESLint v8 (Legacy Config)
|
|
49
|
+
|
|
23
50
|
Add `restrict-replace-import` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
|
|
24
51
|
|
|
25
52
|
```json
|
|
@@ -38,6 +65,8 @@ Then configure the rules you want to use under the rules section.
|
|
|
38
65
|
}
|
|
39
66
|
```
|
|
40
67
|
|
|
68
|
+
## Rule Options
|
|
69
|
+
|
|
41
70
|
You can also specify an alternative package to import instead:
|
|
42
71
|
|
|
43
72
|
```json
|
|
@@ -126,7 +155,7 @@ You can also restrict specific named imports from a package while allowing other
|
|
|
126
155
|
{
|
|
127
156
|
"target": "restricted-module",
|
|
128
157
|
"namedImports": ["restrictedImport", "alsoRestricted"],
|
|
129
|
-
"replacement": "replacement-module"
|
|
158
|
+
"replacement": "replacement-module"
|
|
130
159
|
}
|
|
131
160
|
]
|
|
132
161
|
]
|
|
@@ -167,10 +196,12 @@ import defaultExport, { allowed } from 'restricted-module'
|
|
|
167
196
|
|
|
168
197
|
<!-- begin auto-generated rules list -->
|
|
169
198
|
|
|
199
|
+
💼 Configurations enabled in.\
|
|
200
|
+
✅ Set in the `recommended` configuration.\
|
|
170
201
|
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
|
|
171
202
|
|
|
172
|
-
| Name | Description | 🔧 |
|
|
173
|
-
| :----------------------------------------------- | :--------------------------------------- | :- |
|
|
174
|
-
| [restrict-import](docs/rules/restrict-import.md) | Prevent the Import of a Specific Package | 🔧 |
|
|
203
|
+
| Name | Description | 💼 | 🔧 |
|
|
204
|
+
| :----------------------------------------------- | :--------------------------------------- | :- | :- |
|
|
205
|
+
| [restrict-import](docs/rules/restrict-import.md) | Prevent the Import of a Specific Package | ✅ | 🔧 |
|
|
175
206
|
|
|
176
207
|
<!-- end auto-generated rules list -->
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ESLint, Linter } from 'eslint';
|
|
2
|
+
|
|
3
|
+
declare const configs: Record<string, Linter.LegacyConfig>;
|
|
4
|
+
declare const flatConfigs: Record<string, Linter.Config>;
|
|
5
|
+
declare const plugin: ESLint.Plugin & {
|
|
6
|
+
configs: typeof configs;
|
|
7
|
+
flatConfigs: typeof flatConfigs;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { plugin as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ESLint, Linter } from 'eslint';
|
|
2
|
+
|
|
3
|
+
declare const configs: Record<string, Linter.LegacyConfig>;
|
|
4
|
+
declare const flatConfigs: Record<string, Linter.Config>;
|
|
5
|
+
declare const plugin: ESLint.Plugin & {
|
|
6
|
+
configs: typeof configs;
|
|
7
|
+
flatConfigs: typeof flatConfigs;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export { plugin as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
// src/rules/restrict-import.ts
|
|
4
|
+
var getImportedName = (imported) => {
|
|
5
|
+
if (imported.type === "Identifier") {
|
|
6
|
+
return imported.name;
|
|
7
|
+
}
|
|
8
|
+
return String(imported.value);
|
|
9
|
+
};
|
|
10
|
+
var createRestrictedPackagesMap = (options) => {
|
|
11
|
+
const map = /* @__PURE__ */ new Map();
|
|
12
|
+
options.forEach((config) => {
|
|
13
|
+
if (typeof config === "string") {
|
|
14
|
+
map.set(new RegExp(`^${config}$`), {
|
|
15
|
+
replacement: null,
|
|
16
|
+
namedImports: null
|
|
17
|
+
});
|
|
18
|
+
} else {
|
|
19
|
+
map.set(new RegExp(`^${config.target}$`), {
|
|
20
|
+
replacement: config.replacement ?? null,
|
|
21
|
+
namedImports: config.namedImports ?? null
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return map;
|
|
26
|
+
};
|
|
27
|
+
var checkIsRestrictedImport = (importSource, namedImports, restrictedPackages) => {
|
|
28
|
+
for (const [pattern, restrictedPackageOptions] of restrictedPackages) {
|
|
29
|
+
if (pattern.test(importSource)) {
|
|
30
|
+
if (!restrictedPackageOptions.namedImports?.length) {
|
|
31
|
+
return {
|
|
32
|
+
type: "module",
|
|
33
|
+
pattern
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const restrictedImportedName = restrictedPackageOptions.namedImports.find(
|
|
37
|
+
(namedImport) => namedImports.includes(namedImport)
|
|
38
|
+
);
|
|
39
|
+
if (restrictedImportedName) {
|
|
40
|
+
return {
|
|
41
|
+
type: "importedName",
|
|
42
|
+
pattern,
|
|
43
|
+
restrictedImportedName
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
};
|
|
50
|
+
var getPatternDisplayName = (regExpPatternSource) => regExpPatternSource.slice(1, -1);
|
|
51
|
+
var getQuoteStyle = (target) => target?.includes("'") ? "'" : '"';
|
|
52
|
+
var formatSpecifiers = (specifiers) => {
|
|
53
|
+
return specifiers.map((s) => s.imported === s.local ? s.imported : `${s.imported} as ${s.local}`).join(", ");
|
|
54
|
+
};
|
|
55
|
+
var createImportText = ({ specifiers, source, quote, semicolon = "" }) => {
|
|
56
|
+
const defaultSpecifier = specifiers.find((s) => s.type === "ImportDefaultSpecifier");
|
|
57
|
+
const namespaceSpecifier = specifiers.find((s) => s.type === "ImportNamespaceSpecifier");
|
|
58
|
+
const namedSpecifiers = specifiers.filter((s) => s.type === "ImportSpecifier");
|
|
59
|
+
if (namespaceSpecifier) {
|
|
60
|
+
return `import * as ${namespaceSpecifier.local.name} from ${quote}${source}${quote}${semicolon}`;
|
|
61
|
+
}
|
|
62
|
+
if (defaultSpecifier) {
|
|
63
|
+
if (namedSpecifiers.length === 0) {
|
|
64
|
+
return `import ${defaultSpecifier.local.name} from ${quote}${source}${quote}${semicolon}`;
|
|
65
|
+
}
|
|
66
|
+
const namedText = namedSpecifiers.map((s) => {
|
|
67
|
+
const importedName = getImportedName(s.imported);
|
|
68
|
+
return importedName === s.local.name ? importedName : `${importedName} as ${s.local.name}`;
|
|
69
|
+
}).join(", ");
|
|
70
|
+
return `import ${defaultSpecifier.local.name}, { ${namedText} } from ${quote}${source}${quote}${semicolon}`;
|
|
71
|
+
}
|
|
72
|
+
if (namedSpecifiers.length > 0) {
|
|
73
|
+
const namedText = namedSpecifiers.map((s) => {
|
|
74
|
+
const importedName = getImportedName(s.imported);
|
|
75
|
+
return importedName === s.local.name ? importedName : `${importedName} as ${s.local.name}`;
|
|
76
|
+
}).join(", ");
|
|
77
|
+
return `import { ${namedText} } from ${quote}${source}${quote}${semicolon}`;
|
|
78
|
+
}
|
|
79
|
+
return `import ${quote}${source}${quote}${semicolon}`;
|
|
80
|
+
};
|
|
81
|
+
var updateExistingImport = (fixer, sourceCode, existingImport, specifiersToAdd, quote, semicolon, replacement) => {
|
|
82
|
+
const fixes = [];
|
|
83
|
+
const existingNamedSpecifiers = existingImport.specifiers.filter((s) => s.type === "ImportSpecifier").map((s) => getImportedName(s.imported));
|
|
84
|
+
const newSpecifiersToAdd = specifiersToAdd.filter((s) => !existingNamedSpecifiers.includes(s.imported));
|
|
85
|
+
if (newSpecifiersToAdd.length === 0) {
|
|
86
|
+
return fixes;
|
|
87
|
+
}
|
|
88
|
+
const existingText = sourceCode.getText(existingImport);
|
|
89
|
+
const namedSpecifiers = existingImport.specifiers.filter((s) => s.type === "ImportSpecifier");
|
|
90
|
+
if (namedSpecifiers.length > 0) {
|
|
91
|
+
const existingSpecifiersMatch = existingText.match(/import\s*(?:[^{]*,\s*)?{([^}]*)}/);
|
|
92
|
+
if (existingSpecifiersMatch) {
|
|
93
|
+
const existingSpecifiersText = existingSpecifiersMatch[1].trim();
|
|
94
|
+
const newSpecifierText = formatSpecifiers(newSpecifiersToAdd);
|
|
95
|
+
const combinedSpecifiers = `${existingSpecifiersText}, ${newSpecifierText}`;
|
|
96
|
+
const newImportText = existingText.replace(/\{[^}]*\}/, `{ ${combinedSpecifiers} }`);
|
|
97
|
+
fixes.push(fixer.replaceText(existingImport, newImportText));
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
const defaultSpecifier = existingImport.specifiers.find((s) => s.type === "ImportDefaultSpecifier");
|
|
101
|
+
if (defaultSpecifier) {
|
|
102
|
+
const defaultName = defaultSpecifier.local.name;
|
|
103
|
+
const newSpecifiersText = formatSpecifiers(newSpecifiersToAdd);
|
|
104
|
+
const newText = `import ${defaultName}, { ${newSpecifiersText} } from ${quote}${replacement}${quote}${semicolon}`;
|
|
105
|
+
fixes.push(fixer.replaceText(existingImport, newText));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return fixes;
|
|
109
|
+
};
|
|
110
|
+
var createStringReplacer = (sourceNode, replacement, quote) => {
|
|
111
|
+
return (fixer) => fixer.replaceText(sourceNode, `${quote}${replacement}${quote}`);
|
|
112
|
+
};
|
|
113
|
+
var createPatternReplacer = (sourceNode, replacementPatterns, quote) => {
|
|
114
|
+
return (fixer) => {
|
|
115
|
+
let result = sourceNode.value;
|
|
116
|
+
if (typeof replacementPatterns === "string") {
|
|
117
|
+
return createStringReplacer(sourceNode, replacementPatterns, quote)(fixer);
|
|
118
|
+
}
|
|
119
|
+
for (const [pattern, replacement] of Object.entries(replacementPatterns)) {
|
|
120
|
+
const regex = new RegExp(pattern, "g");
|
|
121
|
+
result = result.replace(regex, replacement);
|
|
122
|
+
}
|
|
123
|
+
return fixer.replaceText(sourceNode, `${quote}${result}${quote}`);
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
var createModuleReplacer = (node, replacement) => {
|
|
127
|
+
if (!replacement) return null;
|
|
128
|
+
const quote = getQuoteStyle(node.source.raw);
|
|
129
|
+
if (typeof replacement === "string") {
|
|
130
|
+
return createStringReplacer(node.source, replacement, quote);
|
|
131
|
+
}
|
|
132
|
+
return createPatternReplacer(node.source, replacement, quote);
|
|
133
|
+
};
|
|
134
|
+
var createMultiNamedImportReplacer = (context, node, importRestrictions) => {
|
|
135
|
+
return (fixer) => {
|
|
136
|
+
if (!importRestrictions.length) return null;
|
|
137
|
+
const quote = getQuoteStyle(node.source.raw);
|
|
138
|
+
const semicolon = node.source.raw?.endsWith(";") || node.source.value.endsWith(";") ? ";" : "";
|
|
139
|
+
const fixes = [];
|
|
140
|
+
const allRestrictedNames = importRestrictions.map((r) => r.importName);
|
|
141
|
+
const groupedByReplacement = importRestrictions.reduce((acc, restriction) => {
|
|
142
|
+
if (!restriction.replacement) return acc;
|
|
143
|
+
if (!acc[restriction.replacement]) {
|
|
144
|
+
acc[restriction.replacement] = [];
|
|
145
|
+
}
|
|
146
|
+
acc[restriction.replacement].push(restriction.importName);
|
|
147
|
+
return acc;
|
|
148
|
+
}, {});
|
|
149
|
+
const remainingSpecifiers = node.specifiers.filter(
|
|
150
|
+
(specifier) => specifier.type !== "ImportSpecifier" || !allRestrictedNames.includes(getImportedName(specifier.imported))
|
|
151
|
+
);
|
|
152
|
+
if (remainingSpecifiers.length === 0) {
|
|
153
|
+
fixes.push(fixer.remove(node));
|
|
154
|
+
} else {
|
|
155
|
+
const newImportText = createImportText({
|
|
156
|
+
specifiers: remainingSpecifiers,
|
|
157
|
+
source: node.source.value,
|
|
158
|
+
quote,
|
|
159
|
+
semicolon
|
|
160
|
+
});
|
|
161
|
+
fixes.push(fixer.replaceText(node, newImportText));
|
|
162
|
+
}
|
|
163
|
+
const sourceCode = context.sourceCode;
|
|
164
|
+
const allImports = sourceCode.ast.body.filter(
|
|
165
|
+
(n) => n.type === "ImportDeclaration" && n.source.type === "Literal"
|
|
166
|
+
);
|
|
167
|
+
Object.entries(groupedByReplacement).forEach(([replacement, restrictedNames]) => {
|
|
168
|
+
const specifiersToMove = restrictedNames.map((name2) => {
|
|
169
|
+
const specifier = node.specifiers.find(
|
|
170
|
+
(s) => s.type === "ImportSpecifier" && getImportedName(s.imported) === name2
|
|
171
|
+
);
|
|
172
|
+
return specifier ? {
|
|
173
|
+
imported: getImportedName(specifier.imported),
|
|
174
|
+
local: specifier.local.name
|
|
175
|
+
} : null;
|
|
176
|
+
}).filter((s) => s !== null);
|
|
177
|
+
if (specifiersToMove.length === 0) return;
|
|
178
|
+
const existingReplacementImport = allImports.find((importNode) => importNode.source.value === replacement);
|
|
179
|
+
if (existingReplacementImport) {
|
|
180
|
+
fixes.push(
|
|
181
|
+
...updateExistingImport(
|
|
182
|
+
fixer,
|
|
183
|
+
sourceCode,
|
|
184
|
+
existingReplacementImport,
|
|
185
|
+
specifiersToMove,
|
|
186
|
+
quote,
|
|
187
|
+
semicolon,
|
|
188
|
+
replacement
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
} else {
|
|
192
|
+
const newSpecifiersText = formatSpecifiers(specifiersToMove);
|
|
193
|
+
const newImport = `import { ${newSpecifiersText} } from ${quote}${replacement}${quote}${semicolon}`;
|
|
194
|
+
fixes.push(fixer.insertTextBefore(node, newImport + "\n"));
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
return fixes;
|
|
198
|
+
};
|
|
199
|
+
};
|
|
200
|
+
var rule = {
|
|
201
|
+
meta: {
|
|
202
|
+
type: "problem",
|
|
203
|
+
docs: {
|
|
204
|
+
description: "Prevent the Import of a Specific Package",
|
|
205
|
+
recommended: false,
|
|
206
|
+
url: "https://github.com/custardcream98/eslint-plugin-restrict-replace-import/blob/main/docs/rules/restrict-import.md"
|
|
207
|
+
},
|
|
208
|
+
fixable: "code",
|
|
209
|
+
messages: {
|
|
210
|
+
ImportRestriction: "`{{ name }}` is restricted from being used.",
|
|
211
|
+
ImportRestrictionWithReplacement: "`{{ name }}` is restricted from being used. Replace it with `{{ replacement }}`.",
|
|
212
|
+
ImportedNameRestriction: "Import of '{{importedName}}' from '{{name}}' is restricted",
|
|
213
|
+
ImportedNameRestrictionWithReplacement: "Import of '{{importedName}}' from '{{name}}' is restricted. Replace it with '{{replacement}}'."
|
|
214
|
+
},
|
|
215
|
+
schema: [
|
|
216
|
+
{
|
|
217
|
+
type: "array",
|
|
218
|
+
items: {
|
|
219
|
+
oneOf: [
|
|
220
|
+
{
|
|
221
|
+
type: "string"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
type: "object",
|
|
225
|
+
properties: {
|
|
226
|
+
target: {
|
|
227
|
+
type: "string",
|
|
228
|
+
description: "The target of the import to be restricted"
|
|
229
|
+
},
|
|
230
|
+
namedImports: {
|
|
231
|
+
type: "array",
|
|
232
|
+
items: { type: "string" },
|
|
233
|
+
description: "The named imports to be restricted. If not provided, all named imports will be restricted."
|
|
234
|
+
},
|
|
235
|
+
replacement: {
|
|
236
|
+
oneOf: [
|
|
237
|
+
{ type: "string" },
|
|
238
|
+
{
|
|
239
|
+
type: "object",
|
|
240
|
+
patternProperties: {
|
|
241
|
+
".*": { type: "string" }
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
description: "The replacement for the import. If a string is provided, it will be used as the replacement for all imports. If an object is provided, the keys will be used as the pattern and the values will be used as the replacement."
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
required: ["target"],
|
|
249
|
+
additionalProperties: false
|
|
250
|
+
}
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
create(context) {
|
|
257
|
+
const options = context.options;
|
|
258
|
+
const restrictedPackages = createRestrictedPackagesMap(options[0]);
|
|
259
|
+
return {
|
|
260
|
+
ImportDeclaration(node) {
|
|
261
|
+
const importNode = node;
|
|
262
|
+
if (importNode.source.type !== "Literal") return;
|
|
263
|
+
const importSource = importNode.source.value;
|
|
264
|
+
const namedImports = importNode.specifiers.filter((specifier) => specifier.type === "ImportSpecifier").map((specifier) => getImportedName(specifier.imported));
|
|
265
|
+
const checkerResult = checkIsRestrictedImport(importSource, namedImports, restrictedPackages);
|
|
266
|
+
if (!checkerResult) return;
|
|
267
|
+
const restrictedPackageOptions = restrictedPackages.get(checkerResult.pattern);
|
|
268
|
+
if (!restrictedPackageOptions) return;
|
|
269
|
+
const patternName = getPatternDisplayName(checkerResult.pattern.source);
|
|
270
|
+
if (checkerResult.type === "module") {
|
|
271
|
+
context.report({
|
|
272
|
+
node,
|
|
273
|
+
messageId: typeof restrictedPackageOptions.replacement === "string" ? "ImportRestrictionWithReplacement" : "ImportRestriction",
|
|
274
|
+
data: {
|
|
275
|
+
name: patternName,
|
|
276
|
+
replacement: restrictedPackageOptions.replacement
|
|
277
|
+
},
|
|
278
|
+
fix: createModuleReplacer(importNode, restrictedPackageOptions.replacement)
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const importRestrictions = [];
|
|
283
|
+
namedImports.forEach((importName) => {
|
|
284
|
+
for (const [pattern, patternOptions] of restrictedPackages.entries()) {
|
|
285
|
+
if (pattern.test(importSource) && patternOptions.namedImports && patternOptions.namedImports.includes(importName) && // TODO: handle options.replacement as an object
|
|
286
|
+
(typeof patternOptions.replacement === "string" || patternOptions.replacement === null)) {
|
|
287
|
+
importRestrictions.push({
|
|
288
|
+
importName,
|
|
289
|
+
replacement: patternOptions.replacement,
|
|
290
|
+
pattern
|
|
291
|
+
});
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
if (importRestrictions.length === 0) {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
importRestrictions.forEach((restriction) => {
|
|
300
|
+
context.report({
|
|
301
|
+
node,
|
|
302
|
+
messageId: restriction.replacement ? "ImportedNameRestrictionWithReplacement" : "ImportedNameRestriction",
|
|
303
|
+
data: {
|
|
304
|
+
importedName: restriction.importName,
|
|
305
|
+
name: importSource,
|
|
306
|
+
replacement: restriction.replacement ?? ""
|
|
307
|
+
},
|
|
308
|
+
fix: restriction.replacement ? createMultiNamedImportReplacer(context, importNode, importRestrictions) : null
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
var restrict_import_default = rule;
|
|
316
|
+
|
|
317
|
+
// src/index.ts
|
|
318
|
+
var name = "eslint-plugin-restrict-replace-import";
|
|
319
|
+
var version = "2.0.0";
|
|
320
|
+
var rules = {
|
|
321
|
+
"restrict-import": restrict_import_default
|
|
322
|
+
};
|
|
323
|
+
var configs = {
|
|
324
|
+
recommended: {
|
|
325
|
+
plugins: ["restrict-replace-import"],
|
|
326
|
+
rules: {
|
|
327
|
+
"restrict-replace-import/restrict-import": "error"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
var flatConfigs = {
|
|
332
|
+
recommended: {
|
|
333
|
+
plugins: {
|
|
334
|
+
"restrict-replace-import": {
|
|
335
|
+
meta: { name, version },
|
|
336
|
+
rules
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
rules: {
|
|
340
|
+
"restrict-replace-import/restrict-import": "error"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
var plugin = {
|
|
345
|
+
meta: {
|
|
346
|
+
name,
|
|
347
|
+
version
|
|
348
|
+
},
|
|
349
|
+
rules,
|
|
350
|
+
configs,
|
|
351
|
+
flatConfigs
|
|
352
|
+
};
|
|
353
|
+
module.exports = plugin;
|
|
354
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rules/restrict-import.ts","../src/index.ts"],"sourcesContent":["import type { Rule, SourceCode } from 'eslint'\nimport type { Identifier, ImportDeclaration, ImportSpecifier, Literal } from 'estree'\n\ntype Replacement = string | Record<string, string>\n\n/**\n * Get the name of an import specifier's imported binding.\n * Handles both Identifier (e.g., `import { foo }`) and Literal (e.g., `import { \"foo\" as bar }`)\n */\nconst getImportedName = (imported: Identifier | Literal): string => {\n if (imported.type === 'Identifier') {\n return imported.name\n }\n // For string literals in imports (e.g., import { \"string-name\" as alias })\n return String(imported.value)\n}\n\ninterface ImportRestrictionOptions {\n replacement: Replacement | null\n namedImports: string[] | null\n}\n\ninterface RestrictedImportCheckResult {\n type: 'module' | 'importedName'\n pattern: RegExp\n restrictedImportedName?: string\n}\n\ninterface ImportRestriction {\n importName: string\n replacement: string | null\n pattern: RegExp\n}\n\ninterface SpecifierInfo {\n imported: string\n local: string\n}\n\ntype QuoteStyle = '\"' | \"'\"\n\nconst createRestrictedPackagesMap = (\n options: Array<string | { target: string; replacement?: Replacement; namedImports?: string[] }>,\n): Map<RegExp, ImportRestrictionOptions> => {\n const map = new Map<RegExp, ImportRestrictionOptions>()\n\n options.forEach((config) => {\n if (typeof config === 'string') {\n map.set(new RegExp(`^${config}$`), {\n replacement: null,\n namedImports: null,\n })\n } else {\n map.set(new RegExp(`^${config.target}$`), {\n replacement: config.replacement ?? null,\n namedImports: config.namedImports ?? null,\n })\n }\n })\n\n return map\n}\n\nconst checkIsRestrictedImport = (\n importSource: string,\n namedImports: string[],\n restrictedPackages: Map<RegExp, ImportRestrictionOptions>,\n): RestrictedImportCheckResult | null => {\n for (const [pattern, restrictedPackageOptions] of restrictedPackages) {\n if (pattern.test(importSource)) {\n if (!restrictedPackageOptions.namedImports?.length) {\n return {\n type: 'module',\n pattern,\n }\n }\n\n const restrictedImportedName = restrictedPackageOptions.namedImports.find((namedImport) =>\n namedImports.includes(namedImport),\n )\n if (restrictedImportedName) {\n return {\n type: 'importedName',\n pattern,\n restrictedImportedName,\n }\n }\n }\n }\n return null\n}\n\n/**\n * Strip the beginning and ending of RegExp pattern (e.g. ^pattern$ -> pattern)\n */\nconst getPatternDisplayName = (regExpPatternSource: string): string => regExpPatternSource.slice(1, -1)\n\nconst getQuoteStyle = (target: string | undefined): QuoteStyle => (target?.includes(\"'\") ? \"'\" : '\"')\n\n/**\n * Format a list of import specifiers as a string\n */\nconst formatSpecifiers = (specifiers: SpecifierInfo[]): string => {\n return specifiers.map((s) => (s.imported === s.local ? s.imported : `${s.imported} as ${s.local}`)).join(', ')\n}\n\ninterface CreateImportTextOptions {\n specifiers: ImportDeclaration['specifiers']\n source: string\n quote: QuoteStyle\n semicolon?: string\n}\n\n/**\n * Creates the text for a new import statement\n */\nconst createImportText = ({ specifiers, source, quote, semicolon = '' }: CreateImportTextOptions): string => {\n const defaultSpecifier = specifiers.find((s) => s.type === 'ImportDefaultSpecifier')\n const namespaceSpecifier = specifiers.find((s) => s.type === 'ImportNamespaceSpecifier')\n const namedSpecifiers = specifiers.filter((s): s is ImportSpecifier => s.type === 'ImportSpecifier')\n\n if (namespaceSpecifier) {\n return `import * as ${namespaceSpecifier.local.name} from ${quote}${source}${quote}${semicolon}`\n }\n\n if (defaultSpecifier) {\n if (namedSpecifiers.length === 0) {\n return `import ${defaultSpecifier.local.name} from ${quote}${source}${quote}${semicolon}`\n }\n\n const namedText = namedSpecifiers\n .map((s) => {\n const importedName = getImportedName(s.imported)\n return importedName === s.local.name ? importedName : `${importedName} as ${s.local.name}`\n })\n .join(', ')\n\n return `import ${defaultSpecifier.local.name}, { ${namedText} } from ${quote}${source}${quote}${semicolon}`\n }\n\n if (namedSpecifiers.length > 0) {\n const namedText = namedSpecifiers\n .map((s) => {\n const importedName = getImportedName(s.imported)\n return importedName === s.local.name ? importedName : `${importedName} as ${s.local.name}`\n })\n .join(', ')\n\n return `import { ${namedText} } from ${quote}${source}${quote}${semicolon}`\n }\n\n return `import ${quote}${source}${quote}${semicolon}`\n}\n\n/**\n * Updates an existing import with new specifiers\n */\nconst updateExistingImport = (\n fixer: Rule.RuleFixer,\n sourceCode: SourceCode,\n existingImport: ImportDeclaration,\n specifiersToAdd: SpecifierInfo[],\n quote: QuoteStyle,\n semicolon: string,\n replacement: string,\n): Rule.Fix[] => {\n const fixes: Rule.Fix[] = []\n const existingNamedSpecifiers = existingImport.specifiers\n .filter((s): s is ImportSpecifier => s.type === 'ImportSpecifier')\n .map((s) => getImportedName(s.imported))\n\n const newSpecifiersToAdd = specifiersToAdd.filter((s) => !existingNamedSpecifiers.includes(s.imported))\n\n if (newSpecifiersToAdd.length === 0) {\n return fixes\n }\n\n const existingText = sourceCode.getText(existingImport)\n const namedSpecifiers = existingImport.specifiers.filter((s): s is ImportSpecifier => s.type === 'ImportSpecifier')\n\n if (namedSpecifiers.length > 0) {\n // Add new specifiers to existing named imports\n const existingSpecifiersMatch = existingText.match(/import\\s*(?:[^{]*,\\s*)?{([^}]*)}/)\n if (existingSpecifiersMatch) {\n const existingSpecifiersText = existingSpecifiersMatch[1].trim()\n const newSpecifierText = formatSpecifiers(newSpecifiersToAdd)\n const combinedSpecifiers = `${existingSpecifiersText}, ${newSpecifierText}`\n const newImportText = existingText.replace(/\\{[^}]*\\}/, `{ ${combinedSpecifiers} }`)\n fixes.push(fixer.replaceText(existingImport, newImportText))\n }\n } else {\n // Handle imports with default but no named imports\n const defaultSpecifier = existingImport.specifiers.find((s) => s.type === 'ImportDefaultSpecifier')\n if (defaultSpecifier) {\n const defaultName = defaultSpecifier.local.name\n const newSpecifiersText = formatSpecifiers(newSpecifiersToAdd)\n const newText = `import ${defaultName}, { ${newSpecifiersText} } from ${quote}${replacement}${quote}${semicolon}`\n fixes.push(fixer.replaceText(existingImport, newText))\n }\n }\n\n return fixes\n}\n\nconst createStringReplacer = (\n sourceNode: ImportDeclaration['source'],\n replacement: string,\n quote: QuoteStyle,\n): ((fixer: Rule.RuleFixer) => Rule.Fix) => {\n return (fixer) => fixer.replaceText(sourceNode, `${quote}${replacement}${quote}`)\n}\n\nconst createPatternReplacer = (\n sourceNode: ImportDeclaration['source'],\n replacementPatterns: Replacement,\n quote: QuoteStyle,\n): ((fixer: Rule.RuleFixer) => Rule.Fix) => {\n return (fixer) => {\n let result = sourceNode.value as string\n\n if (typeof replacementPatterns === 'string') {\n return createStringReplacer(sourceNode, replacementPatterns, quote)(fixer)\n }\n\n for (const [pattern, replacement] of Object.entries(replacementPatterns)) {\n const regex = new RegExp(pattern, 'g')\n result = result.replace(regex, replacement)\n }\n return fixer.replaceText(sourceNode, `${quote}${result}${quote}`)\n }\n}\n\nconst createModuleReplacer = (\n node: ImportDeclaration,\n replacement: Replacement | null,\n): ((fixer: Rule.RuleFixer) => Rule.Fix) | null => {\n if (!replacement) return null\n\n const quote = getQuoteStyle(node.source.raw)\n\n if (typeof replacement === 'string') {\n return createStringReplacer(node.source, replacement, quote)\n }\n\n return createPatternReplacer(node.source, replacement, quote)\n}\n\nconst createMultiNamedImportReplacer = (\n context: Rule.RuleContext,\n node: ImportDeclaration,\n importRestrictions: ImportRestriction[],\n): ((fixer: Rule.RuleFixer) => Rule.Fix[] | null) => {\n return (fixer) => {\n if (!importRestrictions.length) return null\n\n const quote = getQuoteStyle(node.source.raw)\n const semicolon = node.source.raw?.endsWith(';') || (node.source.value as string).endsWith(';') ? ';' : ''\n const fixes: Rule.Fix[] = []\n\n const allRestrictedNames = importRestrictions.map((r) => r.importName)\n\n // Group imports by replacement\n const groupedByReplacement = importRestrictions.reduce<Record<string, string[]>>((acc, restriction) => {\n if (!restriction.replacement) return acc\n\n if (!acc[restriction.replacement]) {\n acc[restriction.replacement] = []\n }\n\n acc[restriction.replacement].push(restriction.importName)\n\n return acc\n }, {})\n\n // Find non-restricted specifiers from the original import\n const remainingSpecifiers = node.specifiers.filter(\n (specifier) =>\n specifier.type !== 'ImportSpecifier' ||\n !allRestrictedNames.includes(getImportedName((specifier as ImportSpecifier).imported)),\n )\n\n // Update or remove the original import\n if (remainingSpecifiers.length === 0) {\n fixes.push(fixer.remove(node))\n } else {\n const newImportText = createImportText({\n specifiers: remainingSpecifiers,\n source: node.source.value as string,\n quote,\n semicolon,\n })\n fixes.push(fixer.replaceText(node, newImportText))\n }\n\n // Create new imports for each replacement module\n const sourceCode = context.sourceCode\n const allImports = sourceCode.ast.body.filter(\n (n): n is ImportDeclaration => n.type === 'ImportDeclaration' && n.source.type === 'Literal',\n )\n\n // Process each replacement module\n Object.entries(groupedByReplacement).forEach(([replacement, restrictedNames]) => {\n // Find specifiers to move\n const specifiersToMove = restrictedNames\n .map((name) => {\n const specifier = node.specifiers.find(\n (s): s is ImportSpecifier => s.type === 'ImportSpecifier' && getImportedName(s.imported) === name,\n )\n return specifier\n ? {\n imported: getImportedName(specifier.imported),\n local: specifier.local.name,\n }\n : null\n })\n .filter((s): s is SpecifierInfo => s !== null)\n\n if (specifiersToMove.length === 0) return\n\n // Find existing import for the same replacement module\n const existingReplacementImport = allImports.find((importNode) => importNode.source.value === replacement)\n\n if (existingReplacementImport) {\n // Add to existing import\n fixes.push(\n ...updateExistingImport(\n fixer,\n sourceCode,\n existingReplacementImport,\n specifiersToMove,\n quote,\n semicolon,\n replacement,\n ),\n )\n } else {\n // Create new import\n const newSpecifiersText = formatSpecifiers(specifiersToMove)\n const newImport = `import { ${newSpecifiersText} } from ${quote}${replacement}${quote}${semicolon}`\n fixes.push(fixer.insertTextBefore(node, newImport + '\\n'))\n }\n })\n\n return fixes\n }\n}\n\ntype RuleOptions = [Array<string | { target: string; replacement?: Replacement; namedImports?: string[] }>]\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Prevent the Import of a Specific Package',\n recommended: false,\n url: 'https://github.com/custardcream98/eslint-plugin-restrict-replace-import/blob/main/docs/rules/restrict-import.md',\n },\n fixable: 'code',\n\n messages: {\n ImportRestriction: '`{{ name }}` is restricted from being used.',\n ImportRestrictionWithReplacement:\n '`{{ name }}` is restricted from being used. Replace it with `{{ replacement }}`.',\n ImportedNameRestriction: \"Import of '{{importedName}}' from '{{name}}' is restricted\",\n ImportedNameRestrictionWithReplacement:\n \"Import of '{{importedName}}' from '{{name}}' is restricted. Replace it with '{{replacement}}'.\",\n },\n\n schema: [\n {\n type: 'array',\n items: {\n oneOf: [\n {\n type: 'string',\n },\n {\n type: 'object',\n properties: {\n target: {\n type: 'string',\n description: 'The target of the import to be restricted',\n },\n namedImports: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'The named imports to be restricted. If not provided, all named imports will be restricted.',\n },\n replacement: {\n oneOf: [\n { type: 'string' },\n {\n type: 'object',\n patternProperties: {\n '.*': { type: 'string' },\n },\n },\n ],\n description:\n 'The replacement for the import. If a string is provided, it will be used as the replacement for all imports. If an object is provided, the keys will be used as the pattern and the values will be used as the replacement.',\n },\n },\n required: ['target'],\n additionalProperties: false,\n },\n ],\n },\n },\n ],\n },\n\n create(context) {\n const options = context.options as RuleOptions\n const restrictedPackages = createRestrictedPackagesMap(options[0])\n\n return {\n ImportDeclaration(node) {\n const importNode = node as unknown as ImportDeclaration\n if (importNode.source.type !== 'Literal') return\n\n const importSource = importNode.source.value as string\n const namedImports = importNode.specifiers\n .filter((specifier): specifier is ImportSpecifier => specifier.type === 'ImportSpecifier')\n .map((specifier) => getImportedName(specifier.imported))\n const checkerResult = checkIsRestrictedImport(importSource, namedImports, restrictedPackages)\n\n if (!checkerResult) return\n\n const restrictedPackageOptions = restrictedPackages.get(checkerResult.pattern)\n if (!restrictedPackageOptions) return\n\n const patternName = getPatternDisplayName(checkerResult.pattern.source)\n\n if (checkerResult.type === 'module') {\n context.report({\n node,\n messageId:\n typeof restrictedPackageOptions.replacement === 'string'\n ? 'ImportRestrictionWithReplacement'\n : 'ImportRestriction',\n data: {\n name: patternName,\n replacement: restrictedPackageOptions.replacement as string,\n },\n fix: createModuleReplacer(importNode, restrictedPackageOptions.replacement),\n })\n return\n }\n\n // Find potential rules and replacement mappings for multiple restricted named imports\n const importRestrictions: ImportRestriction[] = []\n\n // Check each named import for restrictions\n namedImports.forEach((importName) => {\n for (const [pattern, patternOptions] of restrictedPackages.entries()) {\n if (\n pattern.test(importSource) &&\n patternOptions.namedImports &&\n patternOptions.namedImports.includes(importName) &&\n // TODO: handle options.replacement as an object\n (typeof patternOptions.replacement === 'string' || patternOptions.replacement === null)\n ) {\n importRestrictions.push({\n importName,\n replacement: patternOptions.replacement,\n pattern,\n })\n\n break // Only use the first matching restriction for an import\n }\n }\n })\n\n if (importRestrictions.length === 0) {\n return\n }\n\n // Report separate errors for each restricted import\n importRestrictions.forEach((restriction) => {\n context.report({\n node,\n messageId: restriction.replacement ? 'ImportedNameRestrictionWithReplacement' : 'ImportedNameRestriction',\n data: {\n importedName: restriction.importName,\n name: importSource,\n replacement: restriction.replacement ?? '',\n },\n fix: restriction.replacement\n ? createMultiNamedImportReplacer(context, importNode, importRestrictions)\n : null,\n })\n })\n },\n }\n },\n}\n\nexport default rule\n","import type { ESLint, Linter, Rule } from 'eslint'\nimport restrictImport from './rules/restrict-import'\n\n// Read version from package.json at build time\nconst name = 'eslint-plugin-restrict-replace-import'\nconst version = '2.0.0'\n\nconst rules: Record<string, Rule.RuleModule> = {\n 'restrict-import': restrictImport,\n}\n\n// Legacy config (ESLint < 9)\nconst configs: Record<string, Linter.LegacyConfig> = {\n recommended: {\n plugins: ['restrict-replace-import'],\n rules: {\n 'restrict-replace-import/restrict-import': 'error',\n },\n },\n}\n\n// ESLint v9+ flat configs\nconst flatConfigs: Record<string, Linter.Config> = {\n recommended: {\n plugins: {\n 'restrict-replace-import': {\n meta: { name, version },\n rules,\n },\n },\n rules: {\n 'restrict-replace-import/restrict-import': 'error',\n },\n },\n}\n\nconst plugin: ESLint.Plugin & {\n configs: typeof configs\n flatConfigs: typeof flatConfigs\n} = {\n meta: {\n name,\n version,\n },\n rules,\n configs,\n flatConfigs,\n}\n\nexport = plugin\n\n"],"mappings":"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","names":["name"]}
|