@mui/internal-code-infra 0.0.1 → 0.0.2-canary.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.
Files changed (32) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/package.json +26 -23
  4. package/src/eslint/airbnb/base.mjs +18 -0
  5. package/src/eslint/airbnb/typescript.mjs +126 -0
  6. package/src/eslint/baseConfig.mjs +67 -0
  7. package/src/eslint/docsConfig.mjs +20 -0
  8. package/src/eslint/extensions.mjs +5 -0
  9. package/src/eslint/index.mjs +7 -0
  10. package/src/eslint/material-ui/config.mjs +193 -0
  11. package/src/eslint/material-ui/index.mjs +27 -0
  12. package/src/eslint/material-ui/rules/disallow-active-element-as-key-event-target.mjs +65 -0
  13. package/src/eslint/material-ui/rules/disallow-active-elements-as-key-event-target.test.mjs +71 -0
  14. package/src/eslint/material-ui/rules/disallow-react-api-in-server-components.mjs +64 -0
  15. package/src/eslint/material-ui/rules/docgen-ignore-before-comment.mjs +34 -0
  16. package/src/eslint/material-ui/rules/docgen-ignore-before-comment.test.mjs +56 -0
  17. package/src/eslint/material-ui/rules/mui-name-matches-component-name.mjs +161 -0
  18. package/src/eslint/material-ui/rules/mui-name-matches-component-name.test.mjs +257 -0
  19. package/src/eslint/material-ui/rules/no-empty-box.mjs +60 -0
  20. package/src/eslint/material-ui/rules/no-empty-box.test.mjs +42 -0
  21. package/src/eslint/material-ui/rules/no-restricted-resolved-imports.mjs +95 -0
  22. package/src/eslint/material-ui/rules/no-styled-box.mjs +53 -0
  23. package/src/eslint/material-ui/rules/no-styled-box.test.mjs +75 -0
  24. package/src/eslint/material-ui/rules/rules-of-use-theme-variants.mjs +124 -0
  25. package/src/eslint/material-ui/rules/rules-of-use-theme-variants.test.mjs +149 -0
  26. package/src/eslint/material-ui/rules/straight-quotes.mjs +43 -0
  27. package/src/eslint/material-ui/rules/straight-quotes.test.mjs +69 -0
  28. package/src/eslint/testConfig.mjs +104 -0
  29. package/src/estree-typescript.d.ts +21 -0
  30. package/src/prettier.mjs +34 -0
  31. package/src/setupVitest.ts +14 -0
  32. package/src/untyped-plugins.d.ts +96 -0
