diff --git a/.changeset/modern-apricots-flash.md b/.changeset/modern-apricots-flash.md new file mode 100644 index 00000000..1901cb47 --- /dev/null +++ b/.changeset/modern-apricots-flash.md @@ -0,0 +1,5 @@ +--- +'@intlify/eslint-plugin-vue-i18n': minor +--- + +add lowercase option to key-format-style rule diff --git a/docs/rules/key-format-style.md b/docs/rules/key-format-style.md index f038388b..38eb8f52 100644 --- a/docs/rules/key-format-style.md +++ b/docs/rules/key-format-style.md @@ -13,6 +13,7 @@ This rule aims to enforces specific casing for localization key names. ```yaml camelCaseKey: The key for this value is camel case. kebab-case-key: The key for this value is kebab case. +lowercase: The key for this value is lower case. snake_case_key: The key for this value is snake case. mixed_Case-key: Perhaps you don't want to use this casing. ``` @@ -47,7 +48,7 @@ Also, the following localization key definitions are reported as errors, because { "@intlify/vue-i18n/key-format-style": [ "error", - "camelCase" | "kebab-case" | "snake_case", + "camelCase" | "kebab-case" | "lowercase" | "snake_case", { "allowArray": false, "splitByDots": false @@ -112,6 +113,32 @@ appTitle: I18N Management System app_title: I18N Management System ``` +:+1: Examples of **correct** code for this rule with `"lowercase"`: + + + +```yaml +# eslint @intlify/vue-i18n/key-format-style: ['error', 'lowercase'] + +# ✓ GOOD +apptitle: I18N Management System +``` + + + +:-1: Examples of **incorrect** code for this rule with `"lowercase"`: + + + +```yaml +# eslint @intlify/vue-i18n/key-format-style: ['error', 'lowercase'] + +# ✗ BAD +appTitle: I18N Management System +app_title: I18N Management System +APP_TITLE: I18N Management System +``` + :+1: Examples of **correct** code for this rule with `"snake_case"`: diff --git a/lib/rules/key-format-style.ts b/lib/rules/key-format-style.ts index 1842a590..30da1611 100644 --- a/lib/rules/key-format-style.ts +++ b/lib/rules/key-format-style.ts @@ -16,6 +16,7 @@ const debug = debugBuilder('eslint-plugin-vue-i18n:key-format-style') const allowedCaseOptions = [ 'camelCase', 'kebab-case', + 'lowercase', 'snake_case', 'SCREAMING_SNAKE_CASE' ] as const diff --git a/lib/utils/casing.ts b/lib/utils/casing.ts index 1c983385..1ee99d7b 100644 --- a/lib/utils/casing.ts +++ b/lib/utils/casing.ts @@ -75,6 +75,20 @@ export function isCamelCase(str: string): boolean { return true } +/** + * Checks whether the given string is lowercase. + */ +export function isLowerCase(str: string): boolean { + if ( + hasSymbols(str) || + hasUpper(str) || + /-|_|\s/u.exec(str) // kebab or snake or space + ) { + return false + } + return true +} + /** * Checks whether the given string is PascalCase. */ @@ -104,6 +118,7 @@ const checkersMap = { 'kebab-case': isKebabCase, snake_case: isSnakeCase, camelCase: isCamelCase, + lowercase: isLowerCase, PascalCase: isPascalCase, SCREAMING_SNAKE_CASE: isScreamingSnakeCase } @@ -127,6 +142,7 @@ export function pascalCase(str: string): string { export const allowedCaseOptions = [ 'camelCase', 'kebab-case', + 'lowercase', 'PascalCase', 'snake_case', 'SCREAMING_SNAKE_CASE' diff --git a/tests/lib/rules/key-format-style.ts b/tests/lib/rules/key-format-style.ts index 71ac624b..9f758413 100644 --- a/tests/lib/rules/key-format-style.ts +++ b/tests/lib/rules/key-format-style.ts @@ -129,6 +129,41 @@ tester.run('key-format-style', rule as never, { ...options.json.file, options: ['kebab-case'] }, + { + code: ` + lowercase: + foobar: kebab-value + `, + ...options.yaml.file + }, + { + code: `{ + "lowercase": { + "foobar": "kebab-value" + } + } + `, + ...options.json.file + }, + { + code: ` + en-US: + lowercase: + foobar: kebab-value + `, + ...options.yaml.key + }, + { + code: `{ + "en-US": { + "lowercase": { + "foobar": "kebab-value" + } + } + } + `, + ...options.json.key + }, { code: ` snake_case: @@ -379,6 +414,136 @@ tester.run('key-format-style', rule as never, { } ] }, + { + code: ` + foo-bar: baz + `, + ...options.yaml.file, + options: ['lowercase'], + errors: [ + { + message: '"foo-bar" is not lowercase', + line: 2 + } + ] + }, + { + code: ` + en-US: + foo-bar: baz + `, + ...options.yaml.key, + options: ['lowercase'], + errors: [ + { + message: '"foo-bar" is not lowercase', + line: 3 + } + ] + }, + { + code: ` + {"foo-bar": "baz"} + `, + ...options.json.file, + options: ['lowercase'], + errors: [ + { + message: '"foo-bar" is not lowercase', + line: 2 + } + ] + }, + { + code: ` + {"en-US": { + "foo-bar": "baz" + }}`, + ...options.json.key, + options: ['lowercase'], + errors: [ + { + message: '"foo-bar" is not lowercase', + line: 3 + } + ] + }, + { + code: ` + kebab-case: + snake_case: camelCase + `, + ...options.yaml.file, + options: ['lowercase'], + errors: [ + { + message: '"kebab-case" is not lowercase', + line: 2 + }, + { + message: '"snake_case" is not lowercase', + line: 3 + } + ] + }, + { + code: `{ + "kebab-case": { + "snake_case": "camelCase" + } + } + `, + ...options.json.file, + options: ['lowercase'], + errors: [ + { + message: '"kebab-case" is not lowercase', + line: 2 + }, + { + message: '"snake_case" is not lowercase', + line: 3 + } + ] + }, + { + code: ` + SCREAMING_SNAKE_CASE: + PascalCase: camelCase + `, + ...options.yaml.file, + options: ['lowercase'], + errors: [ + { + message: '"SCREAMING_SNAKE_CASE" is not lowercase', + line: 2 + }, + { + message: '"PascalCase" is not lowercase', + line: 3 + } + ] + }, + { + code: `{ + "SCREAMING_SNAKE_CASE": { + "PascalCase": "camelCase" + } + } + `, + ...options.json.file, + options: ['lowercase'], + errors: [ + { + message: '"SCREAMING_SNAKE_CASE" is not lowercase', + line: 2 + }, + { + message: '"PascalCase" is not lowercase', + line: 3 + } + ] + }, { code: ` - foo