Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text-encoding-identifier-case: Auto fix encoding in fs.{readFile,readFileSync}() #1755

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/rules/text-encoding-identifier-case.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
<!-- RULE_NOTICE -->
✅ *This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.*

💡 *This rule provides [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).*
🔧💡 *This rule is [auto-fixable](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) and provides [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).*
<!-- /RULE_NOTICE -->

- Enforce `'utf8'` for [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding.
- Enforce `'ascii'` for [ASCII](https://en.wikipedia.org/wiki/ASCII) encoding.

This rule only auto-fix encoding in `fs.readFile()` and `fs.readFileSync()`.

## Fail

```js
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ Each rule has emojis denoting:
| [require-post-message-target-origin](docs/rules/require-post-message-target-origin.md) | Enforce using the `targetOrigin` argument with `window.postMessage()`. | | | 💡 |
| [string-content](docs/rules/string-content.md) | Enforce better string content. | | 🔧 | 💡 |
| [template-indent](docs/rules/template-indent.md) | Fix whitespace-insensitive template indentation. | ✅ | 🔧 | |
| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | | 💡 |
| [text-encoding-identifier-case](docs/rules/text-encoding-identifier-case.md) | Enforce consistent case for text encoding identifiers. | ✅ | 🔧 | 💡 |
| [throw-new-error](docs/rules/throw-new-error.md) | Require `new` when throwing an error. | ✅ | 🔧 | |
<!-- /RULES_TABLE -->

Expand Down
42 changes: 33 additions & 9 deletions rules/text-encoding-identifier-case.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ const getReplacement = encoding => {
}
};

// `fs.{readFile,readFileSync}()`
const isFsReadFileEncoding = node =>
node.parent.type === 'CallExpression'
&& !node.parent.optional
&& node.parent.arguments[1] === node
&& node.parent.arguments[0]
&& node.parent.arguments[0].type !== 'SpreadElement'
&& node.parent.callee.type === 'MemberExpression'
&& !node.parent.callee.optional
&& !node.parent.callee.computed
&& node.parent.callee.property.type === 'Identifier'
&& (node.parent.callee.property.name === 'readFile' || node.parent.callee.property.name === 'readFileSync');

/** @param {import('eslint').Rule.RuleContext} context */
const create = () => ({
Literal(node) {
Expand All @@ -39,19 +52,29 @@ const create = () => ({
replacement,
};

return {
/** @param {import('eslint').Rule.RuleFixer} fixer */
const fix = fixer => replaceStringLiteral(fixer, node, replacement);

const problem = {
node,
messageId: MESSAGE_ID_ERROR,
data: messageData,
suggest: [
{
messageId: MESSAGE_ID_SUGGESTION,
data: messageData,
/** @param {import('eslint').Rule.RuleFixer} fixer */
fix: fixer => replaceStringLiteral(fixer, node, replacement),
},
],
};

if (isFsReadFileEncoding(node)) {
problem.fix = fix;
return problem;
}

problem.suggest = [
{
messageId: MESSAGE_ID_SUGGESTION,
data: messageData,
fix: fixer => replaceStringLiteral(fixer, node, replacement),
},
];

return problem;
},
});

Expand All @@ -63,6 +86,7 @@ module.exports = {
docs: {
description: 'Enforce consistent case for text encoding identifiers.',
},
fixable: 'code',
hasSuggestions: true,
messages,
},
Expand Down
198 changes: 195 additions & 3 deletions test/snapshots/text-encoding-identifier-case.mjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,207 @@ Generated by [AVA](https://avajs.dev).
`

## Invalid #6
1 | await fs.readFile(file, "UTF-8",)
1 | fs.readFile?.(file, "UTF-8")

> Error 1/1

`␊
> 1 | await fs.readFile(file, "UTF-8",)␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
> 1 | fs.readFile?.(file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs.readFile?.(file, "utf8")␊
`

## Invalid #7
1 | fs?.readFile(file, "UTF-8")

> Error 1/1

`␊
> 1 | fs?.readFile(file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs?.readFile(file, "utf8")␊
`

## Invalid #8
1 | readFile(file, "UTF-8")

> Error 1/1

`␊
> 1 | readFile(file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | readFile(file, "utf8")␊
`

## Invalid #9
1 | fs.readFile(...file, "UTF-8")

> Error 1/1

`␊
> 1 | fs.readFile(...file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs.readFile(...file, "utf8")␊
`

## Invalid #10
1 | new fs.readFile(file, "UTF-8")

> Error 1/1

`␊
> 1 | new fs.readFile(file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | new fs.readFile(file, "utf8")␊
`

## Invalid #11
1 | fs.readFile(file, {encoding: "UTF-8"})

> Error 1/1

`␊
> 1 | fs.readFile(file, {encoding: "UTF-8"})␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs.readFile(file, {encoding: "utf8"})␊
`

## Invalid #12
1 | fs.readFile("UTF-8")

> Error 1/1

`␊
> 1 | fs.readFile("UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs.readFile("utf8")␊
`

## Invalid #13
1 | fs.readFile(file, "UTF-8", () => {})

> Output

`␊
1 | fs.readFile(file, "utf8", () => {})␊
`

> Error 1/1

`␊
> 1 | fs.readFile(file, "UTF-8", () => {})␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`

## Invalid #14
1 | fs.readFileSync(file, "UTF-8")

> Output

`␊
1 | fs.readFileSync(file, "utf8")␊
`

> Error 1/1

`␊
> 1 | fs.readFileSync(file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`

## Invalid #15
1 | fs[readFile](file, "UTF-8")

> Error 1/1

`␊
> 1 | fs[readFile](file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs[readFile](file, "utf8")␊
`

## Invalid #16
1 | fs["readFile"](file, "UTF-8")

> Error 1/1

`␊
> 1 | fs["readFile"](file, "UTF-8")␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
--------------------------------------------------------------------------------␊
Suggestion 1/1: Replace \`UTF-8\` with \`utf8\`.␊
1 | fs["readFile"](file, "utf8")␊
`

## Invalid #17
1 | await fs.readFile(file, "UTF-8",)

> Output

`␊
1 | await fs.readFile(file, "utf8",)␊
`

> Error 1/1

`␊
> 1 | await fs.readFile(file, "UTF-8",)␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`

## Invalid #18
1 | fs.promises.readFile(file, "UTF-8",)

> Output

`␊
1 | fs.promises.readFile(file, "utf8",)␊
`

> Error 1/1

`␊
> 1 | fs.promises.readFile(file, "UTF-8",)␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`

## Invalid #19
1 | whatever.readFile(file, "UTF-8",)

> Output

`␊
1 | whatever.readFile(file, "utf8",)␊
`

> Error 1/1

`␊
> 1 | whatever.readFile(file, "UTF-8",)␊
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`
Binary file modified test/snapshots/text-encoding-identifier-case.mjs.snap
Binary file not shown.
13 changes: 13 additions & 0 deletions test/text-encoding-identifier-case.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ test.snapshot({
'\'utf-8\'',
'"Utf8"',
'"ASCII"',
'fs.readFile?.(file, "UTF-8")',
'fs?.readFile(file, "UTF-8")',
'readFile(file, "UTF-8")',
'fs.readFile(...file, "UTF-8")',
'new fs.readFile(file, "UTF-8")',
'fs.readFile(file, {encoding: "UTF-8"})',
'fs.readFile("UTF-8")',
'fs.readFile(file, "UTF-8", () => {})',
'fs.readFileSync(file, "UTF-8")',
'fs[readFile](file, "UTF-8")',
'fs["readFile"](file, "UTF-8")',
'await fs.readFile(file, "UTF-8",)',
'fs.promises.readFile(file, "UTF-8",)',
'whatever.readFile(file, "UTF-8",)',
],
});