Skip to content

Commit d332fe4

Browse files
committed
Enhance import-style rule with auto-fix capability
- Updated the `import-style` rule to include an `autoFix` option, allowing automatic fixing of import styles. - Modified the rule's documentation to reflect the new `autoFix` feature and its default behavior. - Added test cases to verify the functionality of the new auto-fix feature for various import scenarios. This change improves usability by enabling automatic corrections for import style violations.
1 parent 4e539b4 commit d332fe4

File tree

4 files changed

+119
-1
lines changed

4 files changed

+119
-1
lines changed

Diff for: docs/rules/import-style.md

+18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
💼 This rule is enabled in the ✅ `recommended` [config](https://github.com/sindresorhus/eslint-plugin-unicorn#preset-configs-eslintconfigjs).
44

5+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
6+
57
<!-- end auto-generated rule header -->
68
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` -->
79

@@ -99,3 +101,19 @@ Type: `boolean`\
99101
Default: `true`
100102

101103
Pass `"checkRequire": false` to disable linting of `require` calls completely.
104+
105+
### autoFix
106+
107+
Type: `boolean`\
108+
Default: `true`
109+
110+
Pass `"autoFix": false` to disable automatic fixing of import styles. When disabled, the rule will only report violations without attempting to fix them.
111+
112+
```js
113+
"unicorn/import-style": [
114+
"error",
115+
{
116+
"autoFix": false
117+
}
118+
]
119+
```

Diff for: readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c
123123
| [expiring-todo-comments](docs/rules/expiring-todo-comments.md) | Add expiration conditions to TODO comments. || | |
124124
| [explicit-length-check](docs/rules/explicit-length-check.md) | Enforce explicitly comparing the `length` or `size` property of a value. || 🔧 | 💡 |
125125
| [filename-case](docs/rules/filename-case.md) | Enforce a case style for filenames. || | |
126-
| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. || | |
126+
| [import-style](docs/rules/import-style.md) | Enforce specific import styles per module. || 🔧 | |
127127
| [new-for-builtins](docs/rules/new-for-builtins.md) | Enforce the use of `new` for all builtins, except `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. || 🔧 | |
128128
| [no-abusive-eslint-disable](docs/rules/no-abusive-eslint-disable.md) | Enforce specifying rules to disable in `eslint-disable` comments. || | |
129129
| [no-anonymous-default-export](docs/rules/no-anonymous-default-export.md) | Disallow anonymous functions and classes as the default export. || | 💡 |

Diff for: rules/import-style.js

+24
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ const create = context => {
138138
checkDynamicImport = true,
139139
checkExportFrom = false,
140140
checkRequire = true,
141+
autoFix = false,
141142
} = {},
142143
] = context.options;
143144

@@ -183,6 +184,25 @@ const create = context => {
183184
node,
184185
messageId: MESSAGE_ID,
185186
data,
187+
fix(fixer) {
188+
if (!autoFix) {
189+
return;
190+
}
191+
192+
if (node.type === 'ImportDeclaration' && allowedImportStyles.has('namespace')) {
193+
const importedNames = node.specifiers
194+
.filter(s => s.type === 'ImportSpecifier' || s.type === 'ImportDefaultSpecifier')
195+
.map(s => s.local.name);
196+
197+
if (importedNames.length > 0) {
198+
const namespaceIdentifier = moduleName === 'react' ? 'React' : importedNames[0];
199+
return fixer.replaceText(
200+
node,
201+
`import * as ${namespaceIdentifier} from "${moduleName}"`,
202+
);
203+
}
204+
}
205+
},
186206
});
187207
};
188208

@@ -322,6 +342,9 @@ const schema = {
322342
extendDefaultStyles: {
323343
type: 'boolean',
324344
},
345+
autoFix: {
346+
type: 'boolean',
347+
},
325348
styles: {
326349
$ref: '#/definitions/moduleStyles',
327350
},
@@ -365,6 +388,7 @@ module.exports = {
365388
description: 'Enforce specific import styles per module.',
366389
recommended: true,
367390
},
391+
fixable: 'code',
368392
schema,
369393
defaultOptions: [{}],
370394
messages,

Diff for: test/import-style.mjs

+76
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,82 @@ test({
626626
},
627627
}],
628628
},
629+
630+
{
631+
code: 'import {x} from "namespace"',
632+
output: 'import * as x from "namespace"',
633+
options: [{
634+
styles: {
635+
namespace: {
636+
namespace: true,
637+
named: false,
638+
},
639+
},
640+
autoFix: true,
641+
}],
642+
errors: [namespaceError],
643+
},
644+
{
645+
code: 'import {x, y} from "namespace"',
646+
output: 'import * as x from "namespace"',
647+
options: [{
648+
styles: {
649+
namespace: {
650+
namespace: true,
651+
named: false,
652+
},
653+
},
654+
autoFix: true,
655+
}],
656+
errors: [namespaceError],
657+
},
658+
{
659+
code: 'import {x as y} from "namespace"',
660+
output: 'import * as y from "namespace"',
661+
options: [{
662+
styles: {
663+
namespace: {
664+
namespace: true,
665+
named: false,
666+
},
667+
},
668+
autoFix: true,
669+
}],
670+
errors: [namespaceError],
671+
},
672+
{
673+
code: 'import {x} from "react"',
674+
output: 'import * as React from "react"',
675+
options: [{
676+
styles: {
677+
react: {
678+
namespace: true,
679+
named: false,
680+
},
681+
},
682+
autoFix: true,
683+
}],
684+
errors: [{
685+
messageId: 'importStyle',
686+
data: {
687+
allowedStyles: 'namespace',
688+
moduleName: 'react',
689+
},
690+
}],
691+
},
692+
{
693+
code: 'import {x} from "namespace"',
694+
options: [{
695+
styles: {
696+
namespace: {
697+
namespace: true,
698+
named: false,
699+
},
700+
},
701+
autoFix: false,
702+
}],
703+
errors: [namespaceError],
704+
},
629705
].map(test => addDefaultOptions(test)),
630706
});
631707

0 commit comments

Comments
 (0)