@graphql-eslint/eslint-plugin 3.14.0-alpha-20221222204442-94bf749 â 3.14.0-alpha-20221222211346-788e7eb
Sign up to get free protection for your applications and to get access to all the features.
- package/cjs/configs/operations-all.js +1 -0
- package/cjs/rules/index.js +2 -0
- package/cjs/rules/no-one-place-fragments.js +84 -0
- package/docs/README.md +1 -0
- package/docs/rules/no-one-place-fragments.md +51 -0
- package/package.json +1 -1
- package/typings/configs/index.d.cts +1 -0
- package/typings/configs/index.d.ts +1 -0
- package/typings/configs/operations-all.d.cts +1 -0
- package/typings/configs/operations-all.d.ts +1 -0
- package/typings/rules/index.d.cts +1 -0
- package/typings/rules/index.d.ts +1 -0
- package/typings/rules/no-one-place-fragments.d.cts +2 -0
- package/typings/rules/no-one-place-fragments.d.ts +2 -0
package/cjs/rules/index.js
CHANGED
@@ -16,6 +16,7 @@ const no_case_insensitive_enum_values_duplicates_1 = require("./no-case-insensit
|
|
16
16
|
const no_deprecated_1 = require("./no-deprecated");
|
17
17
|
const no_duplicate_fields_1 = require("./no-duplicate-fields");
|
18
18
|
const no_hashtag_description_1 = require("./no-hashtag-description");
|
19
|
+
const no_one_place_fragments_1 = require("./no-one-place-fragments");
|
19
20
|
const no_root_type_1 = require("./no-root-type");
|
20
21
|
const no_scalar_result_type_on_mutation_1 = require("./no-scalar-result-type-on-mutation");
|
21
22
|
const no_typename_prefix_1 = require("./no-typename-prefix");
|
@@ -49,6 +50,7 @@ exports.rules = {
|
|
49
50
|
'no-deprecated': no_deprecated_1.rule,
|
50
51
|
'no-duplicate-fields': no_duplicate_fields_1.rule,
|
51
52
|
'no-hashtag-description': no_hashtag_description_1.rule,
|
53
|
+
'no-one-place-fragments': no_one_place_fragments_1.rule,
|
52
54
|
'no-root-type': no_root_type_1.rule,
|
53
55
|
'no-scalar-result-type-on-mutation': no_scalar_result_type_on_mutation_1.rule,
|
54
56
|
'no-typename-prefix': no_typename_prefix_1.rule,
|
@@ -0,0 +1,84 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.rule = void 0;
|
4
|
+
const eslint_plugin_1 = require("@graphql-eslint/eslint-plugin");
|
5
|
+
const utils_1 = require("../utils");
|
6
|
+
const path_1 = require("path");
|
7
|
+
const graphql_1 = require("graphql");
|
8
|
+
const RULE_ID = 'no-one-place-fragments';
|
9
|
+
exports.rule = {
|
10
|
+
meta: {
|
11
|
+
type: 'suggestion',
|
12
|
+
docs: {
|
13
|
+
category: 'Operations',
|
14
|
+
description: 'Disallow fragments that are used only in one place.',
|
15
|
+
url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
|
16
|
+
examples: [
|
17
|
+
{
|
18
|
+
title: 'Incorrect',
|
19
|
+
code: /* GraphQL */ `
|
20
|
+
fragment UserFields on User {
|
21
|
+
id
|
22
|
+
}
|
23
|
+
|
24
|
+
{
|
25
|
+
user {
|
26
|
+
...UserFields
|
27
|
+
friends {
|
28
|
+
...UserFields
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
`,
|
33
|
+
},
|
34
|
+
{
|
35
|
+
title: 'Correct',
|
36
|
+
code: /* GraphQL */ `
|
37
|
+
fragment UserFields on User {
|
38
|
+
id
|
39
|
+
}
|
40
|
+
|
41
|
+
{
|
42
|
+
user {
|
43
|
+
...UserFields
|
44
|
+
}
|
45
|
+
}
|
46
|
+
`,
|
47
|
+
},
|
48
|
+
],
|
49
|
+
requiresSiblings: true,
|
50
|
+
},
|
51
|
+
messages: {
|
52
|
+
[RULE_ID]: 'Fragment `{{fragmentName}}` used only once. Inline him in "{{filePath}}".',
|
53
|
+
},
|
54
|
+
schema: [],
|
55
|
+
},
|
56
|
+
create(context) {
|
57
|
+
const operations = (0, eslint_plugin_1.requireSiblingsOperations)(RULE_ID, context);
|
58
|
+
const allDocuments = [...operations.getOperations(), ...operations.getFragments()];
|
59
|
+
const usedFragmentsMap = Object.create(null);
|
60
|
+
for (const { document, filePath } of allDocuments) {
|
61
|
+
const relativeFilePath = (0, path_1.relative)(utils_1.CWD, filePath);
|
62
|
+
(0, graphql_1.visit)(document, {
|
63
|
+
FragmentSpread({ name }) {
|
64
|
+
const spreadName = name.value;
|
65
|
+
usedFragmentsMap[spreadName] || (usedFragmentsMap[spreadName] = []);
|
66
|
+
usedFragmentsMap[spreadName].push(relativeFilePath);
|
67
|
+
},
|
68
|
+
});
|
69
|
+
}
|
70
|
+
return {
|
71
|
+
'FragmentDefinition > Name'(node) {
|
72
|
+
const fragmentName = node.value;
|
73
|
+
const fragmentUsage = usedFragmentsMap[fragmentName];
|
74
|
+
if (fragmentUsage.length === 1) {
|
75
|
+
context.report({
|
76
|
+
node,
|
77
|
+
messageId: RULE_ID,
|
78
|
+
data: { fragmentName, filePath: fragmentUsage[0] },
|
79
|
+
});
|
80
|
+
}
|
81
|
+
},
|
82
|
+
};
|
83
|
+
},
|
84
|
+
};
|
package/docs/README.md
CHANGED
@@ -36,6 +36,7 @@ Name &nbs
|
|
36
36
|
[no-duplicate-fields](rules/no-duplicate-fields.md)|Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.|![recommended][]|đĻ|đ|đĄ
|
37
37
|
[no-fragment-cycles](rules/no-fragment-cycles.md)|A GraphQL fragment is only valid when it does not have cycles in fragments usage.|![recommended][]|đĻ|đŽ|
|
38
38
|
[no-hashtag-description](rules/no-hashtag-description.md)|Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.|![recommended][]|đ|đ|đĄ
|
39
|
+
[no-one-place-fragments](rules/no-one-place-fragments.md)|Disallow fragments that are used only in one place.|![all][]|đĻ|đ|
|
39
40
|
[no-root-type](rules/no-root-type.md)|Disallow using root types `mutation` and/or `subscription`.||đ|đ|đĄ
|
40
41
|
[no-scalar-result-type-on-mutation](rules/no-scalar-result-type-on-mutation.md)|Avoid scalar result type on mutation type to make sure to return a valid state.|![all][]|đ|đ|đĄ
|
41
42
|
[no-typename-prefix](rules/no-typename-prefix.md)|Enforces users to avoid using the type name in a field name while defining your schema.|![recommended][]|đ|đ|đĄ
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# `no-one-place-fragments`
|
2
|
+
|
3
|
+
- Category: `Operations`
|
4
|
+
- Rule name: `@graphql-eslint/no-one-place-fragments`
|
5
|
+
- Requires GraphQL Schema: `false` [âšī¸](../../README.md#extended-linting-rules-with-graphql-schema)
|
6
|
+
- Requires GraphQL Operations: `true`
|
7
|
+
[âšī¸](../../README.md#extended-linting-rules-with-siblings-operations)
|
8
|
+
|
9
|
+
Disallow fragments that are used only in one place.
|
10
|
+
|
11
|
+
## Usage Examples
|
12
|
+
|
13
|
+
### Incorrect
|
14
|
+
|
15
|
+
```graphql
|
16
|
+
# eslint @graphql-eslint/no-one-place-fragments: 'error'
|
17
|
+
|
18
|
+
fragment UserFields on User {
|
19
|
+
id
|
20
|
+
}
|
21
|
+
|
22
|
+
{
|
23
|
+
user {
|
24
|
+
...UserFields
|
25
|
+
friends {
|
26
|
+
...UserFields
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
```
|
31
|
+
|
32
|
+
### Correct
|
33
|
+
|
34
|
+
```graphql
|
35
|
+
# eslint @graphql-eslint/no-one-place-fragments: 'error'
|
36
|
+
|
37
|
+
fragment UserFields on User {
|
38
|
+
id
|
39
|
+
}
|
40
|
+
|
41
|
+
{
|
42
|
+
user {
|
43
|
+
...UserFields
|
44
|
+
}
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
48
|
+
## Resources
|
49
|
+
|
50
|
+
- [Rule source](../../packages/plugin/src/rules/no-one-place-fragments.ts)
|
51
|
+
- [Test source](../../packages/plugin/tests/no-one-place-fragments.spec.ts)
|
package/package.json
CHANGED
@@ -125,6 +125,7 @@ export declare const configs: {
|
|
125
125
|
subscription: string;
|
126
126
|
fragment: string;
|
127
127
|
})[];
|
128
|
+
'@graphql-eslint/no-one-place-fragments': string;
|
128
129
|
'@graphql-eslint/unique-fragment-name': string;
|
129
130
|
'@graphql-eslint/unique-operation-name': string;
|
130
131
|
};
|
@@ -125,6 +125,7 @@ export declare const configs: {
|
|
125
125
|
subscription: string;
|
126
126
|
fragment: string;
|
127
127
|
})[];
|
128
|
+
'@graphql-eslint/no-one-place-fragments': string;
|
128
129
|
'@graphql-eslint/unique-fragment-name': string;
|
129
130
|
'@graphql-eslint/unique-operation-name': string;
|
130
131
|
};
|
@@ -61,6 +61,7 @@ export declare const rules: {
|
|
61
61
|
'no-deprecated': import("..").GraphQLESLintRule<[], true>;
|
62
62
|
'no-duplicate-fields': import("..").GraphQLESLintRule<any[], false>;
|
63
63
|
'no-hashtag-description': import("..").GraphQLESLintRule<any[], false>;
|
64
|
+
'no-one-place-fragments': import("..").GraphQLESLintRule<any[], false>;
|
64
65
|
'no-root-type': import("..").GraphQLESLintRule<{
|
65
66
|
disallow: ("mutation" | "subscription")[];
|
66
67
|
}[], false>;
|
package/typings/rules/index.d.ts
CHANGED
@@ -61,6 +61,7 @@ export declare const rules: {
|
|
61
61
|
'no-deprecated': import("..").GraphQLESLintRule<[], true>;
|
62
62
|
'no-duplicate-fields': import("..").GraphQLESLintRule<any[], false>;
|
63
63
|
'no-hashtag-description': import("..").GraphQLESLintRule<any[], false>;
|
64
|
+
'no-one-place-fragments': import("..").GraphQLESLintRule<any[], false>;
|
64
65
|
'no-root-type': import("..").GraphQLESLintRule<{
|
65
66
|
disallow: ("mutation" | "subscription")[];
|
66
67
|
}[], false>;
|