eslint-plugin-import-next 2.3.15 → 2.3.17
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 +1 -1
- package/package.json +3 -3
- package/src/files/foo.js +1 -6
- package/src/files/no-default.js +1 -4
- package/src/index.js +1 -273
- 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 -107
- 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 -139
- 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 -161
- 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 -145
- 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 -139
- 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,134 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.preferTreeShakeableImports = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
const KNOWN_LARGE_PACKAGES = [
|
|
6
|
-
{ name: 'lodash', subpathPattern: 'lodash/{method}', preferNamed: false },
|
|
7
|
-
{ name: '@mui/material', subpathPattern: '@mui/material/{Component}', preferNamed: true },
|
|
8
|
-
{ name: '@mui/icons-material', subpathPattern: '@mui/icons-material/{Icon}', preferNamed: false },
|
|
9
|
-
{ name: '@heroicons/react', preferNamed: false },
|
|
10
|
-
{ name: 'date-fns', preferNamed: true },
|
|
11
|
-
{ name: 'rxjs', preferNamed: true },
|
|
12
|
-
{ name: 'rxjs/operators', preferNamed: true },
|
|
13
|
-
{ name: 'ramda', subpathPattern: 'ramda/src/{fn}', preferNamed: true },
|
|
14
|
-
{ name: '@fortawesome/free-solid-svg-icons', preferNamed: true },
|
|
15
|
-
{ name: '@fortawesome/free-regular-svg-icons', preferNamed: true },
|
|
16
|
-
{ name: 'antd', preferNamed: true },
|
|
17
|
-
{ name: '@ant-design/icons', preferNamed: true },
|
|
18
|
-
];
|
|
19
|
-
function matchesPackage(importPath, packages) {
|
|
20
|
-
for (const pkg of packages) {
|
|
21
|
-
if (importPath === pkg.name || importPath.startsWith(`${pkg.name}/`)) {
|
|
22
|
-
return pkg;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
exports.preferTreeShakeableImports = (0, eslint_devkit_1.createRule)({
|
|
28
|
-
name: 'prefer-tree-shakeable-imports',
|
|
29
|
-
meta: {
|
|
30
|
-
type: 'suggestion',
|
|
31
|
-
docs: {
|
|
32
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md',
|
|
33
|
-
description: 'Prefer import patterns that enable effective tree-shaking',
|
|
34
|
-
},
|
|
35
|
-
hasSuggestions: true,
|
|
36
|
-
messages: {
|
|
37
|
-
namespaceImport: (0, eslint_devkit_1.formatLLMMessage)({
|
|
38
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
39
|
-
issueName: 'Namespace Import Blocks Tree-Shaking',
|
|
40
|
-
description: "Namespace import 'import * as {{alias}} from \"{{source}}\"' prevents tree-shaking. " +
|
|
41
|
-
'The bundler cannot determine which exports are actually used.',
|
|
42
|
-
severity: 'MEDIUM',
|
|
43
|
-
fix: 'Use named imports instead:\n' +
|
|
44
|
-
" ❌ import * as utils from 'lodash';\n" +
|
|
45
|
-
" ✅ import { debounce, throttle } from 'lodash';",
|
|
46
|
-
documentationLink: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md',
|
|
47
|
-
}),
|
|
48
|
-
defaultImportFromLargePackage: (0, eslint_devkit_1.formatLLMMessage)({
|
|
49
|
-
icon: eslint_devkit_1.MessageIcons.INFO,
|
|
50
|
-
issueName: 'Default Import from Large Package',
|
|
51
|
-
description: "Default import from '{{source}}' may include the entire library. " +
|
|
52
|
-
'This package ({{packageHint}}) works better with named or subpath imports.',
|
|
53
|
-
severity: 'LOW',
|
|
54
|
-
fix: 'Use named imports or subpath imports:\n' +
|
|
55
|
-
" ❌ import _ from 'lodash';\n" +
|
|
56
|
-
" ✅ import { debounce } from 'lodash';\n" +
|
|
57
|
-
" ✅ import debounce from 'lodash/debounce';",
|
|
58
|
-
documentationLink: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md',
|
|
59
|
-
}),
|
|
60
|
-
},
|
|
61
|
-
schema: [
|
|
62
|
-
{
|
|
63
|
-
type: 'object',
|
|
64
|
-
properties: {
|
|
65
|
-
targetPackages: {
|
|
66
|
-
type: 'array',
|
|
67
|
-
items: {
|
|
68
|
-
type: 'object',
|
|
69
|
-
properties: {
|
|
70
|
-
name: { type: 'string' },
|
|
71
|
-
subpathPattern: { type: 'string' },
|
|
72
|
-
preferNamed: { type: 'boolean' },
|
|
73
|
-
},
|
|
74
|
-
required: ['name'],
|
|
75
|
-
},
|
|
76
|
-
default: [],
|
|
77
|
-
description: 'Packages to enforce tree-shakeable imports',
|
|
78
|
-
},
|
|
79
|
-
blockAllNamespaceImports: {
|
|
80
|
-
type: 'boolean',
|
|
81
|
-
default: false,
|
|
82
|
-
description: 'Block all namespace imports',
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
additionalProperties: false,
|
|
86
|
-
},
|
|
87
|
-
],
|
|
88
|
-
},
|
|
89
|
-
defaultOptions: [
|
|
90
|
-
{
|
|
91
|
-
targetPackages: KNOWN_LARGE_PACKAGES,
|
|
92
|
-
blockAllNamespaceImports: false,
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
create(context, [options = {}]) {
|
|
96
|
-
const { targetPackages = KNOWN_LARGE_PACKAGES, blockAllNamespaceImports = false, } = options || {};
|
|
97
|
-
return {
|
|
98
|
-
ImportDeclaration(node) {
|
|
99
|
-
const importPath = node.source.value;
|
|
100
|
-
if (typeof importPath !== 'string')
|
|
101
|
-
return;
|
|
102
|
-
const namespaceSpecifier = node.specifiers.find((spec) => spec.type === eslint_devkit_1.AST_NODE_TYPES.ImportNamespaceSpecifier);
|
|
103
|
-
if (namespaceSpecifier) {
|
|
104
|
-
const matchedPackage = matchesPackage(importPath, targetPackages);
|
|
105
|
-
if (matchedPackage || blockAllNamespaceImports) {
|
|
106
|
-
context.report({
|
|
107
|
-
node,
|
|
108
|
-
messageId: 'namespaceImport',
|
|
109
|
-
data: {
|
|
110
|
-
alias: namespaceSpecifier.local.name,
|
|
111
|
-
source: importPath,
|
|
112
|
-
},
|
|
113
|
-
});
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const defaultSpecifier = node.specifiers.find((spec) => spec.type === eslint_devkit_1.AST_NODE_TYPES.ImportDefaultSpecifier);
|
|
118
|
-
if (defaultSpecifier) {
|
|
119
|
-
const matchedPackage = matchesPackage(importPath, targetPackages);
|
|
120
|
-
if (matchedPackage && importPath === matchedPackage.name) {
|
|
121
|
-
context.report({
|
|
122
|
-
node,
|
|
123
|
-
messageId: 'defaultImportFromLargePackage',
|
|
124
|
-
data: {
|
|
125
|
-
source: importPath,
|
|
126
|
-
packageHint: matchedPackage.subpathPattern || 'use named imports',
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
},
|
|
134
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.preferTreeShakeableImports=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const KNOWN_LARGE_PACKAGES=[{name:"lodash",subpathPattern:"lodash/{method}",preferNamed:false},{name:"@mui/material",subpathPattern:"@mui/material/{Component}",preferNamed:true},{name:"@mui/icons-material",subpathPattern:"@mui/icons-material/{Icon}",preferNamed:false},{name:"@heroicons/react",preferNamed:false},{name:"date-fns",preferNamed:true},{name:"rxjs",preferNamed:true},{name:"rxjs/operators",preferNamed:true},{name:"ramda",subpathPattern:"ramda/src/{fn}",preferNamed:true},{name:"@fortawesome/free-solid-svg-icons",preferNamed:true},{name:"@fortawesome/free-regular-svg-icons",preferNamed:true},{name:"antd",preferNamed:true},{name:"@ant-design/icons",preferNamed:true}];function matchesPackage(importPath,packages){for(const pkg of packages){if(importPath===pkg.name||importPath.startsWith(`${pkg.name}/`)){return pkg}}return null}exports.preferTreeShakeableImports=(0,eslint_devkit_1.createRule)({name:"prefer-tree-shakeable-imports",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md",description:"Prefer import patterns that enable effective tree-shaking"},messages:{namespaceImport:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Namespace Import Blocks Tree-Shaking",description:`Namespace import 'import * as {{alias}} from "{{source}}"' prevents tree-shaking. The bundler cannot determine which exports are actually used.`,severity:"MEDIUM",fix:"Use named imports instead:\n \u274C import * as utils from 'lodash';\n \u2705 import { debounce, throttle } from 'lodash';",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md"}),defaultImportFromLargePackage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Default Import from Large Package",description:"Default import from '{{source}}' may include the entire library. This package ({{packageHint}}) works better with named or subpath imports.",severity:"LOW",fix:"Use named imports or subpath imports:\n \u274C import _ from 'lodash';\n \u2705 import { debounce } from 'lodash';\n \u2705 import debounce from 'lodash/debounce';",documentationLink:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/prefer-tree-shakeable-imports.md"})},schema:[{type:"object",properties:{targetPackages:{type:"array",items:{type:"object",properties:{name:{type:"string"},subpathPattern:{type:"string"},preferNamed:{type:"boolean"}},required:["name"]},default:[],description:"Packages to enforce tree-shakeable imports"},blockAllNamespaceImports:{type:"boolean",default:false,description:"Block all namespace imports"}},additionalProperties:false}]},defaultOptions:[{targetPackages:KNOWN_LARGE_PACKAGES,blockAllNamespaceImports:false}],create(context,[options={}]){const{targetPackages=KNOWN_LARGE_PACKAGES,blockAllNamespaceImports=false}=options||{};return{ImportDeclaration(node){const importPath=node.source.value;if(typeof importPath!=="string")return;const namespaceSpecifier=node.specifiers.find(spec=>spec.type===eslint_devkit_1.AST_NODE_TYPES.ImportNamespaceSpecifier);if(namespaceSpecifier){const matchedPackage=matchesPackage(importPath,targetPackages);if(matchedPackage||blockAllNamespaceImports){context.report({node,messageId:"namespaceImport",data:{alias:namespaceSpecifier.local.name,source:importPath}});return}}const defaultSpecifier=node.specifiers.find(spec=>spec.type===eslint_devkit_1.AST_NODE_TYPES.ImportDefaultSpecifier);if(defaultSpecifier){const matchedPackage=matchesPackage(importPath,targetPackages);if(matchedPackage&&importPath===matchedPackage.name){context.report({node,messageId:"defaultImportFromLargePackage",data:{source:importPath,packageHint:matchedPackage.subpathPattern||"use named imports"}})}}}}}});
|
|
@@ -1,174 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.requireImportApproval = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
function matchPackage(packageName, pattern) {
|
|
6
|
-
if (pattern.endsWith('/*')) {
|
|
7
|
-
const prefix = pattern.slice(0, -2);
|
|
8
|
-
return packageName.startsWith(prefix + '/') || packageName === prefix;
|
|
9
|
-
}
|
|
10
|
-
if (pattern.endsWith('*')) {
|
|
11
|
-
return packageName.startsWith(pattern.slice(0, -1));
|
|
12
|
-
}
|
|
13
|
-
return packageName === pattern;
|
|
14
|
-
}
|
|
15
|
-
function isPackageImport(importPath) {
|
|
16
|
-
return !importPath.startsWith('.') && !importPath.startsWith('/');
|
|
17
|
-
}
|
|
18
|
-
function getPackageName(importPath) {
|
|
19
|
-
if (importPath.startsWith('@')) {
|
|
20
|
-
const parts = importPath.split('/');
|
|
21
|
-
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : importPath;
|
|
22
|
-
}
|
|
23
|
-
return importPath.split('/')[0];
|
|
24
|
-
}
|
|
25
|
-
exports.requireImportApproval = (0, eslint_devkit_1.createRule)({
|
|
26
|
-
name: 'require-import-approval',
|
|
27
|
-
meta: {
|
|
28
|
-
type: 'problem',
|
|
29
|
-
docs: {
|
|
30
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/require-import-approval.md',
|
|
31
|
-
description: 'Enforce explicit approval for high-risk package imports',
|
|
32
|
-
},
|
|
33
|
-
messages: {
|
|
34
|
-
unapprovedPackage: (0, eslint_devkit_1.formatLLMMessage)({
|
|
35
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
36
|
-
issueName: 'Unapproved Package Import',
|
|
37
|
-
description: "Package '{{packageName}}' requires approval before use. " +
|
|
38
|
-
"{{reason}}",
|
|
39
|
-
severity: 'HIGH',
|
|
40
|
-
fix: 'Either:\n' +
|
|
41
|
-
' 1. Submit a package approval request to security team\n' +
|
|
42
|
-
' 2. Use an approved alternative: {{alternative}}\n' +
|
|
43
|
-
' 3. Add to approved packages list in ESLint config',
|
|
44
|
-
documentationLink: '',
|
|
45
|
-
}),
|
|
46
|
-
blockedPackage: (0, eslint_devkit_1.formatLLMMessage)({
|
|
47
|
-
icon: eslint_devkit_1.MessageIcons.SECURITY,
|
|
48
|
-
issueName: 'Blocked Package Import',
|
|
49
|
-
description: "Package '{{packageName}}' is blocked and cannot be used. " +
|
|
50
|
-
"{{reason}}",
|
|
51
|
-
severity: 'CRITICAL',
|
|
52
|
-
fix: 'Use an approved alternative: {{alternative}}\n' +
|
|
53
|
-
'This package has been blocked due to security or policy concerns.',
|
|
54
|
-
documentationLink: '',
|
|
55
|
-
}),
|
|
56
|
-
},
|
|
57
|
-
schema: [
|
|
58
|
-
{
|
|
59
|
-
type: 'object',
|
|
60
|
-
properties: {
|
|
61
|
-
packages: {
|
|
62
|
-
type: 'array',
|
|
63
|
-
items: {
|
|
64
|
-
type: 'object',
|
|
65
|
-
properties: {
|
|
66
|
-
package: { type: 'string' },
|
|
67
|
-
status: { type: 'string', enum: ['approved', 'pending', 'blocked'] },
|
|
68
|
-
reason: { type: 'string' },
|
|
69
|
-
alternative: { type: 'string' },
|
|
70
|
-
approvedBy: { type: 'string' },
|
|
71
|
-
approvedDate: { type: 'string' },
|
|
72
|
-
},
|
|
73
|
-
required: ['package', 'status'],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
defaultPolicy: {
|
|
77
|
-
type: 'string',
|
|
78
|
-
enum: ['allow', 'deny'],
|
|
79
|
-
default: 'allow',
|
|
80
|
-
},
|
|
81
|
-
ignorePatterns: {
|
|
82
|
-
type: 'array',
|
|
83
|
-
items: { type: 'string' },
|
|
84
|
-
default: [],
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
required: ['packages'],
|
|
88
|
-
additionalProperties: false,
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
defaultOptions: [
|
|
93
|
-
{
|
|
94
|
-
packages: [],
|
|
95
|
-
defaultPolicy: 'allow',
|
|
96
|
-
ignorePatterns: [],
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
create(context, [options]) {
|
|
100
|
-
const { packages, defaultPolicy = 'allow', ignorePatterns = [] } = options;
|
|
101
|
-
function checkImport(importPath, node) {
|
|
102
|
-
if (!isPackageImport(importPath))
|
|
103
|
-
return;
|
|
104
|
-
const packageName = getPackageName(importPath);
|
|
105
|
-
for (const pattern of ignorePatterns) {
|
|
106
|
-
if (matchPackage(packageName, pattern))
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const policy = packages.find(p => matchPackage(packageName, p.package));
|
|
110
|
-
if (policy) {
|
|
111
|
-
if (policy.status === 'blocked') {
|
|
112
|
-
context.report({
|
|
113
|
-
node,
|
|
114
|
-
messageId: 'blockedPackage',
|
|
115
|
-
data: {
|
|
116
|
-
packageName,
|
|
117
|
-
reason: policy.reason || 'Policy violation',
|
|
118
|
-
alternative: policy.alternative || 'Contact security team for alternatives',
|
|
119
|
-
},
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
else if (policy.status === 'pending') {
|
|
123
|
-
context.report({
|
|
124
|
-
node,
|
|
125
|
-
messageId: 'unapprovedPackage',
|
|
126
|
-
data: {
|
|
127
|
-
packageName,
|
|
128
|
-
reason: policy.reason || 'Package is pending approval',
|
|
129
|
-
alternative: policy.alternative || 'N/A',
|
|
130
|
-
},
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else if (defaultPolicy === 'deny') {
|
|
135
|
-
context.report({
|
|
136
|
-
node,
|
|
137
|
-
messageId: 'unapprovedPackage',
|
|
138
|
-
data: {
|
|
139
|
-
packageName,
|
|
140
|
-
reason: 'Package not in approved list',
|
|
141
|
-
alternative: 'Check approved packages list',
|
|
142
|
-
},
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return {
|
|
147
|
-
ImportDeclaration(node) {
|
|
148
|
-
const importPath = node.source.value;
|
|
149
|
-
if (typeof importPath === 'string') {
|
|
150
|
-
checkImport(importPath, node);
|
|
151
|
-
}
|
|
152
|
-
},
|
|
153
|
-
ImportExpression(node) {
|
|
154
|
-
if (node.source.type === eslint_devkit_1.AST_NODE_TYPES.Literal) {
|
|
155
|
-
const importPath = node.source.value;
|
|
156
|
-
if (typeof importPath === 'string') {
|
|
157
|
-
checkImport(importPath, node);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
CallExpression(node) {
|
|
162
|
-
if (node.callee.type === eslint_devkit_1.AST_NODE_TYPES.Identifier &&
|
|
163
|
-
node.callee.name === 'require' &&
|
|
164
|
-
node.arguments.length > 0 &&
|
|
165
|
-
node.arguments[0].type === eslint_devkit_1.AST_NODE_TYPES.Literal) {
|
|
166
|
-
const importPath = node.arguments[0].value;
|
|
167
|
-
if (typeof importPath === 'string') {
|
|
168
|
-
checkImport(importPath, node);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
},
|
|
174
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.requireImportApproval=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");function matchPackage(packageName,pattern){if(pattern.endsWith("/*")){const prefix=pattern.slice(0,-2);return packageName.startsWith(prefix+"/")||packageName===prefix}if(pattern.endsWith("*")){return packageName.startsWith(pattern.slice(0,-1))}return packageName===pattern}function isPackageImport(importPath){return!importPath.startsWith(".")&&!importPath.startsWith("/")}function getPackageName(importPath){if(importPath.startsWith("@")){const parts=importPath.split("/");return parts.length>=2?`${parts[0]}/${parts[1]}`:importPath}return importPath.split("/")[0]}exports.requireImportApproval=(0,eslint_devkit_1.createRule)({name:"require-import-approval",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/require-import-approval.md",description:"Enforce explicit approval for high-risk package imports"},messages:{unapprovedPackage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Unapproved Package Import",description:"Package '{{packageName}}' requires approval before use. {{reason}}",severity:"HIGH",fix:"Either:\n 1. Submit a package approval request to security team\n 2. Use an approved alternative: {{alternative}}\n 3. Add to approved packages list in ESLint config",documentationLink:""}),blockedPackage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.SECURITY,issueName:"Blocked Package Import",description:"Package '{{packageName}}' is blocked and cannot be used. {{reason}}",severity:"CRITICAL",fix:"Use an approved alternative: {{alternative}}\nThis package has been blocked due to security or policy concerns.",documentationLink:""})},schema:[{type:"object",properties:{packages:{type:"array",items:{type:"object",properties:{package:{type:"string"},status:{type:"string",enum:["approved","pending","blocked"]},reason:{type:"string"},alternative:{type:"string"},approvedBy:{type:"string"},approvedDate:{type:"string"}},required:["package","status"]}},defaultPolicy:{type:"string",enum:["allow","deny"],default:"allow"},ignorePatterns:{type:"array",items:{type:"string"},default:[]}},required:["packages"],additionalProperties:false}]},defaultOptions:[{packages:[],defaultPolicy:"allow",ignorePatterns:[]}],create(context,[options]){const{packages,defaultPolicy="allow",ignorePatterns=[]}=options;function checkImport(importPath,node){if(!isPackageImport(importPath))return;const packageName=getPackageName(importPath);for(const pattern of ignorePatterns){if(matchPackage(packageName,pattern))return}const policy=packages.find(p=>matchPackage(packageName,p.package));if(policy){if(policy.status==="blocked"){context.report({node,messageId:"blockedPackage",data:{packageName,reason:policy.reason||"Policy violation",alternative:policy.alternative||"Contact security team for alternatives"}})}else if(policy.status==="pending"){context.report({node,messageId:"unapprovedPackage",data:{packageName,reason:policy.reason||"Package is pending approval",alternative:policy.alternative||"N/A"}})}}else if(defaultPolicy==="deny"){context.report({node,messageId:"unapprovedPackage",data:{packageName,reason:"Package not in approved list",alternative:"Check approved packages list"}})}}return{ImportDeclaration(node){const importPath=node.source.value;if(typeof importPath==="string"){checkImport(importPath,node)}},ImportExpression(node){if(node.source.type===eslint_devkit_1.AST_NODE_TYPES.Literal){const importPath=node.source.value;if(typeof importPath==="string"){checkImport(importPath,node)}}},CallExpression(node){if(node.callee.type===eslint_devkit_1.AST_NODE_TYPES.Identifier&&node.callee.name==="require"&&node.arguments.length>0&&node.arguments[0].type===eslint_devkit_1.AST_NODE_TYPES.Literal){const importPath=node.arguments[0].value;if(typeof importPath==="string"){checkImport(importPath,node)}}}}}});
|
package/src/rules/unambiguous.js
CHANGED
|
@@ -1,70 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.unambiguous = void 0;
|
|
4
|
-
const eslint_devkit_1 = require("@interlace/eslint-devkit");
|
|
5
|
-
exports.unambiguous = (0, eslint_devkit_1.createRule)({
|
|
6
|
-
name: 'unambiguous',
|
|
7
|
-
meta: {
|
|
8
|
-
type: 'suggestion',
|
|
9
|
-
docs: {
|
|
10
|
-
url: 'https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/unambiguous.md',
|
|
11
|
-
description: 'Forbid potentially ambiguous parse goal (script vs. module)',
|
|
12
|
-
cwe: 'CWE-1078',
|
|
13
|
-
cvss: 2.5,
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
ambiguous: (0, eslint_devkit_1.formatLLMMessage)({
|
|
17
|
-
icon: eslint_devkit_1.MessageIcons.ARCHITECTURE,
|
|
18
|
-
issueName: 'Ambiguous Module',
|
|
19
|
-
cwe: 'CWE-1078',
|
|
20
|
-
description: 'This file could be parsed as either a script or a module',
|
|
21
|
-
severity: 'LOW',
|
|
22
|
-
fix: 'Add an import, export, or "use strict" directive to clarify the parse goal',
|
|
23
|
-
documentationLink: 'https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md',
|
|
24
|
-
}),
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
},
|
|
28
|
-
defaultOptions: [],
|
|
29
|
-
create(context) {
|
|
30
|
-
let hasModuleSyntax = false;
|
|
31
|
-
return {
|
|
32
|
-
ImportDeclaration() {
|
|
33
|
-
hasModuleSyntax = true;
|
|
34
|
-
},
|
|
35
|
-
ImportExpression() {
|
|
36
|
-
hasModuleSyntax = true;
|
|
37
|
-
},
|
|
38
|
-
ExportDefaultDeclaration() {
|
|
39
|
-
hasModuleSyntax = true;
|
|
40
|
-
},
|
|
41
|
-
ExportNamedDeclaration() {
|
|
42
|
-
hasModuleSyntax = true;
|
|
43
|
-
},
|
|
44
|
-
ExportAllDeclaration() {
|
|
45
|
-
hasModuleSyntax = true;
|
|
46
|
-
},
|
|
47
|
-
'Program:exit'(node) {
|
|
48
|
-
if (hasModuleSyntax) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const hasUseStrict = node.body.some((statement) => statement.type === eslint_devkit_1.AST_NODE_TYPES.ExpressionStatement &&
|
|
52
|
-
statement.expression.type === eslint_devkit_1.AST_NODE_TYPES.Literal &&
|
|
53
|
-
statement.expression.value === 'use strict');
|
|
54
|
-
if (hasUseStrict) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (node.body.length === 0) {
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const hasStatements = node.body.some((statement) => statement.type !== eslint_devkit_1.AST_NODE_TYPES.EmptyStatement);
|
|
61
|
-
if (hasStatements) {
|
|
62
|
-
context.report({
|
|
63
|
-
node,
|
|
64
|
-
messageId: 'ambiguous',
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
},
|
|
70
|
-
});
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.unambiguous=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.unambiguous=(0,eslint_devkit_1.createRule)({name:"unambiguous",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-import-next/docs/rules/unambiguous.md",description:"Forbid potentially ambiguous parse goal (script vs. module)",cwe:"CWE-1078",cvss:2.5},messages:{ambiguous:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.ARCHITECTURE,issueName:"Ambiguous Module",cwe:"CWE-1078",description:"This file could be parsed as either a script or a module",severity:"LOW",fix:'Add an import, export, or "use strict" directive to clarify the parse goal',documentationLink:"https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md"})},schema:[]},defaultOptions:[],create(context){let hasModuleSyntax=false;return{ImportDeclaration(){hasModuleSyntax=true},ImportExpression(){hasModuleSyntax=true},ExportDefaultDeclaration(){hasModuleSyntax=true},ExportNamedDeclaration(){hasModuleSyntax=true},ExportAllDeclaration(){hasModuleSyntax=true},"Program:exit"(node){if(hasModuleSyntax){return}const hasUseStrict=node.body.some(statement=>statement.type===eslint_devkit_1.AST_NODE_TYPES.ExpressionStatement&&statement.expression.type===eslint_devkit_1.AST_NODE_TYPES.Literal&&statement.expression.value==="use strict");if(hasUseStrict){return}if(node.body.length===0){return}const hasStatements=node.body.some(statement=>statement.type!==eslint_devkit_1.AST_NODE_TYPES.EmptyStatement);if(hasStatements){context.report({node,messageId:"ambiguous"})}}}}});
|
package/src/types/index.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});
|
|
@@ -1,23 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.loadTypeScript = loadTypeScript;
|
|
4
|
-
exports.aliasSymbolFlag = aliasSymbolFlag;
|
|
5
|
-
exports.resetTypeScriptPeerCache = resetTypeScriptPeerCache;
|
|
6
|
-
let cached;
|
|
7
|
-
function loadTypeScript() {
|
|
8
|
-
if (cached === undefined) {
|
|
9
|
-
try {
|
|
10
|
-
cached = require('typescript');
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
cached = null;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
return cached;
|
|
17
|
-
}
|
|
18
|
-
function aliasSymbolFlag() {
|
|
19
|
-
return loadTypeScript()?.SymbolFlags.Alias ?? 0;
|
|
20
|
-
}
|
|
21
|
-
function resetTypeScriptPeerCache() {
|
|
22
|
-
cached = undefined;
|
|
23
|
-
}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.loadTypeScript=loadTypeScript;exports.aliasSymbolFlag=aliasSymbolFlag;exports.resetTypeScriptPeerCache=resetTypeScriptPeerCache;let cached;function loadTypeScript(){if(cached===void 0){try{cached=require("typescript")}catch{cached=null}}return cached}function aliasSymbolFlag(){return loadTypeScript()?.SymbolFlags.Alias??0}function resetTypeScriptPeerCache(){cached=void 0}
|