@graphql-eslint/eslint-plugin 3.3.0 → 3.4.0-alpha-d977284.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/README.md CHANGED
@@ -42,7 +42,7 @@ npm install --save-dev @graphql-eslint/eslint-plugin
42
42
 
43
43
  > Make sure you have `graphql` dependency in your project.
44
44
 
45
- ### Configuration
45
+ ## Configuration
46
46
 
47
47
  To get started, define an override in your ESLint config to apply this plugin to `.graphql` files. Add the [rules](docs/README.md) you want applied.
48
48
 
@@ -65,7 +65,7 @@ To get started, define an override in your ESLint config to apply this plugin to
65
65
 
66
66
  If your GraphQL definitions are defined only in `.graphql` files, and you're only using rules that apply to individual files, you should be good to go 👍. If you would like use a remote schema or use rules that apply across the entire collection of definitions at once, see [here](#using-a-remote-schema-or-rules-with-constraints-that-span-the-entire-schema).
67
67
 
68
- #### Tell ESLint to apply this plugin to GraphQL definitions defined in code files
68
+ ### Apply this plugin to GraphQL definitions defined in code files
69
69
 
70
70
  If you are defining GraphQL schema or GraphQL operations in code files, you'll want to define an additional override to extend the functionality of this plugin to the schema and operations in those files.
71
71
 
@@ -90,7 +90,7 @@ If you are defining GraphQL schema or GraphQL operations in code files, you'll w
90
90
 
91
91
  Under the hood, specifying the `@graphql-eslint/graphql` processor for code files will cause `graphql-eslint/graphql` to extract the schema and operation definitions from these files into virtual GraphQL documents with `.graphql` extensions. This will allow the overrides you've defined for `.graphql` files, via `"files": ["*.graphql"]`, to get applied to the definitions defined in your code files.
92
92
 
93
- #### Using a remote schema or rules with constraints that span the entire schema
93
+ ### Extended linting rules with GraphQL Schema
94
94
 
