@graphql-eslint/eslint-plugin 4.1.0-alpha-20241128213211-47212e29bd7289aab6adc9e573221d04e2818bac → 4.1.0-alpha-20241129084707-436164c7c2041bfc29ccb7abed9a3c3fb4db5520
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.d.cts +2 -2
- package/cjs/meta.js +1 -1
- package/cjs/rules/index.d.cts +2 -2
- package/cjs/rules/naming-convention/index.d.cts +2 -2
- package/cjs/rules/naming-convention/index.js +14 -12
- package/cjs/rules/no-unused-fields/index.js +1 -3
- package/cjs/rules/require-description/index.d.cts +3 -2
- package/cjs/rules/require-description/index.js +60 -6
- package/cjs/utils.d.cts +2 -1
- package/cjs/utils.js +6 -1
- package/esm/index.d.ts +2 -2
- package/esm/meta.js +1 -1
- package/esm/rules/index.d.ts +2 -2
- package/esm/rules/naming-convention/index.d.ts +2 -2
- package/esm/rules/naming-convention/index.js +14 -12
- package/esm/rules/no-unused-fields/index.js +2 -4
- package/esm/rules/require-description/index.d.ts +3 -2
- package/esm/rules/require-description/index.js +61 -7
- package/esm/utils.d.ts +2 -1
- package/esm/utils.js +5 -0
- package/index.browser.js +73 -22
- package/package.json +1 -1
package/cjs/index.d.cts
CHANGED
@@ -98,10 +98,10 @@ declare const _default: {
|
|
98
98
|
style?: ("camelCase" | "PascalCase" | "snake_case" | "UPPER_CASE") | undefined;
|
99
99
|
suffix?: string | undefined;
|
100
100
|
prefix?: string | undefined;
|
101
|
-
|
101
|
+
forbiddenPatterns?: {
|
102
102
|
[x: string]: unknown;
|
103
103
|
}[] | undefined;
|
104
|
-
|
104
|
+
requiredPatterns?: {
|
105
105
|
[x: string]: unknown;
|
106
106
|
}[] | undefined;
|
107
107
|
forbiddenPrefixes?: string[] | undefined;
|
package/cjs/meta.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true});const version = "4.1.0-alpha-
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});const version = "4.1.0-alpha-20241129084707-436164c7c2041bfc29ccb7abed9a3c3fb4db5520";
|
2
2
|
|
3
3
|
|
4
4
|
exports.version = version;
|
package/cjs/rules/index.d.cts
CHANGED
@@ -61,10 +61,10 @@ declare const rules: {
|
|
61
61
|
style?: ("camelCase" | "PascalCase" | "snake_case" | "UPPER_CASE") | undefined;
|
62
62
|
suffix?: string | undefined;
|
63
63
|
prefix?: string | undefined;
|
64
|
-
|
64
|
+
forbiddenPatterns?: {
|
65
65
|
[x: string]: unknown;
|
66
66
|
}[] | undefined;
|
67
|
-
|
67
|
+
requiredPatterns?: {
|
68
68
|
[x: string]: unknown;
|
69
69
|
}[] | undefined;
|
70
70
|
forbiddenPrefixes?: string[] | undefined;
|
@@ -28,7 +28,7 @@ declare const schema: {
|
|
28
28
|
readonly suffix: {
|
29
29
|
readonly type: "string";
|
30
30
|
};
|
31
|
-
readonly
|
31
|
+
readonly forbiddenPatterns: {
|
32
32
|
readonly items: {
|
33
33
|
readonly type: "object";
|
34
34
|
};
|
@@ -37,7 +37,7 @@ declare const schema: {
|
|
37
37
|
readonly uniqueItems: true;
|
38
38
|
readonly minItems: 1;
|
39
39
|
};
|
40
|
-
readonly
|
40
|
+
readonly requiredPatterns: {
|
41
41
|
readonly items: {
|
42
42
|
readonly type: "object";
|
43
43
|
};
|
@@ -47,14 +47,14 @@ const KindToDisplayName = {
|
|
47
47
|
style: { enum: ALLOWED_STYLES },
|
48
48
|
prefix: { type: "string" },
|
49
49
|
suffix: { type: "string" },
|
50
|
-
|
50
|
+
forbiddenPatterns: {
|
51
51
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
52
52
|
items: {
|
53
53
|
type: "object"
|
54
54
|
},
|
55
55
|
description: "Should be of instance of `RegEx`"
|
56
56
|
},
|
57
|
-
|
57
|
+
requiredPatterns: {
|
58
58
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
59
59
|
items: {
|
60
60
|
type: "object"
|
@@ -63,19 +63,19 @@ const KindToDisplayName = {
|
|
63
63
|
},
|
64
64
|
forbiddenPrefixes: {
|
65
65
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
66
|
-
description: descriptionPrefixesSuffixes("
|
66
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
67
67
|
},
|
68
68
|
forbiddenSuffixes: {
|
69
69
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
70
|
-
description: descriptionPrefixesSuffixes("
|
70
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
71
71
|
},
|
72
72
|
requiredPrefixes: {
|
73
73
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
74
|
-
description: descriptionPrefixesSuffixes("
|
74
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
75
75
|
},
|
76
76
|
requiredSuffixes: {
|
77
77
|
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
78
|
-
description: descriptionPrefixesSuffixes("
|
78
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
79
79
|
},
|
80
80
|
ignorePattern: {
|
81
81
|
type: "string",
|
@@ -101,7 +101,9 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
101
101
|
kind,
|
102
102
|
{
|
103
103
|
...schemaOption,
|
104
|
-
description:
|
104
|
+
description: `> [!NOTE]
|
105
|
+
>
|
106
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`
|
105
107
|
}
|
106
108
|
])
|
107
109
|
),
|
@@ -356,8 +358,8 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
356
358
|
ignorePattern,
|
357
359
|
requiredPrefixes,
|
358
360
|
requiredSuffixes,
|
359
|
-
|
360
|
-
|
361
|
+
forbiddenPatterns,
|
362
|
+
requiredPatterns
|
361
363
|
} = normalisePropertyOption(selector), nodeName = node.value, error = getError();
|
362
364
|
if (error) {
|
363
365
|
const { errorMessage, renameToNames } = error, [leadingUnderscores] = nodeName.match(/^_*/), [trailingUnderscores] = nodeName.match(/_*$/), suggestedNames = renameToNames.map(
|
@@ -383,15 +385,15 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
383
385
|
errorMessage: `have "${suffix}" suffix`,
|
384
386
|
renameToNames: [name + suffix]
|
385
387
|
};
|
386
|
-
const forbidden = _optionalChain([
|
388
|
+
const forbidden = _optionalChain([forbiddenPatterns, 'optionalAccess', _ => _.find, 'call', _2 => _2((pattern) => pattern.test(name))]);
|
387
389
|
if (forbidden)
|
388
390
|
return {
|
389
391
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
390
392
|
renameToNames: [name.replace(forbidden, "")]
|
391
393
|
};
|
392
|
-
if (
|
394
|
+
if (requiredPatterns && !requiredPatterns.some((pattern) => pattern.test(name)))
|
393
395
|
return {
|
394
|
-
errorMessage: `contain the required pattern: ${_utilsjs.englishJoinWords.call(void 0,
|
396
|
+
errorMessage: `contain the required pattern: ${_utilsjs.englishJoinWords.call(void 0, requiredPatterns.map((re) => re.source))}`,
|
395
397
|
renameToNames: []
|
396
398
|
};
|
397
399
|
const forbiddenPrefix = _optionalChain([forbiddenPrefixes, 'optionalAccess', _3 => _3.find, 'call', _4 => _4((prefix2) => name.startsWith(prefix2))]);
|
@@ -82,9 +82,7 @@ const RULE_ID = "no-unused-fields", RELAY_SCHEMA = (
|
|
82
82
|
"```json",
|
83
83
|
JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
|
84
84
|
"```",
|
85
|
-
|
86
|
-
"> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).",
|
87
|
-
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector."
|
85
|
+
_utilsjs.eslintSelectorsTip
|
88
86
|
].join(`
|
89
87
|
`),
|
90
88
|
items: {
|
@@ -1,5 +1,12 @@
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _graphql = require('graphql');
|
2
2
|
var _utils = require('@graphql-tools/utils');
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
3
10
|
var _utilsjs = require('../../utils.js');
|
4
11
|
const RULE_ID = "require-description", ALLOWED_KINDS = [
|
5
12
|
..._utilsjs.TYPES_KINDS,
|
@@ -19,18 +26,34 @@ const RULE_ID = "require-description", ALLOWED_KINDS = [
|
|
19
26
|
properties: {
|
20
27
|
types: {
|
21
28
|
type: "boolean",
|
29
|
+
enum: [!0],
|
22
30
|
description: `Includes:
|
23
31
|
${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
24
32
|
`)}`
|
25
33
|
},
|
26
34
|
rootField: {
|
27
35
|
type: "boolean",
|
36
|
+
enum: [!0],
|
28
37
|
description: "Definitions within `Query`, `Mutation`, and `Subscription` root types."
|
29
38
|
},
|
39
|
+
ignoredSelectors: {
|
40
|
+
..._utilsjs.ARRAY_DEFAULT_OPTIONS,
|
41
|
+
description: ["Ignore specific selectors", _utilsjs.eslintSelectorsTip].join(`
|
42
|
+
`)
|
43
|
+
},
|
30
44
|
...Object.fromEntries(
|
31
45
|
[...ALLOWED_KINDS].sort().map((kind) => {
|
32
|
-
let description =
|
33
|
-
|
46
|
+
let description = `> [!NOTE]
|
47
|
+
>
|
48
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
49
|
+
return kind === _graphql.Kind.OPERATION_DEFINITION && (description += [
|
50
|
+
"",
|
51
|
+
"",
|
52
|
+
"> [!WARNING]",
|
53
|
+
">",
|
54
|
+
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
55
|
+
].join(`
|
56
|
+
`)), [kind, { type: "boolean", description }];
|
34
57
|
})
|
35
58
|
)
|
36
59
|
}
|
@@ -101,6 +124,36 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
101
124
|
}
|
102
125
|
`
|
103
126
|
)
|
127
|
+
},
|
128
|
+
{
|
129
|
+
title: "Correct",
|
130
|
+
usage: [
|
131
|
+
{
|
132
|
+
ignoredSelectors: [
|
133
|
+
"[type=ObjectTypeDefinition][name.value=PageInfo]",
|
134
|
+
"[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]"
|
135
|
+
]
|
136
|
+
}
|
137
|
+
],
|
138
|
+
code: (
|
139
|
+
/* GraphQL */
|
140
|
+
`
|
141
|
+
type FriendConnection {
|
142
|
+
edges: [FriendEdge]
|
143
|
+
pageInfo: PageInfo!
|
144
|
+
}
|
145
|
+
type FriendEdge {
|
146
|
+
cursor: String!
|
147
|
+
node: Friend!
|
148
|
+
}
|
149
|
+
type PageInfo {
|
150
|
+
hasPreviousPage: Boolean!
|
151
|
+
hasNextPage: Boolean!
|
152
|
+
startCursor: String
|
153
|
+
endCursor: String
|
154
|
+
}
|
155
|
+
`
|
156
|
+
)
|
104
157
|
}
|
105
158
|
],
|
106
159
|
configOptions: [
|
@@ -119,7 +172,7 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
119
172
|
schema
|
120
173
|
},
|
121
174
|
create(context) {
|
122
|
-
const { types, rootField, ...restOptions } = context.options[0] || {}, kinds = new Set(types ? _utilsjs.TYPES_KINDS : []);
|
175
|
+
const { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {}, kinds = new Set(types ? _utilsjs.TYPES_KINDS : []);
|
123
176
|
for (const [kind, isEnabled] of Object.entries(restOptions))
|
124
177
|
isEnabled ? kinds.add(kind) : kinds.delete(kind);
|
125
178
|
if (rootField) {
|
@@ -130,10 +183,11 @@ ${_utilsjs.TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
130
183
|
].join(",")})$/] > FieldDefinition`
|
131
184
|
);
|
132
185
|
}
|
133
|
-
|
134
|
-
|
186
|
+
let selector = `:matches(${[...kinds]})`;
|
187
|
+
for (const str of ignoredSelectors)
|
188
|
+
selector += `:not(${str})`;
|
135
189
|
return {
|
136
|
-
[
|
190
|
+
[selector](node) {
|
137
191
|
let description = "";
|
138
192
|
const isOperation = node.kind === _graphql.Kind.OPERATION_DEFINITION;
|
139
193
|
if (isOperation) {
|
package/cjs/utils.d.cts
CHANGED
@@ -41,5 +41,6 @@ type Truthy<T> = T extends '' | 0 | false | null | undefined ? never : T;
|
|
41
41
|
declare function truthy<T>(value: T): value is Truthy<T>;
|
42
42
|
declare function displayNodeName(node: GraphQLESTreeNode<ASTNode, boolean>): string;
|
43
43
|
declare function getNodeName(node: GraphQLESTreeNode<ASTNode>): string;
|
44
|
+
declare const eslintSelectorsTip = "> [!TIP]\n>\n> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).\n> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.";
|
44
45
|
|
45
|
-
export { ARRAY_DEFAULT_OPTIONS, CWD, type CaseStyle, REPORT_ON_FIRST_CHARACTER, TYPES_KINDS, VIRTUAL_DOCUMENT_REGEX, camelCase, convertCase, displayNodeName, englishJoinWords, getLocation, getNodeName, getTypeName, logger, pascalCase, requireGraphQLOperations, requireGraphQLSchema, slash, truthy };
|
46
|
+
export { ARRAY_DEFAULT_OPTIONS, CWD, type CaseStyle, REPORT_ON_FIRST_CHARACTER, TYPES_KINDS, VIRTUAL_DOCUMENT_REGEX, camelCase, convertCase, displayNodeName, englishJoinWords, eslintSelectorsTip, getLocation, getNodeName, getTypeName, logger, pascalCase, requireGraphQLOperations, requireGraphQLSchema, slash, truthy };
|
package/cjs/utils.js
CHANGED
@@ -144,6 +144,10 @@ function getNodeName(node) {
|
|
144
144
|
}
|
145
145
|
return "";
|
146
146
|
}
|
147
|
+
const eslintSelectorsTip = `> [!TIP]
|
148
|
+
>
|
149
|
+
> These fields are defined by ESLint [\`selectors\`](https://eslint.org/docs/developer-guide/selectors).
|
150
|
+
> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.`;
|
147
151
|
|
148
152
|
|
149
153
|
|
@@ -163,4 +167,5 @@ function getNodeName(node) {
|
|
163
167
|
|
164
168
|
|
165
169
|
|
166
|
-
|
170
|
+
|
171
|
+
exports.ARRAY_DEFAULT_OPTIONS = ARRAY_DEFAULT_OPTIONS; exports.CWD = CWD; exports.REPORT_ON_FIRST_CHARACTER = REPORT_ON_FIRST_CHARACTER; exports.TYPES_KINDS = TYPES_KINDS; exports.VIRTUAL_DOCUMENT_REGEX = VIRTUAL_DOCUMENT_REGEX; exports.camelCase = camelCase; exports.convertCase = convertCase; exports.displayNodeName = displayNodeName; exports.englishJoinWords = englishJoinWords; exports.eslintSelectorsTip = eslintSelectorsTip; exports.getLocation = getLocation; exports.getNodeName = getNodeName; exports.getTypeName = getTypeName; exports.logger = logger; exports.pascalCase = pascalCase; exports.requireGraphQLOperations = requireGraphQLOperations; exports.requireGraphQLSchema = requireGraphQLSchema; exports.slash = slash; exports.truthy = truthy;
|
package/esm/index.d.ts
CHANGED
@@ -98,10 +98,10 @@ declare const _default: {
|
|
98
98
|
style?: ("camelCase" | "PascalCase" | "snake_case" | "UPPER_CASE") | undefined;
|
99
99
|
suffix?: string | undefined;
|
100
100
|
prefix?: string | undefined;
|
101
|
-
|
101
|
+
forbiddenPatterns?: {
|
102
102
|
[x: string]: unknown;
|
103
103
|
}[] | undefined;
|
104
|
-
|
104
|
+
requiredPatterns?: {
|
105
105
|
[x: string]: unknown;
|
106
106
|
}[] | undefined;
|
107
107
|
forbiddenPrefixes?: string[] | undefined;
|
package/esm/meta.js
CHANGED
package/esm/rules/index.d.ts
CHANGED
@@ -61,10 +61,10 @@ declare const rules: {
|
|
61
61
|
style?: ("camelCase" | "PascalCase" | "snake_case" | "UPPER_CASE") | undefined;
|
62
62
|
suffix?: string | undefined;
|
63
63
|
prefix?: string | undefined;
|
64
|
-
|
64
|
+
forbiddenPatterns?: {
|
65
65
|
[x: string]: unknown;
|
66
66
|
}[] | undefined;
|
67
|
-
|
67
|
+
requiredPatterns?: {
|
68
68
|
[x: string]: unknown;
|
69
69
|
}[] | undefined;
|
70
70
|
forbiddenPrefixes?: string[] | undefined;
|
@@ -28,7 +28,7 @@ declare const schema: {
|
|
28
28
|
readonly suffix: {
|
29
29
|
readonly type: "string";
|
30
30
|
};
|
31
|
-
readonly
|
31
|
+
readonly forbiddenPatterns: {
|
32
32
|
readonly items: {
|
33
33
|
readonly type: "object";
|
34
34
|
};
|
@@ -37,7 +37,7 @@ declare const schema: {
|
|
37
37
|
readonly uniqueItems: true;
|
38
38
|
readonly minItems: 1;
|
39
39
|
};
|
40
|
-
readonly
|
40
|
+
readonly requiredPatterns: {
|
41
41
|
readonly items: {
|
42
42
|
readonly type: "object";
|
43
43
|
};
|
@@ -47,14 +47,14 @@ const KindToDisplayName = {
|
|
47
47
|
style: { enum: ALLOWED_STYLES },
|
48
48
|
prefix: { type: "string" },
|
49
49
|
suffix: { type: "string" },
|
50
|
-
|
50
|
+
forbiddenPatterns: {
|
51
51
|
...ARRAY_DEFAULT_OPTIONS,
|
52
52
|
items: {
|
53
53
|
type: "object"
|
54
54
|
},
|
55
55
|
description: "Should be of instance of `RegEx`"
|
56
56
|
},
|
57
|
-
|
57
|
+
requiredPatterns: {
|
58
58
|
...ARRAY_DEFAULT_OPTIONS,
|
59
59
|
items: {
|
60
60
|
type: "object"
|
@@ -63,19 +63,19 @@ const KindToDisplayName = {
|
|
63
63
|
},
|
64
64
|
forbiddenPrefixes: {
|
65
65
|
...ARRAY_DEFAULT_OPTIONS,
|
66
|
-
description: descriptionPrefixesSuffixes("
|
66
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
67
67
|
},
|
68
68
|
forbiddenSuffixes: {
|
69
69
|
...ARRAY_DEFAULT_OPTIONS,
|
70
|
-
description: descriptionPrefixesSuffixes("
|
70
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
71
71
|
},
|
72
72
|
requiredPrefixes: {
|
73
73
|
...ARRAY_DEFAULT_OPTIONS,
|
74
|
-
description: descriptionPrefixesSuffixes("
|
74
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
75
75
|
},
|
76
76
|
requiredSuffixes: {
|
77
77
|
...ARRAY_DEFAULT_OPTIONS,
|
78
|
-
description: descriptionPrefixesSuffixes("
|
78
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
79
79
|
},
|
80
80
|
ignorePattern: {
|
81
81
|
type: "string",
|
@@ -101,7 +101,9 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
101
101
|
kind,
|
102
102
|
{
|
103
103
|
...schemaOption,
|
104
|
-
description:
|
104
|
+
description: `> [!NOTE]
|
105
|
+
>
|
106
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`
|
105
107
|
}
|
106
108
|
])
|
107
109
|
),
|
@@ -356,8 +358,8 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
356
358
|
ignorePattern,
|
357
359
|
requiredPrefixes,
|
358
360
|
requiredSuffixes,
|
359
|
-
|
360
|
-
|
361
|
+
forbiddenPatterns,
|
362
|
+
requiredPatterns
|
361
363
|
} = normalisePropertyOption(selector), nodeName = node.value, error = getError();
|
362
364
|
if (error) {
|
363
365
|
const { errorMessage, renameToNames } = error, [leadingUnderscores] = nodeName.match(/^_*/), [trailingUnderscores] = nodeName.match(/_*$/), suggestedNames = renameToNames.map(
|
@@ -383,15 +385,15 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
383
385
|
errorMessage: `have "${suffix}" suffix`,
|
384
386
|
renameToNames: [name + suffix]
|
385
387
|
};
|
386
|
-
const forbidden =
|
388
|
+
const forbidden = forbiddenPatterns?.find((pattern) => pattern.test(name));
|
387
389
|
if (forbidden)
|
388
390
|
return {
|
389
391
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
390
392
|
renameToNames: [name.replace(forbidden, "")]
|
391
393
|
};
|
392
|
-
if (
|
394
|
+
if (requiredPatterns && !requiredPatterns.some((pattern) => pattern.test(name)))
|
393
395
|
return {
|
394
|
-
errorMessage: `contain the required pattern: ${englishJoinWords(
|
396
|
+
errorMessage: `contain the required pattern: ${englishJoinWords(requiredPatterns.map((re) => re.source))}`,
|
395
397
|
renameToNames: []
|
396
398
|
};
|
397
399
|
const forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { TypeInfo, visit, visitWithTypeInfo } from "graphql";
|
2
2
|
import { ModuleCache } from "../../cache.js";
|
3
|
-
import { requireGraphQLOperations, requireGraphQLSchema } from "../../utils.js";
|
3
|
+
import { eslintSelectorsTip, requireGraphQLOperations, requireGraphQLSchema } from "../../utils.js";
|
4
4
|
const RULE_ID = "no-unused-fields", RELAY_SCHEMA = (
|
5
5
|
/* GraphQL */
|
6
6
|
`
|
@@ -82,9 +82,7 @@ const RULE_ID = "no-unused-fields", RELAY_SCHEMA = (
|
|
82
82
|
"```json",
|
83
83
|
JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
|
84
84
|
"```",
|
85
|
-
|
86
|
-
"> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).",
|
87
|
-
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector."
|
85
|
+
eslintSelectorsTip
|
88
86
|
].join(`
|
89
87
|
`),
|
90
88
|
items: {
|
@@ -1,6 +1,13 @@
|
|
1
1
|
import { Kind, TokenKind } from "graphql";
|
2
2
|
import { getRootTypeNames } from "@graphql-tools/utils";
|
3
|
-
import {
|
3
|
+
import {
|
4
|
+
ARRAY_DEFAULT_OPTIONS,
|
5
|
+
eslintSelectorsTip,
|
6
|
+
getLocation,
|
7
|
+
getNodeName,
|
8
|
+
requireGraphQLSchema,
|
9
|
+
TYPES_KINDS
|
10
|
+
} from "../../utils.js";
|
4
11
|
const RULE_ID = "require-description", ALLOWED_KINDS = [
|
5
12
|
...TYPES_KINDS,
|
6
13
|
Kind.DIRECTIVE_DEFINITION,
|
@@ -19,18 +26,34 @@ const RULE_ID = "require-description", ALLOWED_KINDS = [
|
|
19
26
|
properties: {
|
20
27
|
types: {
|
21
28
|
type: "boolean",
|
29
|
+
enum: [!0],
|
22
30
|
description: `Includes:
|
23
31
|
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
24
32
|
`)}`
|
25
33
|
},
|
26
34
|
rootField: {
|
27
35
|
type: "boolean",
|
36
|
+
enum: [!0],
|
28
37
|
description: "Definitions within `Query`, `Mutation`, and `Subscription` root types."
|
29
38
|
},
|
39
|
+
ignoredSelectors: {
|
40
|
+
...ARRAY_DEFAULT_OPTIONS,
|
41
|
+
description: ["Ignore specific selectors", eslintSelectorsTip].join(`
|
42
|
+
`)
|
43
|
+
},
|
30
44
|
...Object.fromEntries(
|
31
45
|
[...ALLOWED_KINDS].sort().map((kind) => {
|
32
|
-
let description =
|
33
|
-
|
46
|
+
let description = `> [!NOTE]
|
47
|
+
>
|
48
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
49
|
+
return kind === Kind.OPERATION_DEFINITION && (description += [
|
50
|
+
"",
|
51
|
+
"",
|
52
|
+
"> [!WARNING]",
|
53
|
+
">",
|
54
|
+
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
55
|
+
].join(`
|
56
|
+
`)), [kind, { type: "boolean", description }];
|
34
57
|
})
|
35
58
|
)
|
36
59
|
}
|
@@ -101,6 +124,36 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
101
124
|
}
|
102
125
|
`
|
103
126
|
)
|
127
|
+
},
|
128
|
+
{
|
129
|
+
title: "Correct",
|
130
|
+
usage: [
|
131
|
+
{
|
132
|
+
ignoredSelectors: [
|
133
|
+
"[type=ObjectTypeDefinition][name.value=PageInfo]",
|
134
|
+
"[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]"
|
135
|
+
]
|
136
|
+
}
|
137
|
+
],
|
138
|
+
code: (
|
139
|
+
/* GraphQL */
|
140
|
+
`
|
141
|
+
type FriendConnection {
|
142
|
+
edges: [FriendEdge]
|
143
|
+
pageInfo: PageInfo!
|
144
|
+
}
|
145
|
+
type FriendEdge {
|
146
|
+
cursor: String!
|
147
|
+
node: Friend!
|
148
|
+
}
|
149
|
+
type PageInfo {
|
150
|
+
hasPreviousPage: Boolean!
|
151
|
+
hasNextPage: Boolean!
|
152
|
+
startCursor: String
|
153
|
+
endCursor: String
|
154
|
+
}
|
155
|
+
`
|
156
|
+
)
|
104
157
|
}
|
105
158
|
],
|
106
159
|
configOptions: [
|
@@ -119,7 +172,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
119
172
|
schema
|
120
173
|
},
|
121
174
|
create(context) {
|
122
|
-
const { types, rootField, ...restOptions } = context.options[0] || {}, kinds = new Set(types ? TYPES_KINDS : []);
|
175
|
+
const { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {}, kinds = new Set(types ? TYPES_KINDS : []);
|
123
176
|
for (const [kind, isEnabled] of Object.entries(restOptions))
|
124
177
|
isEnabled ? kinds.add(kind) : kinds.delete(kind);
|
125
178
|
if (rootField) {
|
@@ -130,10 +183,11 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
130
183
|
].join(",")})$/] > FieldDefinition`
|
131
184
|
);
|
132
185
|
}
|
133
|
-
|
134
|
-
|
186
|
+
let selector = `:matches(${[...kinds]})`;
|
187
|
+
for (const str of ignoredSelectors)
|
188
|
+
selector += `:not(${str})`;
|
135
189
|
return {
|
136
|
-
[
|
190
|
+
[selector](node) {
|
137
191
|
let description = "";
|
138
192
|
const isOperation = node.kind === Kind.OPERATION_DEFINITION;
|
139
193
|
if (isOperation) {
|
package/esm/utils.d.ts
CHANGED
@@ -41,5 +41,6 @@ type Truthy<T> = T extends '' | 0 | false | null | undefined ? never : T;
|
|
41
41
|
declare function truthy<T>(value: T): value is Truthy<T>;
|
42
42
|
declare function displayNodeName(node: GraphQLESTreeNode<ASTNode, boolean>): string;
|
43
43
|
declare function getNodeName(node: GraphQLESTreeNode<ASTNode>): string;
|
44
|
+
declare const eslintSelectorsTip = "> [!TIP]\n>\n> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).\n> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.";
|
44
45
|
|
45
|
-
export { ARRAY_DEFAULT_OPTIONS, CWD, type CaseStyle, REPORT_ON_FIRST_CHARACTER, TYPES_KINDS, VIRTUAL_DOCUMENT_REGEX, camelCase, convertCase, displayNodeName, englishJoinWords, getLocation, getNodeName, getTypeName, logger, pascalCase, requireGraphQLOperations, requireGraphQLSchema, slash, truthy };
|
46
|
+
export { ARRAY_DEFAULT_OPTIONS, CWD, type CaseStyle, REPORT_ON_FIRST_CHARACTER, TYPES_KINDS, VIRTUAL_DOCUMENT_REGEX, camelCase, convertCase, displayNodeName, englishJoinWords, eslintSelectorsTip, getLocation, getNodeName, getTypeName, logger, pascalCase, requireGraphQLOperations, requireGraphQLSchema, slash, truthy };
|
package/esm/utils.js
CHANGED
@@ -144,6 +144,10 @@ function getNodeName(node) {
|
|
144
144
|
}
|
145
145
|
return "";
|
146
146
|
}
|
147
|
+
const eslintSelectorsTip = `> [!TIP]
|
148
|
+
>
|
149
|
+
> These fields are defined by ESLint [\`selectors\`](https://eslint.org/docs/developer-guide/selectors).
|
150
|
+
> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.`;
|
147
151
|
export {
|
148
152
|
ARRAY_DEFAULT_OPTIONS,
|
149
153
|
CWD,
|
@@ -154,6 +158,7 @@ export {
|
|
154
158
|
convertCase,
|
155
159
|
displayNodeName,
|
156
160
|
englishJoinWords,
|
161
|
+
eslintSelectorsTip,
|
157
162
|
getLocation,
|
158
163
|
getNodeName,
|
159
164
|
getTypeName,
|
package/index.browser.js
CHANGED
@@ -150,7 +150,7 @@ function convertToESTree(node, schema16) {
|
|
150
150
|
}
|
151
151
|
|
152
152
|
// src/meta.ts
|
153
|
-
var version = "4.1.0-alpha-
|
153
|
+
var version = "4.1.0-alpha-20241129084707-436164c7c2041bfc29ccb7abed9a3c3fb4db5520";
|
154
154
|
|
155
155
|
// src/siblings.ts
|
156
156
|
import {
|
@@ -305,6 +305,10 @@ function getNodeName(node) {
|
|
305
305
|
}
|
306
306
|
return "";
|
307
307
|
}
|
308
|
+
var eslintSelectorsTip = `> [!TIP]
|
309
|
+
>
|
310
|
+
> These fields are defined by ESLint [\`selectors\`](https://eslint.org/docs/developer-guide/selectors).
|
311
|
+
> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.`;
|
308
312
|
|
309
313
|
// src/siblings.ts
|
310
314
|
var siblingOperationsCache = /* @__PURE__ */ new Map();
|
@@ -1934,14 +1938,14 @@ var KindToDisplayName = {
|
|
1934
1938
|
style: { enum: ALLOWED_STYLES },
|
1935
1939
|
prefix: { type: "string" },
|
1936
1940
|
suffix: { type: "string" },
|
1937
|
-
|
1941
|
+
forbiddenPatterns: {
|
1938
1942
|
...ARRAY_DEFAULT_OPTIONS,
|
1939
1943
|
items: {
|
1940
1944
|
type: "object"
|
1941
1945
|
},
|
1942
1946
|
description: "Should be of instance of `RegEx`"
|
1943
1947
|
},
|
1944
|
-
|
1948
|
+
requiredPatterns: {
|
1945
1949
|
...ARRAY_DEFAULT_OPTIONS,
|
1946
1950
|
items: {
|
1947
1951
|
type: "object"
|
@@ -1950,19 +1954,19 @@ var KindToDisplayName = {
|
|
1950
1954
|
},
|
1951
1955
|
forbiddenPrefixes: {
|
1952
1956
|
...ARRAY_DEFAULT_OPTIONS,
|
1953
|
-
description: descriptionPrefixesSuffixes("
|
1957
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
1954
1958
|
},
|
1955
1959
|
forbiddenSuffixes: {
|
1956
1960
|
...ARRAY_DEFAULT_OPTIONS,
|
1957
|
-
description: descriptionPrefixesSuffixes("
|
1961
|
+
description: descriptionPrefixesSuffixes("forbiddenPatterns")
|
1958
1962
|
},
|
1959
1963
|
requiredPrefixes: {
|
1960
1964
|
...ARRAY_DEFAULT_OPTIONS,
|
1961
|
-
description: descriptionPrefixesSuffixes("
|
1965
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
1962
1966
|
},
|
1963
1967
|
requiredSuffixes: {
|
1964
1968
|
...ARRAY_DEFAULT_OPTIONS,
|
1965
|
-
description: descriptionPrefixesSuffixes("
|
1969
|
+
description: descriptionPrefixesSuffixes("requiredPatterns")
|
1966
1970
|
},
|
1967
1971
|
ignorePattern: {
|
1968
1972
|
type: "string",
|
@@ -1988,7 +1992,9 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
1988
1992
|
kind,
|
1989
1993
|
{
|
1990
1994
|
...schemaOption2,
|
1991
|
-
description:
|
1995
|
+
description: `> [!NOTE]
|
1996
|
+
>
|
1997
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`
|
1992
1998
|
}
|
1993
1999
|
])
|
1994
2000
|
),
|
@@ -2243,8 +2249,8 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2243
2249
|
ignorePattern,
|
2244
2250
|
requiredPrefixes,
|
2245
2251
|
requiredSuffixes,
|
2246
|
-
|
2247
|
-
|
2252
|
+
forbiddenPatterns,
|
2253
|
+
requiredPatterns
|
2248
2254
|
} = normalisePropertyOption(selector), nodeName = node.value, error = getError();
|
2249
2255
|
if (error) {
|
2250
2256
|
let { errorMessage, renameToNames } = error, [leadingUnderscores] = nodeName.match(/^_*/), [trailingUnderscores] = nodeName.match(/_*$/), suggestedNames = renameToNames.map(
|
@@ -2270,15 +2276,15 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
2270
2276
|
errorMessage: `have "${suffix}" suffix`,
|
2271
2277
|
renameToNames: [name + suffix]
|
2272
2278
|
};
|
2273
|
-
let forbidden =
|
2279
|
+
let forbidden = forbiddenPatterns?.find((pattern) => pattern.test(name));
|
2274
2280
|
if (forbidden)
|
2275
2281
|
return {
|
2276
2282
|
errorMessage: `not contain the forbidden pattern "${forbidden}"`,
|
2277
2283
|
renameToNames: [name.replace(forbidden, "")]
|
2278
2284
|
};
|
2279
|
-
if (
|
2285
|
+
if (requiredPatterns && !requiredPatterns.some((pattern) => pattern.test(name)))
|
2280
2286
|
return {
|
2281
|
-
errorMessage: `contain the required pattern: ${englishJoinWords(
|
2287
|
+
errorMessage: `contain the required pattern: ${englishJoinWords(requiredPatterns.map((re) => re.source))}`,
|
2282
2288
|
renameToNames: []
|
2283
2289
|
};
|
2284
2290
|
let forbiddenPrefix = forbiddenPrefixes?.find((prefix2) => name.startsWith(prefix2));
|
@@ -3281,9 +3287,7 @@ var RULE_ID10 = "no-unused-fields", RELAY_SCHEMA = (
|
|
3281
3287
|
"```json",
|
3282
3288
|
JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2),
|
3283
3289
|
"```",
|
3284
|
-
|
3285
|
-
"> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).",
|
3286
|
-
"> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector."
|
3290
|
+
eslintSelectorsTip
|
3287
3291
|
].join(`
|
3288
3292
|
`),
|
3289
3293
|
items: {
|
@@ -4033,18 +4037,34 @@ var RULE_ID14 = "require-description", ALLOWED_KINDS2 = [
|
|
4033
4037
|
properties: {
|
4034
4038
|
types: {
|
4035
4039
|
type: "boolean",
|
4040
|
+
enum: [!0],
|
4036
4041
|
description: `Includes:
|
4037
4042
|
${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
4038
4043
|
`)}`
|
4039
4044
|
},
|
4040
4045
|
rootField: {
|
4041
4046
|
type: "boolean",
|
4047
|
+
enum: [!0],
|
4042
4048
|
description: "Definitions within `Query`, `Mutation`, and `Subscription` root types."
|
4043
4049
|
},
|
4050
|
+
ignoredSelectors: {
|
4051
|
+
...ARRAY_DEFAULT_OPTIONS,
|
4052
|
+
description: ["Ignore specific selectors", eslintSelectorsTip].join(`
|
4053
|
+
`)
|
4054
|
+
},
|
4044
4055
|
...Object.fromEntries(
|
4045
4056
|
[...ALLOWED_KINDS2].sort().map((kind) => {
|
4046
|
-
let description =
|
4047
|
-
|
4057
|
+
let description = `> [!NOTE]
|
4058
|
+
>
|
4059
|
+
> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`;
|
4060
|
+
return kind === Kind17.OPERATION_DEFINITION && (description += [
|
4061
|
+
"",
|
4062
|
+
"",
|
4063
|
+
"> [!WARNING]",
|
4064
|
+
">",
|
4065
|
+
'> You must use only comment syntax `#` and not description syntax `"""` or `"`.'
|
4066
|
+
].join(`
|
4067
|
+
`)), [kind, { type: "boolean", description }];
|
4048
4068
|
})
|
4049
4069
|
)
|
4050
4070
|
}
|
@@ -4115,6 +4135,36 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4115
4135
|
}
|
4116
4136
|
`
|
4117
4137
|
)
|
4138
|
+
},
|
4139
|
+
{
|
4140
|
+
title: "Correct",
|
4141
|
+
usage: [
|
4142
|
+
{
|
4143
|
+
ignoredSelectors: [
|
4144
|
+
"[type=ObjectTypeDefinition][name.value=PageInfo]",
|
4145
|
+
"[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]"
|
4146
|
+
]
|
4147
|
+
}
|
4148
|
+
],
|
4149
|
+
code: (
|
4150
|
+
/* GraphQL */
|
4151
|
+
`
|
4152
|
+
type FriendConnection {
|
4153
|
+
edges: [FriendEdge]
|
4154
|
+
pageInfo: PageInfo!
|
4155
|
+
}
|
4156
|
+
type FriendEdge {
|
4157
|
+
cursor: String!
|
4158
|
+
node: Friend!
|
4159
|
+
}
|
4160
|
+
type PageInfo {
|
4161
|
+
hasPreviousPage: Boolean!
|
4162
|
+
hasNextPage: Boolean!
|
4163
|
+
startCursor: String
|
4164
|
+
endCursor: String
|
4165
|
+
}
|
4166
|
+
`
|
4167
|
+
)
|
4118
4168
|
}
|
4119
4169
|
],
|
4120
4170
|
configOptions: [
|
@@ -4133,7 +4183,7 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4133
4183
|
schema: schema12
|
4134
4184
|
},
|
4135
4185
|
create(context) {
|
4136
|
-
let { types, rootField, ...restOptions } = context.options[0] || {}, kinds = new Set(types ? TYPES_KINDS : []);
|
4186
|
+
let { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {}, kinds = new Set(types ? TYPES_KINDS : []);
|
4137
4187
|
for (let [kind, isEnabled] of Object.entries(restOptions))
|
4138
4188
|
isEnabled ? kinds.add(kind) : kinds.delete(kind);
|
4139
4189
|
if (rootField) {
|
@@ -4144,10 +4194,11 @@ ${TYPES_KINDS.map((kind) => `- \`${kind}\``).join(`
|
|
4144
4194
|
].join(",")})$/] > FieldDefinition`
|
4145
4195
|
);
|
4146
4196
|
}
|
4147
|
-
|
4148
|
-
|
4197
|
+
let selector = `:matches(${[...kinds]})`;
|
4198
|
+
for (let str of ignoredSelectors)
|
4199
|
+
selector += `:not(${str})`;
|
4149
4200
|
return {
|
4150
|
-
[
|
4201
|
+
[selector](node) {
|
4151
4202
|
let description = "", isOperation = node.kind === Kind17.OPERATION_DEFINITION;
|
4152
4203
|
if (isOperation) {
|
4153
4204
|
let rawNode = node.rawNode(), { prev, line } = rawNode.loc.startToken;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@graphql-eslint/eslint-plugin",
|
3
|
-
"version": "4.1.0-alpha-
|
3
|
+
"version": "4.1.0-alpha-20241129084707-436164c7c2041bfc29ccb7abed9a3c3fb4db5520",
|
4
4
|
"type": "module",
|
5
5
|
"description": "GraphQL plugin for ESLint",
|
6
6
|
"repository": "https://github.com/dimaMachina/graphql-eslint",
|