@@ -0,0 +1,71 @@
1
+ import eslint from 'eslint';
2
+ import parser from '@typescript-eslint/parser';
3
+ import rule from './disallow-active-element-as-key-event-target.mjs';
4
+
5
+ const ruleTester = new eslint.RuleTester({
6
+ languageOptions: {
7
+ parser,
8
+ parserOptions: { sourceType: 'module' },
9
+ },
10
+ });
11
+
12
+ ruleTester.run('disallow-active-element-as-key-event-target', rule, {
13
+ valid: [
14
+ "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyDown(getByRole('button'), { key: ' ' })",
15
+ "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyDown(document.body, { key: 'Escape' })",
16
+ "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyUp(document.body, { key: 'Tab' })",
17
+ ],
18
+ invalid: [
19
+ {
20
+ code: "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyUp(document.activeElement, { key: 'LeftArrow' })",
21
+ errors: [
22
+ {
23
+ message:
24
+ "Don't use document.activeElement as a target for keyboard events. Prefer the actual element.",
25
+ type: 'MemberExpression',
26
+ },
27
+ ],
28
+ },
29
+ {
30
+ code: "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyDown(document.activeElement, { key: 'DownArrow' })",
31
+ errors: [
32
+ {
33
+ message:
34
+ "Don't use document.activeElement as a target for keyboard events. Prefer the actual element.",
35
+ type: 'MemberExpression',
36
+ },
37
+ ],
38
+ },
39
+ {
40
+ code: "import { fireEvent } from 'any-path';\nfireEvent.keyDown(document.activeElement, { key: 'DownArrow' })",
41
+ errors: [
42
+ {
43
+ message:
44
+ "Don't use document.activeElement as a target for keyboard events. Prefer the actual element.",
45
+ type: 'MemberExpression',
46
+ },
47
+ ],
48
+ },
49
+ {
50
+ code: "fireEvent.keyDown(document.activeElement, { key: 'DownArrow' })",
51
+ errors: [
52
+ {
53
+ message:
54
+ "Don't use document.activeElement as a target for keyboard events. Prefer the actual element.",
55
+ type: 'MemberExpression',
56
+ },
57
+ ],
58
+ },
59
+ {
60
+ // test non-null assertion operator
61
+ code: "import { fireEvent } from '@mui/internal-test-utils';\nfireEvent.keyUp(document.activeElement!, { key: 'LeftArrow' })",
62
+ errors: [
63
+ {
64
+ message:
65
+ "Don't use document.activeElement as a target for keyboard events. Prefer the actual element.",
66
+ type: 'TSNonNullExpression',
67
+ },
68
+ ],
69
+ },
70
+ ],
71
+ });
@@ -0,0 +1,64 @@
1
+ /// @ts-check
2
+
3
+ const REACT_CLIENT_APIS = new Set([
4
+ 'useState',
5
+ 'useEffect',
6
+ 'useLayoutEffect',
7
+ 'useReducer',
8
+ 'useTransition',
9
+ 'createContext',
10
+ ]);
11
+
12
+ /**
13
+ * @param {import('eslint').AST.Program} ast
14
+ * @param {string} directive
15
+ * @returns
16
+ */
17
+ function hasDirective(ast, directive) {
18
+ return ast.body.some(
19
+ (statement) =>
20
+ statement.type === 'ExpressionStatement' &&
21
+ statement.expression.type === 'Literal' &&
22
+ statement.expression.value === directive,
23
+ );
24
+ }
25
+
26
+ export default /** @type {import('eslint').Rule.RuleModule} */ ({
27
+ create(context) {
28
+ let hasUseClientDirective = false;
29
+ let hasUseServerDirective = false;
30
+ return {
31
+ /** @param {import('eslint').AST.Program} node */
32
+ Program(node) {
33
+ hasUseServerDirective = hasDirective(node, 'use server');
34
+ hasUseClientDirective = hasDirective(node, 'use client');
35
+ },
36
+ CallExpression(node) {
37
+ if (
38
+ !hasUseClientDirective &&
39
+ node.callee.type === 'MemberExpression' &&
40
+ node.callee.object.type === 'Identifier' &&
41
+ node.callee.object.name === 'React' &&
42
+ node.callee.property.type === 'Identifier' &&
43
+ REACT_CLIENT_APIS.has(node.callee.property.name)
44
+ ) {
45
+ context.report({
46
+ node,
47
+ message: `Using 'React.${node.callee.property.name}' is forbidden if the file doesn't have a 'use client' directive.`,
48
+ fix(fixer) {
49
+ if (hasUseServerDirective) {
50
+ return null;
51
+ }
52
+
53
+ const firstToken = context.sourceCode.ast.body[0];
54
+ return fixer.insertTextBefore(firstToken, "'use client';\n");
55
+ },
56
+ });
57
+ }
58
+ },
59
+ };
60
+ },
61
+ meta: {
62
+ fixable: 'code',
63
+ },
64
+ });
@@ -0,0 +1,34 @@
1
+ export default /** @type {import('eslint').Rule.RuleModule} */ ({
2
+ meta: {
3
+ messages: {
4
+ ignoreBeforeComment: '@ignore should be at the beginning of a block comment.',
5
+ },
6
+ },
7
+ create: (context) => {
8
+ const { sourceCode } = context;
9
+ sourceCode.getAllComments().forEach((comment) => {
10
+ if (comment.type !== 'Block') {
11
+ return;
12
+ }
13
+
14
+ /**
15
+ * The regex has 5 groups (mostly for readability) that match:
16
+ * 1. '/**',
17
+ * 2. One or more comment lines beginning with '*',
18
+ * 3. '* @ignore',
19
+ * 4. Any number of comment lines beginning with '*',
20
+ * 5. '* /' (without the space).
21
+ *
22
+ * All lines can begin with any number of spaces.
23
+ */
24
+ if (comment.value.match(/( *\*\n)( *\*.*\n)+( *\* @ignore\n)( *\*.*\n)*( )/)) {
25
+ context.report({
26
+ node: comment,
27
+ messageId: 'ignoreBeforeComment',
28
+ });
29
+ }
30
+ });
31
+
32
+ return {};
33
+ },
34
+ });
@@ -0,0 +1,56 @@
1
+ import eslint from 'eslint';
2
+ import parser from '@typescript-eslint/parser';
3
+ import rule from './docgen-ignore-before-comment.mjs';
4
+
5
+ const ruleTester = new eslint.RuleTester({
6
+ languageOptions: {
7
+ parser,
8
+ },
9
+ });
10
+
11
+ ruleTester.run('ignore-before-comment', rule, {
12
+ valid: [
13
+ '\n/**\n * @ignore\n */\n',
14
+ '\n/**\n * @ignore\n * Comment.\n */\n',
15
+ '\n/**\n * @ignore\n * Multi-line\n * comment.\n */\n',
16
+ '\n /**\n * @ignore\n * Indented\n * multi-line\n * comment.\n */\n',
17
+ ],
18
+ invalid: [
19
+ {
20
+ code: '\n/**\n * Comment.\n * @ignore\n */\n',
21
+ errors: [
22
+ {
23
+ message: '@ignore should be at the beginning of a block comment.',
24
+ type: 'Block',
25
+ },
26
+ ],
27
+ },
28
+ {
29
+ code: '\n /**\n * Multi-line\n * comment.\n * @ignore\n */\n',
30
+ errors: [
31
+ {
32
+ message: '@ignore should be at the beginning of a block comment.',
33
+ type: 'Block',
34
+ },
35
+ ],
36
+ },
37
+ {
38
+ code: '\n /**\n * Multi-line\n * @ignore\n * comment.\n */\n',
39
+ errors: [
40
+ {
41
+ message: '@ignore should be at the beginning of a block comment.',
42
+ type: 'Block',
43
+ },
44
+ ],
45
+ },
46
+ {
47
+ code: '\n /**\n * Indented\n * multi-line\n * comment.\n * @ignore\n */\n',
48
+ errors: [
49
+ {
50
+ message: '@ignore should be at the beginning of a block comment.',
51
+ type: 'Block',
52
+ },
53
+ ],
54
+ },
55
+ ],
56
+ });
@@ -0,0 +1,161 @@
1
+ /**
2
+ * @type {import('eslint').Rule.RuleModule}
3
+ */
4
+ const rule = {
5
+ meta: {
6
+ messages: {
7
+ nameMismatch: "Expected `name` to be 'Mui{{ componentName }}' but instead got '{{ name }}'.",
8
+ noComponent: 'Unable to find component for this call.',
9
+ noNameProperty: 'Unable to find `name` property. Did you forget to pass `name`?',
10
+ noNameSecondArgument:
11
+ "Unable to find name argument. Expected `{{ customHook }}(firstParameter, 'MuiComponent')`.",
12
+ noNameValue:
13
+ 'Unable to resolve `name`. Please hardcode the `name` i.e. use a string literal.',
14
+ },
15
+ schema: [
16
+ {
17
+ type: 'object',
18
+ properties: {
19
+ customHooks: {
20
+ type: 'array',
21
+ items: {
22
+ type: 'string',
23
+ },
24
+ },
25
+ },
26
+ additionalProperties: false,
27
+ },
28
+ ],
29
+ },
30
+ create(context) {
31
+ const [options = {}] = context.options;
32
+ const { customHooks = [] } = options;
33
+
34
+ /**
35
+ * Resolves the name literal from the useThemeProps call.
36
+ * @param {import('estree').CallExpression & import('eslint').Rule.NodeParentExtension} node
37
+ */
38
+ function resolveUseThemePropsNameLiteral(node) {
39
+ const firstArg = /** @type {import('estree').ObjectExpression} */ (node.arguments[0]);
40
+ if (!firstArg.properties) {
41
+ return null;
42
+ }
43
+ const nameProperty = firstArg.properties.find(
44
+ (property) =>
45
+ property.type === 'Property' &&
46
+ /** @type {import('estree').Identifier} */ (property.key).name === 'name',
47
+ );
48
+ if (nameProperty === undefined) {
49
+ context.report({
50
+ node: firstArg,
51
+ messageId: 'noNameProperty',
52
+ });
53
+ return null;
54
+ }
55
+ if (nameProperty.type === 'Property' && nameProperty.value.type !== 'Literal') {
56
+ context.report({ node: nameProperty.value, messageId: 'noNameValue' });
57
+ return null;
58
+ }
59
+ return /** @type {import('estree').Property} */ (nameProperty).value;
60
+ }
61
+
62
+ /**
63
+ * Resolves the name literal from the useThemeProps call.
64
+ * @param {import('estree').CallExpression & import('eslint').Rule.NodeParentExtension} node
65
+ */
66
+ function resolveCustomHookNameLiteral(node) {
67
+ const secondArgument = node.arguments[1];
68
+ if (secondArgument === undefined) {
69
+ context.report({
70
+ node: node.arguments[0],
71
+ messageId: 'noNameSecondArgument',
72
+ data: { customHook: /** @type {import('estree').Identifier} */ (node.callee).name },
73
+ });
74
+ return null;
75
+ }
76
+ if (secondArgument.type !== 'Literal') {
77
+ context.report({ node: secondArgument, messageId: 'noNameValue' });
78
+ return null;
79
+ }
80
+ return secondArgument;
81
+ }
82
+
83
+ return {
84
+ CallExpression(node) {
85
+ let nameLiteral = null;
86
+ const callee = /** @type {import('estree').Identifier} */ (node.callee);
87
+ const isUseDefaultPropsCall =
88
+ callee.name === 'useDefaultProps' || callee.name === 'useThemeProps';
89
+ if (isUseDefaultPropsCall) {
90
+ let isCalledFromCustomHook = false;
91
+ let { parent } = node;
92
+ while (parent != null) {
93
+ if (parent.type === 'FunctionExpression' || parent.type === 'FunctionDeclaration') {
94
+ if (
95
+ customHooks.includes(/** @type {import('estree').Identifier} */ (parent.id).name)
96
+ ) {
97
+ isCalledFromCustomHook = true;
98
+ }
99
+ break;
100
+ }
101
+
102
+ parent = parent.parent;
103
+ }
104
+ if (!isCalledFromCustomHook) {
105
+ nameLiteral = resolveUseThemePropsNameLiteral(node);
106
+ }
107
+ } else if (
108
+ customHooks.includes(/** @type {import('estree').Identifier} */ (node.callee).name)
109
+ ) {
110
+ nameLiteral = resolveCustomHookNameLiteral(node);
111
+ }
112
+
113
+ if (nameLiteral !== null) {
114
+ let componentName = null;
115
+ let { parent } = node;
116
+ while (parent != null && componentName === null) {
117
+ if (parent.type === 'FunctionExpression' || parent.type === 'FunctionDeclaration') {
118
+ componentName = /** @type {import('estree').Identifier} */ (parent.id).name;
119
+ }
120
+
121
+ if (
122
+ parent.type === 'VariableDeclarator' &&
123
+ parent.init &&
124
+ (parent.init.type === 'CallExpression' || parent.init.type === 'TSAsExpression')
125
+ ) {
126
+ const parentCallee =
127
+ parent.init.type === 'TSAsExpression'
128
+ ? /** @type {import('estree').CallExpression} */ (parent.init.expression).callee
129
+ : parent.init.callee;
130
+ if (
131
+ /** @type {import('estree').Identifier} */ (parentCallee).name.includes(
132
+ /** @type {import('estree').Identifier} */ (parent.id).name,
133
+ )
134
+ ) {
135
+ // For component factory, for example const Container = createContainer({ ... })
136
+ componentName = /** @type {import('estree').Identifier} */ (parent.id).name;
137
+ }
138
+ }
139
+
140
+ parent = parent.parent;
141
+ }
142
+
143
+ const name = /** @type {string} */ (
144
+ /** @type {import('estree').Literal} */ (nameLiteral).value
145
+ );
146
+ if (componentName === null) {
147
+ context.report({ node, messageId: 'noComponent' });
148
+ } else if (name !== `Mui${componentName}`) {
149
+ context.report({
150
+ node: nameLiteral,
151
+ messageId: `nameMismatch`,
152
+ data: { componentName, name },
153
+ });
154
+ }
155
+ }
156
+ },
157
+ };
158
+ },
159
+ };
160
+
161
+ export default rule;
@@ -0,0 +1,257 @@
1
+ import eslint from 'eslint';
2
+ import parser from '@typescript-eslint/parser';
3
+ import rule from './mui-name-matches-component-name.mjs';
4
+
5
+ const ruleTester = new eslint.RuleTester({
6
+ languageOptions: {
7
+ parser,
8
+ },
9
+ });
10
+
11
+ ruleTester.run('mui-name-matches-component-name', rule, {
12
+ valid: [
13
+ // useThemeProps
14
+ `
15
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
16
+ inProps: StaticDateRangePickerProps<TDate>,
17
+ ref: React.Ref<HTMLDivElement>,
18
+ ) {
19
+ const props = useThemeProps({ props: inProps, name: 'MuiStaticDateRangePicker' });
20
+ });
21
+ `,
22
+ `
23
+ function CssBaseline(inProps) {
24
+ useThemeProps({ props: inProps, name: 'MuiCssBaseline' });
25
+ }
26
+ `,
27
+ `
28
+ const Container = createContainer({
29
+ createStyledComponent: styled('div', {
30
+ name: 'MuiContainer',
31
+ slot: 'Root',
32
+ overridesResolver: (props, styles) => {
33
+ const { ownerState } = props;
34
+
35
+ return [
36
+ styles.root,
37
+ ownerState.fixed && styles.fixed,
38
+ ownerState.disableGutters && styles.disableGutters,
39
+ ];
40
+ },
41
+ }),
42
+ useThemeProps: (inProps) => useThemeProps({ props: inProps, name: 'MuiContainer' }),
43
+ });
44
+ `,
45
+ `
46
+ const Grid = createGrid({
47
+ createStyledComponent: styled('div', {
48
+ name: 'MuiGrid',
49
+ overridesResolver: (props, styles) => styles.root,
50
+ }),
51
+ componentName: 'MuiGrid',
52
+ useThemeProps: (inProps) => useThemeProps({ props: inProps, name: 'MuiGrid' }),
53
+ }) as OverridableComponent<GridTypeMap>;
54
+ `,
55
+ {
56
+ code: `
57
+ function useDatePickerDefaultizedProps(props, name) {
58
+ useThemeProps({ props, name });
59
+ }
60
+ `,
61
+ options: [{ customHooks: ['useDatePickerDefaultizedProps'] }],
62
+ },
63
+ // ================
64
+ // useDefaultProps
65
+ `
66
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
67
+ inProps: StaticDateRangePickerProps<TDate>,
68
+ ref: React.Ref<HTMLDivElement>,
69
+ ) {
70
+ const props = useDefaultProps({ props: inProps, name: 'MuiStaticDateRangePicker' });
71
+ });
72
+ `,
73
+ `
74
+ function CssBaseline(inProps) {
75
+ useDefaultProps({ props: inProps, name: 'MuiCssBaseline' });
76
+ }
77
+ `,
78
+ `
79
+ const Container = createContainer({
80
+ createStyledComponent: styled('div', {
81
+ name: 'MuiContainer',
82
+ slot: 'Root',
83
+ overridesResolver: (props, styles) => {
84
+ const { ownerState } = props;
85
+
86
+ return [
87
+ styles.root,
88
+ ownerState.fixed && styles.fixed,
89
+ ownerState.disableGutters && styles.disableGutters,
90
+ ];
91
+ },
92
+ }),
93
+ useDefaultProps: (inProps) => useDefaultProps({ props: inProps, name: 'MuiContainer' }),
94
+ });
95
+ `,
96
+ `
97
+ const Grid = createGrid({
98
+ createStyledComponent: styled('div', {
99
+ name: 'MuiGrid',
100
+ overridesResolver: (props, styles) => styles.root,
101
+ }),
102
+ componentName: 'MuiGrid',
103
+ useDefaultProps: (inProps) => useDefaultProps({ props: inProps, name: 'MuiGrid' }),
104
+ }) as OverridableComponent<GridTypeMap>;
105
+ `,
106
+ {
107
+ code: `
108
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
109
+ inProps: StaticDateRangePickerProps<TDate>,
110
+ ref: React.Ref<HTMLDivElement>,
111
+ ) {
112
+ const props = useDatePickerDefaultizedProps(inProps, 'MuiStaticDateRangePicker');
113
+ });
114
+ `,
115
+ options: [{ customHooks: ['useDatePickerDefaultizedProps'] }],
116
+ },
117
+ {
118
+ code: `
119
+ function useDatePickerDefaultizedProps(props, name) {
120
+ useDefaultProps({ props, name });
121
+ }
122
+ `,
123
+ options: [{ customHooks: ['useDatePickerDefaultizedProps'] }],
124
+ },
125
+ ],
126
+ invalid: [
127
+ // useThemeProps
128
+ {
129
+ code: `
130
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
131
+ inProps: StaticDateRangePickerProps<TDate>,
132
+ ref: React.Ref<HTMLDivElement>,
133
+ ) {
134
+ const props = useThemeProps({ props: inProps, name: 'MuiPickersDateRangePicker' });
135
+ });
136
+ `,
137
+ errors: [
138
+ {
139
+ message:
140
+ "Expected `name` to be 'MuiStaticDateRangePicker' but instead got 'MuiPickersDateRangePicker'.",
141
+ type: 'Literal',
142
+ },
143
+ ],
144
+ },
145
+ {
146
+ code: 'useThemeProps({ props: inProps })',
147
+ errors: [
148
+ {
149
+ message: 'Unable to find `name` property. Did you forget to pass `name`?',
150
+ type: 'ObjectExpression',
151
+ },
152
+ ],
153
+ },
154
+ {
155
+ code: 'useThemeProps({ props: inProps, name })',
156
+ errors: [
157
+ {
158
+ message:
159
+ 'Unable to resolve `name`. Please hardcode the `name` i.e. use a string literal.',
160
+ type: 'Identifier',
161
+ },
162
+ ],
163
+ },
164
+ {
165
+ code: "useThemeProps({ props: inProps, name: 'MuiPickersDateRangePicker' })",
166
+ errors: [
167
+ {
168
+ message: 'Unable to find component for this call.',
169
+ type: 'CallExpression',
170
+ },
171
+ ],
172
+ },
173
+ {
174
+ code: `
175
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
176
+ inProps: StaticDateRangePickerProps<TDate>,
177
+ ref: React.Ref<HTMLDivElement>,
178
+ ) {
179
+ const props = useDatePickerDefaultizedProps(inProps, 'MuiPickersDateRangePicker');
180
+ });
181
+ `,
182
+ options: [{ customHooks: ['useDatePickerDefaultizedProps'] }],
183
+ errors: [
184
+ {
185
+ message:
186
+ "Expected `name` to be 'MuiStaticDateRangePicker' but instead got 'MuiPickersDateRangePicker'.",
187
+ type: 'Literal',
188
+ },
189
+ ],
190
+ },
191
+ // ================
192
+ // useDefaultProps
193
+ {
194
+ code: `
195
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
196
+ inProps: StaticDateRangePickerProps<TDate>,
197
+ ref: React.Ref<HTMLDivElement>,
198
+ ) {
199
+ const props = useDefaultProps({ props: inProps, name: 'MuiPickersDateRangePicker' });
200
+ });
201
+ `,
202
+ errors: [
203
+ {
204
+ message:
205
+ "Expected `name` to be 'MuiStaticDateRangePicker' but instead got 'MuiPickersDateRangePicker'.",
206
+ type: 'Literal',
207
+ },
208
+ ],
209
+ },
210
+ {
211
+ code: 'useDefaultProps({ props: inProps })',
212
+ errors: [
213
+ {
214
+ message: 'Unable to find `name` property. Did you forget to pass `name`?',
215
+ type: 'ObjectExpression',
216
+ },
217
+ ],
218
+ },
219
+ {
220
+ code: 'useDefaultProps({ props: inProps, name })',
221
+ errors: [
222
+ {
223
+ message:
224
+ 'Unable to resolve `name`. Please hardcode the `name` i.e. use a string literal.',
225
+ type: 'Identifier',
226
+ },
227
+ ],
228
+ },
229
+ {
230
+ code: "useDefaultProps({ props: inProps, name: 'MuiPickersDateRangePicker' })",
231
+ errors: [
232
+ {
233
+ message: 'Unable to find component for this call.',
234
+ type: 'CallExpression',
235
+ },
236
+ ],
237
+ },
238
+ {
239
+ code: `
240
+ const StaticDateRangePicker = React.forwardRef(function StaticDateRangePicker<TDate>(
241
+ inProps: StaticDateRangePickerProps<TDate>,
242
+ ref: React.Ref<HTMLDivElement>,
243
+ ) {
244
+ const props = useDatePickerDefaultizedProps(inProps);
245
+ });
246
+ `,
247
+ options: [{ customHooks: ['useDatePickerDefaultizedProps'] }],
248
+ errors: [
249
+ {
250
+ message:
251
+ "Unable to find name argument. Expected `useDatePickerDefaultizedProps(firstParameter, 'MuiComponent')`.",
252
+ type: 'Identifier',
253
+ },
254
+ ],
255
+ },
256
+ ],
257
+ });