Skip to content

Commit 7251269

Browse files
authored
🎉 [new rule] relay-connection-types, relay-edge-types, relay-page-info, relay-arguments (#982)
* add create-rule script and dummy rule * add changeset * update snapshots after rebase * [relay-page-info]: allow scalar for startCursor/endCursor * refactor * improve types * add `relay-arguments` * add includeBoth option * run test with ruletester before snapshots tests * refactor
1 parent 1194923 commit 7251269

File tree

105 files changed

+3755
-1079
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+3755
-1079
lines changed

.changeset/ninety-seas-beg.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 `relay-connection-types`, `relay-edge-types`, `relay-page-info` and `relay-arguments` rules

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ module.exports = {
2727
'unicorn/no-useless-fallback-in-spread': 'error',
2828
'unicorn/better-regex': 'error',
2929
'prefer-destructuring': ['error', { object: true }],
30+
quotes: ['error', 'single', { avoidEscape: true }], // Matches Prettier, but also replaces backticks
3031
},
3132
overrides: [
3233
{

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ See [docs/deprecated-rules.md](docs/deprecated-rules.md).
193193
|[`schema-all`](packages/plugin/src/configs/schema-all.json)|enables all rules for schema (SDL) development, except for those that require `parserOptions.operations` option|
194194
|[`operations-recommended`](packages/plugin/src/configs/operations-recommended.json) |enables recommended rules for consuming GraphQL (operations) development|
195195
|[`operations-all`](packages/plugin/src/configs/operations-all.json)|enables all rules for consuming GraphQL (operations) development|
196+
|[`relay`](packages/plugin/src/configs/relay.json)|enables rules from Relay specification for schema (SDL) development|
196197
<!-- prettier-ignore-end -->
197198

198199
> If you are in a project that develops the GraphQL schema, you'll need `schema` rules.

docs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs
4444
[possible-fragment-spread](rules/possible-fragment-spread.md)|A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.|![recommended][]|🔮|
4545
[possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind.||🔮|
4646
[provided-required-arguments](rules/provided-required-arguments.md)|A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.|![recommended][]|🔮|
47+
[relay-arguments](rules/relay-arguments.md)|Set of rules to follow Relay specification for Arguments.||🚀|
48+
[relay-connection-types](rules/relay-connection-types.md)|Set of rules to follow Relay specification for Connection types.||🚀|
49+
[relay-edge-types](rules/relay-edge-types.md)|Set of rules to follow Relay specification for Edge types.||🚀|
50+
[relay-page-info](rules/relay-page-info.md)|Set of rules to follow Relay specification for `PageInfo` object.||🚀|
4751
[require-deprecation-date](rules/require-deprecation-date.md)|Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.|![all][]|🚀|💡
4852
[require-deprecation-reason](rules/require-deprecation-reason.md)|Require all deprecation directives to specify a reason.|![recommended][]|🚀|
4953
[require-description](rules/require-description.md)|Enforce descriptions in type definitions and operations.|![recommended][]|🚀|

docs/custom-rules.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export const rule = {
118118
}
119119
```
120120

121-
The structure of the return value of `.typeInfo()` is [defined here](https://github.com/B2o5T/graphql-eslint/blob/master/packages/plugin/src/estree-parser/converter.ts#L63-L71). So based on the `node` you are using, you'll get a different values on `.typeInfo()` result.
121+
The structure of the return value of `.typeInfo()` is [defined here](https://github.com/B2o5T/graphql-eslint/blob/master/packages/plugin/src/estree-parser/converter.ts#L32-L40). So based on the `node` you are using, you'll get a different values on `.typeInfo()` result.
122122

123123
## Testing your rules
124124

docs/rules/relay-arguments.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# `relay-arguments`
2+
3+
- Category: `Schema`
4+
- Rule name: `@graphql-eslint/relay-arguments`
5+
- Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
6+
- Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
7+
8+
Set of rules to follow Relay specification for Arguments.
9+
10+
- A field that returns a Connection type must include forward pagination arguments (`first` and `after`), backward pagination arguments (`last` and `before`), or both
11+
12+
Forward pagination arguments
13+
14+
- `first` takes a non-negative integer
15+
- `after` takes the Cursor type
16+
17+
Backward pagination arguments
18+
19+
- `last` takes a non-negative integer
20+
- `before` takes the Cursor type
21+
22+
## Usage Examples
23+
24+
### Incorrect
25+
26+
```graphql
27+
# eslint @graphql-eslint/relay-arguments: 'error'
28+
29+
type User {
30+
posts: PostConnection
31+
}
32+
```
33+
34+
### Correct
35+
36+
```graphql
37+
# eslint @graphql-eslint/relay-arguments: 'error'
38+
39+
type User {
40+
posts(after: String, first: Int, before: String, last: Int): PostConnection
41+
}
42+
```
43+
44+
## Config Schema
45+
46+
The schema defines the following properties:
47+
48+
### `includeBoth` (boolean)
49+
50+
Enforce including both forward and backward pagination arguments
51+
52+
Default: `true`
53+
54+
## Resources
55+
56+
- [Rule source](../../packages/plugin/src/rules/relay-arguments.ts)
57+
- [Test source](../../packages/plugin/tests/relay-arguments.spec.ts)

docs/rules/relay-connection-types.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# `relay-connection-types`
2+
3+
- Category: `Schema`
4+
- Rule name: `@graphql-eslint/relay-connection-types`
5+
- Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
6+
- Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
7+
8+
Set of rules to follow Relay specification for Connection types.
9+
10+
- Any type whose name ends in "Connection" is considered by spec to be a `Connection type`
11+
- Connection type must be an Object type
12+
- Connection type must contain a field `edges` that return a list type which wraps an edge type
13+
- Connection type must contain a field `pageInfo` that return a non-null `PageInfo` Object type
14+
15+
## Usage Examples
16+
17+
### Incorrect
18+
19+
```graphql
20+
# eslint @graphql-eslint/relay-connection-types: 'error'
21+
22+
type UserPayload { # should be an Object type with `Connection` suffix
23+
edges: UserEdge! # should return a list type
24+
pageInfo: PageInfo # should return a non-null `PageInfo` Object type
25+
}
26+
```
27+
28+
### Correct
29+
30+
```graphql
31+
# eslint @graphql-eslint/relay-connection-types: 'error'
32+
33+
type UserConnection {
34+
edges: [UserEdge]
35+
pageInfo: PageInfo!
36+
}
37+
```
38+
39+
## Resources
40+
41+
- [Rule source](../../packages/plugin/src/rules/relay-connection-types.ts)
42+
- [Test source](../../packages/plugin/tests/relay-connection-types.spec.ts)

docs/rules/relay-edge-types.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# `relay-edge-types`
2+
3+
- Category: `Schema`
4+
- Rule name: `@graphql-eslint/relay-edge-types`
5+
- Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
6+
- Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
7+
8+
Set of rules to follow Relay specification for Edge types.
9+
10+
- A type that is returned in list form by a connection type's `edges` field is considered by this spec to be an Edge type
11+
- Edge type must be an Object type
12+
- Edge type must contain a field `node` that return either a Scalar, Enum, Object, Interface, Union, or a non-null wrapper around one of those types. Notably, this field cannot return a list
13+
- Edge type must contain a field `cursor` that return a String, Scalar, or a non-null wrapper wrapper around one of those types
14+
- Edge type name must end in "Edge" _(optional)_
15+
- Edge type's field `node` must implement `Node` interface _(optional)_
16+
- A list type should only wrap an edge type _(optional)_
17+
18+
## Usage Examples
19+
20+
### Correct
21+
22+
```graphql
23+
# eslint @graphql-eslint/relay-edge-types: 'error'
24+
25+
type UserConnection {
26+
edges: [UserEdge]
27+
pageInfo: PageInfo!
28+
}
29+
```
30+
31+
## Config Schema
32+
33+
The schema defines the following properties:
34+
35+
### `withEdgeSuffix` (boolean)
36+
37+
Edge type name must end in "Edge".
38+
39+
Default: `true`
40+
41+
### `shouldImplementNode` (boolean)
42+
43+
Edge type's field `node` must implement `Node` interface.
44+
45+
Default: `true`
46+
47+
### `listTypeCanWrapOnlyEdgeType` (boolean)
48+
49+
A list type should only wrap an edge type.
50+
51+
Default: `true`
52+
53+
## Resources
54+
55+
- [Rule source](../../packages/plugin/src/rules/relay-edge-types.ts)
56+
- [Test source](../../packages/plugin/tests/relay-edge-types.spec.ts)

docs/rules/relay-page-info.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# `relay-page-info`
2+
3+
- Category: `Schema`
4+
- Rule name: `@graphql-eslint/relay-page-info`
5+
- Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
6+
- Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
7+
8+
Set of rules to follow Relay specification for `PageInfo` object.
9+
10+
- `PageInfo` must be an Object type
11+
- `PageInfo` must contain fields `hasPreviousPage` and `hasNextPage`, which return non-null Boolean
12+
- `PageInfo` must contain fields `startCursor` and `endCursor`, which return non-null String or Scalar
13+
14+
## Usage Examples
15+
16+
### Correct
17+
18+
```graphql
19+
# eslint @graphql-eslint/relay-page-info: 'error'
20+
21+
type PageInfo {
22+
hasPreviousPage: Boolean!
23+
hasNextPage: Boolean!
24+
startCursor: String!
25+
endCursor: String!
26+
}
27+
```
28+
29+
## Resources
30+
31+
- [Rule source](../../packages/plugin/src/rules/relay-page-info.ts)
32+
- [Test source](../../packages/plugin/tests/relay-page-info.spec.ts)

docs/rules/strict-id-in-types.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Default:
7878

7979
Additional restrictions:
8080

81+
* Minimum items: `1`
8182
* Unique items: `true`
8283

8384
### `acceptedIdTypes` (array)
@@ -94,6 +95,7 @@ Default:
9495

9596
Additional restrictions:
9697

98+
* Minimum items: `1`
9799
* Unique items: `true`
98100

99101
### `exceptions` (object)

0 commit comments

Comments
 (0)