diff --git a/.eslintrc.yaml b/.eslintrc.yaml index f4af8aef..bd61553e 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -18,3 +18,8 @@ plugins: - '@typescript-eslint' rules: '@typescript-eslint/explicit-module-boundary-types': off +overrides: + - files: + - '__tests__/**' + rules: + filenames-simple/extname: off diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e84badb..5664a393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Use `core-js` as replacement of my own polyfill implementation. * [#147](https://github.com/epaew/eslint-plugin-filenames-simple/pull/147) Refactor utils/pluralize: Remove dependency on `eslint` package. +* [#149](https://github.com/epaew/eslint-plugin-filenames-simple/pull/149) +Refactoring: Replace utils/preset-cases with utils/preset-rules. # 0.4.0 ## Features diff --git a/__tests__/test-utils/fetch-rule-names.ts b/__tests__/test-utils/fetch-rule-names.ts index b05f776b..f6f9274f 100644 --- a/__tests__/test-utils/fetch-rule-names.ts +++ b/__tests__/test-utils/fetch-rule-names.ts @@ -1,7 +1,7 @@ import path from 'path'; import glob from 'glob'; -import { presetCaseConverters } from '#/utils/preset-case-converters'; +import { presetRules } from '#/utils/preset-rules'; import { asyncArrayFilter } from './async-array-filter'; export const fetchAllRuleNames = () => @@ -12,7 +12,7 @@ export const fetchAllRuleNames = () => export const fetchAvailableRuleNames = async () => { return asyncArrayFilter(fetchAllRuleNames(), async name => { - const camelizedName = presetCaseConverters['camelCase'](name); + const camelizedName = presetRules.camelCase.recommendationBuilder(name); try { const rule = await import(name); diff --git a/__tests__/utils/get-rule.test.ts b/__tests__/utils/get-rule.test.ts new file mode 100644 index 00000000..328477fc --- /dev/null +++ b/__tests__/utils/get-rule.test.ts @@ -0,0 +1,21 @@ +import { getRule, presetRules } from '#/utils/preset-rules'; + +describe('getRule', () => { + const subject = getRule; + + describe('when the rule is camelCale', () => { + const rule = 'camelCase'; + + it('returns presetRules.camelCase', () => { + expect(subject(rule)).toEqual(presetRules.camelCase); + }); + }); + + describe('when the rule is not defined in presetRules', () => { + const rule = 'index'; + + it('returns a new object with the field `expression` constructed based on the specified rule.', () => { + expect(subject(rule)).toEqual({ expression: new RegExp(`^${rule}$`) }); + }); + }); +}); diff --git a/__tests__/utils/preset-case-converters.test.ts b/__tests__/utils/preset-case-converters.test.ts deleted file mode 100644 index 5abfc8c5..00000000 --- a/__tests__/utils/preset-case-converters.test.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { presetCaseConverters } from '#/utils/preset-case-converters'; - -import targetNames from './seeds.json'; - -describe('PresetConverter of camelCase', () => { - const subject = (name: string) => presetCaseConverters.camelCase(name); - - test('should return same strings when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); - }); - - test('should return same strings when name is camelCase', () => { - expect(targetNames.camelCase.map(subject)).toEqual(targetNames.camelCase); - }); - - test('should return camelized strings when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject)).toEqual([ - 'kebabCase', - 'threeOrMoreWordsIncludingKebabCase', - 'kebab0Case', - 'kebabCase0', - ]); - }); - - test('should return camelized strings when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject)).toEqual([ - 'pascalCase', - 'threeOrMoreWordsIncludingPascalCase', - 'pascal0Case', - 'pascalCase0', - ]); - }); - - test('should return camelized strings when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject)).toEqual([ - 'snakeCase', - 'threeOrMoreWordsIncludingSnakeCase', - 'snake0Case', - 'snakeCase0', - ]); - }); -}); - -describe('PresetConverter of kebab-case', () => { - const subject = (name: string) => presetCaseConverters['kebab-case'](name); - - test('should return same strings when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); - }); - - test('should return hyphenized strings when name is camelCase', () => { - expect(targetNames.camelCase.map(subject)).toEqual([ - 'camel-case', - 'three-or-more-words-including-camel-case', - 'camel0-case', - 'camel-case0', - ]); - }); - - test('should return same strings when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject)).toEqual(targetNames.kebabCase); - }); - - test('should return hyphenized strings when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject)).toEqual([ - 'pascal-case', - 'three-or-more-words-including-pascal-case', - 'pascal0-case', - 'pascal-case0', - ]); - }); - - test('should return hyphenized strings when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject)).toEqual([ - 'snake-case', - 'three-or-more-words-including-snake-case', - 'snake0-case', - 'snake-case0', - ]); - }); -}); - -describe('PresetConverter of PascalCase', () => { - const subject = (name: string) => presetCaseConverters.PascalCase(name); - - test('should return pascalized strings when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject)).toEqual([ - 'Normalcase', - 'Threeormorewordsincludingnormalcase', - 'Normal0case', - 'Normalcase0', - ]); - }); - - test('should return pascalized strings when name is camelCase', () => { - expect(targetNames.camelCase.map(subject)).toEqual([ - 'CamelCase', - 'ThreeOrMoreWordsIncludingCamelCase', - 'Camel0Case', - 'CamelCase0', - ]); - }); - - test('should return pascalized strings when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject)).toEqual([ - 'KebabCase', - 'ThreeOrMoreWordsIncludingKebabCase', - 'Kebab0Case', - 'KebabCase0', - ]); - }); - - test('should return same strings when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject)).toEqual(targetNames.pascalCase); - }); - - test('should return pascalized strings when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject)).toEqual([ - 'SnakeCase', - 'ThreeOrMoreWordsIncludingSnakeCase', - 'Snake0Case', - 'SnakeCase0', - ]); - }); -}); - -describe('PresetConverter of snake_case', () => { - const subject = (name: string) => presetCaseConverters.snake_case(name); - - test('should return same strings when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); - }); - - test('should return underscorized strings when name is camelCase', () => { - expect(targetNames.camelCase.map(subject)).toEqual([ - 'camel_case', - 'three_or_more_words_including_camel_case', - 'camel0_case', - 'camel_case0', - ]); - }); - - test('should return underscorized strings when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject)).toEqual([ - 'kebab_case', - 'three_or_more_words_including_kebab_case', - 'kebab0_case', - 'kebab_case0', - ]); - }); - - test('should return underscorized strings when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject)).toEqual([ - 'pascal_case', - 'three_or_more_words_including_pascal_case', - 'pascal0_case', - 'pascal_case0', - ]); - }); - - test('should return same strings when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject)).toEqual(targetNames.snakeCase); - }); -}); diff --git a/__tests__/utils/preset-cases.test.ts b/__tests__/utils/preset-cases.test.ts deleted file mode 100644 index 04e72ab3..00000000 --- a/__tests__/utils/preset-cases.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { presetCases } from '#/utils/preset-cases'; - -import targetNames from './seeds.json'; - -describe('Preset RegExp of camelCase', () => { - const subject = (name: string) => presetCases.camelCase.test(name); - - test('should return true when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return true when name is camelCase', () => { - expect(targetNames.camelCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is chaos case', () => { - expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); - }); -}); - -describe('Preset RegExp of kebab-case', () => { - const subject = (name: string) => presetCases['kebab-case'].test(name); - - test('should return true when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is camelCase', () => { - expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return true when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is chaos case', () => { - expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); - }); -}); - -describe('Preset RegExp of PascalCase', () => { - const subject = (name: string) => presetCases.PascalCase.test(name); - - test('should return false when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is camelCase', () => { - expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return true when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is chaos case', () => { - expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); - }); -}); - -describe('Preset RegExp of snake_case', () => { - const subject = (name: string) => presetCases.snake_case.test(name); - - test('should return true when name is narmalcase', () => { - expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is camelCase', () => { - expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is kebab-case', () => { - expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return false when name is PascalCase', () => { - expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); - }); - - test('should return true when name is snake_case', () => { - expect(targetNames.snakeCase.map(subject).every(n => n)).toBeTruthy(); - }); - - test('should return false when name is chaos case', () => { - expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); - }); -}); diff --git a/__tests__/utils/preset-rules.PascalCase.test.ts b/__tests__/utils/preset-rules.PascalCase.test.ts new file mode 100644 index 00000000..9ab72335 --- /dev/null +++ b/__tests__/utils/preset-rules.PascalCase.test.ts @@ -0,0 +1,77 @@ +import { presetRules } from '#/utils/preset-rules'; + +import targetNames from './seeds.json'; + +describe('presetRules.PascalCase', () => { + describe('.expression', () => { + const subject = (name: string) => presetRules.PascalCase.expression.test(name); + + test('should return false when name is normalcase', () => { + expect(targetNames.normalCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is camelCase', () => { + expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return true when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is chaos case', () => { + expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); + }); + }); + + describe('.recommendationBuilder', () => { + const subject = (name: string) => presetRules.PascalCase.recommendationBuilder(name); + + test('should return pascalized strings when name is narmalcase', () => { + expect(targetNames.normalCase.map(subject)).toEqual([ + 'Normalcase', + 'Threeormorewordsincludingnormalcase', + 'Normal0case', + 'Normalcase0', + ]); + }); + + test('should return pascalized strings when name is camelCase', () => { + expect(targetNames.camelCase.map(subject)).toEqual([ + 'CamelCase', + 'ThreeOrMoreWordsIncludingCamelCase', + 'Camel0Case', + 'CamelCase0', + ]); + }); + + test('should return pascalized strings when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject)).toEqual([ + 'KebabCase', + 'ThreeOrMoreWordsIncludingKebabCase', + 'Kebab0Case', + 'KebabCase0', + ]); + }); + + test('should return same strings when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject)).toEqual(targetNames.pascalCase); + }); + + test('should return pascalized strings when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject)).toEqual([ + 'SnakeCase', + 'ThreeOrMoreWordsIncludingSnakeCase', + 'Snake0Case', + 'SnakeCase0', + ]); + }); + }); +}); diff --git a/__tests__/utils/preset-rules.camelCase.test.ts b/__tests__/utils/preset-rules.camelCase.test.ts new file mode 100644 index 00000000..583ec470 --- /dev/null +++ b/__tests__/utils/preset-rules.camelCase.test.ts @@ -0,0 +1,72 @@ +import { presetRules } from '#/utils/preset-rules'; + +import targetNames from './seeds.json'; + +describe('presetRules.camelCase', () => { + describe('.expression', () => { + const subject = (name: string) => presetRules.camelCase.expression.test(name); + + test('should return true when name is normalcase', () => { + expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return true when name is camelCase', () => { + expect(targetNames.camelCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is chaos case', () => { + expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); + }); + }); + + describe('.recommendationBuilder', () => { + const subject = (name: string) => presetRules.camelCase.recommendationBuilder(name); + + test('should return same strings when name is narmalcase', () => { + expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); + }); + + test('should return same strings when name is camelCase', () => { + expect(targetNames.camelCase.map(subject)).toEqual(targetNames.camelCase); + }); + + test('should return camelized strings when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject)).toEqual([ + 'kebabCase', + 'threeOrMoreWordsIncludingKebabCase', + 'kebab0Case', + 'kebabCase0', + ]); + }); + + test('should return camelized strings when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject)).toEqual([ + 'pascalCase', + 'threeOrMoreWordsIncludingPascalCase', + 'pascal0Case', + 'pascalCase0', + ]); + }); + + test('should return camelized strings when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject)).toEqual([ + 'snakeCase', + 'threeOrMoreWordsIncludingSnakeCase', + 'snake0Case', + 'snakeCase0', + ]); + }); + }); +}); diff --git a/__tests__/utils/preset-rules.kebab-case.test.ts b/__tests__/utils/preset-rules.kebab-case.test.ts new file mode 100644 index 00000000..517ea098 --- /dev/null +++ b/__tests__/utils/preset-rules.kebab-case.test.ts @@ -0,0 +1,72 @@ +import { presetRules } from '#/utils/preset-rules'; + +import targetNames from './seeds.json'; + +describe('presetRules.kebab-case', () => { + describe('.expression', () => { + const subject = (name: string) => presetRules['kebab-case'].expression.test(name); + + test('should return true when name is normalcase', () => { + expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is camelCase', () => { + expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return true when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is chaos case', () => { + expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); + }); + }); + + describe('.recommendationBuilder', () => { + const subject = (name: string) => presetRules['kebab-case'].recommendationBuilder(name); + + test('should return same strings when name is narmalcase', () => { + expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); + }); + + test('should return hyphenized strings when name is camelCase', () => { + expect(targetNames.camelCase.map(subject)).toEqual([ + 'camel-case', + 'three-or-more-words-including-camel-case', + 'camel0-case', + 'camel-case0', + ]); + }); + + test('should return same strings when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject)).toEqual(targetNames.kebabCase); + }); + + test('should return hyphenized strings when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject)).toEqual([ + 'pascal-case', + 'three-or-more-words-including-pascal-case', + 'pascal0-case', + 'pascal-case0', + ]); + }); + + test('should return hyphenized strings when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject)).toEqual([ + 'snake-case', + 'three-or-more-words-including-snake-case', + 'snake0-case', + 'snake-case0', + ]); + }); + }); +}); diff --git a/__tests__/utils/preset-rules.snake_case.test.ts b/__tests__/utils/preset-rules.snake_case.test.ts new file mode 100644 index 00000000..b25d1f03 --- /dev/null +++ b/__tests__/utils/preset-rules.snake_case.test.ts @@ -0,0 +1,72 @@ +import { presetRules } from '#/utils/preset-rules'; + +import targetNames from './seeds.json'; + +describe('presetRules.snake_case', () => { + describe('.expression', () => { + const subject = (name: string) => presetRules.snake_case.expression.test(name); + + test('should return true when name is normalcase', () => { + expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is camelCase', () => { + expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return false when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy(); + }); + + test('should return true when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject).every(n => n)).toBeTruthy(); + }); + + test('should return false when name is chaos case', () => { + expect(targetNames.chaosCase.map(subject).some(n => n)).toBeFalsy(); + }); + }); + + describe('.recommendationBuilder', () => { + const subject = (name: string) => presetRules.snake_case.recommendationBuilder(name); + + test('should return same strings when name is narmalcase', () => { + expect(targetNames.normalCase.map(subject)).toEqual(targetNames.normalCase); + }); + + test('should return underscorized strings when name is camelCase', () => { + expect(targetNames.camelCase.map(subject)).toEqual([ + 'camel_case', + 'three_or_more_words_including_camel_case', + 'camel0_case', + 'camel_case0', + ]); + }); + + test('should return underscorized strings when name is kebab-case', () => { + expect(targetNames.kebabCase.map(subject)).toEqual([ + 'kebab_case', + 'three_or_more_words_including_kebab_case', + 'kebab0_case', + 'kebab_case0', + ]); + }); + + test('should return underscorized strings when name is PascalCase', () => { + expect(targetNames.pascalCase.map(subject)).toEqual([ + 'pascal_case', + 'three_or_more_words_including_pascal_case', + 'pascal0_case', + 'pascal_case0', + ]); + }); + + test('should return same strings when name is snake_case', () => { + expect(targetNames.snakeCase.map(subject)).toEqual(targetNames.snakeCase); + }); + }); +}); diff --git a/package.json b/package.json index 8ed99915..725dc48d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "eslint:fix": "eslint --fix .", "prepack": "npm-run-all eslint test clean build", "test": "jest", - "test:coverage": "jest --coverage" + "test:coverage": "jest --coverage", + "test:watch": "jest --coverage --watchAll" }, "dependencies": { "core-js": "^3.6.5", diff --git a/src/rules/named-export.ts b/src/rules/named-export.ts index a37623fe..1dd67f52 100644 --- a/src/rules/named-export.ts +++ b/src/rules/named-export.ts @@ -3,7 +3,7 @@ import { Rule } from 'eslint'; import { Identifier, Program, ESTreeParser } from '../utils/estree-parser'; import { isSameName } from '../utils/is-same-name'; -import { presetCaseConverters } from '../utils/preset-case-converters'; +import { presetRules } from '../utils/preset-rules'; import { Pluralize } from '../utils/pluralize'; type PluralizeRule = 'always' | 'singular' | 'plural'; @@ -54,8 +54,8 @@ export const namedExport: Rule.RuleModule = { message: 'The export name must match the filename. You need to rename to {{ pascalCase }} or {{ camelCase }}.', data: { - pascalCase: presetCaseConverters.PascalCase(filename), - camelCase: presetCaseConverters.camelCase(filename), + pascalCase: presetRules.PascalCase.recommendationBuilder(filename), + camelCase: presetRules.camelCase.recommendationBuilder(filename), }, }); }, diff --git a/src/rules/naming-convention.ts b/src/rules/naming-convention.ts index 26c73914..a985b58c 100644 --- a/src/rules/naming-convention.ts +++ b/src/rules/naming-convention.ts @@ -1,8 +1,7 @@ import path from 'path'; import { Rule } from 'eslint'; -import { presetCases } from '../utils/preset-cases'; -import { presetCaseConverters } from '../utils/preset-case-converters'; +import { getRule } from '../utils/preset-rules'; export const namingConvention: Rule.RuleModule = { meta: { @@ -30,11 +29,11 @@ export const namingConvention: Rule.RuleModule = { }, create: context => { - const { rule, excepts }: { rule: string; excepts: string[] } = context.options[0] ?? { + const { rule: ruleName, excepts }: { rule: string; excepts: string[] } = context.options[0] ?? { rule: 'kebab-case', excepts: ['index'], }; - const ruleRegExp = presetCases[rule] ?? new RegExp(`^${rule}$`); + const rule = getRule(ruleName); const exceptRegExps = excepts.map(e => new RegExp(`^${e}$`)); return { @@ -47,16 +46,16 @@ export const namingConvention: Rule.RuleModule = { if (exceptRegExps.some(re => re.test(filename))) return; - if (!ruleRegExp.test(filename)) { + if (!rule.expression.test(filename)) { const suggest = (() => { - if (!presetCaseConverters[rule]) return null; + if (!rule.recommendationBuilder) return null; - const alterName = presetCaseConverters[rule](filename) ?? ''; - if (!ruleRegExp.test(alterName)) return null; + const alterName = rule.recommendationBuilder(filename); + if (!rule.expression.test(alterName)) return null; return ` Should rename to ${[alterName, ...rest].join('.')}.`; })(); - const message = `The filename must follow the rule: '${rule}'.${suggest ?? ''}`; + const message = `The filename must follow the rule: '${ruleName}'.${suggest ?? ''}`; context.report({ node, message }); } diff --git a/src/utils/preset-case-converters.ts b/src/utils/preset-case-converters.ts deleted file mode 100644 index cad1491a..00000000 --- a/src/utils/preset-case-converters.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { splitName } from './split-name'; - -const buildCamelCase = (words: string[]): string => - words - .map((word, i) => { - if (i === 0) return word; - - const [first, ...rest] = word; - return `${first.toUpperCase()}${rest.join('')}`; - }) - .join(''); -const buildKebabCase = (words: string[]): string => words.join('-'); -const buildPascalCase = (words: string[]): string => - words - .map(word => { - const [first, ...rest] = word; - return `${first.toUpperCase()}${rest.join('')}`; - }) - .join(''); -const buildSnakeCase = (words: string[]): string => words.join('_'); - -type PresetCaseConverters = { - camelCase: (name: string) => string; - 'kebab-case': (name: string) => string; - PascalCase: (name: string) => string; - snake_case: (name: string) => string; - [key: string]: (name: string) => string | undefined; -}; - -export const presetCaseConverters: PresetCaseConverters = { - camelCase: name => buildCamelCase(splitName(name)), - 'kebab-case': name => buildKebabCase(splitName(name)), - PascalCase: name => buildPascalCase(splitName(name)), - snake_case: name => buildSnakeCase(splitName(name)), -}; diff --git a/src/utils/preset-cases.ts b/src/utils/preset-cases.ts deleted file mode 100644 index b369024a..00000000 --- a/src/utils/preset-cases.ts +++ /dev/null @@ -1,14 +0,0 @@ -type PresetCases = { - camelCase: RegExp; - 'kebab-case': RegExp; - PascalCase: RegExp; - snake_case: RegExp; - [key: string]: RegExp | undefined; -}; - -export const presetCases: PresetCases = { - camelCase: /^[a-z][a-zA-Z0-9]*$/, - 'kebab-case': /^[a-z][-a-z0-9]*$/, - PascalCase: /^[A-Z][a-zA-Z0-9]*$/, - snake_case: /^[a-z][_a-z0-9]*$/, -}; diff --git a/src/utils/preset-rules.ts b/src/utils/preset-rules.ts new file mode 100644 index 00000000..24ee3592 --- /dev/null +++ b/src/utils/preset-rules.ts @@ -0,0 +1,57 @@ +import { splitName } from './split-name'; + +type Rule = { + expression: RegExp; + recommendationBuilder?: (name: string) => string; +}; +type PresetRules = { + [key: string]: Required | undefined; + camelCase: Required; + 'kebab-case': Required; + PascalCase: Required; + snake_case: Required; +}; + +export const presetRules: PresetRules = { + camelCase: { + expression: /^[a-z][a-zA-Z0-9]*$/, + recommendationBuilder: name => { + return splitName(name) + .map((word, i) => { + if (i === 0) return word; + + const [first, ...rest] = word; + return `${first.toUpperCase()}${rest.join('')}`; + }) + .join(''); + }, + }, + 'kebab-case': { + expression: /^[a-z][-a-z0-9]*$/, + recommendationBuilder: name => { + return splitName(name).join('-'); + }, + }, + PascalCase: { + expression: /^[A-Z][a-zA-Z0-9]*$/, + recommendationBuilder: name => { + return splitName(name) + .map(word => { + const [first, ...rest] = word; + return `${first.toUpperCase()}${rest.join('')}`; + }) + .join(''); + }, + }, + snake_case: { + expression: /^[a-z][_a-z0-9]*$/, + recommendationBuilder: name => { + return splitName(name).join('_'); + }, + }, +}; + +export const getRule = (expression: string): Rule => { + const rule = presetRules[expression]; + return rule ?? { expression: new RegExp(`^${expression}$`) }; +};