Skip to content

Commit

Permalink
Merge pull request #3 from epaew/bugfix/suggestion
Browse files Browse the repository at this point in the history
[Bugfix] suggested filenames
  • Loading branch information
epaew authored May 30, 2020
2 parents 3ab2238 + 1d4e5d6 commit 150c6d4
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 70 deletions.
2 changes: 1 addition & 1 deletion .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
arrowParens: avoid
printWidth: 120
printWidth: 100
singleQuote: true
trailingComma: all
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"scripts": {
"build": "tsc",
"clean": "rimraf dist/*",
"console": "ts-node",
"eslint": "eslint --ext .js,.ts src",
"eslint:fix": "eslint --fix --ext .js,.ts src",
"prepack": "npm-run-all eslint test clean build",
Expand All @@ -38,6 +39,7 @@
"prettier": "^2.0.5",
"rimraf": "^3.0.2",
"ts-jest": "^26.0.0",
"ts-node": "^8.10.2",
"typescript": "^3.9.3"
},
"peerDependencies": {
Expand Down
6 changes: 4 additions & 2 deletions src/rules/naming-convention.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ export const namingConvention: Rule.RuleModule = {
const suggest = (() => {
if (!presetCaseConverters[rule]) return null;

const name = [presetCaseConverters[rule](filename), ...rest].join('.');
return ` Should rename to ${name}`;
const alterName = presetCaseConverters[rule](filename) ?? '';
if (!ruleRegExp.test(alterName)) return null;

return ` Should rename to ${[alterName, ...rest].join('.')}.`;
})();
const message = `The filename must follow the rule: '${rule}'.${suggest ?? ''}`;

Expand Down
48 changes: 17 additions & 31 deletions src/utils/preset-case-converters.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
const toCamelCase = (name: string) =>
name
// for PascalCase
.replace(/^[A-Z]/, match => match.toLowerCase())
// for kebab-case and snake_case
.replace(/[-_]([a-z])/, (_, p1) => p1.toUpperCase());
// Replace char at beginning of name
const camel2Pascal = (name: string) => name.replace(/^[a-z]/, match => match.toUpperCase());
const pascal2Camel = (name: string) => name.replace(/^[A-Z]/, match => match.toLowerCase());

const toKebabCase = (name: string) =>
name
// for camelCase and PascalCase
.replace(/([a-z0-9])([A-Z])|([A-Z])([A-Z])(?:[a-z])/, '$1-$2')
.toLowerCase()
// for snake_case
.replace('_', '-');
// Replace all hyphen and underscore
const kebab2Snake = (name: string) => name.replace(/-/g, '_');
const snake2Kebab = (name: string) => name.replace(/_/g, '-');
const kebabAndSnake2CamelAndPascal = (name: string) =>
name.replace(/[-_]([a-z])/g, (_, p1) => p1.toUpperCase());

const toPascalCase = (name: string) =>
name
// for camelCase, kebab-case and snake_case
.replace(/^[a-z]/, match => match.toUpperCase())
// for kebab-case and snake_case
.replace(/[-_]([a-z])/, (_, p1) => p1.toUpperCase());

const toSnakeCase = (name: string) =>
name
// for camelCase and PascalCase
.replace(/([a-z0-9])([A-Z])|([A-Z])([A-Z])(?:[a-z])/, '$1_$2')
.toLowerCase()
// for kebab-case
.replace('-', '_');
// Replace all uppercase chars with hyphen or underscore, and lowercase
const camelAndPascal2Kebab = (name: string) =>
name.replace(/([a-z0-9])([A-Z])|([A-Z])([A-Z])(?:[a-z])/g, '$1-$2').toLowerCase();
const camelAndPascal2Snake = (name: string) =>
name.replace(/([a-z0-9])([A-Z])|([A-Z])([A-Z])(?:[a-z])/g, '$1_$2').toLowerCase();

type PresetCaseConverters = {
camelCase: (name: string) => string;
Expand All @@ -37,8 +23,8 @@ type PresetCaseConverters = {
};

export const presetCaseConverters: PresetCaseConverters = {
camelCase: toCamelCase,
'kebab-case': toKebabCase,
PascalCase: toPascalCase,
snake_case: toSnakeCase,
camelCase: name => kebabAndSnake2CamelAndPascal(pascal2Camel(name)),
'kebab-case': name => snake2Kebab(camelAndPascal2Kebab(name)),
PascalCase: name => kebabAndSnake2CamelAndPascal(camel2Pascal(name)),
snake_case: name => kebab2Snake(camelAndPascal2Snake(name)),
};
7 changes: 6 additions & 1 deletion tests/rules/naming-convention.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ ruleTester.run('naming-convention', namingConvention, {
{
code: '',
filename: 'camelCase.js',
errors: ["The filename must follow the rule: 'kebab-case'. Should rename to camel-case.js"],
errors: ["The filename must follow the rule: 'kebab-case'. Should rename to camel-case.js."],
},
{
code: '',
filename: '00001_chaos-Name.js',
errors: ["The filename must follow the rule: 'kebab-case'."],
},
{
code: '',
Expand Down
91 changes: 78 additions & 13 deletions tests/utils/preset-case-converters.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,30 @@ describe('PresetConverter of camelCase', () => {
});

test('should return camelized strings when name is kebab-case', () => {
expect(targetNames.kebabCase.map(subject)).toEqual(['kebabCase', 'kebab0Case', 'kebabCase0']);
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', 'pascal0Case', 'pascalCase0']);
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', 'snake0Case', 'snakeCase0']);
expect(targetNames.snakeCase.map(subject)).toEqual([
'snakeCase',
'threeOrMoreWordsIncludingSnakeCase',
'snake0Case',
'snakeCase0',
]);
});
});

Expand All @@ -34,43 +49,78 @@ describe('PresetConverter of kebab-case', () => {
});

test('should return hyphenized strings when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual(['camel-case', 'camel0-case', 'camel-case0']);
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', 'pascal0-case', 'pascal-case0']);
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', 'snake0-case', 'snake-case0']);
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', 'Normal0case', 'Normalcase0']);
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', 'Camel0Case', 'CamelCase0']);
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', 'Kebab0Case', 'KebabCase0']);
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', 'Snake0Case', 'SnakeCase0']);
expect(targetNames.snakeCase.map(subject)).toEqual([
'SnakeCase',
'ThreeOrMoreWordsIncludingSnakeCase',
'Snake0Case',
'SnakeCase0',
]);
});
});

Expand All @@ -82,15 +132,30 @@ describe('PresetConverter of snake_case', () => {
});

test('should return underscorized strings when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual(['camel_case', 'camel0_case', 'camel_case0']);
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', 'kebab0_case', 'kebab_case0']);
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', 'pascal0_case', 'pascal_case0']);
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', () => {
Expand Down
56 changes: 36 additions & 20 deletions tests/utils/preset-cases.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,94 +6,110 @@ 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)).toEqual([true, true, true]);
expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return true when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual([true, true, true]);
expect(targetNames.camelCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return false when name is kebab-case', () => {
expect(targetNames.kebabCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is PascalCase', () => {
expect(targetNames.pascalCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is snake_case', () => {
expect(targetNames.snakeCase.map(subject)).toEqual([false, false, false]);
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)).toEqual([true, true, true]);
expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return false when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return true when name is kebab-case', () => {
expect(targetNames.kebabCase.map(subject)).toEqual([true, true, true]);
expect(targetNames.kebabCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return false when name is PascalCase', () => {
expect(targetNames.pascalCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is snake_case', () => {
expect(targetNames.snakeCase.map(subject)).toEqual([false, false, false]);
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)).toEqual([false, false, false]);
expect(targetNames.normalCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is kebab-case', () => {
expect(targetNames.kebabCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return true when name is PascalCase', () => {
expect(targetNames.pascalCase.map(subject)).toEqual([true, true, true]);
expect(targetNames.pascalCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return false when name is snake_case', () => {
expect(targetNames.snakeCase.map(subject)).toEqual([false, false, false]);
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)).toEqual([true, true, true]);
expect(targetNames.normalCase.map(subject).every(n => n)).toBeTruthy();
});

test('should return false when name is camelCase', () => {
expect(targetNames.camelCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.camelCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is kebab-case', () => {
expect(targetNames.kebabCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.kebabCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return false when name is PascalCase', () => {
expect(targetNames.pascalCase.map(subject)).toEqual([false, false, false]);
expect(targetNames.pascalCase.map(subject).some(n => n)).toBeFalsy();
});

test('should return true when name is snake_case', () => {
expect(targetNames.snakeCase.map(subject)).toEqual([true, true, true]);
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();
});
});
Loading

0 comments on commit 150c6d4

Please sign in to comment.