Skip to content

Commit

Permalink
feat(eslint-plugin): [camelcase] add genericType option
Browse files Browse the repository at this point in the history
  • Loading branch information
a-tarasyuk committed Aug 30, 2019
1 parent 6bd7f2d commit 25870b3
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 9 deletions.
55 changes: 46 additions & 9 deletions packages/eslint-plugin/src/rules/camelcase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ import * as util from '../util';
type Options = util.InferOptionsTypeFromRule<typeof baseRule>;
type MessageIds = util.InferMessageIdsTypeFromRule<typeof baseRule>;

const schema = util.deepMerge(
Array.isArray(baseRule.meta.schema)
? baseRule.meta.schema[0]
: baseRule.meta.schema,
{
properties: {
genericType: {
enum: ['always', 'never'],
},
},
},
);

export default util.createRule<Options, MessageIds>({
name: 'camelcase',
meta: {
Expand All @@ -17,14 +30,15 @@ export default util.createRule<Options, MessageIds>({
category: 'Stylistic Issues',
recommended: 'error',
},
schema: baseRule.meta.schema,
schema: [schema],
messages: baseRule.meta.messages,
},
defaultOptions: [
{
allow: ['^UNSAFE_'],
ignoreDestructuring: false,
properties: 'never',
genericType: 'never',
},
],
create(context, [options]) {
Expand All @@ -36,6 +50,7 @@ export default util.createRule<Options, MessageIds>({
AST_NODE_TYPES.TSAbstractClassProperty,
];

const genericType = options.genericType;
const properties = options.properties;
const allow = (options.allow || []).map(entry => ({
name: entry,
Expand Down Expand Up @@ -72,17 +87,35 @@ export default util.createRule<Options, MessageIds>({
* @private
*/
function isTSPropertyType(node: TSESTree.Node): boolean {
if (!node.parent) {
return false;
if (TS_PROPERTY_TYPES.includes(node.type)) {
return true;
}

if (node.type === AST_NODE_TYPES.AssignmentPattern) {
return (
node.parent !== undefined &&
TS_PROPERTY_TYPES.includes(node.parent.type)
);
}
if (TS_PROPERTY_TYPES.includes(node.parent.type)) {

return false;
}

/**
* Checks if the the node is a valid TypeScript generic type parameter
* @param node the node to be validated
* @returns true if the node is a TypeScript generic type parameter
* @private
*/
function isTSTypeParameter(node: TSESTree.Node): boolean {
if (node.type === AST_NODE_TYPES.TSTypeParameter) {
return true;
}

if (node.parent.type === AST_NODE_TYPES.AssignmentPattern) {
if (node.type === AST_NODE_TYPES.TSTypeReference) {
return (
node.parent.parent !== undefined &&
TS_PROPERTY_TYPES.includes(node.parent.parent.type)
node.parent !== undefined &&
node.parent.type === AST_NODE_TYPES.TSTypeParameter
);
}

Expand All @@ -103,8 +136,12 @@ export default util.createRule<Options, MessageIds>({
}

// Check TypeScript specific nodes
if (isTSPropertyType(node)) {
if (properties === 'always' && isUnderscored(name)) {
const parent = node.parent;
if (parent && (isTSPropertyType(parent) || isTSTypeParameter(parent))) {
if (
[properties, genericType].includes('always') &&
isUnderscored(name)
) {
context.report({
node,
messageId: 'notCamelCase',
Expand Down
184 changes: 184 additions & 0 deletions packages/eslint-plugin/tests/rules/camelcase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,78 @@ ruleTester.run('camelcase', rule, {
code: 'abstract class Foo { abstract bar: number = 0; }',
options: [{ properties: 'always' }],
},
{
code: 'interface Foo<t_foo> {}',
options: [{ genericType: 'never' }],
},
{
code: 'interface Foo<T> {}',
options: [{ genericType: 'always' }],
},
{
code: 'interface Foo<t> {}',
options: [{ genericType: 'always' }],
},
{
code: 'function fn<t_foo>() {}',
options: [{ genericType: 'never' }],
},
{
code: 'function fn<T>() {}',
options: [{ genericType: 'always' }],
},
{
code: 'function fn<t>() {}',
options: [{ genericType: 'always' }],
},
{
code: 'class Foo<t_foo> {}',
options: [{ genericType: 'never' }],
},
{
code: 'class Foo<T> {}',
options: [{ genericType: 'always' }],
},
{
code: 'class Foo<t> {}',
options: [{ genericType: 'always' }],
},
{
code: `
class Foo {
method<t_foo>() {}
}
`,
options: [{ genericType: 'never' }],
},
{
code: `
class Foo {
method<T>() {}
}
`,
options: [{ genericType: 'always' }],
},
{
code: `
class Foo {
method<t>() {}
}
`,
options: [{ genericType: 'always' }],
},
{
code: `
type Foo<T extends object> = {}
`,
options: [{ genericType: 'always' }],
},
{
code: `
type Foo<T extends t_object> = {}
`,
options: [{ genericType: 'never' }],
},
],

invalid: [
Expand Down Expand Up @@ -194,5 +266,117 @@ ruleTester.run('camelcase', rule, {
},
],
},
{
code: 'interface Foo<t_foo> {}',
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 1,
column: 15,
},
],
},
{
code: 'function fn<t_foo>() {}',
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 1,
column: 13,
},
],
},
{
code: 'class Foo<t_foo> {}',
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 1,
column: 11,
},
],
},
{
code: `
class Foo {
method<t_foo>() {}
}
`,
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 3,
column: 10,
},
],
},
{
code: `
class Foo {
method<t_foo extends t_bar>() {}
}
`,
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 3,
column: 10,
},
{
messageId: 'notCamelCase',
data: {
name: 't_bar',
},
line: 3,
column: 24,
},
],
},
{
code: `
class Foo {
method<t_foo = t_bar>() {}
}
`,
options: [{ genericType: 'always' }],
errors: [
{
messageId: 'notCamelCase',
data: {
name: 't_foo',
},
line: 3,
column: 10,
},
{
messageId: 'notCamelCase',
data: {
name: 't_bar',
},
line: 3,
column: 18,
},
],
},
],
});
1 change: 1 addition & 0 deletions packages/eslint-plugin/typings/eslint-rules.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ declare module 'eslint/lib/rules/camelcase' {
allow?: string[];
ignoreDestructuring?: boolean;
properties?: 'always' | 'never';
genericType?: 'never' | 'always';
},
],
{
Expand Down

0 comments on commit 25870b3

Please sign in to comment.