eslint-plugin-import-next 2.3.14 → 2.3.16
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/package.json +9 -4
- package/src/files/foo.js +1 -6
- package/src/files/no-default.js +1 -4
- package/src/index.js +1 -326
- package/src/oxlint.js +1 -3
- package/src/rules/consistent-type-specifier-style.js +1 -109
- package/src/rules/default.js +1 -56
- package/src/rules/dynamic-import-chunkname.js +1 -115
- package/src/rules/enforce-dependency-direction.js +1 -213
- package/src/rules/enforce-import-order.js +1 -299
- package/src/rules/enforce-team-boundaries.js +1 -191
- package/src/rules/export.js +1 -111
- package/src/rules/exports-last.js +1 -67
- package/src/rules/extensions.js +1 -105
- package/src/rules/first.js +1 -53
- package/src/rules/group-exports.js +1 -69
- package/src/rules/max-dependencies.js +1 -241
- package/src/rules/named.js +1 -67
- package/src/rules/namespace.js +1 -64
- package/src/rules/newline-after-import.js +1 -57
- package/src/rules/no-absolute-path.js +1 -107
- package/src/rules/no-amd.js +1 -108
- package/src/rules/no-anonymous-default-export.js +1 -135
- package/src/rules/no-barrel-file.js +1 -194
- package/src/rules/no-barrel-import.js +1 -135
- package/src/rules/no-commonjs.js +1 -312
- package/src/rules/no-cross-domain-imports.js +1 -233
- package/src/rules/no-cycle.js +2 -396
- package/src/rules/no-default-export.js +2 -213
- package/src/rules/no-deprecated.js +1 -316
- package/src/rules/no-duplicates.js +1 -81
- package/src/rules/no-dynamic-require.js +1 -78
- package/src/rules/no-empty-named-blocks.js +1 -103
- package/src/rules/no-extraneous-dependencies.js +7 -385
- package/src/rules/no-full-package-import.js +1 -134
- package/src/rules/no-import-module-exports.js +1 -76
- package/src/rules/no-internal-modules.js +1 -256
- package/src/rules/no-legacy-imports.js +1 -125
- package/src/rules/no-mutable-exports.js +1 -146
- package/src/rules/no-named-as-default-member.js +1 -73
- package/src/rules/no-named-as-default.js +1 -90
- package/src/rules/no-named-default.js +1 -48
- package/src/rules/no-named-export.js +1 -174
- package/src/rules/no-namespace.js +1 -71
- package/src/rules/no-nodejs-modules.js +1 -229
- package/src/rules/no-relative-packages.js +1 -129
- package/src/rules/no-relative-parent-imports.js +1 -118
- package/src/rules/no-restricted-paths.js +1 -89
- package/src/rules/no-self-import.js +1 -113
- package/src/rules/no-unassigned-import.js +1 -115
- package/src/rules/no-unresolved.js +1 -189
- package/src/rules/no-unused-modules.js +1 -82
- package/src/rules/no-useless-path-segments.js +1 -107
- package/src/rules/prefer-default-export.js +1 -188
- package/src/rules/prefer-direct-import.js +1 -170
- package/src/rules/prefer-modern-api.js +1 -212
- package/src/rules/prefer-node-protocol.js +1 -174
- package/src/rules/prefer-tree-shakeable-imports.js +1 -134
- package/src/rules/require-import-approval.js +1 -174
- package/src/rules/unambiguous.js +1 -70
- package/src/types/index.js +1 -2
- package/src/utils/typescript-peer.js +1 -23
|
@@ -1,90 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noNamedAsDefault = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noNamedAsDefault = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-named-as-default',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'problem',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-as-default.md',
|
|
11
|
-
description: 'Forbid use of exported name as identifier of default export',
|
|
12
|
-
cwe: 'CWE-1078',
|
|
13
|
-
cvss: 5,
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
namedAsDefault: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.ARCHITECTURE,
|
|
18
|
-
issueName: 'Named as Default',
|
|
19
|
-
cwe: 'CWE-1078',
|
|
20
|
-
description: 'Using exported name "{{name}}" as default import may shadow the named export',
|
|
21
|
-
severity: 'MEDIUM',
|
|
22
|
-
fix: 'Use a different name for the default import or import the named export instead',
|
|
23
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default.md',
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
const exportedNames = new Set();
|
|
31
|
-
let defaultExportName = null;
|
|
32
|
-
return {
|
|
33
|
-
ExportNamedDeclaration(node) {
|
|
34
|
-
if (node.declaration) {
|
|
35
|
-
if ((node.declaration.type === 'FunctionDeclaration' ||
|
|
36
|
-
node.declaration.type === 'ClassDeclaration') &&
|
|
37
|
-
node.declaration.id) {
|
|
38
|
-
exportedNames.add(node.declaration.id.name);
|
|
39
|
-
}
|
|
40
|
-
else if (node.declaration.type === 'VariableDeclaration') {
|
|
41
|
-
node.declaration.declarations.forEach((decl) => {
|
|
42
|
-
if (decl.id.type === 'Identifier') {
|
|
43
|
-
exportedNames.add(decl.id.name);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
node.specifiers.forEach((spec) => {
|
|
49
|
-
if (spec.exported.type === 'Identifier') {
|
|
50
|
-
exportedNames.add(spec.exported.name);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
},
|
|
54
|
-
ExportDefaultDeclaration(node) {
|
|
55
|
-
if (node.declaration.type === 'Identifier') {
|
|
56
|
-
defaultExportName = node.declaration.name;
|
|
57
|
-
}
|
|
58
|
-
else if ((node.declaration.type === 'FunctionDeclaration' ||
|
|
59
|
-
node.declaration.type === 'ClassDeclaration') &&
|
|
60
|
-
node.declaration.id) {
|
|
61
|
-
defaultExportName = node.declaration.id.name;
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
'Program:exit'() {
|
|
65
|
-
if (defaultExportName && exportedNames.has(defaultExportName)) {
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
ImportDeclaration(node) {
|
|
69
|
-
const defaultSpec = node.specifiers.find((s) => s.type === 'ImportDefaultSpecifier');
|
|
70
|
-
if (!defaultSpec)
|
|
71
|
-
return;
|
|
72
|
-
const defaultName = defaultSpec.local.name;
|
|
73
|
-
const namedSpecs = node.specifiers.filter((s) => s.type === 'ImportSpecifier');
|
|
74
|
-
for (const namedSpec of namedSpecs) {
|
|
75
|
-
const importedName = namedSpec.imported.type === 'Identifier'
|
|
76
|
-
? namedSpec.imported.name
|
|
77
|
-
: namedSpec.imported.value;
|
|
78
|
-
if (importedName === defaultName) {
|
|
79
|
-
context.report({
|
|
80
|
-
node: defaultSpec,
|
|
81
|
-
messageId: 'namedAsDefault',
|
|
82
|
-
data: { name: defaultName },
|
|
83
|
-
});
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
};
|
|
89
|
-
},
|
|
90
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noNamedAsDefault=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noNamedAsDefault=(0,eslint_devkit_1.createRule)({name:"no-named-as-default",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-as-default.md",description:"Forbid use of exported name as identifier of default export",cwe:"CWE-1078",cvss:5},messages:{namedAsDefault:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Named as Default",cwe:"CWE-1078",description:'Using exported name "{{name}}" as default import may shadow the named export',severity:"MEDIUM",fix:"Use a different name for the default import or import the named export instead",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default.md"})},schema:[]},defaultOptions:[],create(context){const exportedNames=new Set;let defaultExportName=null;return{ExportNamedDeclaration(node){if(node.declaration){if((node.declaration.type==="FunctionDeclaration"||node.declaration.type==="ClassDeclaration")&&node.declaration.id){exportedNames.add(node.declaration.id.name)}else if(node.declaration.type==="VariableDeclaration"){node.declaration.declarations.forEach(decl=>{if(decl.id.type==="Identifier"){exportedNames.add(decl.id.name)}})}}node.specifiers.forEach(spec=>{if(spec.exported.type==="Identifier"){exportedNames.add(spec.exported.name)}})},ExportDefaultDeclaration(node){if(node.declaration.type==="Identifier"){defaultExportName=node.declaration.name}else if((node.declaration.type==="FunctionDeclaration"||node.declaration.type==="ClassDeclaration")&&node.declaration.id){defaultExportName=node.declaration.id.name}},"Program:exit"(){if(defaultExportName&&exportedNames.has(defaultExportName)){}},ImportDeclaration(node){const defaultSpec=node.specifiers.find(s=>s.type==="ImportDefaultSpecifier");if(!defaultSpec)return;const defaultName=defaultSpec.local.name;const namedSpecs=node.specifiers.filter(s=>s.type==="ImportSpecifier");for(const namedSpec of namedSpecs){const importedName=namedSpec.imported.type==="Identifier"?namedSpec.imported.name:namedSpec.imported.value;if(importedName===defaultName){context.report({node:defaultSpec,messageId:"namedAsDefault",data:{name:defaultName}});break}}}}}});
|
|
@@ -1,48 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noNamedDefault = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noNamedDefault = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-named-default',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'suggestion',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-default.md',
|
|
11
|
-
description: 'Forbid named default exports',
|
|
12
|
-
cwe: 'CWE-1078',
|
|
13
|
-
cvss: 2.5,
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
namedDefault: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.ARCHITECTURE,
|
|
18
|
-
issueName: 'Named Default Import',
|
|
19
|
-
cwe: 'CWE-1078',
|
|
20
|
-
description: 'Using named import of default export',
|
|
21
|
-
severity: 'LOW',
|
|
22
|
-
fix: 'Use default import syntax: import foo from "..." instead of import { default as foo } from "..."',
|
|
23
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-default.md',
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
return {
|
|
31
|
-
ImportDeclaration(node) {
|
|
32
|
-
node.specifiers.forEach((spec) => {
|
|
33
|
-
if (spec.type === 'ImportSpecifier') {
|
|
34
|
-
const importedName = spec.imported.type === 'Identifier'
|
|
35
|
-
? spec.imported.name
|
|
36
|
-
: spec.imported.value;
|
|
37
|
-
if (importedName === 'default') {
|
|
38
|
-
context.report({
|
|
39
|
-
node: spec,
|
|
40
|
-
messageId: 'namedDefault',
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
},
|
|
48
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noNamedDefault=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noNamedDefault=(0,eslint_devkit_1.createRule)({name:"no-named-default",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-default.md",description:"Forbid named default exports",cwe:"CWE-1078",cvss:2.5},messages:{namedDefault:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Named Default Import",cwe:"CWE-1078",description:"Using named import of default export",severity:"LOW",fix:'Use default import syntax: import foo from "..." instead of import { default as foo } from "..."',documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-default.md"})},schema:[]},defaultOptions:[],create(context){return{ImportDeclaration(node){node.specifiers.forEach(spec=>{if(spec.type==="ImportSpecifier"){const importedName=spec.imported.type==="Identifier"?spec.imported.name:spec.imported.value;if(importedName==="default"){context.report({node:spec,messageId:"namedDefault"})}}})}}}});
|
|
@@ -1,174 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noNamedExport = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
-
exports.noNamedExport = (0, eslint_devkit_1.createRule)({
|
|
7
|
-
name: 'no-named-export',
|
|
8
|
-
meta: {
|
|
9
|
-
type: 'problem',
|
|
10
|
-
docs: {
|
|
11
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-export.md',
|
|
12
|
-
description: 'Prevents named exports',
|
|
13
|
-
},
|
|
14
|
-
hasSuggestions: false,
|
|
15
|
-
messages: {
|
|
16
|
-
namedExport: (0, eslint_devkit_2.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_2.MessageIcons.ARCHITECTURE,
|
|
18
|
-
issueName: 'Named Export Detected',
|
|
19
|
-
description: 'Named export violates import style guidelines',
|
|
20
|
-
severity: 'MEDIUM',
|
|
21
|
-
fix: 'Use default export instead of named export',
|
|
22
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-export.md',
|
|
23
|
-
}),
|
|
24
|
-
suggestDefault: (0, eslint_devkit_2.formatLLMMessage)({
|
|
25
|
-
icon: eslint_devkit_2.MessageIcons.INFO,
|
|
26
|
-
issueName: 'Use Default Export',
|
|
27
|
-
description: 'Convert to default export',
|
|
28
|
-
severity: 'LOW',
|
|
29
|
-
fix: 'export default MyComponent;',
|
|
30
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-export.md',
|
|
31
|
-
}),
|
|
32
|
-
},
|
|
33
|
-
schema: [
|
|
34
|
-
{
|
|
35
|
-
type: 'object',
|
|
36
|
-
properties: {
|
|
37
|
-
allowInFiles: {
|
|
38
|
-
type: 'array',
|
|
39
|
-
items: {
|
|
40
|
-
type: 'string',
|
|
41
|
-
},
|
|
42
|
-
description: 'Allow named exports in specific files.',
|
|
43
|
-
},
|
|
44
|
-
allowNames: {
|
|
45
|
-
type: 'array',
|
|
46
|
-
items: {
|
|
47
|
-
type: 'string',
|
|
48
|
-
},
|
|
49
|
-
description: 'Allow specific named exports.',
|
|
50
|
-
},
|
|
51
|
-
allowPatterns: {
|
|
52
|
-
type: 'array',
|
|
53
|
-
items: {
|
|
54
|
-
type: 'string',
|
|
55
|
-
},
|
|
56
|
-
description: 'Allow named exports for specific patterns.',
|
|
57
|
-
},
|
|
58
|
-
suggestDefault: {
|
|
59
|
-
type: 'boolean',
|
|
60
|
-
default: true,
|
|
61
|
-
description: 'Suggest default export alternative.',
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
additionalProperties: false,
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
},
|
|
68
|
-
defaultOptions: [
|
|
69
|
-
{
|
|
70
|
-
allowInFiles: [],
|
|
71
|
-
allowNames: [],
|
|
72
|
-
allowPatterns: [],
|
|
73
|
-
suggestDefault: true,
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
create(context) {
|
|
77
|
-
const [options] = context.options;
|
|
78
|
-
const { allowInFiles = [], allowNames = [], allowPatterns = [], } = options || {};
|
|
79
|
-
const filename = context.filename;
|
|
80
|
-
function shouldAllow(specifier) {
|
|
81
|
-
if (!filename) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
const allowedByFile = allowInFiles.some((pattern) => {
|
|
85
|
-
if (pattern.includes('*')) {
|
|
86
|
-
const regexStr = '^' + pattern
|
|
87
|
-
.replace(/[.+?^${}()|[\]\\]/g, (match) => {
|
|
88
|
-
return '\\' + match;
|
|
89
|
-
})
|
|
90
|
-
.replace(/\*\*/g, '.*')
|
|
91
|
-
.replace(/\*/g, '[^/]*') + '$';
|
|
92
|
-
const regex = new RegExp(regexStr);
|
|
93
|
-
return regex.test(filename);
|
|
94
|
-
}
|
|
95
|
-
return filename.includes(pattern);
|
|
96
|
-
});
|
|
97
|
-
if (allowedByFile) {
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
const allowedByPattern = allowPatterns.some((pattern) => {
|
|
101
|
-
if (pattern.includes('*')) {
|
|
102
|
-
const regexStr = '^' + pattern
|
|
103
|
-
.replace(/[.+?^${}()|[\]\\]/g, (match) => {
|
|
104
|
-
return '\\' + match;
|
|
105
|
-
})
|
|
106
|
-
.replace(/\*\*/g, '.*')
|
|
107
|
-
.replace(/\*/g, '[^/]*') + '$';
|
|
108
|
-
const regex = new RegExp(regexStr);
|
|
109
|
-
return regex.test(filename);
|
|
110
|
-
}
|
|
111
|
-
return filename.includes(pattern);
|
|
112
|
-
});
|
|
113
|
-
if (allowedByPattern) {
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
if (specifier &&
|
|
117
|
-
specifier.exported.type === 'Identifier' &&
|
|
118
|
-
allowNames.includes(specifier.exported.name)) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
return {
|
|
124
|
-
ExportNamedDeclaration(node) {
|
|
125
|
-
if (node.exportKind === 'type' ||
|
|
126
|
-
(node.declaration &&
|
|
127
|
-
(node.declaration.type === 'TSInterfaceDeclaration' ||
|
|
128
|
-
node.declaration.type === 'TSTypeAliasDeclaration'))) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (node.specifiers && node.specifiers.length > 0) {
|
|
132
|
-
for (const specifier of node.specifiers) {
|
|
133
|
-
if (specifier.exported.type === 'Identifier' &&
|
|
134
|
-
specifier.exported.name !== 'default' &&
|
|
135
|
-
!shouldAllow(specifier)) {
|
|
136
|
-
if (specifier.exportKind !== 'type') {
|
|
137
|
-
context.report({
|
|
138
|
-
node: specifier,
|
|
139
|
-
messageId: 'namedExport',
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else if (node.declaration) {
|
|
146
|
-
if (node.declaration.type === 'VariableDeclaration') {
|
|
147
|
-
for (const declarator of node.declaration.declarations) {
|
|
148
|
-
const varName = declarator.id.type === 'Identifier'
|
|
149
|
-
? declarator.id.name
|
|
150
|
-
: undefined;
|
|
151
|
-
const isAllowed = (varName && allowNames.includes(varName)) || shouldAllow();
|
|
152
|
-
if (!isAllowed) {
|
|
153
|
-
context.report({
|
|
154
|
-
node: declarator,
|
|
155
|
-
messageId: 'namedExport',
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
else if (node.declaration.type === 'FunctionDeclaration' ||
|
|
161
|
-
node.declaration.type === 'ClassDeclaration') {
|
|
162
|
-
const name = node.declaration.id?.name;
|
|
163
|
-
if (name && !allowNames.includes(name) && !shouldAllow()) {
|
|
164
|
-
context.report({
|
|
165
|
-
node: node.declaration,
|
|
166
|
-
messageId: 'namedExport',
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
},
|
|
174
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noNamedExport=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");exports.noNamedExport=(0,eslint_devkit_1.createRule)({name:"no-named-export",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-named-export.md",description:"Prevents named exports"},hasSuggestions:false,messages:{namedExport:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Named Export Detected",description:"Named export violates import style guidelines",severity:"MEDIUM",fix:"Use default export instead of named export",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-export.md"}),suggestDefault:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.INFO,issueName:"Use Default Export",description:"Convert to default export",severity:"LOW",fix:"export default MyComponent;",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-export.md"})},schema:[{type:"object",properties:{allowInFiles:{type:"array",items:{type:"string"},description:"Allow named exports in specific files."},allowNames:{type:"array",items:{type:"string"},description:"Allow specific named exports."},allowPatterns:{type:"array",items:{type:"string"},description:"Allow named exports for specific patterns."},suggestDefault:{type:"boolean",default:true,description:"Suggest default export alternative."}},additionalProperties:false}]},defaultOptions:[{allowInFiles:[],allowNames:[],allowPatterns:[],suggestDefault:true}],create(context){const[options]=context.options;const{allowInFiles=[],allowNames=[],allowPatterns=[]}=options||{};const filename=context.filename;function shouldAllow(specifier){if(!filename){return false}const allowedByFile=allowInFiles.some(pattern=>{if(pattern.includes("*")){const regexStr="^"+pattern.replace(/[.+?^${}()|[\]\\]/g,match=>{return"\\"+match}).replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$";const regex=new RegExp(regexStr);return regex.test(filename)}return filename.includes(pattern)});if(allowedByFile){return true}const allowedByPattern=allowPatterns.some(pattern=>{if(pattern.includes("*")){const regexStr="^"+pattern.replace(/[.+?^${}()|[\]\\]/g,match=>{return"\\"+match}).replace(/\*\*/g,".*").replace(/\*/g,"[^/]*")+"$";const regex=new RegExp(regexStr);return regex.test(filename)}return filename.includes(pattern)});if(allowedByPattern){return true}if(specifier&&specifier.exported.type==="Identifier"&&allowNames.includes(specifier.exported.name)){return true}return false}return{ExportNamedDeclaration(node){if(node.exportKind==="type"||node.declaration&&(node.declaration.type==="TSInterfaceDeclaration"||node.declaration.type==="TSTypeAliasDeclaration")){return}if(node.specifiers&&node.specifiers.length>0){for(const specifier of node.specifiers){if(specifier.exported.type==="Identifier"&&specifier.exported.name!=="default"&&!shouldAllow(specifier)){if(specifier.exportKind!=="type"){context.report({node:specifier,messageId:"namedExport"})}}}}else if(node.declaration){if(node.declaration.type==="VariableDeclaration"){for(const declarator of node.declaration.declarations){const varName=declarator.id.type==="Identifier"?declarator.id.name:void 0;const isAllowed=varName&&allowNames.includes(varName)||shouldAllow();if(!isAllowed){context.report({node:declarator,messageId:"namedExport"})}}}else if(node.declaration.type==="FunctionDeclaration"||node.declaration.type==="ClassDeclaration"){const name=node.declaration.id?.name;if(name&&!allowNames.includes(name)&&!shouldAllow()){context.report({node:node.declaration,messageId:"namedExport"})}}}}}}});
|
|
@@ -1,71 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noNamespace = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.noNamespace = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'no-namespace',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'suggestion',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-namespace.md',
|
|
11
|
-
description: 'Forbid namespace (a.k.a. "wildcard" *) imports',
|
|
12
|
-
cwe: 'CWE-1078',
|
|
13
|
-
cvss: 2.5,
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
noNamespace: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.ARCHITECTURE,
|
|
18
|
-
issueName: 'Namespace Import',
|
|
19
|
-
cwe: 'CWE-1078',
|
|
20
|
-
description: 'Namespace imports are not recommended',
|
|
21
|
-
severity: 'LOW',
|
|
22
|
-
fix: 'Use named imports instead: import { foo, bar } from "..."',
|
|
23
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-namespace.md',
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
schema: [
|
|
27
|
-
{
|
|
28
|
-
type: 'object',
|
|
29
|
-
properties: {
|
|
30
|
-
ignore: {
|
|
31
|
-
type: 'array',
|
|
32
|
-
items: { type: 'string' },
|
|
33
|
-
},
|
|
34
|
-
},
|
|
35
|
-
additionalProperties: false,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
},
|
|
39
|
-
defaultOptions: [{ ignore: [] }],
|
|
40
|
-
create(context) {
|
|
41
|
-
const options = context.options[0] || {};
|
|
42
|
-
const ignorePatterns = options.ignore || [];
|
|
43
|
-
function isIgnored(source) {
|
|
44
|
-
return ignorePatterns.some((pattern) => {
|
|
45
|
-
const escaped = pattern.replace(/[.+^${}()|[\]\\*?]/g, '\\$&');
|
|
46
|
-
const regex = new RegExp('^' +
|
|
47
|
-
escaped
|
|
48
|
-
.replace(/\\\*/g, '.*')
|
|
49
|
-
.replace(/\\\?/g, '.') +
|
|
50
|
-
'$');
|
|
51
|
-
return regex.test(source);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
ImportDeclaration(node) {
|
|
56
|
-
const source = node.source.value;
|
|
57
|
-
if (isIgnored(source)) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
node.specifiers.forEach((spec) => {
|
|
61
|
-
if (spec.type === 'ImportNamespaceSpecifier') {
|
|
62
|
-
context.report({
|
|
63
|
-
node: spec,
|
|
64
|
-
messageId: 'noNamespace',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
},
|
|
71
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noNamespace=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.noNamespace=(0,eslint_devkit_1.createRule)({name:"no-namespace",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-namespace.md",description:'Forbid namespace (a.k.a. "wildcard" *) imports',cwe:"CWE-1078",cvss:2.5},messages:{noNamespace:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Namespace Import",cwe:"CWE-1078",description:"Namespace imports are not recommended",severity:"LOW",fix:'Use named imports instead: import { foo, bar } from "..."',documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-namespace.md"})},schema:[{type:"object",properties:{ignore:{type:"array",items:{type:"string"}}},additionalProperties:false}]},defaultOptions:[{ignore:[]}],create(context){const options=context.options[0]||{};const ignorePatterns=options.ignore||[];function isIgnored(source){return ignorePatterns.some(pattern=>{const escaped=pattern.replace(/[.+^${}()|[\]\\*?]/g,"\\$&");const regex=new RegExp("^"+escaped.replace(/\\\*/g,".*").replace(/\\\?/g,".")+"$");return regex.test(source)})}return{ImportDeclaration(node){const source=node.source.value;if(isIgnored(source)){return}node.specifiers.forEach(spec=>{if(spec.type==="ImportNamespaceSpecifier"){context.report({node:spec,messageId:"noNamespace"})}})}}}});
|
|
@@ -1,229 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.noNodejsModules = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const eslint_devkit_2 = require("@interlace/eslint-devkit");
|
|
6
|
-
const NODEJS_BUILTINS = new Set([
|
|
7
|
-
'assert',
|
|
8
|
-
'buffer',
|
|
9
|
-
'child_process',
|
|
10
|
-
'cluster',
|
|
11
|
-
'crypto',
|
|
12
|
-
'dgram',
|
|
13
|
-
'dns',
|
|
14
|
-
'domain',
|
|
15
|
-
'events',
|
|
16
|
-
'fs',
|
|
17
|
-
'http',
|
|
18
|
-
'https',
|
|
19
|
-
'net',
|
|
20
|
-
'os',
|
|
21
|
-
'path',
|
|
22
|
-
'punycode',
|
|
23
|
-
'querystring',
|
|
24
|
-
'readline',
|
|
25
|
-
'stream',
|
|
26
|
-
'string_decoder',
|
|
27
|
-
'timers',
|
|
28
|
-
'tls',
|
|
29
|
-
'tty',
|
|
30
|
-
'url',
|
|
31
|
-
'util',
|
|
32
|
-
'v8',
|
|
33
|
-
'vm',
|
|
34
|
-
'zlib',
|
|
35
|
-
'constants',
|
|
36
|
-
'module',
|
|
37
|
-
'process',
|
|
38
|
-
]);
|
|
39
|
-
const BUILTIN_ALTERNATIVES = {
|
|
40
|
-
fs: 'Use platform-specific file APIs or isomorphic libraries',
|
|
41
|
-
path: 'Use URL constructor or path utilities from your bundler',
|
|
42
|
-
crypto: 'Use Web Crypto API (crypto.subtle) or crypto libraries',
|
|
43
|
-
buffer: 'Use Uint8Array or ArrayBuffer for binary data',
|
|
44
|
-
child_process: 'Use Web Workers or platform-specific APIs',
|
|
45
|
-
os: 'Use navigator.userAgent or platform detection libraries',
|
|
46
|
-
http: 'Use fetch() API or HTTP client libraries',
|
|
47
|
-
https: 'Use fetch() API or HTTP client libraries',
|
|
48
|
-
stream: 'Use ReadableStream/WriteableStream or streaming libraries',
|
|
49
|
-
events: 'Use DOM events or event libraries',
|
|
50
|
-
util: 'Use utility libraries or built-in language features',
|
|
51
|
-
url: 'Use URL constructor and URLSearchParams',
|
|
52
|
-
querystring: 'Use URLSearchParams or query parsing libraries',
|
|
53
|
-
timers: 'Use setTimeout/setInterval or timer libraries',
|
|
54
|
-
};
|
|
55
|
-
exports.noNodejsModules = (0, eslint_devkit_1.createRule)({
|
|
56
|
-
name: 'no-nodejs-modules',
|
|
57
|
-
meta: {
|
|
58
|
-
type: 'problem',
|
|
59
|
-
docs: {
|
|
60
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-nodejs-modules.md',
|
|
61
|
-
description: 'Prevents Node.js builtin imports',
|
|
62
|
-
},
|
|
63
|
-
messages: {
|
|
64
|
-
nodejsBuiltinImport: (0, eslint_devkit_2.formatLLMMessage)({
|
|
65
|
-
icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
|
|
66
|
-
issueName: 'Node.js Builtin Import',
|
|
67
|
-
description: 'Node.js builtin module import detected',
|
|
68
|
-
severity: 'HIGH',
|
|
69
|
-
fix: 'Replace with browser-compatible alternative or conditional import',
|
|
70
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md',
|
|
71
|
-
}),
|
|
72
|
-
nodejsBuiltinRequire: (0, eslint_devkit_2.formatLLMMessage)({
|
|
73
|
-
icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
|
|
74
|
-
issueName: 'Node.js Builtin Require',
|
|
75
|
-
description: 'Node.js builtin module require() detected',
|
|
76
|
-
severity: 'HIGH',
|
|
77
|
-
fix: 'Replace with browser-compatible alternative or conditional require',
|
|
78
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md',
|
|
79
|
-
}),
|
|
80
|
-
nodejsBuiltinDynamic: (0, eslint_devkit_2.formatLLMMessage)({
|
|
81
|
-
icon: eslint_devkit_2.MessageIcons.DEVELOPMENT,
|
|
82
|
-
issueName: 'Node.js Builtin Dynamic Import',
|
|
83
|
-
description: 'Node.js builtin module dynamic import detected',
|
|
84
|
-
severity: 'HIGH',
|
|
85
|
-
fix: 'Use conditional dynamic import with browser-compatible fallback',
|
|
86
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md',
|
|
87
|
-
}),
|
|
88
|
-
},
|
|
89
|
-
schema: [
|
|
90
|
-
{
|
|
91
|
-
type: 'object',
|
|
92
|
-
properties: {
|
|
93
|
-
allow: {
|
|
94
|
-
type: 'array',
|
|
95
|
-
items: {
|
|
96
|
-
type: 'string',
|
|
97
|
-
},
|
|
98
|
-
description: 'Node.js builtins to allow.',
|
|
99
|
-
},
|
|
100
|
-
additionalBuiltins: {
|
|
101
|
-
type: 'array',
|
|
102
|
-
items: {
|
|
103
|
-
type: 'string',
|
|
104
|
-
},
|
|
105
|
-
description: 'Additional modules to treat as builtins.',
|
|
106
|
-
},
|
|
107
|
-
suggestAlternatives: {
|
|
108
|
-
type: 'boolean',
|
|
109
|
-
default: true,
|
|
110
|
-
description: 'Suggest browser-compatible alternatives.',
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
additionalProperties: false,
|
|
114
|
-
},
|
|
115
|
-
],
|
|
116
|
-
},
|
|
117
|
-
defaultOptions: [
|
|
118
|
-
{
|
|
119
|
-
allow: [],
|
|
120
|
-
additionalBuiltins: [],
|
|
121
|
-
suggestAlternatives: true,
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
create(context) {
|
|
125
|
-
const [options] = context.options;
|
|
126
|
-
const { allow = [], additionalBuiltins = [], suggestAlternatives = true, } = options || {};
|
|
127
|
-
const allBuiltins = new Set([...NODEJS_BUILTINS, ...additionalBuiltins]);
|
|
128
|
-
const allowedBuiltins = new Set(allow);
|
|
129
|
-
function isNodejsBuiltin(moduleName) {
|
|
130
|
-
if (allBuiltins.has(moduleName)) {
|
|
131
|
-
return !allowedBuiltins.has(moduleName);
|
|
132
|
-
}
|
|
133
|
-
if (moduleName.startsWith('node:')) {
|
|
134
|
-
const builtinName = moduleName.slice(5);
|
|
135
|
-
return (allBuiltins.has(builtinName) && !allowedBuiltins.has(builtinName));
|
|
136
|
-
}
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
function getBuiltinName(moduleName) {
|
|
140
|
-
if (moduleName.startsWith('node:')) {
|
|
141
|
-
return moduleName.slice(5);
|
|
142
|
-
}
|
|
143
|
-
return moduleName;
|
|
144
|
-
}
|
|
145
|
-
function generateAlternativeSuggestion(builtinName) {
|
|
146
|
-
if (!suggestAlternatives) {
|
|
147
|
-
return '';
|
|
148
|
-
}
|
|
149
|
-
const alternative = BUILTIN_ALTERNATIVES[builtinName];
|
|
150
|
-
if (alternative) {
|
|
151
|
-
return `// Alternative: ${alternative}`;
|
|
152
|
-
}
|
|
153
|
-
return '// Consider using a browser-compatible library or conditional import';
|
|
154
|
-
}
|
|
155
|
-
function reportBuiltin(node, moduleName, importType) {
|
|
156
|
-
const builtinName = getBuiltinName(moduleName);
|
|
157
|
-
const alternative = generateAlternativeSuggestion(builtinName);
|
|
158
|
-
let messageId;
|
|
159
|
-
let fixSuggestion;
|
|
160
|
-
switch (importType) {
|
|
161
|
-
case 'static':
|
|
162
|
-
messageId = 'nodejsBuiltinImport';
|
|
163
|
-
fixSuggestion =
|
|
164
|
-
'Use conditional import or browser-compatible alternative';
|
|
165
|
-
break;
|
|
166
|
-
case 'require':
|
|
167
|
-
messageId = 'nodejsBuiltinRequire';
|
|
168
|
-
fixSuggestion =
|
|
169
|
-
'Use dynamic import with fallback or browser-compatible alternative';
|
|
170
|
-
break;
|
|
171
|
-
case 'dynamic':
|
|
172
|
-
messageId = 'nodejsBuiltinDynamic';
|
|
173
|
-
fixSuggestion = 'Add browser-compatible fallback in dynamic import';
|
|
174
|
-
break;
|
|
175
|
-
}
|
|
176
|
-
context.report({
|
|
177
|
-
node,
|
|
178
|
-
messageId,
|
|
179
|
-
data: {
|
|
180
|
-
moduleName,
|
|
181
|
-
builtinName,
|
|
182
|
-
currentFile: context.filename,
|
|
183
|
-
alternative,
|
|
184
|
-
suggestion: fixSuggestion,
|
|
185
|
-
},
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
return {
|
|
189
|
-
ImportDeclaration(node) {
|
|
190
|
-
const moduleName = node.source.value;
|
|
191
|
-
if (typeof moduleName === 'string' && isNodejsBuiltin(moduleName)) {
|
|
192
|
-
reportBuiltin(node.source, moduleName, 'static');
|
|
193
|
-
}
|
|
194
|
-
},
|
|
195
|
-
CallExpression(node) {
|
|
196
|
-
if (node.callee.type === 'Identifier' &&
|
|
197
|
-
node.callee.name === 'require' &&
|
|
198
|
-
node.arguments.length === 1) {
|
|
199
|
-
const arg = node.arguments[0];
|
|
200
|
-
if (arg.type === 'Literal' && typeof arg.value === 'string') {
|
|
201
|
-
const moduleName = arg.value;
|
|
202
|
-
if (isNodejsBuiltin(moduleName)) {
|
|
203
|
-
reportBuiltin(arg, moduleName, 'require');
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
ImportExpression(node) {
|
|
209
|
-
const source = node.source;
|
|
210
|
-
if (source.type === 'Literal' && typeof source.value === 'string') {
|
|
211
|
-
const moduleName = source.value;
|
|
212
|
-
if (isNodejsBuiltin(moduleName)) {
|
|
213
|
-
reportBuiltin(source, moduleName, 'dynamic');
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
TSImportEqualsDeclaration(node) {
|
|
218
|
-
if (node.moduleReference.type === 'TSExternalModuleReference' &&
|
|
219
|
-
node.moduleReference.expression.type === 'Literal' &&
|
|
220
|
-
typeof node.moduleReference.expression.value === 'string') {
|
|
221
|
-
const moduleName = node.moduleReference.expression.value;
|
|
222
|
-
if (isNodejsBuiltin(moduleName)) {
|
|
223
|
-
reportBuiltin(node.moduleReference, moduleName, 'require');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
},
|
|
229
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noNodejsModules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const NODEJS_BUILTINS=new Set(["assert","buffer","child_process","cluster","crypto","dgram","dns","domain","events","fs","http","https","net","os","path","punycode","querystring","readline","stream","string_decoder","timers","tls","tty","url","util","v8","vm","zlib","constants","module","process"]);const BUILTIN_ALTERNATIVES={fs:"Use platform-specific file APIs or isomorphic libraries",path:"Use URL constructor or path utilities from your bundler",crypto:"Use Web Crypto API (crypto.subtle) or crypto libraries",buffer:"Use Uint8Array or ArrayBuffer for binary data",child_process:"Use Web Workers or platform-specific APIs",os:"Use navigator.userAgent or platform detection libraries",http:"Use fetch() API or HTTP client libraries",https:"Use fetch() API or HTTP client libraries",stream:"Use ReadableStream/WriteableStream or streaming libraries",events:"Use DOM events or event libraries",util:"Use utility libraries or built-in language features",url:"Use URL constructor and URLSearchParams",querystring:"Use URLSearchParams or query parsing libraries",timers:"Use setTimeout/setInterval or timer libraries"};exports.noNodejsModules=(0,eslint_devkit_1.createRule)({name:"no-nodejs-modules",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/no-nodejs-modules.md",description:"Prevents Node.js builtin imports"},messages:{nodejsBuiltinImport:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"Node.js Builtin Import",description:"Node.js builtin module import detected",severity:"HIGH",fix:"Replace with browser-compatible alternative or conditional import",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md"}),nodejsBuiltinRequire:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"Node.js Builtin Require",description:"Node.js builtin module require() detected",severity:"HIGH",fix:"Replace with browser-compatible alternative or conditional require",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md"}),nodejsBuiltinDynamic:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.DEVELOPMENT,issueName:"Node.js Builtin Dynamic Import",description:"Node.js builtin module dynamic import detected",severity:"HIGH",fix:"Use conditional dynamic import with browser-compatible fallback",documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md"})},schema:[{type:"object",properties:{allow:{type:"array",items:{type:"string"},description:"Node.js builtins to allow."},additionalBuiltins:{type:"array",items:{type:"string"},description:"Additional modules to treat as builtins."},suggestAlternatives:{type:"boolean",default:true,description:"Suggest browser-compatible alternatives."}},additionalProperties:false}]},defaultOptions:[{allow:[],additionalBuiltins:[],suggestAlternatives:true}],create(context){const[options]=context.options;const{allow=[],additionalBuiltins=[],suggestAlternatives=true}=options||{};const allBuiltins=new Set([...NODEJS_BUILTINS,...additionalBuiltins]);const allowedBuiltins=new Set(allow);function isNodejsBuiltin(moduleName){if(allBuiltins.has(moduleName)){return!allowedBuiltins.has(moduleName)}if(moduleName.startsWith("node:")){const builtinName=moduleName.slice(5);return allBuiltins.has(builtinName)&&!allowedBuiltins.has(builtinName)}return false}function getBuiltinName(moduleName){if(moduleName.startsWith("node:")){return moduleName.slice(5)}return moduleName}function generateAlternativeSuggestion(builtinName){if(!suggestAlternatives){return""}const alternative=BUILTIN_ALTERNATIVES[builtinName];if(alternative){return`// Alternative: ${alternative}`}return"// Consider using a browser-compatible library or conditional import"}function reportBuiltin(node,moduleName,importType){const builtinName=getBuiltinName(moduleName);const alternative=generateAlternativeSuggestion(builtinName);let messageId;let fixSuggestion;switch(importType){case"static":messageId="nodejsBuiltinImport";fixSuggestion="Use conditional import or browser-compatible alternative";break;case"require":messageId="nodejsBuiltinRequire";fixSuggestion="Use dynamic import with fallback or browser-compatible alternative";break;case"dynamic":messageId="nodejsBuiltinDynamic";fixSuggestion="Add browser-compatible fallback in dynamic import";break}context.report({node,messageId,data:{moduleName,builtinName,currentFile:context.filename,alternative,suggestion:fixSuggestion}})}return{ImportDeclaration(node){const moduleName=node.source.value;if(typeof moduleName==="string"&&isNodejsBuiltin(moduleName)){reportBuiltin(node.source,moduleName,"static")}},CallExpression(node){if(node.callee.type==="Identifier"&&node.callee.name==="require"&&node.arguments.length===1){const arg=node.arguments[0];if(arg.type==="Literal"&&typeof arg.value==="string"){const moduleName=arg.value;if(isNodejsBuiltin(moduleName)){reportBuiltin(arg,moduleName,"require")}}}},ImportExpression(node){const source=node.source;if(source.type==="Literal"&&typeof source.value==="string"){const moduleName=source.value;if(isNodejsBuiltin(moduleName)){reportBuiltin(source,moduleName,"dynamic")}}},TSImportEqualsDeclaration(node){if(node.moduleReference.type==="TSExternalModuleReference"&&node.moduleReference.expression.type==="Literal"&&typeof node.moduleReference.expression.value==="string"){const moduleName=node.moduleReference.expression.value;if(isNodejsBuiltin(moduleName)){reportBuiltin(node.moduleReference,moduleName,"require")}}}}}});
|