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

Refactor utils/pluralize.ts #147

Merged
merged 3 commits into from
Oct 10, 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: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
## Others
* [#51](https://github.com/epaew/eslint-plugin-filenames-simple/pull/51)
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.

# 0.4.0
## Features
Expand Down
66 changes: 23 additions & 43 deletions __tests__/utils/pluralize.test.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { Rule } from 'eslint';
import * as pluralize from '#/utils/pluralize';
import { Dictionaries, Pluralize } from '#/utils/pluralize';

describe('pluralize.correct', () => {
const subject = pluralize.correct;

describe('when the rule is undefined', () => {
const rule = undefined;

it('returns same name', () => {
const names = ['test', 'tests'];
expect(names.map(name => subject(name, rule))).toEqual(names);
});
});
const pluralize = new Pluralize();
const subject: typeof pluralize.correct = (name, rule) => pluralize.correct(name, rule);

describe('when the rule is singular', () => {
const rule = 'singular';
Expand All @@ -33,16 +24,8 @@ describe('pluralize.correct', () => {
});

describe('pluralize.isValidName', () => {
const subject = pluralize.isValidName;

describe('when the rule is undefined', () => {
const rule = undefined;

it('returns always true', () => {
const names = ['test', 'tests'];
expect(names.map(name => subject(name, rule))).toEqual([true, true]);
});
});
const pluralize = new Pluralize();
const subject: typeof pluralize.isValidName = (name, rule) => pluralize.isValidName(name, rule);

describe('when the rule is singular', () => {
const rule = 'singular';
Expand All @@ -64,36 +47,33 @@ describe('pluralize.isValidName', () => {
});

// NOTE: This test affects other tests because the instance of `pluralize` is a singleton.
describe('pluralize.initPluralize', () => {
const subject = (context: Pick<Rule.RuleContext, 'settings'>) => pluralize.initPluralize(context);
describe('new Pluralize()', () => {
const subject = (dictionaries?: Dictionaries) => new Pluralize(dictionaries);

describe('when dictionaries are empty', () => {
const context = { settings: {} };
describe('when the dictionaries are undefined', () => {
const dictionaries = undefined;

it('does not throw error', () => {
subject(context);
});
});

describe('when dictionaries are present', () => {
const dictionaries = {
irregular: [['regular', 'irregular']] as [string, string][],
plural: [['index', 'indexes']] as [string, string][],
singular: [['shoes', 'shoes']] as [string, string][],
uncountable: ['test'],
};
const context = { settings: { 'filenames-simple': { pluralize: dictionaries } } };
it('uses default dictionaries of pluralize.', () => {
const pluralize = subject(dictionaries);

it('set the dictionaries of pluralize', () => {
// before setDictionaries()
expect(pluralize.correct('regular', 'plural')).toBe('regulars');
expect(pluralize.correct('index', 'plural')).toBe('indices');
expect(pluralize.correct('shoes', 'singular')).toBe('shoe');
expect(pluralize.correct('test', 'plural')).toBe('tests');
});
});

describe('when the dictionaries are present', () => {
const dictionaries: Dictionaries = {
irregular: [['regular', 'irregular']],
plural: [['index', 'indexes']],
singular: [['shoes', 'shoes']],
uncountable: ['test'],
};

subject(context);
it('uses customized dictionaries.', () => {
const pluralize = subject(dictionaries);

// after setDictionaries()
expect(pluralize.correct('regular', 'plural')).toBe('irregular');
expect(pluralize.correct('index', 'plural')).toBe('indexes');
expect(pluralize.correct('shoes', 'singular')).toBe('shoes');
Expand Down
10 changes: 5 additions & 5 deletions src/rules/named-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ 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 { initPluralize, isValidName } from '../utils/pluralize';
import { Pluralize } from '../utils/pluralize';

type Pluralize = 'always' | 'singular' | 'plural';
type PluralizeRule = 'always' | 'singular' | 'plural';

const fetchFilename = (context: Rule.RuleContext) => {
const absolutePath = path.resolve(context.getFilename());
Expand Down Expand Up @@ -36,14 +36,14 @@ export const namedExport: Rule.RuleModule = {
schema: [{ enum: ['always', 'singular', 'plural'] }],
},
create: context => {
initPluralize(context);
const pluralize: Pluralize = context.options[0] ?? 'always';
const pluralize = new Pluralize(context.settings?.['filenames-simple']?.pluralize);
const rule: PluralizeRule = context.options[0] ?? 'always';

return {
Program: node => {
const filename = fetchFilename(context);

if (!(pluralize === 'always' || isValidName(filename, pluralize))) return;
if (!(rule === 'always' || pluralize.isValidName(filename, rule))) return;

const [target, ...rest] = fetchTargets(node as Program);
if (!target || rest.length !== 0) return;
Expand Down
18 changes: 13 additions & 5 deletions src/rules/pluralize.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import path from 'path';
import { Rule } from 'eslint';
import { correct, initPluralize, isValidName } from '../utils/pluralize';

import { Pluralize, PluralizeRule } from '../utils/pluralize';

type Rules = {
parentDir?: 'singular' | 'plural';
Expand Down Expand Up @@ -30,22 +31,29 @@ export const pluralize: Rule.RuleModule = {
],
},
create: context => {
initPluralize(context);
const pluralize = new Pluralize(context.settings?.['filenames-simple']?.pluralize);
const rules: Rules = context.options[0] ?? {};

const correctedName = (name: string, rule?: PluralizeRule) =>
rule ? pluralize.correct(name, rule) : name;
const isValidName = (name: string, rule?: PluralizeRule) =>
rule ? pluralize.isValidName(name, rule) : true;

return {
Program: node => {
const [dirname, [filename, ...rest]] = fetchFilename(context);

if (isValidName(dirname, rules.parentDir) && isValidName(filename, rules.file)) return;
if (isValidName(dirname, rules.parentDir) && isValidName(filename, rules.file)) {
return;
}

context.report({
node: node,
message:
'The filename must follow the pluralize rule. Should rename to {{ dirname }}/{{ filename }}.{{ extname }}',
data: {
dirname: correct(dirname, rules.parentDir),
filename: correct(filename, rules.file),
dirname: correctedName(dirname, rules.parentDir),
filename: correctedName(filename, rules.file),
extname: rest.join('.'),
},
});
Expand Down
48 changes: 0 additions & 48 deletions src/utils/pluralize.ts

This file was deleted.

43 changes: 43 additions & 0 deletions src/utils/pluralize/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import pluralize from 'pluralize';

import { Dictionaries, PluralizeRule } from './types';
export { Dictionaries, PluralizeRule };

export class Pluralize {
readonly #pluralize: typeof pluralize;

constructor(dictionaries?: Dictionaries) {
this.#pluralize = pluralize;
dictionaries && this.setDictionaries(dictionaries);
}

correct(name: string, rule: PluralizeRule): string {
const corrector = {
singular: this.#pluralize.singular,
plural: this.#pluralize.plural,
};
return corrector[rule](name);
}

isValidName(name: string, rule: PluralizeRule): boolean {
const validator = {
singular: this.#pluralize.isSingular,
plural: this.#pluralize.isPlural,
};
return validator[rule](name);
}

private setDictionaries({ irregular, plural, singular, uncountable }: Dictionaries) {
irregular &&
irregular.forEach(([singular, plural]) => this.#pluralize.addIrregularRule(singular, plural));
plural &&
plural.forEach(([plural, singular]) =>
this.#pluralize.addPluralRule(new RegExp(plural), singular),
);
singular &&
singular.forEach(([singular, plural]) =>
this.#pluralize.addSingularRule(new RegExp(singular), plural),
);
uncountable && uncountable.forEach(this.#pluralize.addUncountableRule);
}
}
7 changes: 7 additions & 0 deletions src/utils/pluralize/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type Dictionaries = {
irregular?: [string, string][];
plural?: [string, string][];
singular?: [string, string][];
uncountable?: string[];
};
export type PluralizeRule = 'singular' | 'plural';