Skip to content

Commit 8c92e97

Browse files
author
Brijesh Bittu
committed
Sync with changes in core
1 parent d420d80 commit 8c92e97

File tree

4 files changed

+119
-16
lines changed

4 files changed

+119
-16
lines changed

packages/mui-infra/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"eslint-config-airbnb-base": "^15.0.0",
3636
"eslint-config-airbnb": "^19.0.4",
3737
"eslint-config-prettier": "^10.1.5",
38-
"eslint-import-resolver-typescript": "^4.4.1",
38+
"eslint-module-utils": "^2.12.0",
3939
"eslint-plugin-import": "^2.31.0",
4040
"eslint-plugin-jsx-a11y": "^6.10.2",
4141
"eslint-plugin-mocha": "^11.1.0",
@@ -44,6 +44,7 @@
4444
"eslint-plugin-react-hooks": "^6.0.0",
4545
"eslint-plugin-testing-library": "^7.2.2",
4646
"globals": "^16.2.0",
47+
"minimatch": "^10.0.1",
4748
"typescript-eslint": "^8.33.0"
4849
},
4950
"peerDependencies": {

packages/mui-infra/src/eslint/material-ui/index.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import docgenIgnoreBeforeComment from './rules/docgen-ignore-before-comment.mjs'
44
import muiNameMatchesComponentName from './rules/mui-name-matches-component-name.mjs';
55
import noEmptyBox from './rules/no-empty-box.mjs';
66
import noHardcodedLabels from './rules/no-hardcoded-labels.mjs';
7+
import noRestrictedResolvedImports from './rules/no-restricted-resolved-imports.mjs';
78
import noStyledBox from './rules/no-styled-box.mjs';
89
import rulesOfUseThemeVariants from './rules/rules-of-use-theme-variants.mjs';
910
import straightQuotes from './rules/straight-quotes.mjs';
@@ -26,5 +27,6 @@ export default {
2627
'no-styled-box': noStyledBox,
2728
'straight-quotes': straightQuotes,
2829
'disallow-react-api-in-server-components': disallowReactApiInServerComponents,
30+
'no-restricted-resolved-imports': noRestrictedResolvedImports,
2931
},
3032
};
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import moduleVisitorModule from 'eslint-module-utils/moduleVisitor';
2+
import resolveModule from 'eslint-module-utils/resolve';
3+
import { minimatch } from 'minimatch';
4+
import * as path from 'node:path';
5+
6+
const moduleVisitor = moduleVisitorModule.default || moduleVisitorModule;
7+
const resolve = resolveModule.default || resolveModule;
8+
9+
/**
10+
* @typedef {Object} PatternConfig
11+
* @property {string} pattern - The pattern to match against resolved imports
12+
* @property {string} [message] - Custom message to show when the pattern matches
13+
*/
14+
15+
/**
16+
* Creates an ESLint rule that restricts imports based on their resolved paths.
17+
* Works with both ESM (import) and CommonJS (require) imports.
18+
*
19+
* @type {import('eslint').Rule.RuleModule}
20+
*/
21+
export default {
22+
meta: {
23+
docs: {
24+
description: 'Disallow imports that resolve to certain patterns.',
25+
},
26+
messages: {
27+
restrictedResolvedImport:
28+
'Importing from "{{importSource}}" is restricted because it resolves to "{{resolvedPath}}", which matches the pattern "{{pattern}}".{{customMessage}}',
29+
},
30+
type: 'suggestion',
31+
schema: [
32+
{
33+
type: 'array',
34+
items: {
35+
type: 'object',
36+
properties: {
37+
pattern: { type: 'string' },
38+
message: { type: 'string' },
39+
},
40+
required: ['pattern'],
41+
additionalProperties: false,
42+
},
43+
},
44+
],
45+
},
46+
create(context) {
47+
const options = context.options[0] || [];
48+
49+
if (!Array.isArray(options) || options.length === 0) {
50+
return {};
51+
}
52+
53+
return moduleVisitor(
54+
(source, node) => {
55+
// Get the resolved path of the import
56+
const resolvedPath = resolve(source.value, context);
57+
58+
if (!resolvedPath) {
59+
return;
60+
}
61+
62+
// Normalize the resolved path to use forward slashes
63+
const normalizedPath = resolvedPath.split(path.sep).join('/');
64+
65+
// Check each pattern against the resolved path
66+
for (const option of options) {
67+
const { pattern, message = '' } = option;
68+
69+
if (minimatch(normalizedPath, pattern)) {
70+
context.report({
71+
node,
72+
messageId: 'restrictedResolvedImport',
73+
data: {
74+
importSource: source.value,
75+
resolvedPath: normalizedPath,
76+
pattern,
77+
customMessage: message ? ` ${message}` : '',
78+
},
79+
});
80+
81+
// Stop after first match
82+
break;
83+
}
84+
}
85+
},
86+
{ commonjs: true, es6: true },
87+
); // This handles both require() and import statements
88+
},
89+
};

pnpm-lock.yaml

Lines changed: 26 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)