95
95
  Some rules require an understanding of the entire schema at once. For example, [no-unreachable-types](https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/no-unreachable-types.md#no-unreachable-types) checks that all types are reachable by root-level fields.
96
96
 
@@ -120,7 +120,7 @@ The parser allows you to specify a json file / graphql files(s) / url / raw stri
120
120
 
121
121
  > Some rules require type information to operate, it's marked in the docs for each rule!
122
122
 
123
- #### Extended linting rules with siblings operations
123
+ ### Extended linting rules with siblings operations
124
124
 
125
125
  While implementing this tool, we had to find solutions for a better integration of the GraphQL ecosystem and ESLint core.
126
126
 
@@ -180,7 +180,7 @@ You can find a list of [ESLint directives here](https://eslint.org/docs/2.13.1/u
180
180
 
181
181
  You can find a complete list of [all available rules here](docs/README.md).
182
182
 
183
- ## Deprecated Rules
183
+ ### Deprecated Rules
184
184
 
185
185
  See [docs/deprecated-rules.md](docs/deprecated-rules.md).
186
186
 
@@ -201,7 +201,7 @@ See [docs/deprecated-rules.md](docs/deprecated-rules.md).
201
201
 
202
202
  > If you are in a monorepo project, you probably need both sets of rules.
203
203
 
204
- ## Config usage
204
+ ### Config usage
205
205
 
206
206
  For example, to enable the `schema-recommended` config, enable it in your `.eslintrc` file with the `extends` option:
207
207
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  - Category: `Schema`
4
4
  - Rule name: `@graphql-eslint/possible-type-extension`
5
- - Requires GraphQL Schema: `false` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
5
+ - Requires GraphQL Schema: `true` [ℹ️](../../README.md#extended-linting-rules-with-graphql-schema)
6
6
  - Requires GraphQL Operations: `false` [ℹ️](../../README.md#extended-linting-rules-with-siblings-operations)
7
7
 
8
8
  A type extension is only valid if the type is defined and has the same kind.
@@ -1,3 +1,3 @@
1
1
  import { GraphQLConfig } from 'graphql-config';
2
2
  import { ParserOptions } from './types';
3
- export declare function loadGraphqlConfig(options: ParserOptions): GraphQLConfig;
3
+ export declare function loadGraphQLConfig(options: ParserOptions): GraphQLConfig;
package/index.js CHANGED
@@ -10,9 +10,10 @@ const fs = require('fs');
10
10
  const path = require('path');
11
11
  const utils = require('@graphql-tools/utils');
12
12
  const lowerCase = _interopDefault(require('lodash.lowercase'));
13
+ const chalk = _interopDefault(require('chalk'));
13
14
  const depthLimit = _interopDefault(require('graphql-depth-limit'));
14
15
  const graphqlTagPluck = require('@graphql-tools/graphql-tag-pluck');
15
- const graphqlConfig$1 = require('graphql-config');
16
+ const graphqlConfig = require('graphql-config');
16
17
  const codeFileLoader = require('@graphql-tools/code-file-loader');
17
18
  const eslint = require('eslint');
18
19
  const codeFrame = require('@babel/code-frame');
@@ -192,6 +193,12 @@ function requireGraphQLSchemaFromContext(ruleName, context) {
192
193
  }
193
194
  return context.parserServices.schema;
194
195
  }
196
+ const logger = {
197
+ // eslint-disable-next-line no-console
198
+ error: (...args) => console.error(chalk.red('error'), '[graphql-eslint]', chalk(...args)),
199
+ // eslint-disable-next-line no-console
200
+ warn: (...args) => console.warn(chalk.yellow('warning'), '[graphql-eslint]', chalk(...args)),
201
+ };
195
202
  function requireReachableTypesFromContext(ruleName, context) {
196
203
  const schema = requireGraphQLSchemaFromContext(ruleName, context);
197
204
  return context.parserServices.reachableTypes(schema);
@@ -326,14 +333,14 @@ function getLocation(loc, fieldName = '', offset) {
326
333
  };
327
334
  }
328
335
 
329
- function validateDocument(sourceNode, context, schema, documentNode, rule) {
336
+ function validateDocument(context, schema = null, documentNode, rule) {
330
337
  if (documentNode.definitions.length === 0) {
331
338
  return;
332
339
  }
333
340
  try {
334
341
  const validationErrors = schema
335
342
  ? graphql.validate(schema, documentNode, [rule])
336
- : validate.validateSDL(documentNode, null, [rule]);
343
+ : validate.validateSDL(documentNode, schema, [rule]);
337
344
  for (const error of validationErrors) {
338
345
  /*
339
346
  * TODO: Fix ESTree-AST converter because currently it's incorrectly convert loc.end
@@ -358,7 +365,8 @@ function validateDocument(sourceNode, context, schema, documentNode, rule) {
358
365
  }
359
366
  catch (e) {
360
367
  context.report({
361
- node: sourceNode,
368
+ // Report on first character
369
+ loc: { column: 0, line: 1 },
362
370
  message: e.message,
363
371
  });
364
372
  }
@@ -440,18 +448,17 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode) => {
440
448
  },
441
449
  },
442
450
  create(context) {
451
+ if (!ruleFn) {
452
+ logger.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
453
+ return {};
454
+ }
443
455
  return {
444
456
  Document(node) {
445
- if (!ruleFn) {
446
- // eslint-disable-next-line no-console
447
- console.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
448
- return;
449
- }
450
457
  const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
451
458
  const documentNode = getDocumentNode
452
459
  ? getDocumentNode({ ruleId, context, schema, node: node.rawNode() })
453
460
  : node.rawNode();
454
- validateDocument(node, context, schema, documentNode, ruleFn);
461
+ validateDocument(context, schema, documentNode, ruleFn);
455
462
  },
456
463
  };
457
464
  },
@@ -601,7 +608,8 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
601
608
  }), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
602
609
  category: 'Schema',
603
610
  description: `A type extension is only valid if the type is defined and has the same kind.`,
604
- recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
611
+ recommended: false,
612
+ requiresSchema: true,
605
613
  }), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
606
614
  category: ['Schema', 'Operations'],
607
615
  description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
@@ -3034,12 +3042,13 @@ const rule$j = {
3034
3042
  },
3035
3043
  };
3036
3044
 
3045
+ const RULE_ID$2 = 'selection-set-depth';
3037
3046
  const rule$k = {
3038
3047
  meta: {
3039
3048
  docs: {
3040
3049
  category: 'Operations',
3041
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).`,
3042
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
3051
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
3043
3052
  requiresSiblings: true,
3044
3053
  examples: [
3045
3054
  {
@@ -3113,11 +3122,10 @@ const rule$k = {
3113
3122
  create(context) {
3114
3123
  let siblings = null;
3115
3124
  try {
3116
- siblings = requireSiblingsOperations('selection-set-depth', context);
3125
+ siblings = requireSiblingsOperations(RULE_ID$2, context);
3117
3126
  }
3118
3127
  catch (e) {
3119
- // eslint-disable-next-line no-console
3120
- console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3128
+ logger.warn(`Rule "${RULE_ID$2}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3121
3129
  }
3122
3130
  const { maxDepth } = context.options[0];
3123
3131
  const ignore = context.options[0].ignore || [];
@@ -3142,8 +3150,7 @@ const rule$k = {
3142
3150
  });
3143
3151
  }
3144
3152
  catch (e) {
3145
- // eslint-disable-next-line no-console
3146
- console.warn(`Rule "selection-set-depth" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3153
+ logger.warn(`Rule "${RULE_ID$2}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3147
3154
  }
3148
3155
  },
3149
3156
  };
@@ -3525,8 +3532,7 @@ function createGraphqlProcessor() {
3525
3532
  }
3526
3533
  }
3527
3534
  catch (e) {
3528
- // eslint-disable-next-line no-console
3529
- console.warn(`[graphql-eslint/processor]: Unable to process file "${filename}": `, e);
3535
+ logger.warn(`Unable to process file "${filename}"`, e);
3530
3536
  }
3531
3537
  }
3532
3538
  return [text];
@@ -3566,20 +3572,25 @@ const schemaCache = new Map();
3566
3572
  function getSchema(options = {}, gqlConfig) {
3567
3573
  const realFilepath = options.filePath ? getOnDiskFilepath(options.filePath) : null;
3568
3574
  const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
3569
- const schemaKey = utils.asArray(projectForFile.schema)
3570
- .sort()
3571
- .join(',');
3575
+ const schemaKey = utils.asArray(projectForFile.schema).sort().join(',');
3572
3576
  if (!schemaKey) {
3573
3577
  return null;
3574
3578
  }
3575
- let schema = schemaCache.get(schemaKey);
3576
- if (!schema) {
3579
+ if (schemaCache.has(schemaKey)) {
3580
+ return schemaCache.get(schemaKey);
3581
+ }
3582
+ let schema;
3583
+ try {
3577
3584
  schema = projectForFile.loadSchemaSync(projectForFile.schema, 'GraphQLSchema', {
3578
3585
  cache: loaderCache,
3579
- ...options.schemaOptions
3586
+ ...options.schemaOptions,
3580
3587
  });
3581
- schemaCache.set(schemaKey, schema);
3582
3588
  }
3589
+ catch (e) {
3590
+ schema = null;
3591
+ logger.error('Error while loading schema\n', e);
3592
+ }
3593
+ schemaCache.set(schemaKey, schema);
3583
3594
  return schema;
3584
3595
  }
3585
3596
 
@@ -3592,10 +3603,10 @@ const handleVirtualPath = (documents) => {
3592
3603
  return source;
3593
3604
  }
3594
3605
  (_a = filepathMap[location]) !== null && _a !== void 0 ? _a : (filepathMap[location] = -1);
3595
- const index = filepathMap[location] += 1;
3606
+ const index = (filepathMap[location] += 1);
3596
3607
  return {
3597
3608
  ...source,
3598
- location: path.resolve(location, `${index}_document.graphql`)
3609
+ location: path.resolve(location, `${index}_document.graphql`),
3599
3610
  };
3600
3611
  });
3601
3612
  };
@@ -3604,9 +3615,7 @@ const siblingOperationsCache = new Map();
3604
3615
  const getSiblings = (filePath, gqlConfig) => {
3605
3616
  const realFilepath = filePath ? getOnDiskFilepath(filePath) : null;
3606
3617
  const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
3607
- const documentsKey = utils.asArray(projectForFile.documents)
3608
- .sort()
3609
- .join(',');
3618
+ const documentsKey = utils.asArray(projectForFile.documents).sort().join(',');
3610
3619
  if (!documentsKey) {
3611
3620
  return [];
3612
3621
  }
@@ -3614,7 +3623,7 @@ const getSiblings = (filePath, gqlConfig) => {
3614
3623
  if (!siblings) {
3615
3624
  const documents = projectForFile.loadDocumentsSync(projectForFile.documents, {
3616
3625
  skipGraphQLImport: true,
3617
- cache: loaderCache
3626
+ cache: loaderCache,
3618
3627
  });
3619
3628
  siblings = handleVirtualPath(documents);
3620
3629
  operationsCache.set(documentsKey, siblings);
@@ -3627,8 +3636,7 @@ function getSiblingOperations(options, gqlConfig) {
3627
3636
  let printed = false;
3628
3637
  const noopWarn = () => {
3629
3638
  if (!printed) {
3630
- // eslint-disable-next-line no-console
3631
- console.warn(`getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!`);
3639
+ logger.warn(`getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!`);
3632
3640
  printed = true;
3633
3641
  }
3634
3642
  return [];
@@ -3692,8 +3700,7 @@ function getSiblingOperations(options, gqlConfig) {
3692
3700
  const name = spread.name.value;
3693
3701
  const fragmentInfo = getFragment(name);
3694
3702
  if (fragmentInfo.length === 0) {
3695
- // eslint-disable-next-line no-console
3696
- console.warn(`Unable to locate fragment named "${name}", please make sure it's loaded using "parserOptions.operations"`);
3703
+ logger.warn(`Unable to locate fragment named "${name}", please make sure it's loaded using "parserOptions.operations"`);
3697
3704
  return;
3698
3705
  }
3699
3706
  const fragment = fragmentInfo[0];
@@ -3723,35 +3730,36 @@ function getSiblingOperations(options, gqlConfig) {
3723
3730
  return siblingOperations;
3724
3731
  }
3725
3732
 
3726
- let graphqlConfig;
3727
- function loadGraphqlConfig(options) {
3733
+ let graphQLConfig;
3734
+ function loadGraphQLConfig(options) {
3728
3735
  // We don't want cache config on test environment
3729
3736
  // Otherwise schema and documents will be same for all tests
3730
- if (process.env.NODE_ENV !== 'test' && graphqlConfig) {
3731
- return graphqlConfig;
3737
+ if (process.env.NODE_ENV !== 'test' && graphQLConfig) {
3738
+ return graphQLConfig;
3732
3739
  }
3733
3740
  const onDiskConfig = options.skipGraphQLConfig
3734
3741
  ? null
3735
- : graphqlConfig$1.loadConfigSync({
3742
+ : graphqlConfig.loadConfigSync({
3736
3743
  throwOnEmpty: false,
3737
3744
  throwOnMissing: false,
3738
3745
  extensions: [addCodeFileLoaderExtension],
3739
3746
  });
3740
- graphqlConfig =
3747
+ const configOptions = options.projects
3748
+ ? { projects: options.projects }
3749
+ : {
3750
+ schema: (options.schema || ''),
3751
+ documents: options.documents || options.operations,
3752
+ extensions: options.extensions,
3753
+ include: options.include,
3754
+ exclude: options.exclude,
3755
+ };
3756
+ graphQLConfig =
3741
3757
  onDiskConfig ||
3742
- new graphqlConfig$1.GraphQLConfig({
3743
- config: options.projects
3744
- ? { projects: options.projects }
3745
- : {
3746
- schema: (options.schema || ''),
3747
- documents: options.documents || options.operations,
3748
- extensions: options.extensions,
3749
- include: options.include,
3750
- exclude: options.exclude,
3751
- },
3758
+ new graphqlConfig.GraphQLConfig({
3759
+ config: configOptions,
3752
3760
  filepath: 'virtual-config',
3753
3761
  }, [addCodeFileLoaderExtension]);
3754
- return graphqlConfig;
3762
+ return graphQLConfig;
3755
3763
  }
3756
3764
  const addCodeFileLoaderExtension = api => {
3757
3765
  api.loaders.schema.register(new codeFileLoader.CodeFileLoader());
@@ -3841,7 +3849,7 @@ function parse(code, options) {
3841
3849
  return parseForESLint(code, options).ast;
3842
3850
  }
3843
3851
  function parseForESLint(code, options = {}) {
3844
- const gqlConfig = loadGraphqlConfig(options);
3852
+ const gqlConfig = loadGraphQLConfig(options);
3845
3853
  const schema = getSchema(options, gqlConfig);
3846
3854
  const parserServices = {
3847
3855
  hasTypeInfo: schema !== null,
@@ -3873,6 +3881,7 @@ function parseForESLint(code, options = {}) {
3873
3881
  };
3874
3882
  }
3875
3883
  catch (e) {
3884
+ e.message = `[graphql-eslint] ${e.message}`;
3876
3885
  // In case of GraphQL parser error, we report it to ESLint as a parser error that matches the requirements
3877
3886
  // of ESLint. This will make sure to display it correctly in IDEs and lint results.
3878
3887
  if (e instanceof graphql.GraphQLError) {
@@ -3880,11 +3889,10 @@ function parseForESLint(code, options = {}) {
3880
3889
  index: e.positions[0],
3881
3890
  lineNumber: e.locations[0].line,
3882
3891
  column: e.locations[0].column,
3883
- message: `[graphql-eslint]: ${e.message}`,
3892
+ message: e.message,
3884
3893
  };
3885
3894
  throw eslintError;
3886
3895
  }
3887
- e.message = `[graphql-eslint]: ${e.message}`;
3888
3896
  throw e;
3889
3897
  }
3890
3898
  }
package/index.mjs CHANGED
@@ -4,6 +4,7 @@ import { statSync, existsSync, readFileSync } from 'fs';
4
4
  import { dirname, extname, basename, relative, resolve } from 'path';
5
5
  import { asArray, parseGraphQLSDL } from '@graphql-tools/utils';
6
6
  import lowerCase from 'lodash.lowercase';
7
+ import chalk from 'chalk';
7
8
  import depthLimit from 'graphql-depth-limit';
8
9
  import { parseCode } from '@graphql-tools/graphql-tag-pluck';
9
10
  import { loadConfigSync, GraphQLConfig } from 'graphql-config';
@@ -186,6 +187,12 @@ function requireGraphQLSchemaFromContext(ruleName, context) {
186
187
  }
187
188
  return context.parserServices.schema;
188
189
  }
190
+ const logger = {
191
+ // eslint-disable-next-line no-console
192
+ error: (...args) => console.error(chalk.red('error'), '[graphql-eslint]', chalk(...args)),
193
+ // eslint-disable-next-line no-console
194
+ warn: (...args) => console.warn(chalk.yellow('warning'), '[graphql-eslint]', chalk(...args)),
195
+ };
189
196
  function requireReachableTypesFromContext(ruleName, context) {
190
197
  const schema = requireGraphQLSchemaFromContext(ruleName, context);
191
198
  return context.parserServices.reachableTypes(schema);
@@ -320,14 +327,14 @@ function getLocation(loc, fieldName = '', offset) {
320
327
  };
321
328
  }
322
329
 
323
- function validateDocument(sourceNode, context, schema, documentNode, rule) {
330
+ function validateDocument(context, schema = null, documentNode, rule) {
324
331
  if (documentNode.definitions.length === 0) {
325
332
  return;
326
333
  }
327
334
  try {
328
335
  const validationErrors = schema
329
336
  ? validate(schema, documentNode, [rule])
330
- : validateSDL(documentNode, null, [rule]);
337
+ : validateSDL(documentNode, schema, [rule]);
331
338
  for (const error of validationErrors) {
332
339
  /*
333
340
  * TODO: Fix ESTree-AST converter because currently it's incorrectly convert loc.end
@@ -352,7 +359,8 @@ function validateDocument(sourceNode, context, schema, documentNode, rule) {
352
359
  }
353
360
  catch (e) {
354
361
  context.report({
355
- node: sourceNode,
362
+ // Report on first character
363
+ loc: { column: 0, line: 1 },
356
364
  message: e.message,
357
365
  });
358
366
  }
@@ -434,18 +442,17 @@ const validationToRule = (ruleId, ruleName, docs, getDocumentNode) => {
434
442
  },
435
443
  },
436
444
  create(context) {
445
+ if (!ruleFn) {
446
+ logger.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
447
+ return {};
448
+ }
437
449
  return {
438
450
  Document(node) {
439
- if (!ruleFn) {
440
- // eslint-disable-next-line no-console
441
- console.warn(`You rule "${ruleId}" depends on a GraphQL validation rule "${ruleName}" but it's not available in the "graphql-js" version you are using. Skipping...`);
442
- return;
443
- }
444
451
  const schema = docs.requiresSchema ? requireGraphQLSchemaFromContext(ruleId, context) : null;
445
452
  const documentNode = getDocumentNode
446
453
  ? getDocumentNode({ ruleId, context, schema, node: node.rawNode() })
447
454
  : node.rawNode();
448
- validateDocument(node, context, schema, documentNode, ruleFn);
455
+ validateDocument(context, schema, documentNode, ruleFn);
449
456
  },
450
457
  };
451
458
  },
@@ -595,7 +602,8 @@ const GRAPHQL_JS_VALIDATIONS = Object.assign({}, validationToRule('executable-de
595
602
  }), validationToRule('possible-type-extension', 'PossibleTypeExtensions', {
596
603
  category: 'Schema',
597
604
  description: `A type extension is only valid if the type is defined and has the same kind.`,
598
- recommended: false, // TODO: enable after https://github.com/dotansimha/graphql-eslint/issues/787 will be fixed
605
+ recommended: false,
606
+ requiresSchema: true,
599
607
  }), validationToRule('provided-required-arguments', 'ProvidedRequiredArguments', {
600
608
  category: ['Schema', 'Operations'],
601
609
  description: `A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.`,
@@ -3028,12 +3036,13 @@ const rule$j = {
3028
3036
  },
3029
3037
  };
3030
3038
 
3039
+ const RULE_ID$2 = 'selection-set-depth';
3031
3040
  const rule$k = {
3032
3041
  meta: {
3033
3042
  docs: {
3034
3043
  category: 'Operations',
3035
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).`,
3036
- url: 'https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/selection-set-depth.md',
3045
+ url: `https://github.com/dotansimha/graphql-eslint/blob/master/docs/rules/${RULE_ID$2}.md`,
3037
3046
  requiresSiblings: true,
3038
3047
  examples: [
3039
3048
  {
@@ -3107,11 +3116,10 @@ const rule$k = {
3107
3116
  create(context) {
3108
3117
  let siblings = null;
3109
3118
  try {
3110
- siblings = requireSiblingsOperations('selection-set-depth', context);
3119
+ siblings = requireSiblingsOperations(RULE_ID$2, context);
3111
3120
  }
3112
3121
  catch (e) {
3113
- // eslint-disable-next-line no-console
3114
- console.warn(`Rule "selection-set-depth" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3122
+ logger.warn(`Rule "${RULE_ID$2}" works best with siblings operations loaded. For more info: http://bit.ly/graphql-eslint-operations`);
3115
3123
  }
3116
3124
  const { maxDepth } = context.options[0];
3117
3125
  const ignore = context.options[0].ignore || [];
@@ -3136,8 +3144,7 @@ const rule$k = {
3136
3144
  });
3137
3145
  }
3138
3146
  catch (e) {
3139
- // eslint-disable-next-line no-console
3140
- console.warn(`Rule "selection-set-depth" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3147
+ logger.warn(`Rule "${RULE_ID$2}" check failed due to a missing siblings operations. For more info: http://bit.ly/graphql-eslint-operations`, e);
3141
3148
  }
3142
3149
  },
3143
3150
  };
@@ -3519,8 +3526,7 @@ function createGraphqlProcessor() {
3519
3526
  }
3520
3527
  }
3521
3528
  catch (e) {
3522
- // eslint-disable-next-line no-console
3523
- console.warn(`[graphql-eslint/processor]: Unable to process file "${filename}": `, e);
3529
+ logger.warn(`Unable to process file "${filename}"`, e);
3524
3530
  }
3525
3531
  }
3526
3532
  return [text];
@@ -3560,20 +3566,25 @@ const schemaCache = new Map();
3560
3566
  function getSchema(options = {}, gqlConfig) {
3561
3567
  const realFilepath = options.filePath ? getOnDiskFilepath(options.filePath) : null;
3562
3568
  const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
3563
- const schemaKey = asArray(projectForFile.schema)
3564
- .sort()
3565
- .join(',');
3569
+ const schemaKey = asArray(projectForFile.schema).sort().join(',');
3566
3570
  if (!schemaKey) {
3567
3571
  return null;
3568
3572
  }
3569
- let schema = schemaCache.get(schemaKey);
3570
- if (!schema) {
3573
+ if (schemaCache.has(schemaKey)) {
3574
+ return schemaCache.get(schemaKey);
3575
+ }
3576
+ let schema;
3577
+ try {
3571
3578
  schema = projectForFile.loadSchemaSync(projectForFile.schema, 'GraphQLSchema', {
3572
3579
  cache: loaderCache,
3573
- ...options.schemaOptions
3580
+ ...options.schemaOptions,
3574
3581
  });
3575
- schemaCache.set(schemaKey, schema);
3576
3582
  }
3583
+ catch (e) {
3584
+ schema = null;
3585
+ logger.error('Error while loading schema\n', e);
3586
+ }
3587
+ schemaCache.set(schemaKey, schema);
3577
3588
  return schema;
3578
3589
  }
3579
3590
 
@@ -3586,10 +3597,10 @@ const handleVirtualPath = (documents) => {
3586
3597
  return source;
3587
3598
  }
3588
3599
  (_a = filepathMap[location]) !== null && _a !== void 0 ? _a : (filepathMap[location] = -1);
3589
- const index = filepathMap[location] += 1;
3600
+ const index = (filepathMap[location] += 1);
3590
3601
  return {
3591
3602
  ...source,
3592
- location: resolve(location, `${index}_document.graphql`)
3603
+ location: resolve(location, `${index}_document.graphql`),
3593
3604
  };
3594
3605
  });
3595
3606
  };
@@ -3598,9 +3609,7 @@ const siblingOperationsCache = new Map();
3598
3609
  const getSiblings = (filePath, gqlConfig) => {
3599
3610
  const realFilepath = filePath ? getOnDiskFilepath(filePath) : null;
3600
3611
  const projectForFile = realFilepath ? gqlConfig.getProjectForFile(realFilepath) : gqlConfig.getDefault();
3601
- const documentsKey = asArray(projectForFile.documents)
3602
- .sort()
3603
- .join(',');
3612
+ const documentsKey = asArray(projectForFile.documents).sort().join(',');
3604
3613
  if (!documentsKey) {
3605
3614
  return [];
3606
3615
  }
@@ -3608,7 +3617,7 @@ const getSiblings = (filePath, gqlConfig) => {
3608
3617
  if (!siblings) {
3609
3618
  const documents = projectForFile.loadDocumentsSync(projectForFile.documents, {
3610
3619
  skipGraphQLImport: true,
3611
- cache: loaderCache
3620
+ cache: loaderCache,
3612
3621
  });
3613
3622
  siblings = handleVirtualPath(documents);
3614
3623
  operationsCache.set(documentsKey, siblings);
@@ -3621,8 +3630,7 @@ function getSiblingOperations(options, gqlConfig) {
3621
3630
  let printed = false;
3622
3631
  const noopWarn = () => {
3623
3632
  if (!printed) {
3624
- // eslint-disable-next-line no-console
3625
- console.warn(`getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!`);
3633
+ logger.warn(`getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!`);
3626
3634
  printed = true;
3627
3635
  }
3628
3636
  return [];
@@ -3686,8 +3694,7 @@ function getSiblingOperations(options, gqlConfig) {
3686
3694
  const name = spread.name.value;
3687
3695
  const fragmentInfo = getFragment(name);
3688
3696
  if (fragmentInfo.length === 0) {
3689
- // eslint-disable-next-line no-console
3690
- console.warn(`Unable to locate fragment named "${name}", please make sure it's loaded using "parserOptions.operations"`);
3697
+ logger.warn(`Unable to locate fragment named "${name}", please make sure it's loaded using "parserOptions.operations"`);
3691
3698
  return;
3692
3699
  }
3693
3700
  const fragment = fragmentInfo[0];
@@ -3717,12 +3724,12 @@ function getSiblingOperations(options, gqlConfig) {
3717
3724
  return siblingOperations;
3718
3725
  }
3719
3726
 
3720
- let graphqlConfig;
3721
- function loadGraphqlConfig(options) {
3727
+ let graphQLConfig;
3728
+ function loadGraphQLConfig(options) {
3722
3729
  // We don't want cache config on test environment
3723
3730
  // Otherwise schema and documents will be same for all tests
3724
- if (process.env.NODE_ENV !== 'test' && graphqlConfig) {
3725
- return graphqlConfig;
3731
+ if (process.env.NODE_ENV !== 'test' && graphQLConfig) {
3732
+ return graphQLConfig;
3726
3733
  }
3727
3734
  const onDiskConfig = options.skipGraphQLConfig
3728
3735
  ? null
@@ -3731,21 +3738,22 @@ function loadGraphqlConfig(options) {
3731
3738
  throwOnMissing: false,
3732
3739
  extensions: [addCodeFileLoaderExtension],
3733
3740
  });
3734
- graphqlConfig =
3741
+ const configOptions = options.projects
3742
+ ? { projects: options.projects }
3743
+ : {
3744
+ schema: (options.schema || ''),
3745
+ documents: options.documents || options.operations,
3746
+ extensions: options.extensions,
3747
+ include: options.include,
3748
+ exclude: options.exclude,
3749
+ };
3750
+ graphQLConfig =
3735
3751
  onDiskConfig ||
3736
3752
  new GraphQLConfig({
3737
- config: options.projects
3738
- ? { projects: options.projects }
3739
- : {
3740
- schema: (options.schema || ''),
3741
- documents: options.documents || options.operations,
3742
- extensions: options.extensions,
3743
- include: options.include,
3744
- exclude: options.exclude,
3745
- },
3753
+ config: configOptions,
3746
3754
  filepath: 'virtual-config',
3747
3755
  }, [addCodeFileLoaderExtension]);
3748
- return graphqlConfig;
3756
+ return graphQLConfig;
3749
3757
  }
3750
3758
  const addCodeFileLoaderExtension = api => {
3751
3759
  api.loaders.schema.register(new CodeFileLoader());
@@ -3835,7 +3843,7 @@ function parse(code, options) {
3835
3843
  return parseForESLint(code, options).ast;
3836
3844
  }
3837
3845
  function parseForESLint(code, options = {}) {
3838
- const gqlConfig = loadGraphqlConfig(options);
3846
+ const gqlConfig = loadGraphQLConfig(options);
3839
3847
  const schema = getSchema(options, gqlConfig);
3840
3848
  const parserServices = {
3841
3849
  hasTypeInfo: schema !== null,
@@ -3867,6 +3875,7 @@ function parseForESLint(code, options = {}) {
3867
3875
  };
3868
3876
  }
3869
3877
  catch (e) {
3878
+ e.message = `[graphql-eslint] ${e.message}`;
3870
3879
  // In case of GraphQL parser error, we report it to ESLint as a parser error that matches the requirements
3871
3880
  // of ESLint. This will make sure to display it correctly in IDEs and lint results.
3872
3881
  if (e instanceof GraphQLError) {
@@ -3874,11 +3883,10 @@ function parseForESLint(code, options = {}) {
3874
3883
  index: e.positions[0],
3875
3884
  lineNumber: e.locations[0].line,
3876
3885
  column: e.locations[0].column,
3877
- message: `[graphql-eslint]: ${e.message}`,
3886
+ message: e.message,
3878
3887
  };
3879
3888
  throw eslintError;
3880
3889
  }
3881
- e.message = `[graphql-eslint]: ${e.message}`;
3882
3890
  throw e;
3883
3891
  }
3884
3892
  }
package/package.json CHANGED
@@ -1,16 +1,17 @@
1
1
  {
2
2
  "name": "@graphql-eslint/eslint-plugin",
3
- "version": "3.3.0",
3
+ "version": "3.4.0-alpha-d977284.0",
4
4
  "description": "GraphQL plugin for ESLint",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
7
  "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"
8
8
  },
9
9
  "dependencies": {
10
- "@babel/code-frame": "7.16.0",
10
+ "@babel/code-frame": "7.16.7",
11
11
  "@graphql-tools/code-file-loader": "7.2.3",
12
12
  "@graphql-tools/graphql-tag-pluck": "7.1.4",
13
13
  "@graphql-tools/utils": "8.5.5",
14
+ "chalk": "4.1.2",
14
15
  "graphql-config": "4.1.0",
15
16
  "graphql-depth-limit": "1.1.0",
16
17
  "lodash.lowercase": "4.3.0"
package/utils.d.ts CHANGED
@@ -6,6 +6,10 @@ import { SiblingOperations } from './sibling-operations';
6
6
  import { UsedFields, ReachableTypes } from './graphql-ast';
7
7
  export declare function requireSiblingsOperations(ruleName: string, context: GraphQLESLintRuleContext): SiblingOperations | never;
8
8
  export declare function requireGraphQLSchemaFromContext(ruleName: string, context: GraphQLESLintRuleContext): GraphQLSchema | never;
9
+ export declare const logger: {
10
+ error: (...args: any[]) => void;
11
+ warn: (...args: any[]) => void;
12
+ };
9
13
  export declare function requireReachableTypesFromContext(ruleName: string, context: GraphQLESLintRuleContext): ReachableTypes | never;
10
14
  export declare function requireUsedFieldsFromContext(ruleName: string, context: GraphQLESLintRuleContext): UsedFields | never;
11
15
  export declare function extractTokens(source: Source): AST.Token[];