@graphql-eslint/eslint-plugin 3.0.1 → 3.1.0-alpha-878c908.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.
@@ -54,10 +54,25 @@ query user {
54
54
 
55
55
  The schema defines the following properties:
56
56
 
57
- ### `fieldName` (string)
57
+ ### `fieldName`
58
+
59
+ The object must be one of the following types:
60
+
61
+ * `asString`
62
+ * `asArray`
58
63
 
59
64
  Default: `"id"`
60
65
 
66
+ ---
67
+
68
+ # Sub Schemas
69
+
70
+ The schema defines the following additional types:
71
+
72
+ ## `asString` (string)
73
+
74
+ ## `asArray` (array)
75
+
61
76
  ## Resources
62
77
 
63
78
  - [Rule source](../../packages/plugin/src/rules/require-id-when-available.ts)
package/index.js CHANGED
@@ -2852,9 +2852,22 @@ const rule$j = {
2852
2852
  recommended: true,
2853
2853
  },
2854
2854
  messages: {
2855
- [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{ checkedFragments }} specifies the field "{{ fieldName }}".`,
2855
+ [REQUIRE_ID_WHEN_AVAILABLE]: [
2856
+ `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2857
+ `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2858
+ ].join('\n'),
2856
2859
  },
2857
2860
  schema: {
2861
+ definitions: {
2862
+ asString: {
2863
+ type: 'string',
2864
+ },
2865
+ asArray: {
2866
+ type: 'array',
2867
+ minItems: 1,
2868
+ uniqueItems: true,
2869
+ },
2870
+ },
2858
2871
  type: 'array',
2859
2872
  maxItems: 1,
2860
2873
  items: {
@@ -2862,7 +2875,7 @@ const rule$j = {
2862
2875
  additionalProperties: false,
2863
2876
  properties: {
2864
2877
  fieldName: {
2865
- type: 'string',
2878
+ oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asArray' }],
2866
2879
  default: DEFAULT_ID_FIELD_NAME,
2867
2880
  },
2868
2881
  },
@@ -2870,69 +2883,64 @@ const rule$j = {
2870
2883
  },
2871
2884
  },
2872
2885
  create(context) {
2886
+ requireGraphQLSchemaFromContext('require-id-when-available', context);
2887
+ const siblings = requireSiblingsOperations('require-id-when-available', context);
2888
+ const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2889
+ const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2890
+ const isFound = (s) => s.kind === graphql.Kind.FIELD && idNames.includes(s.name.value);
2873
2891
  return {
2874
2892
  SelectionSet(node) {
2875
2893
  var _a, _b;
2876
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2877
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2878
- const fieldName = (context.options[0] || {}).fieldName || DEFAULT_ID_FIELD_NAME;
2879
- if (!node.selections || node.selections.length === 0) {
2894
+ const typeInfo = node.typeInfo();
2895
+ if (!typeInfo.gqlType) {
2880
2896
  return;
2881
2897
  }
2882
- const typeInfo = node.typeInfo();
2883
- if (typeInfo && typeInfo.gqlType) {
2884
- const rawType = getBaseType(typeInfo.gqlType);
2885
- if (rawType instanceof graphql.GraphQLObjectType || rawType instanceof graphql.GraphQLInterfaceType) {
2886
- const fields = rawType.getFields();
2887
- const hasIdFieldInType = !!fields[fieldName];
2888
- const checkedFragmentSpreads = new Set();
2889
- if (hasIdFieldInType) {
2890
- let found = false;
2891
- for (const selection of node.selections) {
2892
- if (selection.kind === 'Field' && selection.name.value === fieldName) {
2893
- found = true;
2894
- }
2895
- else if (selection.kind === 'InlineFragment') {
2896
- found = (((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2897
- }
2898
- else if (selection.kind === 'FragmentSpread') {
2899
- const foundSpread = siblings.getFragment(selection.name.value);
2900
- if (foundSpread[0]) {
2901
- checkedFragmentSpreads.add(foundSpread[0].document.name.value);
2902
- found = (((_b = foundSpread[0].document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2903
- }
2904
- }
2905
- if (found) {
2906
- break;
2907
- }
2908
- }
2909
- const { parent } = node;
2910
- const hasIdFieldInInterfaceSelectionSet = parent &&
2911
- parent.kind === 'InlineFragment' &&
2912
- parent.parent &&
2913
- parent.parent.kind === 'SelectionSet' &&
2914
- parent.parent.selections.some(s => s.kind === 'Field' && s.name.value === fieldName);
2915
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
2916
- context.report({
2917
- loc: {
2918
- start: {
2919
- line: node.loc.start.line,
2920
- column: node.loc.start.column - 1,
2921
- },
2922
- end: {
2923
- line: node.loc.end.line,
2924
- column: node.loc.end.column - 1,
2925
- },
2926
- },
2927
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
2928
- data: {
2929
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${Array.from(checkedFragmentSpreads).join(', ')})`,
2930
- fieldName,
2931
- },
2932
- });
2933
- }
2898
+ const rawType = getBaseType(typeInfo.gqlType);
2899
+ const isObjectType = rawType instanceof graphql.GraphQLObjectType;
2900
+ const isInterfaceType = rawType instanceof graphql.GraphQLInterfaceType;
2901
+ if (!isObjectType && !isInterfaceType) {
2902
+ return;
2903
+ }
2904
+ const fields = rawType.getFields();
2905
+ const hasIdFieldInType = idNames.some(name => fields[name]);
2906
+ if (!hasIdFieldInType) {
2907
+ return;
2908
+ }
2909
+ const checkedFragmentSpreads = new Set();
2910
+ let found = false;
2911
+ for (const selection of node.selections) {
2912
+ if (isFound(selection)) {
2913
+ found = true;
2914
+ }
2915
+ else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
2916
+ found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
2917
+ }
2918
+ else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
2919
+ const [foundSpread] = siblings.getFragment(selection.name.value);
2920
+ if (foundSpread) {
2921
+ checkedFragmentSpreads.add(foundSpread.document.name.value);
2922
+ found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
2934
2923
  }
