File tree Expand file tree Collapse file tree 9 files changed +205
-3
lines changed Expand file tree Collapse file tree 9 files changed +205
-3
lines changed Original file line number Diff line number Diff line change
1
+ ---
2
+ ' @graphql-eslint/eslint-plugin ' : minor
3
+ ---
4
+
5
+ add new rule ` require-type-pattern-with-oneof `
Original file line number Diff line number Diff line change @@ -59,6 +59,7 @@ Name &nbs
59
59
[ require-field-of-type-query-in-mutation-result] ( rules/require-field-of-type-query-in-mutation-result.md ) |Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.|![ all] [ ] |📄|🚀|
60
60
[ require-id-when-available] ( rules/require-id-when-available.md ) |Enforce selecting specific fields when they are available on the GraphQL type.|![ recommended] [ ] |📦|🚀|💡
61
61
[ require-nullable-fields-with-oneof] ( rules/require-nullable-fields-with-oneof.md ) |Require are ` input ` or ` type ` fields be non nullable with ` @oneOf ` directive.|![ all] [ ] |📄|🚀|
62
+ [ require-type-pattern-with-oneof] ( rules/require-type-pattern-with-oneof.md ) |Enforce types with ` @oneOf ` directive have ` error ` and ` ok ` fields.|![ all] [ ] |📄|🚀|
62
63
[ scalar-leafs] ( rules/scalar-leafs.md ) |A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.|![ recommended] [ ] |📦|🔮|💡
63
64
[ selection-set-depth] ( rules/selection-set-depth.md ) |Limit the complexity of the GraphQL operations solely by their depth. Based on [ graphql-depth-limit] ( https://npmjs.com/package/graphql-depth-limit ) .|![ recommended] [ ] |📦|🚀|💡
64
65
[ strict-id-in-types] ( rules/strict-id-in-types.md ) |Requires output types to have one unique identifier unless they do not have a logical one. Exceptions can be used to ignore output types that do not have unique identifiers.|![ recommended] [ ] |📄|🚀|
Original file line number Diff line number Diff line change
1
+ # ` require-type-pattern-with-oneof `
2
+
3
+ - Category: ` Schema `
4
+ - Rule name: ` @graphql-eslint/require-type-pattern-with-oneof `
5
+ - Requires GraphQL Schema: ` false ` [ ℹ️] ( ../../README.md#extended-linting-rules-with-graphql-schema )
6
+ - Requires GraphQL Operations: ` false `
7
+ [ ℹ️] ( ../../README.md#extended-linting-rules-with-siblings-operations )
8
+
9
+ Enforce types with ` @oneOf ` directive have ` error ` and ` ok ` fields.
10
+
11
+ ## Usage Examples
12
+
13
+ ### Correct
14
+
15
+ ``` graphql
16
+ # eslint @graphql-eslint/require-type-pattern-with-oneof: 'error'
17
+
18
+ type Mutation {
19
+ doSomething : DoSomethingMutationResult !
20
+ }
21
+
22
+ interface Error {
23
+ message : String !
24
+ }
25
+
26
+ type DoSomethingMutationResult @oneOf {
27
+ ok : DoSomethingSuccess
28
+ error : Error
29
+ }
30
+
31
+ type DoSomethingSuccess {
32
+ # ...
33
+ }
34
+ ```
35
+
36
+ ## Resources
37
+
38
+ - [Rule source ](../../packages/plugin/src/rules/require-type-pattern-with-oneof.ts)
39
+ - [Test source ](../../packages/plugin/tests/require-type-pattern-with-oneof.spec.ts)
Original file line number Diff line number Diff line change @@ -18,5 +18,6 @@ export default {
18
18
'@graphql-eslint/require-deprecation-date' : 'error' ,
19
19
'@graphql-eslint/require-field-of-type-query-in-mutation-result' : 'error' ,
20
20
'@graphql-eslint/require-nullable-fields-with-oneof' : 'error' ,
21
+ '@graphql-eslint/require-type-pattern-with-oneof' : 'error' ,
21
22
} ,
22
23
} ;
Original file line number Diff line number Diff line change @@ -29,6 +29,7 @@ import { rule as requireDescription } from './require-description';
29
29
import { rule as requireFieldOfTypeQueryInMutationResult } from './require-field-of-type-query-in-mutation-result' ;
30
30
import { rule as requireIdWhenAvailable } from './require-id-when-available' ;
31
31
import { rule as requireNullableFieldsWithOneof } from './require-nullable-fields-with-oneof' ;
32
+ import { rule as requireTypePatternWithOneof } from './require-type-pattern-with-oneof' ;
32
33
import { rule as selectionSetDepth } from './selection-set-depth' ;
33
34
import { rule as strictIdInTypes } from './strict-id-in-types' ;
34
35
import { rule as uniqueFragmentName } from './unique-fragment-name' ;
@@ -62,6 +63,7 @@ export const rules = {
62
63
'require-field-of-type-query-in-mutation-result' : requireFieldOfTypeQueryInMutationResult ,
63
64
'require-id-when-available' : requireIdWhenAvailable ,
64
65
'require-nullable-fields-with-oneof' : requireNullableFieldsWithOneof ,
66
+ 'require-type-pattern-with-oneof' : requireTypePatternWithOneof ,
65
67
'selection-set-depth' : selectionSetDepth ,
66
68
'strict-id-in-types' : strictIdInTypes ,
67
69
'unique-fragment-name' : uniqueFragmentName ,
Original file line number Diff line number Diff line change @@ -39,17 +39,19 @@ export const rule: GraphQLESLintRule = {
39
39
} ,
40
40
create ( context ) {
41
41
return {
42
- 'Directive[name.value=oneOf]' ( node : {
42
+ 'Directive[name.value=oneOf]' ( {
43
+ parent,
44
+ } : {
43
45
parent : GraphQLESTreeNode < InputObjectTypeDefinitionNode | ObjectTypeDefinitionNode > ;
44
46
} ) {
45
47
const isTypeOrInput = [
46
48
Kind . OBJECT_TYPE_DEFINITION ,
47
49
Kind . INPUT_OBJECT_TYPE_DEFINITION ,
48
- ] . includes ( node . parent . kind ) ;
50
+ ] . includes ( parent . kind ) ;
49
51
if ( ! isTypeOrInput ) {
50
52
return ;
51
53
}
52
- for ( const field of node . parent . fields ) {
54
+ for ( const field of parent . fields ) {
53
55
if ( field . gqlType . kind === Kind . NON_NULL_TYPE ) {
54
56
context . report ( {
55
57
node : field . name ,
Original file line number Diff line number Diff line change
1
+ import { GraphQLESLintRule } from '../types' ;
2
+ import { GraphQLESTreeNode } from '../estree-converter' ;
3
+ import { ObjectTypeDefinitionNode } from 'graphql/index' ;
4
+
5
+ const RULE_ID = 'require-type-pattern-with-oneof' ;
6
+
7
+ export const rule : GraphQLESLintRule = {
8
+ meta : {
9
+ type : 'suggestion' ,
10
+ docs : {
11
+ category : 'Schema' ,
12
+ description : 'Enforce types with `@oneOf` directive have `error` and `ok` fields.' ,
13
+ url : `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${ RULE_ID } .md` ,
14
+ examples : [
15
+ {
16
+ title : 'Correct' ,
17
+ code : /* GraphQL */ `
18
+ type Mutation {
19
+ doSomething: DoSomethingMutationResult!
20
+ }
21
+
22
+ interface Error {
23
+ message: String!
24
+ }
25
+
26
+ type DoSomethingMutationResult @oneOf {
27
+ ok: DoSomethingSuccess
28
+ error: Error
29
+ }
30
+
31
+ type DoSomethingSuccess {
32
+ # ...
33
+ }
34
+ ` ,
35
+ } ,
36
+ ] ,
37
+ } ,
38
+ messages : {
39
+ [ RULE_ID ] : 'Type `{{typeName}}` should have `{{fieldName}}` field.' ,
40
+ } ,
41
+ schema : [ ] ,
42
+ } ,
43
+ create ( context ) {
44
+ return {
45
+ 'Directive[name.value=oneOf][parent.kind=ObjectTypeDefinition]' ( {
46
+ parent,
47
+ } : {
48
+ parent : GraphQLESTreeNode < ObjectTypeDefinitionNode > ;
49
+ } ) {
50
+ const requiredFields = [ 'error' , 'ok' ] ;
51
+ for ( const fieldName of requiredFields ) {
52
+ if ( ! parent . fields . some ( field => field . name . value === fieldName ) ) {
53
+ context . report ( {
54
+ node : parent . name ,
55
+ messageId : RULE_ID ,
56
+ data : {
57
+ typeName : parent . name . value ,
58
+ fieldName,
59
+ } ,
60
+ } ) ;
61
+ }
62
+ }
63
+ } ,
64
+ } ;
65
+ } ,
66
+ } ;
Original file line number Diff line number Diff line change
1
+ // Vitest Snapshot v1
2
+
3
+ exports[ ` should validate \ ` error\` field 1` ] = `
4
+ #### ⌨️ Code
5
+
6
+ 1 | type T @oneOf {
7
+ 2 | ok: Ok
8
+ 3 | err: Error
9
+ 4 | }
10
+
11
+ #### ❌ Error
12
+
13
+ > 1 | type T @oneOf {
14
+ | ^ Type \`T\` should have \`error\` field.
15
+ 2 | ok: Ok
16
+ `;
17
+
18
+ exports[ ` should validate \ ` ok\` field 1` ] = `
19
+ #### ⌨️ Code
20
+
21
+ 1 | type T @oneOf {
22
+ 2 | notok: Ok
23
+ 3 | error: Error
24
+ 4 | }
25
+
26
+ #### ❌ Error
27
+
28
+ > 1 | type T @oneOf {
29
+ | ^ Type \`T\` should have \`ok\` field.
30
+ 2 | notok: Ok
31
+ `;
Original file line number Diff line number Diff line change
1
+ import { GraphQLRuleTester } from '../src' ;
2
+ import { rule } from '../src/rules/require-type-pattern-with-oneof' ;
3
+
4
+ const ruleTester = new GraphQLRuleTester ( ) ;
5
+
6
+ ruleTester . runGraphQLTests ( 'require-type-pattern-with-oneof' , rule , {
7
+ valid : [
8
+ /* GraphQL */ `
9
+ type T @oneOf {
10
+ ok: Ok
11
+ error: Error
12
+ }
13
+ ` ,
14
+ {
15
+ name : 'should ignore types without `@oneOf` directive' ,
16
+ code : /* GraphQL */ `
17
+ type T {
18
+ notok: Ok
19
+ err: Error
20
+ }
21
+ ` ,
22
+ } ,
23
+ {
24
+ name : 'should validate only `type` with `@oneOf` directive' ,
25
+ code : /* GraphQL */ `
26
+ input I {
27
+ notok: Ok
28
+ err: Error
29
+ }
30
+ ` ,
31
+ } ,
32
+ ] ,
33
+ invalid : [
34
+ {
35
+ name : 'should validate `ok` field' ,
36
+ code : /* GraphQL */ `
37
+ type T @oneOf {
38
+ notok: Ok
39
+ error: Error
40
+ }
41
+ ` ,
42
+ errors : [ { message : 'Type `T` should have `ok` field.' } ] ,
43
+ } ,
44
+ {
45
+ name : 'should validate `error` field' ,
46
+ code : /* GraphQL */ `
47
+ type T @oneOf {
48
+ ok: Ok
49
+ err: Error
50
+ }
51
+ ` ,
52
+ errors : [ { message : 'Type `T` should have `error` field.' } ] ,
53
+ } ,
54
+ ] ,
55
+ } ) ;
You can’t perform that action at this time.
0 commit comments