@graphql-eslint/eslint-plugin 3.4.0 → 3.5.0
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/docs/rules/require-id-when-available.md +2 -2
- package/index.js +38 -38
- package/index.mjs +38 -38
- package/package.json +1 -1
- package/rules/index.d.ts +1 -3
- package/rules/require-id-when-available.d.ts +2 -2
package/index.js
CHANGED
@@ -2896,7 +2896,8 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2896
2896
|
}
|
2897
2897
|
};
|
2898
2898
|
|
2899
|
-
const
|
2899
|
+
const RULE_ID$2 = 'require-id-when-available';
|
2900
|
+
const MESSAGE_ID = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2900
2901
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2901
2902
|
const rule$j = {
|
2902
2903
|
meta: {
|
@@ -2904,7 +2905,7 @@ const rule$j = {
|
|
2904
2905
|
docs: {
|
2905
2906
|
category: 'Operations',
|
2906
2907
|
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2907
|
-
url:
|
2908
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
|
2908
2909
|
requiresSchema: true,
|
2909
2910
|
requiresSiblings: true,
|
2910
2911
|
examples: [
|
@@ -2918,7 +2919,7 @@ const rule$j = {
|
|
2918
2919
|
}
|
2919
2920
|
|
2920
2921
|
# Query
|
2921
|
-
query
|
2922
|
+
query {
|
2922
2923
|
user {
|
2923
2924
|
name
|
2924
2925
|
}
|
@@ -2935,7 +2936,7 @@ const rule$j = {
|
|
2935
2936
|
}
|
2936
2937
|
|
2937
2938
|
# Query
|
2938
|
-
query
|
2939
|
+
query {
|
2939
2940
|
user {
|
2940
2941
|
id
|
2941
2942
|
name
|
@@ -2947,7 +2948,7 @@ const rule$j = {
|
|
2947
2948
|
recommended: true,
|
2948
2949
|
},
|
2949
2950
|
messages: {
|
2950
|
-
[
|
2951
|
+
[MESSAGE_ID]: [
|
2951
2952
|
`Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
|
2952
2953
|
`If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
|
2953
2954
|
].join('\n'),
|
@@ -2978,14 +2979,16 @@ const rule$j = {
|
|
2978
2979
|
},
|
2979
2980
|
},
|
2980
2981
|
create(context) {
|
2981
|
-
requireGraphQLSchemaFromContext(
|
2982
|
-
const siblings = requireSiblingsOperations(
|
2982
|
+
requireGraphQLSchemaFromContext(RULE_ID$2, context);
|
2983
|
+
const siblings = requireSiblingsOperations(RULE_ID$2, context);
|
2983
2984
|
const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
|
2984
|
-
const idNames =
|
2985
|
+
const idNames = utils.asArray(fieldName);
|
2985
2986
|
const isFound = (s) => s.kind === graphql.Kind.FIELD && idNames.includes(s.name.value);
|
2987
|
+
// Skip check selections in FragmentDefinition
|
2988
|
+
const selector = 'OperationDefinition SelectionSet[parent.kind!=OperationDefinition]';
|
2986
2989
|
return {
|
2987
|
-
|
2988
|
-
var _a
|
2990
|
+
[selector](node) {
|
2991
|
+
var _a;
|
2989
2992
|
const typeInfo = node.typeInfo();
|
2990
2993
|
if (!typeInfo.gqlType) {
|
2991
2994
|
return;
|
@@ -3002,53 +3005,50 @@ const rule$j = {
|
|
3002
3005
|
return;
|
3003
3006
|
}
|
3004
3007
|
const checkedFragmentSpreads = new Set();
|
3005
|
-
let found = false;
|
3006
3008
|
for (const selection of node.selections) {
|
3007
3009
|
if (isFound(selection)) {
|
3008
|
-
|
3010
|
+
return;
|
3009
3011
|
}
|
3010
|
-
|
3011
|
-
|
3012
|
+
if (selection.kind === graphql.Kind.INLINE_FRAGMENT && selection.selectionSet.selections.some(isFound)) {
|
3013
|
+
return;
|
3012
3014
|
}
|
3013
|
-
|
3015
|
+
if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
|
3014
3016
|
const [foundSpread] = siblings.getFragment(selection.name.value);
|
3015
3017
|
if (foundSpread) {
|
3016
3018
|
checkedFragmentSpreads.add(foundSpread.document.name.value);
|
3017
|
-
|
3019
|
+
if (foundSpread.document.selectionSet.selections.some(isFound)) {
|
3020
|
+
return;
|
3021
|
+
}
|
3018
3022
|
}
|
3019
3023
|
}
|
3020
|
-
if (found) {
|
3021
|
-
break;
|
3022
|
-
}
|
3023
3024
|
}
|
3024
3025
|
const { parent } = node;
|
3025
|
-
const hasIdFieldInInterfaceSelectionSet = parent &&
|
3026
|
-
parent.kind === graphql.Kind.
|
3027
|
-
parent.parent
|
3028
|
-
|
3029
|
-
|
3030
|
-
if (!found && !hasIdFieldInInterfaceSelectionSet) {
|
3031
|
-
context.report({
|
3032
|
-
loc: getLocation(node.loc),
|
3033
|
-
messageId: REQUIRE_ID_WHEN_AVAILABLE,
|
3034
|
-
data: {
|
3035
|
-
checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
|
3036
|
-
fieldName: idNames.map(name => `"${name}"`).join(' or '),
|
3037
|
-
},
|
3038
|
-
});
|
3026
|
+
const hasIdFieldInInterfaceSelectionSet = (parent === null || parent === void 0 ? void 0 : parent.kind) === graphql.Kind.INLINE_FRAGMENT &&
|
3027
|
+
((_a = parent.parent) === null || _a === void 0 ? void 0 : _a.kind) === graphql.Kind.SELECTION_SET &&
|
3028
|
+
parent.parent.selections.some(isFound);
|
3029
|
+
if (hasIdFieldInInterfaceSelectionSet) {
|
3030
|
+
return;
|
3039
3031
|
}
|
3032
|
+
context.report({
|
3033
|
+
loc: getLocation(node.loc),
|
3034
|
+
messageId: MESSAGE_ID,
|
3035
|
+
data: {
|
3036
|
+
checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
|
3037
|
+
fieldName: idNames.map(name => `"${name}"`).join(' or '),
|
3038
|
+
},
|
3039
|
+
});
|
3040
3040
|
},
|
3041
3041
|
};
|
3042
3042
|
},
|
3043
3043
|
};
|
3044
3044
|
|
3045
|
-
const RULE_ID$
|
3045
|
+
const RULE_ID$3 = 'selection-set-depth';
|
3046
3046
|
const rule$k = {
|
3047
3047
|
meta: {
|
3048
3048
|
docs: {
|
3049
3049
|
category: 'Operations',
|
3050
3050
|
description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
|
3051
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$
|
3051
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$3}.md`,
|
3052
3052
|
requiresSiblings: true,
|
3053
3053
|
examples: [
|
3054
3054
|
{
|
@@ -3122,10 +3122,10 @@ const rule$k = {
|
|
3122
3122
|
create(context) {
|
3123
3123
|
let siblings = null;
|
3124
3124
|
try {
|
3125
|
-
siblings = requireSiblingsOperations(RULE_ID$
|
3125
|
+
siblings = requireSiblingsOperations(RULE_ID$3, context);
|
3126
3126
|
}
|
3127
3127
|
catch (e) {
|
3128
|
-
logger.warn(`Rule "${RULE_ID$
|
3128
|
+
logger.warn(`Rule "${RULE_ID$3}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
|
3129
3129
|
}
|
3130
3130
|
const { maxDepth } = context.options[0];
|
3131
3131
|
const ignore = context.options[0].ignore || [];
|
@@ -3150,7 +3150,7 @@ const rule$k = {
|
|
3150
3150
|
});
|
3151
3151
|
}
|
3152
3152
|
catch (e) {
|
3153
|
-
logger.warn(`Rule "${RULE_ID$
|
3153
|
+
logger.warn(`Rule "${RULE_ID$3}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
|
3154
3154
|
}
|
3155
3155
|
},
|
3156
3156
|
};
|
package/index.mjs
CHANGED
@@ -2890,7 +2890,8 @@ const convertNode = (typeInfo) => (node, key, parent) => {
|
|
2890
2890
|
}
|
2891
2891
|
};
|
2892
2892
|
|
2893
|
-
const
|
2893
|
+
const RULE_ID$2 = 'require-id-when-available';
|
2894
|
+
const MESSAGE_ID = 'REQUIRE_ID_WHEN_AVAILABLE';
|
2894
2895
|
const DEFAULT_ID_FIELD_NAME = 'id';
|
2895
2896
|
const rule$j = {
|
2896
2897
|
meta: {
|
@@ -2898,7 +2899,7 @@ const rule$j = {
|
|
2898
2899
|
docs: {
|
2899
2900
|
category: 'Operations',
|
2900
2901
|
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
2901
|
-
url:
|
2902
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
|
2902
2903
|
requiresSchema: true,
|
2903
2904
|
requiresSiblings: true,
|
2904
2905
|
examples: [
|
@@ -2912,7 +2913,7 @@ const rule$j = {
|
|
2912
2913
|
}
|
2913
2914
|
|
2914
2915
|
# Query
|
2915
|
-
query
|
2916
|
+
query {
|
2916
2917
|
user {
|
2917
2918
|
name
|
2918
2919
|
}
|
@@ -2929,7 +2930,7 @@ const rule$j = {
|
|
2929
2930
|
}
|
2930
2931
|
|
2931
2932
|
# Query
|
2932
|
-
query
|
2933
|
+
query {
|
2933
2934
|
user {
|
2934
2935
|
id
|
2935
2936
|
name
|
@@ -2941,7 +2942,7 @@ const rule$j = {
|
|
2941
2942
|
recommended: true,
|
2942
2943
|
},
|
2943
2944
|
messages: {
|
2944
|
-
[
|
2945
|
+
[MESSAGE_ID]: [
|
2945
2946
|
`Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
|
2946
2947
|
`If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
|
2947
2948
|
].join('\n'),
|
@@ -2972,14 +2973,16 @@ const rule$j = {
|
|
2972
2973
|
},
|
2973
2974
|
},
|
2974
2975
|
create(context) {
|
2975
|
-
requireGraphQLSchemaFromContext(
|
2976
|
-
const siblings = requireSiblingsOperations(
|
2976
|
+
requireGraphQLSchemaFromContext(RULE_ID$2, context);
|
2977
|
+
const siblings = requireSiblingsOperations(RULE_ID$2, context);
|
2977
2978
|
const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
|
2978
|
-
const idNames =
|
2979
|
+
const idNames = asArray(fieldName);
|
2979
2980
|
const isFound = (s) => s.kind === Kind.FIELD && idNames.includes(s.name.value);
|
2981
|
+
// Skip check selections in FragmentDefinition
|
2982
|
+
const selector = 'OperationDefinition SelectionSet[parent.kind!=OperationDefinition]';
|
2980
2983
|
return {
|
2981
|
-
|
2982
|
-
var _a
|
2984
|
+
[selector](node) {
|
2985
|
+
var _a;
|
2983
2986
|
const typeInfo = node.typeInfo();
|
2984
2987
|
if (!typeInfo.gqlType) {
|
2985
2988
|
return;
|
@@ -2996,53 +2999,50 @@ const rule$j = {
|
|
2996
2999
|
return;
|
2997
3000
|
}
|
2998
3001
|
const checkedFragmentSpreads = new Set();
|
2999
|
-
let found = false;
|
3000
3002
|
for (const selection of node.selections) {
|
3001
3003
|
if (isFound(selection)) {
|
3002
|
-
|
3004
|
+
return;
|
3003
3005
|
}
|
3004
|
-
|
3005
|
-
|
3006
|
+
if (selection.kind === Kind.INLINE_FRAGMENT && selection.selectionSet.selections.some(isFound)) {
|
3007
|
+
return;
|
3006
3008
|
}
|
3007
|
-
|
3009
|
+
if (selection.kind === Kind.FRAGMENT_SPREAD) {
|
3008
3010
|
const [foundSpread] = siblings.getFragment(selection.name.value);
|
3009
3011
|
if (foundSpread) {
|
3010
3012
|
checkedFragmentSpreads.add(foundSpread.document.name.value);
|
3011
|
-
|
3013
|
+
if (foundSpread.document.selectionSet.selections.some(isFound)) {
|
3014
|
+
return;
|
3015
|
+
}
|
3012
3016
|
}
|
3013
3017
|
}
|
3014
|
-
if (found) {
|
3015
|
-
break;
|
3016
|
-
}
|
3017
3018
|
}
|
3018
3019
|
const { parent } = node;
|
3019
|
-
const hasIdFieldInInterfaceSelectionSet = parent &&
|
3020
|
-
parent.kind === Kind.
|
3021
|
-
parent.parent
|
3022
|
-
|
3023
|
-
|
3024
|
-
if (!found && !hasIdFieldInInterfaceSelectionSet) {
|
3025
|
-
context.report({
|
3026
|
-
loc: getLocation(node.loc),
|
3027
|
-
messageId: REQUIRE_ID_WHEN_AVAILABLE,
|
3028
|
-
data: {
|
3029
|
-
checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
|
3030
|
-
fieldName: idNames.map(name => `"${name}"`).join(' or '),
|
3031
|
-
},
|
3032
|
-
});
|
3020
|
+
const hasIdFieldInInterfaceSelectionSet = (parent === null || parent === void 0 ? void 0 : parent.kind) === Kind.INLINE_FRAGMENT &&
|
3021
|
+
((_a = parent.parent) === null || _a === void 0 ? void 0 : _a.kind) === Kind.SELECTION_SET &&
|
3022
|
+
parent.parent.selections.some(isFound);
|
3023
|
+
if (hasIdFieldInInterfaceSelectionSet) {
|
3024
|
+
return;
|
3033
3025
|
}
|
3026
|
+
context.report({
|
3027
|
+
loc: getLocation(node.loc),
|
3028
|
+
messageId: MESSAGE_ID,
|
3029
|
+
data: {
|
3030
|
+
checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
|
3031
|
+
fieldName: idNames.map(name => `"${name}"`).join(' or '),
|
3032
|
+
},
|
3033
|
+
});
|
3034
3034
|
},
|
3035
3035
|
};
|
3036
3036
|
},
|
3037
3037
|
};
|
3038
3038
|
|
3039
|
-
const RULE_ID$
|
3039
|
+
const RULE_ID$3 = 'selection-set-depth';
|
3040
3040
|
const rule$k = {
|
3041
3041
|
meta: {
|
3042
3042
|
docs: {
|
3043
3043
|
category: 'Operations',
|
3044
3044
|
description: `Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://github.com/stems/graphql-depth-limit).`,
|
3045
|
-
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$
|
3045
|
+
url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$3}.md`,
|
3046
3046
|
requiresSiblings: true,
|
3047
3047
|
examples: [
|
3048
3048
|
{
|
@@ -3116,10 +3116,10 @@ const rule$k = {
|
|
3116
3116
|
create(context) {
|
3117
3117
|
let siblings = null;
|
3118
3118
|
try {
|
3119
|
-
siblings = requireSiblingsOperations(RULE_ID$
|
3119
|
+
siblings = requireSiblingsOperations(RULE_ID$3, context);
|
3120
3120
|
}
|
3121
3121
|
catch (e) {
|
3122
|
-
logger.warn(`Rule "${RULE_ID$
|
3122
|
+
logger.warn(`Rule "${RULE_ID$3}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
|
3123
3123
|
}
|
3124
3124
|
const { maxDepth } = context.options[0];
|
3125
3125
|
const ignore = context.options[0].ignore || [];
|
@@ -3144,7 +3144,7 @@ const rule$k = {
|
|
3144
3144
|
});
|
3145
3145
|
}
|
3146
3146
|
catch (e) {
|
3147
|
-
logger.warn(`Rule "${RULE_ID$
|
3147
|
+
logger.warn(`Rule "${RULE_ID$3}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
|
3148
3148
|
}
|
3149
3149
|
},
|
3150
3150
|
};
|
package/package.json
CHANGED
package/rules/index.d.ts
CHANGED
@@ -48,9 +48,7 @@ export declare const rules: {
|
|
48
48
|
DirectiveDefinition?: boolean;
|
49
49
|
}], false>;
|
50
50
|
'require-field-of-type-query-in-mutation-result': import("..").GraphQLESLintRule<any[], false>;
|
51
|
-
'require-id-when-available': import("..").GraphQLESLintRule<[
|
52
|
-
fieldName: string;
|
53
|
-
}], true>;
|
51
|
+
'require-id-when-available': import("..").GraphQLESLintRule<[import("./require-id-when-available").RequireIdWhenAvailableRuleConfig], true>;
|
54
52
|
'selection-set-depth': import("..").GraphQLESLintRule<[{
|
55
53
|
maxDepth: number;
|
56
54
|
ignore?: string[];
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { GraphQLESLintRule } from '../types';
|
2
|
-
declare type RequireIdWhenAvailableRuleConfig = {
|
3
|
-
fieldName: string;
|
2
|
+
export declare type RequireIdWhenAvailableRuleConfig = {
|
3
|
+
fieldName: string | string[];
|
4
4
|
};
|
5
5
|
declare const rule: GraphQLESLintRule<[RequireIdWhenAvailableRuleConfig], true>;
|
6
6
|
export default rule;
|