2935
2924
  }
2925
+ if (found) {
2926
+ break;
2927
+ }
2928
+ }
2929
+ const { parent } = node;
2930
+ const hasIdFieldInInterfaceSelectionSet = parent &&
2931
+ parent.kind === graphql.Kind.INLINE_FRAGMENT &&
2932
+ parent.parent &&
2933
+ parent.parent.kind === graphql.Kind.SELECTION_SET &&
2934
+ parent.parent.selections.some(s => isFound(s));
2935
+ if (!found && !hasIdFieldInInterfaceSelectionSet) {
2936
+ context.report({
2937
+ loc: getLocation(node.loc),
2938
+ messageId: REQUIRE_ID_WHEN_AVAILABLE,
2939
+ data: {
2940
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
2941
+ fieldName: idNames.map(name => `"${name}"`).join(' or '),
2942
+ },
2943
+ });
2936
2944
  }
2937
2945
  },
2938
2946
  };
@@ -3024,7 +3032,7 @@ const rule$k = {
3024
3032
  // eslint-disable-next-line no-console
3025
3033
  console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3026
3034
  }
3027
- const maxDepth = context.options[0].maxDepth;
3035
+ const { maxDepth } = context.options[0];
3028
3036
  const ignore = context.options[0].ignore || [];
3029
3037
  const checkFn = depthLimit(maxDepth, { ignore });
