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

[Bugfix] suggested filenames #3

Merged
merged 6 commits into from
May 30, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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