diff --git a/docs/rules/text-encoding-identifier-case.md b/docs/rules/text-encoding-identifier-case.md
index 7492995349..ba5f7245a3 100644
--- a/docs/rules/text-encoding-identifier-case.md
+++ b/docs/rules/text-encoding-identifier-case.md
@@ -37,3 +37,26 @@ const string = buffer.toString('utf-8');
// ✅
const string = buffer.toString('utf8');
```
+
+## Options
+
+Type: `object`
+
+### withDash
+
+Type: `boolean`\
+Default: `false`
+
+Use WHATWG standard encoding notation with dashes (e.g., `utf-8` instead of `utf8`).
+
+```js
+// ❌
+/* eslint unicorn/text-encoding-identifier-case: ["error", {"withDash": true}] */
+await fs.readFile(file, 'utf8');
+```
+
+```js
+// ✅
+/* eslint unicorn/text-encoding-identifier-case: ["error", {"withDash": true}] */
+await fs.readFile(file, 'utf-8');
+```
diff --git a/rules/text-encoding-identifier-case.js b/rules/text-encoding-identifier-case.js
index 5f2b7818fd..037a9d880b 100644
--- a/rules/text-encoding-identifier-case.js
+++ b/rules/text-encoding-identifier-case.js
@@ -8,12 +8,13 @@ const messages = {
[MESSAGE_ID_SUGGESTION]: 'Replace `{{value}}` with `{{replacement}}`.',
};
-const getReplacement = encoding => {
+const getReplacement = (encoding, withDash) => {
switch (encoding.toLowerCase()) {
// eslint-disable-next-line unicorn/text-encoding-identifier-case
case 'utf-8':
case 'utf8': {
- return 'utf8';
+ // eslint-disable-next-line unicorn/text-encoding-identifier-case
+ return withDash ? 'utf-8' : 'utf8';
}
case 'ascii': {
@@ -34,8 +35,12 @@ const isFsReadFileEncoding = node =>
&& node.parent.arguments[0].type !== 'SpreadElement';
/** @param {import('eslint').Rule.RuleContext} context */
-const create = () => ({
- Literal(node) {
+const create = context => {
+ const {
+ withDash,
+ } = context.options[0];
+
+ context.on('Literal', node => {
if (typeof node.value !== 'string') {
return;
}
@@ -58,7 +63,7 @@ const create = () => ({
const {raw} = node;
const value = raw.slice(1, -1);
- const replacement = getReplacement(value);
+ const replacement = getReplacement(value, withDash);
if (!replacement || replacement === value) {
return;
}
@@ -88,8 +93,20 @@ const create = () => ({
];
return problem;
+ });
+};
+
+const schema = [
+ {
+ type: 'object',
+ additionalProperties: false,
+ properties: {
+ withDash: {
+ type: 'boolean',
+ },
+ },
},
-});
+];
/** @type {import('eslint').Rule.RuleModule} */
const config = {
@@ -102,6 +119,10 @@ const config = {
},
fixable: 'code',
hasSuggestions: true,
+ schema,
+ defaultOptions: [{
+ withDash: false,
+ }],
messages,
},
};
diff --git a/test/snapshots/text-encoding-identifier-case.js.md b/test/snapshots/text-encoding-identifier-case.js.md
index 4a7984e3fd..00c8858638 100644
--- a/test/snapshots/text-encoding-identifier-case.js.md
+++ b/test/snapshots/text-encoding-identifier-case.js.md
@@ -375,7 +375,7 @@ Generated by [AVA](https://avajs.dev).
| ^^^^^^^ Prefer \`utf8\` over \`UTF-8\`.␊
`
-## invalid(1):
+## invalid(20):
> Input
@@ -394,7 +394,7 @@ Generated by [AVA](https://avajs.dev).
1 | ␊
`
-## invalid(2):
+## invalid(21):
> Input
@@ -413,7 +413,7 @@ Generated by [AVA](https://avajs.dev).
1 | ␊
`
-## invalid(3):
+## invalid(22):
> Input
@@ -432,7 +432,7 @@ Generated by [AVA](https://avajs.dev).
1 | ␊
`
-## invalid(4):
+## invalid(23):
> Input
@@ -450,3 +450,355 @@ Generated by [AVA](https://avajs.dev).
Suggestion 1/1: Replace \`ASCII\` with \`ascii\`.␊
1 | ␊
`
+
+## invalid(1): "UTF-8";
+
+> Input
+
+ `␊
+ 1 | "UTF-8";␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | "UTF-8";␊
+ | ^^^^^^^ Prefer \`utf-8\` over \`UTF-8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`UTF-8\` with \`utf-8\`.␊
+ 1 | "utf-8";␊
+ `
+
+## invalid(2): "UTF8";
+
+> Input
+
+ `␊
+ 1 | "UTF8";␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | "UTF8";␊
+ | ^^^^^^ Prefer \`utf-8\` over \`UTF8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`UTF8\` with \`utf-8\`.␊
+ 1 | "utf-8";␊
+ `
+
+## invalid(3): "utf8";
+
+> Input
+
+ `␊
+ 1 | "utf8";␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | "utf8";␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | "utf-8";␊
+ `
+
+## invalid(4): 'utf8';
+
+> Input
+
+ `␊
+ 1 | 'utf8';␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | 'utf8';␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | 'utf-8';␊
+ `
+
+## invalid(5): "Utf8";
+
+> Input
+
+ `␊
+ 1 | "Utf8";␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | "Utf8";␊
+ | ^^^^^^ Prefer \`utf-8\` over \`Utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`Utf8\` with \`utf-8\`.␊
+ 1 | "utf-8";␊
+ `
+
+## invalid(6): "ASCII";
+
+> Input
+
+ `␊
+ 1 | "ASCII";␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | "ASCII";␊
+ | ^^^^^^^ Prefer \`ascii\` over \`ASCII\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`ASCII\` with \`ascii\`.␊
+ 1 | "ascii";␊
+ `
+
+## invalid(7): fs.readFile(file, "utf8",);
+
+> Input
+
+ `␊
+ 1 | fs.readFile(file, "utf8",);␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Output
+
+ `␊
+ 1 | fs.readFile(file, "utf-8",);␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | fs.readFile(file, "utf8",);␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ `
+
+## invalid(8): whatever.readFile(file, "UTF8",)
+
+> Input
+
+ `␊
+ 1 | whatever.readFile(file, "UTF8",)␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Output
+
+ `␊
+ 1 | whatever.readFile(file, "utf-8",)␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | whatever.readFile(file, "UTF8",)␊
+ | ^^^^^^ Prefer \`utf-8\` over \`UTF8\`.␊
+ `
+
+## invalid(9):
+
+> Input
+
+ `␊
+ 1 | ␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | ␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | ␊
+ `
+
+## invalid(10):
+
+> Input
+
+ `␊
+ 1 | ␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | ␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | ␊
+ `
+
+## invalid(11):
+
+> Input
+
+ `␊
+ 1 | ␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | ␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | ␊
+ `
+
+## invalid(12):
+
+> Input
+
+ `␊
+ 1 | ␊
+ `
+
+> Options
+
+ `␊
+ [␊
+ {␊
+ "withDash": true␊
+ }␊
+ ]␊
+ `
+
+> Error 1/1
+
+ `␊
+ > 1 | ␊
+ | ^^^^^^ Prefer \`utf-8\` over \`utf8\`.␊
+ ␊
+ --------------------------------------------------------------------------------␊
+ Suggestion 1/1: Replace \`utf8\` with \`utf-8\`.␊
+ 1 | ␊
+ `
diff --git a/test/snapshots/text-encoding-identifier-case.js.snap b/test/snapshots/text-encoding-identifier-case.js.snap
index 0e93a762c2..9780210a70 100644
Binary files a/test/snapshots/text-encoding-identifier-case.js.snap and b/test/snapshots/text-encoding-identifier-case.js.snap differ
diff --git a/test/text-encoding-identifier-case.js b/test/text-encoding-identifier-case.js
index 2b0930d659..7b50214065 100644
--- a/test/text-encoding-identifier-case.js
+++ b/test/text-encoding-identifier-case.js
@@ -3,6 +3,15 @@ import {getTester} from './utils/test.js';
const {test} = getTester(import.meta);
test.snapshot({
+ testerOptions: {
+ languageOptions: {
+ parserOptions: {
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ },
+ },
valid: [
'`UTF-8`',
'"utf8"',
@@ -12,6 +21,8 @@ test.snapshot({
String.raw`"\u0055tf8"`,
'const ASCII = 1',
'const UTF8 = 1',
+ '',
+ '',
],
invalid: [
'"UTF-8"',
@@ -33,10 +44,14 @@ test.snapshot({
'await fs.readFile(file, "UTF-8",)',
'fs.promises.readFile(file, "UTF-8",)',
'whatever.readFile(file, "UTF-8",)',
+ '',
+ '',
+ '',
+ '',
],
});
-// JSX
+// `withDash` option
test.snapshot({
testerOptions: {
languageOptions: {
@@ -48,13 +63,26 @@ test.snapshot({
},
},
valid: [
- '',
- '',
- ],
+ '`Utf-8`;',
+ '"utf-8";',
+ '" Utf8 ";',
+ '\'utf-8\';',
+ 'const utf8 = 2;',
+ '',
+ '',
+ ].map(code => ({code, options: [{withDash: true}]})),
invalid: [
- '',
- '',
- '',
- '',
- ],
+ '"UTF-8";',
+ '"UTF8";',
+ '"utf8";',
+ '\'utf8\';',
+ '"Utf8";',
+ '"ASCII";',
+ 'fs.readFile(file, "utf8",);',
+ 'whatever.readFile(file, "UTF8",)',
+ '',
+ '',
+ '',
+ '',
+ ].map(code => ({code, options: [{withDash: true}]})),
});