3030
3038
  return {
package/index.mjs CHANGED
@@ -2846,9 +2846,22 @@ const rule$j = {
2846
2846
  recommended: true,
2847
2847
  },
2848
2848
  messages: {
2849
- [REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!\nIf you are using fragments, make sure that all used fragments {{ checkedFragments }} specifies the field "{{ fieldName }}".`,
2849
+ [REQUIRE_ID_WHEN_AVAILABLE]: [
2850
+ `Field {{ fieldName }} must be selected when it's available on a type. Please make sure to include it in your selection set!`,
2851
+ `If you are using fragments, make sure that all used fragments {{ checkedFragments }}specifies the field {{ fieldName }}.`,
2852
+ ].join('\n'),
2850
2853
  },
2851
2854
  schema: {
2855
+ definitions: {
2856
+ asString: {
2857
+ type: 'string',
2858
+ },
2859
+ asArray: {
2860
+ type: 'array',
2861
+ minItems: 1,
2862
+ uniqueItems: true,
2863
+ },
2864
+ },
2852
2865
  type: 'array',
2853
2866
  maxItems: 1,
2854
2867
  items: {
@@ -2856,7 +2869,7 @@ const rule$j = {
2856
2869
  additionalProperties: false,
2857
2870
  properties: {
2858
2871
  fieldName: {
2859
- type: 'string',
2872
+ oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asArray' }],
2860
2873
  default: DEFAULT_ID_FIELD_NAME,
2861
2874
  },
2862
2875
  },
@@ -2864,69 +2877,64 @@ const rule$j = {
2864
2877
  },
2865
2878
  },
2866
2879
  create(context) {
2880
+ requireGraphQLSchemaFromContext('require-id-when-available', context);
2881
+ const siblings = requireSiblingsOperations('require-id-when-available', context);
2882
+ const { fieldName = DEFAULT_ID_FIELD_NAME } = context.options[0] || {};
2883
+ const idNames = Array.isArray(fieldName) ? fieldName : [fieldName];
2884
+ const isFound = (s) => s.kind === Kind.FIELD && idNames.includes(s.name.value);
2867
2885
  return {
2868
2886
  SelectionSet(node) {
2869
2887
  var _a, _b;
2870
- requireGraphQLSchemaFromContext('require-id-when-available', context);
2871
- const siblings = requireSiblingsOperations('require-id-when-available', context);
2872
- const fieldName = (context.options[0] || {}).fieldName || DEFAULT_ID_FIELD_NAME;
2873
- if (!node.selections || node.selections.length === 0) {
2888
+ const typeInfo = node.typeInfo();
2889
+ if (!typeInfo.gqlType) {
2874
2890
  return;
2875
2891
  }
2876
- const typeInfo = node.typeInfo();
2877
- if (typeInfo && typeInfo.gqlType) {
2878
- const rawType = getBaseType(typeInfo.gqlType);
2879
- if (rawType instanceof GraphQLObjectType || rawType instanceof GraphQLInterfaceType) {
2880
- const fields = rawType.getFields();
2881
- const hasIdFieldInType = !!fields[fieldName];
2882
- const checkedFragmentSpreads = new Set();
2883
- if (hasIdFieldInType) {
2884
- let found = false;
2885
- for (const selection of node.selections) {
2886
- if (selection.kind === 'Field' && selection.name.value === fieldName) {
2887
- found = true;
2888
- }
2889
- else if (selection.kind === 'InlineFragment') {
2890
- found = (((_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2891
- }
2892
- else if (selection.kind === 'FragmentSpread') {
2893
- const foundSpread = siblings.getFragment(selection.name.value);
2894
- if (foundSpread[0]) {
2895
- checkedFragmentSpreads.add(foundSpread[0].document.name.value);
2896
- found = (((_b = foundSpread[0].document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections) || []).some(s => s.kind === 'Field' && s.name.value === fieldName);
2897
- }
2898
- }
2899
- if (found) {
2900
- break;
2901
- }
2902
- }
2903
- const { parent } = node;
2904
- const hasIdFieldInInterfaceSelectionSet = parent &&
2905
- parent.kind === 'InlineFragment' &&
2906
- parent.parent &&
2907
- parent.parent.kind === 'SelectionSet' &&
2908
- parent.parent.selections.some(s => s.kind === 'Field' && s.name.value === fieldName);
2909
- if (!found && !hasIdFieldInInterfaceSelectionSet) {
2910
- context.report({
2911
- loc: {
2912
- start: {
2913
- line: node.loc.start.line,
2914
- column: node.loc.start.column - 1,
2915
- },
2916
- end: {
2917
- line: node.loc.end.line,
2918
- column: node.loc.end.column - 1,
2919
- },
2920
- },
2921
- messageId: REQUIRE_ID_WHEN_AVAILABLE,
2922
- data: {
2923
- checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${Array.from(checkedFragmentSpreads).join(', ')})`,
2924
- fieldName,
2925
- },
2926
- });
2927
- }
2892
+ const rawType = getBaseType(typeInfo.gqlType);
2893
+ const isObjectType = rawType instanceof GraphQLObjectType;
2894
+ const isInterfaceType = rawType instanceof GraphQLInterfaceType;
2895
+ if (!isObjectType && !isInterfaceType) {
2896
+ return;
2897
+ }
2898
+ const fields = rawType.getFields();
2899
+ const hasIdFieldInType = idNames.some(name => fields[name]);
2900
+ if (!hasIdFieldInType) {
2901
+ return;
2902
+ }
2903
+ const checkedFragmentSpreads = new Set();
2904
+ let found = false;
2905
+ for (const selection of node.selections) {
2906
+ if (isFound(selection)) {
2907
+ found = true;
2908
+ }
2909
+ else if (selection.kind === Kind.INLINE_FRAGMENT) {
2910
+ found = (_a = selection.selectionSet) === null || _a === void 0 ? void 0 : _a.selections.some(s => isFound(s));
2911
+ }
2912
+ else if (selection.kind === Kind.FRAGMENT_SPREAD) {
2913
+ const [foundSpread] = siblings.getFragment(selection.name.value);
2914
+ if (foundSpread) {
2915
+ checkedFragmentSpreads.add(foundSpread.document.name.value);
2916
+ found = (_b = foundSpread.document.selectionSet) === null || _b === void 0 ? void 0 : _b.selections.some(s => isFound(s));
2928
2917
  }
2929
2918
  }
2919
+ if (found) {
2920
+ break;
2921
+ }
2922
+ }
2923
+ const { parent } = node;
2924
+ const hasIdFieldInInterfaceSelectionSet = parent &&
2925
+ parent.kind === Kind.INLINE_FRAGMENT &&
2926
+ parent.parent &&
2927
+ parent.parent.kind === Kind.SELECTION_SET &&
2928
+ parent.parent.selections.some(s => isFound(s));
2929
+ if (!found && !hasIdFieldInInterfaceSelectionSet) {
2930
+ context.report({
2931
+ loc: getLocation(node.loc),
2932
+ messageId: REQUIRE_ID_WHEN_AVAILABLE,
2933
+ data: {
2934
+ checkedFragments: checkedFragmentSpreads.size === 0 ? '' : `(${[...checkedFragmentSpreads].join(', ')}) `,
2935
+ fieldName: idNames.map(name => `"${name}"`).join(' or '),
2936
+ },
2937
+ });
2930
2938
  }
2931
2939
  },
2932
2940
  };
@@ -3018,7 +3026,7 @@ const rule$k = {
3018
3026
  // eslint-disable-next-line no-console
3019
3027
  console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3020
3028
  }
3021
- const maxDepth = context.options[0].maxDepth;
3029
+ const { maxDepth } = context.options[0];
3022
3030
  const ignore = context.options[0].ignore || [];
3023
3031
  const checkFn = depthLimit(maxDepth, { ignore });
3024
3032
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.0.1",
3
+ "version": "3.1.0-alpha-878c908.0",
4
4
  "sideEffects": false,
5
5
  "peerDependencies": {
6
6
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0"