Skip to content

Commit b4c5d55

Browse files
authored
feat: add new option ignorePattern for naming-convention rule (#865)
1 parent e33af13 commit b4c5d55

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

.changeset/lazy-walls-chew.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': minor
3+
---
4+
5+
feat: add new option ignorePattern for `naming-convention` rule

docs/rules/naming-convention.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ type Query {
7171
}
7272
```
7373

74+
### Correct
75+
76+
```graphql
77+
# eslint @graphql-eslint/naming-convention: ['error', { FieldDefinition: { style: 'camelCase', ignorePattern: '^(EAN13|UPC|UK)' } }]
78+
79+
type Product {
80+
EAN13: String
81+
UPC: String
82+
UKFlag: String
83+
}
84+
```
85+
7486
## Config Schema
7587

7688
> It's possible to use a [`selector`](https://eslint.org/docs/developer-guide/selectors) that starts with allowed `ASTNode` names which are described below.
@@ -276,6 +288,10 @@ Additional restrictions:
276288
* Minimum items: `1`
277289
* Unique items: `true`
278290

291+
### `ignorePattern` (string)
292+
293+
Option to skip validation of some words, e.g. acronyms
294+
279295
## Resources
280296

281297
- [Rule source](../../packages/plugin/src/rules/naming-convention.ts)

packages/plugin/src/rules/naming-convention.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ type PropertySchema = {
4747
prefix?: string;
4848
forbiddenPrefixes?: string[];
4949
forbiddenSuffixes?: string[];
50+
ignorePattern?: string;
5051
};
5152

5253
type Options = AllowedStyle | PropertySchema;
@@ -124,6 +125,17 @@ const rule: GraphQLESLintRule<[NamingConventionRuleConfig]> = {
124125
}
125126
`,
126127
},
128+
{
129+
title: 'Correct',
130+
usage: [{ FieldDefinition: { style: 'camelCase', ignorePattern: '^(EAN13|UPC|UK)' } }],
131+
code: /* GraphQL */ `
132+
type Product {
133+
EAN13: String
134+
UPC: String
135+
UKFlag: String
136+
}
137+
`,
138+
},
127139
],
128140
configOptions: {
129141
schema: [
@@ -191,6 +203,10 @@ const rule: GraphQLESLintRule<[NamingConventionRuleConfig]> = {
191203
minItems: 1,
192204
items: { type: 'string' },
193205
},
206+
ignorePattern: {
207+
type: 'string',
208+
description: 'Option to skip validation of some words, e.g. acronyms',
209+
},
194210
},
195211
},
196212
},
@@ -249,15 +265,16 @@ const rule: GraphQLESLintRule<[NamingConventionRuleConfig]> = {
249265
if (!node) {
250266
return;
251267
}
252-
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style } = normalisePropertyOption(selector);
268+
const { prefix, suffix, forbiddenPrefixes, forbiddenSuffixes, style, ignorePattern } =
269+
normalisePropertyOption(selector);
253270
const nodeType = KindToDisplayName[n.kind] || n.kind;
254271
const nodeName = node.value;
255272
const error = getError();
256273
if (error) {
257274
const { errorMessage, renameToName } = error;
258-
const [leadingUnderscore] = nodeName.match(/^_*/);
259-
const [trailingUnderscore] = nodeName.match(/_*$/);
260-
const suggestedName = leadingUnderscore + renameToName + trailingUnderscore;
275+
const [leadingUnderscores] = nodeName.match(/^_*/);
276+
const [trailingUnderscores] = nodeName.match(/_*$/);
277+
const suggestedName = leadingUnderscores + renameToName + trailingUnderscores;
261278
context.report({
262279
loc: getLocation(node.loc, node.value),
263280
message: `${nodeType} "${nodeName}" should ${errorMessage}`,
@@ -275,6 +292,9 @@ const rule: GraphQLESLintRule<[NamingConventionRuleConfig]> = {
275292
renameToName: string;
276293
} | void {
277294
const name = nodeName.replace(/(^_+)|(_+$)/g, '');
295+
if (ignorePattern && new RegExp(ignorePattern, 'u').test(name)) {
296+
return;
297+
}
278298
if (prefix && !name.startsWith(prefix)) {
279299
return {
280300
errorMessage: `have "${prefix}" prefix`,
@@ -301,8 +321,12 @@ const rule: GraphQLESLintRule<[NamingConventionRuleConfig]> = {
301321
renameToName: name.replace(new RegExp(`${forbiddenSuffix}$`), ''),
302322
};
303323
}
324+
// Style is optional
325+
if (!style) {
326+
return;
327+
}
304328
const caseRegex = StyleToRegex[style];
305-
if (caseRegex && !caseRegex.test(name)) {
329+
if (!caseRegex.test(name)) {
306330
return {
307331
errorMessage: `be in ${style} format`,
308332
renameToName: convertCase(style, name),

packages/plugin/tests/naming-convention.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,34 @@ ruleTester.runGraphQLTests<[NamingConventionRuleConfig]>('naming-convention', ru
112112
options: [{ OperationDefinition: { style: 'PascalCase' } }],
113113
},
114114
'{ test { __typename ok_ } }',
115+
{
116+
name: 'should ignore fields',
117+
code: /* GraphQL */ `
118+
type Test {
119+
EU: ID
120+
EUIntlFlag: ID
121+
IE: ID
122+
IEIntlFlag: ID
123+
GB: ID
124+
UKFlag: ID
125+
UKService_Badge: ID
126+
CCBleaching: ID
127+
CCDryCleaning: ID
128+
CCIroning: ID
129+
UPC: ID
130+
CMWA: ID
131+
EAN13: ID
132+
}
133+
`,
134+
options: [
135+
{
136+
FieldDefinition: {
137+
style: 'camelCase',
138+
ignorePattern: '^(EU|IE|GB|UK|CC|UPC|CMWA|EAN13)',
139+
},
140+
},
141+
],
142+
},
115143
],
116144
invalid: [
117145
{

0 commit comments

Comments
 (0)