From dff40474bd4fb9929b3d68bad4e608b5e5d91c43 Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:13:38 +0100 Subject: [PATCH 1/9] Switch to new ValidationContext API, use `onError`, remove `getErrors` --- src/QueryComplexity.ts | 2 +- src/__tests__/QueryComplexity-test.ts | 43 +++++++++++-------- .../__tests__/directiveEstimator-test.ts | 28 ++++++------ .../__tests__/fieldConfigEstimator-test.ts | 35 ++++++++------- .../fieldExtensionsEstimator-test.ts | 35 ++++++++------- .../legacy/__tests__/legacyEstimator-test.ts | 36 +++++++++------- .../simple/__tests__/simpleEstimator-test.ts | 26 +++++------ 7 files changed, 112 insertions(+), 93 deletions(-) diff --git a/src/QueryComplexity.ts b/src/QueryComplexity.ts index 4245358..c10ef1d 100644 --- a/src/QueryComplexity.ts +++ b/src/QueryComplexity.ts @@ -91,7 +91,7 @@ export function getComplexity(options: { }): number { const typeInfo = new TypeInfo(options.schema); - const context = new ValidationContext(options.schema, options.query, typeInfo); + const context = new ValidationContext(options.schema, options.query, typeInfo, () => null); const visitor = new QueryComplexity(context, { // Maximum complexity does not matter since we're only interested in the calculated complexity. maximumComplexity: Infinity, diff --git a/src/__tests__/QueryComplexity-test.ts b/src/__tests__/QueryComplexity-test.ts index 3d0b491..1e82772 100644 --- a/src/__tests__/QueryComplexity-test.ts +++ b/src/__tests__/QueryComplexity-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -154,7 +155,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -173,7 +174,8 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = []; + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -186,8 +188,8 @@ describe('QueryComplexity analysis', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -203,7 +205,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -230,7 +232,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -257,7 +259,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -284,7 +286,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -310,7 +312,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -332,7 +334,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -353,7 +355,8 @@ describe('QueryComplexity analysis', () => { requiredArgs } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = []; + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -364,8 +367,8 @@ describe('QueryComplexity analysis', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); it('should report error when no estimator is configured', () => { @@ -374,14 +377,15 @@ describe('QueryComplexity analysis', () => { scalar } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = []; + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'No complexity could be calculated for field Query.scalar. ' + 'At least one complexity estimator has to return a complexity score.' ); @@ -393,7 +397,8 @@ describe('QueryComplexity analysis', () => { scalar } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = []; + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -401,8 +406,8 @@ describe('QueryComplexity analysis', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'No complexity could be calculated for field Query.scalar. ' + 'At least one complexity estimator has to return a complexity score.' ); diff --git a/src/estimators/directive/__tests__/directiveEstimator-test.ts b/src/estimators/directive/__tests__/directiveEstimator-test.ts index 3dec3d1..a0d7209 100644 --- a/src/estimators/directive/__tests__/directiveEstimator-test.ts +++ b/src/estimators/directive/__tests__/directiveEstimator-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -27,7 +28,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -46,7 +47,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -65,7 +66,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -84,7 +85,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -107,7 +108,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -128,7 +129,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -149,7 +150,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -170,7 +171,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -191,7 +192,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -212,7 +213,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -231,7 +232,8 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = []; + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -240,8 +242,8 @@ describe('directiveEstimator analysis', () => { }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.context.getErrors().length).to.equal(1); - expect(visitor.context.getErrors()[0].message).to.include( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.include( 'No complexity could be calculated for field Query.noDirective', ); }); diff --git a/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts b/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts index 791555d..262e669 100644 --- a/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts +++ b/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -28,7 +29,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -50,7 +51,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -72,7 +73,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -94,7 +95,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -116,7 +117,8 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -129,8 +131,8 @@ describe('fieldConfig estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -146,7 +148,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -173,7 +175,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -200,7 +202,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -227,7 +229,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -253,7 +255,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -275,7 +277,7 @@ describe('fieldConfig estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -296,7 +298,8 @@ describe('fieldConfig estimator', () => { requiredArgs } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -307,7 +310,7 @@ describe('fieldConfig estimator', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); }); diff --git a/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts b/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts index 7130bb9..868409f 100644 --- a/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts +++ b/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -28,7 +29,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -50,7 +51,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -72,7 +73,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -94,7 +95,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -116,7 +117,8 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -129,8 +131,8 @@ describe('fieldExtensions estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -146,7 +148,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -173,7 +175,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -200,7 +202,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -227,7 +229,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -253,7 +255,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -275,7 +277,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -296,7 +298,8 @@ describe('fieldExtensions estimator', () => { requiredArgs } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -307,7 +310,7 @@ describe('fieldExtensions estimator', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); }); diff --git a/src/estimators/legacy/__tests__/legacyEstimator-test.ts b/src/estimators/legacy/__tests__/legacyEstimator-test.ts index 6a75644..7df139a 100644 --- a/src/estimators/legacy/__tests__/legacyEstimator-test.ts +++ b/src/estimators/legacy/__tests__/legacyEstimator-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -28,7 +29,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -48,7 +49,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -68,7 +69,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -88,7 +89,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -108,7 +109,8 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -119,8 +121,8 @@ describe('legacy estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -136,7 +138,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -161,7 +163,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -186,7 +188,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -211,7 +213,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -235,7 +237,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -255,7 +257,7 @@ describe('legacy estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -274,7 +276,9 @@ describe('legacy estimator', () => { requiredArgs } `); - const context = new ValidationContext(schema, ast, typeInfo); + + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -283,7 +287,7 @@ describe('legacy estimator', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); }); diff --git a/src/estimators/simple/__tests__/simpleEstimator-test.ts b/src/estimators/simple/__tests__/simpleEstimator-test.ts index 10d47a9..6085a4d 100644 --- a/src/estimators/simple/__tests__/simpleEstimator-test.ts +++ b/src/estimators/simple/__tests__/simpleEstimator-test.ts @@ -3,6 +3,7 @@ */ import { + GraphQLError, parse, TypeInfo, ValidationContext, @@ -27,7 +28,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -46,7 +47,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -65,7 +66,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -84,7 +85,8 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const validationErrors: GraphQLError[] = [] + const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -94,8 +96,8 @@ describe('simple estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(context.getErrors().length).to.equal(1); - expect(context.getErrors()[0].message).to.equal( + expect(validationErrors.length).to.equal(1); + expect(validationErrors[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -111,7 +113,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -135,7 +137,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -158,7 +160,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -182,7 +184,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -205,7 +207,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -224,7 +226,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo); + const context = new ValidationContext(schema, ast, typeInfo, () => null); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ From 38aafdc81cf7936d27696e3c6e6cf3d792254eb8 Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:16:27 +0100 Subject: [PATCH 2/9] Bump graphql dev dependency to ^15.0.0. Bump peer dependency to ^14.5.0 || ^15.0.0 (onError was introduced in 14.5.0) --- package.json | 5 ++--- yarn.lock | 19 ++----------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 36fbfee..31d95db 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "lodash.get": "^4.4.2" }, "peerDependencies": { - "graphql": "^0.13.0 || ^14.0.0" + "graphql": "^14.5.0 || ^15.0.0" }, "files": [ "dist", @@ -41,14 +41,13 @@ "devDependencies": { "@types/assert": "^1.4.6", "@types/chai": "^4.2.11", - "@types/graphql": "^0.13.0 || ^14.0.0", "@types/lodash.get": "^4.4.6", "@types/mocha": "^7.0.2", "@typescript-eslint/eslint-plugin": "^2.27.0", "@typescript-eslint/parser": "^2.27.0", "chai": "^4.2.0", "eslint": "^6.8.0", - "graphql": "^0.13.0 || ^14.0.0", + "graphql": "15.0.0", "mocha": "^7.1.1", "rimraf": "^3.0.2", "ts-node": "^8.8.2", diff --git a/yarn.lock b/yarn.lock index 014afdb..344f698 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,12 +36,6 @@ version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" -"@types/graphql@^0.13.0 || ^14.0.0": - version "14.5.0" - resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-14.5.0.tgz#a545fb3bc8013a3547cf2f07f5e13a33642b75d6" - dependencies: - graphql "*" - "@types/json-schema@^7.0.3": version "7.0.4" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" @@ -616,15 +610,10 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -graphql@*: +graphql@15.0.0: version "15.0.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.0.0.tgz#042a5eb5e2506a2e2111ce41eb446a8e570b8be9" - -"graphql@^0.13.0 || ^14.0.0": - version "14.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.6.0.tgz#57822297111e874ea12f5cd4419616930cd83e49" - dependencies: - iterall "^1.2.2" + integrity sha512-ZyVO1xIF9F+4cxfkdhOJINM+51B06Friuv4M66W7HzUOeFd+vNzUn4vtswYINPi6sysjf1M2Ri/rwZALqgwbaQ== growl@1.10.5: version "1.10.5" @@ -762,10 +751,6 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" -iterall@^1.2.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" From 5444e2759f1d6c956e00a3aa3b68dbd30b4175db Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:23:43 +0100 Subject: [PATCH 3/9] Replace fieldConfigEstimator usage in tests with fieldExtensionsEstimator. Remove fieldConfigEstimator and legacyEstimator. --- src/QueryComplexity.ts | 6 +- src/__tests__/QueryComplexity-test.ts | 26 +- src/__tests__/fixtures/schema.ts | 20 +- src/estimators/fieldConfig/README.md | 90 ----- .../__tests__/fieldConfigEstimator-test.ts | 316 ------------------ .../fieldConfig/__tests__/fixtures/schema.ts | 133 -------- src/estimators/fieldConfig/index.ts | 19 -- src/estimators/index.ts | 2 - src/estimators/legacy/README.md | 57 ---- .../legacy/__tests__/fixtures/schema.ts | 131 -------- .../legacy/__tests__/legacyEstimator-test.ts | 293 ---------------- src/estimators/legacy/index.ts | 12 - 12 files changed, 29 insertions(+), 1076 deletions(-) delete mode 100644 src/estimators/fieldConfig/README.md delete mode 100644 src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts delete mode 100644 src/estimators/fieldConfig/__tests__/fixtures/schema.ts delete mode 100644 src/estimators/fieldConfig/index.ts delete mode 100644 src/estimators/legacy/README.md delete mode 100644 src/estimators/legacy/__tests__/fixtures/schema.ts delete mode 100644 src/estimators/legacy/__tests__/legacyEstimator-test.ts delete mode 100644 src/estimators/legacy/index.ts diff --git a/src/QueryComplexity.ts b/src/QueryComplexity.ts index c10ef1d..6cf0b55 100644 --- a/src/QueryComplexity.ts +++ b/src/QueryComplexity.ts @@ -30,8 +30,7 @@ import { GraphQLError } from 'graphql'; import { - simpleEstimator, - legacyEstimator + simpleEstimator } from './estimators'; declare module 'graphql/type/definition' { @@ -135,7 +134,6 @@ export default class QueryComplexity { } this.estimators = options.estimators || [ - legacyEstimator(), simpleEstimator() ]; @@ -178,7 +176,7 @@ export default class QueryComplexity { if (typeof this.options.operationName === 'string' && this.options.operationName !== operation.name.value) { return; } - + if (this.options.onComplete) { this.options.onComplete(this.complexity); } diff --git a/src/__tests__/QueryComplexity-test.ts b/src/__tests__/QueryComplexity-test.ts index 1e82772..d34a5cd 100644 --- a/src/__tests__/QueryComplexity-test.ts +++ b/src/__tests__/QueryComplexity-test.ts @@ -19,7 +19,7 @@ import ComplexityVisitor, {getComplexity} from '../QueryComplexity'; import { simpleEstimator, directiveEstimator, - fieldConfigEstimator, + fieldExtensionsEstimator, } from '../index'; describe('QueryComplexity analysis', () => { @@ -136,7 +136,7 @@ describe('QueryComplexity analysis', () => { const complexity = getComplexity({ estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({defaultComplexity: 1}) ], schema, @@ -179,7 +179,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -209,7 +209,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -236,7 +236,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -263,7 +263,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -290,7 +290,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -316,7 +316,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -338,7 +338,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -360,7 +360,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({ defaultComplexity: 1 }) @@ -402,7 +402,7 @@ describe('QueryComplexity analysis', () => { const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ - fieldConfigEstimator() + fieldExtensionsEstimator() ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); @@ -468,7 +468,7 @@ describe('QueryComplexity analysis', () => { const complexity1 = getComplexity({ estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({defaultComplexity: 1}) ], schema, @@ -478,7 +478,7 @@ describe('QueryComplexity analysis', () => { const complexity2 = getComplexity({ estimators: [ - fieldConfigEstimator(), + fieldExtensionsEstimator(), simpleEstimator({defaultComplexity: 1}) ], schema, diff --git a/src/__tests__/fixtures/schema.ts b/src/__tests__/fixtures/schema.ts index 9d9e982..ef7fa96 100644 --- a/src/__tests__/fixtures/schema.ts +++ b/src/__tests__/fixtures/schema.ts @@ -21,7 +21,9 @@ const Item: GraphQLObjectType = new GraphQLObjectType({ fields: () => ({ variableList: { type: Item, - complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10), + extensions: { + complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10) + }, args: { count: { type: GraphQLInt @@ -29,10 +31,12 @@ const Item: GraphQLObjectType = new GraphQLObjectType({ } }, scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, + complexScalar: { type: GraphQLString, extensions: { complexity: 20 } }, variableScalar: { type: Item, - complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10), + extensions: { + complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10) + }, args: { count: { type: GraphQLInt @@ -97,7 +101,9 @@ const Query = new GraphQLObjectType({ name: { type: GraphQLString }, variableList: { type: Item, - complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10), + extensions: { + complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10) + }, args: { count: { type: GraphQLInt @@ -107,11 +113,13 @@ const Query = new GraphQLObjectType({ interface: {type: NameInterface}, enum: {type: EnumType}, scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, + complexScalar: { type: GraphQLString, extensions: { complexity: 20 } }, union: { type: Union }, variableScalar: { type: Item, - complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10), + extensions: { + complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10) + }, args: { count: { type: GraphQLInt diff --git a/src/estimators/fieldConfig/README.md b/src/estimators/fieldConfig/README.md deleted file mode 100644 index 16b3caf..0000000 --- a/src/estimators/fieldConfig/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Field Config Estimator - -The `fieldConfigEstimator` lets you define a numeric value or a custom estimator -in the field config of your GraphQL schema. If no complexity is set in the field config, -the estimator does not return any value and the next estimator in the chain is executed. - -## Usage - -```typescript -import queryComplexity, { - fieldConfigEstimator, - simpleEstimator -} from 'graphql-query-complexity'; - -const rule = queryComplexity({ - estimators: [ - fieldConfigEstimator(), - - // We use the simpleEstimator as fallback so we only need to - // define the complexity for non 1 values (this is not required...) - simpleEstimator({defaultComplexity: 1}) - ] - // ... other config -}); -``` - -You can set a custom complexity as a numeric value in the field config: - -```javascript -const Post = new GraphQLObjectType({ - name: 'Post', - fields: () => ({ - title: { type: GraphQLString }, - text: { type: GraphQLString, complexity: 5 }, - }), -}); -``` - -**Example Query:** - -```graphql -query { - posts(count: 10) { - title - text - } -} -``` - -This query would result in a complexity of 7. -5 for the `text` field and 1 for each of the other fields. - -You can also pass an estimator in the field config to determine a custom complexity. -This function will provide the complexity of the child nodes as well as the field input arguments. - -The function signature is the same as for the main estimator which lets you reuse estimators: - -```typescript -type ComplexityEstimatorArgs = { - type: GraphQLCompositeType, - field: GraphQLField, - args: {[key: string]: any}, - childComplexity: number -} - -type ComplexityEstimator = (options: ComplexityEstimatorArgs) => number | void; -``` - -That way you can make a more realistic estimation of individual field complexity values: - -```javascript -const Query = new GraphQLObjectType({ - name: 'Query', - fields: () => ({ - posts: { - type: new GraphQLList(Post), - complexity: ({args, childComplexity}) => childComplexity * args.count, - args: { - count: { - type: GraphQLInt, - defaultValue: 10 - } - } - }, - }), -}); -``` - -This would result in a complexity of 60 since the `childComplexity` of posts (`text` 5, `title` 1) is multiplied by the -number of posts (`args.count`). diff --git a/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts b/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts deleted file mode 100644 index 262e669..0000000 --- a/src/estimators/fieldConfig/__tests__/fieldConfigEstimator-test.ts +++ /dev/null @@ -1,316 +0,0 @@ -/** - * Created by Ivo Meißner on 28.07.17. - */ - -import { - GraphQLError, - parse, - TypeInfo, - ValidationContext, - visit, - visitWithTypeInfo, -} from 'graphql'; - -import {expect} from 'chai'; - -import schema from './fixtures/schema'; - -import ComplexityVisitor from '../../../QueryComplexity'; -import simpleEstimator from '../../simple'; -import fieldConfigEstimator from '../index'; - -describe('fieldConfig estimator', () => { - const typeInfo = new TypeInfo(schema); - - it('should consider default scalar cost', () => { - const ast = parse(` - query { - scalar - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1); - }); - - it('should consider custom scalar cost', () => { - const ast = parse(` - query { - complexScalar - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(20); - }); - - it('should consider variable scalar cost', () => { - const ast = parse(` - query { - variableScalar(count: 100) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1000); - }); - - it('should not allow negative cost', () => { - const ast = parse(` - query { - variableScalar(count: -100) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(0); - }); - - it('should report error above threshold', () => { - const ast = parse(` - query { - variableScalar(count: 100) - } - `); - - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1000); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( - 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' - ); - }); - - it('should add inline fragments', () => { - const ast = parse(` - query { - variableScalar(count: 5) - ...on Query { - scalar - alias: scalar - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(52); - }); - - it('should add fragments', () => { - const ast = parse(` - query { - scalar - ...QueryFragment - } - - fragment QueryFragment on Query { - variableScalar(count: 2) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(21); - }); - - it('should add complexity for union types', () => { - const ast = parse(` - query { - union { - ...on Item { - scalar - complexScalar - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(22); - }); - - it('should add complexity for interface types', () => { - const ast = parse(` - query { - interface { - name - ...on NameInterface { - name - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(3); - }); - - it('should add complexity for inline fragments without type condition', () => { - const ast = parse(` - query { - interface { - ... { - name - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(2); - }); - - it('should add complexity for enum types', () => { - const ast = parse(` - query { - enum - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1); - }); - - it('should error on a missing non-null argument', () => { - const ast = parse(` - query { - requiredArgs - } - `); - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - fieldConfigEstimator(), - simpleEstimator({ - defaultComplexity: 1 - }) - ] - }); - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); - }); -}); diff --git a/src/estimators/fieldConfig/__tests__/fixtures/schema.ts b/src/estimators/fieldConfig/__tests__/fixtures/schema.ts deleted file mode 100644 index 8ff1a3b..0000000 --- a/src/estimators/fieldConfig/__tests__/fixtures/schema.ts +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Created by Ivo Meißner on 28.07.17. - */ - -import { - GraphQLList, - GraphQLObjectType, - GraphQLNonNull, - GraphQLSchema, - GraphQLString, - GraphQLInt, - GraphQLEnumType, - GraphQLUnionType, - GraphQLInterfaceType, -} from 'graphql'; - -import {ComplexityEstimatorArgs} from '../../../../QueryComplexity'; - -const Item: GraphQLObjectType = new GraphQLObjectType({ - name: 'Item', - fields: () => ({ - variableList: { - type: Item, - complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, - variableScalar: { - type: Item, - complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - list: { type: new GraphQLList(Item) }, - nonNullItem: { - type: new GraphQLNonNull(Item), - resolve: () => ({}), - }, - nonNullList: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Item))), - resolve: () => [], - }, - }), -}); - -const NameInterface = new GraphQLInterfaceType({ - name: 'NameInterface', - fields: { - name: { type: GraphQLString } - }, - resolveType: () => Item -}); - -const SecondItem = new GraphQLObjectType({ - name: 'SecondItem', - fields: () => ({ - name: {type: GraphQLString}, - scalar: {type: GraphQLString} - }), - interfaces: [ NameInterface ] -}); - -const EnumType = new GraphQLEnumType({ - name: 'RGB', - values: { - RED: { value: 0 }, - GREEN: { value: 1 }, - BLUE: { value: 2 } - } -}); - -const Union = new GraphQLUnionType({ - name: 'Union', - types: [ Item, SecondItem ], - resolveType: () => Item -}); - -const Query = new GraphQLObjectType({ - name: 'Query', - fields: () => ({ - name: { type: GraphQLString }, - variableList: { - type: Item, - complexity: (args: ComplexityEstimatorArgs) => args.childComplexity * (args.args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - interface: {type: NameInterface}, - enum: {type: EnumType}, - scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, - union: { type: Union }, - variableScalar: { - type: Item, - complexity: (args: ComplexityEstimatorArgs) => 10 * (args.args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - list: { type: new GraphQLList(Item) }, - nonNullItem: { - type: new GraphQLNonNull(Item), - resolve: () => ({}), - }, - nonNullList: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Item))), - resolve: () => [], - }, - requiredArgs: { - type: Item, - args: { - count: { - type: new GraphQLNonNull(GraphQLInt) - } - } - } - }), -}); - -export default new GraphQLSchema({ query: Query }); diff --git a/src/estimators/fieldConfig/index.ts b/src/estimators/fieldConfig/index.ts deleted file mode 100644 index 407b9b8..0000000 --- a/src/estimators/fieldConfig/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {ComplexityEstimator, ComplexityEstimatorArgs} from '../../QueryComplexity'; - -/** - * @deprecated Use fieldExtensionsEstimator instead - */ -export default function (): ComplexityEstimator { - console.warn( - 'DEPRECATION WARNING: fieldConfigEstimator is deprecated. Use fieldExtensionsEstimator instead' - ); - - return (args: ComplexityEstimatorArgs) => { - // Calculate complexity score - if (typeof args.field.complexity === 'number') { - return args.childComplexity + args.field.complexity; - } else if (typeof args.field.complexity === 'function') { - return args.field.complexity(args); - } - }; -} diff --git a/src/estimators/index.ts b/src/estimators/index.ts index bdd1c08..2efd4b2 100644 --- a/src/estimators/index.ts +++ b/src/estimators/index.ts @@ -1,5 +1,3 @@ export {default as simpleEstimator} from './simple'; -export {default as legacyEstimator} from './legacy'; -export {default as fieldConfigEstimator} from './fieldConfig'; export {default as directiveEstimator} from './directive'; export {default as fieldExtensionsEstimator} from './fieldExtensions'; diff --git a/src/estimators/legacy/README.md b/src/estimators/legacy/README.md deleted file mode 100644 index 5bc34ff..0000000 --- a/src/estimators/legacy/README.md +++ /dev/null @@ -1,57 +0,0 @@ -# Legacy Estimator - -WARNING: The legacy estimator is only part of the library to provide the functionality of previous versions. -You should use the fieldConfig estimator for new projects and migrate old implementations. - -## Usage - -````typescript -import queryComplexity, {legacyEstimator} from 'graphql-query-complexity'; - -const rule = queryComplexity({ - estimators: [ - legacyEstimator() - ] - // ... other config -}); -```` - -You can set a custom complexity in the field config: - -```javascript -const Post = new GraphQLObjectType({ - name: 'Post', - fields: () => ({ - title: { type: GraphQLString }, - text: { type: GraphQLString, complexity: 5 }, - }), -}); -``` -The same query would now result in a complexity of 7. -5 for the `text` field and 1 for each of the other fields. - -You can also pass a calculation function in the field config to determine a custom complexity. -This function will provide the complexity of the child nodes as well as the field input arguments. - -That way you can make a more realistic estimation of individual field complexity values: - -```javascript -const Query = new GraphQLObjectType({ - name: 'Query', - fields: () => ({ - posts: { - type: new GraphQLList(Post), - complexity: (args, childComplexity) => childComplexity * args.count, - args: { - count: { - type: GraphQLInt, - defaultValue: 10 - } - } - }, - }), -}); -``` - -This would result in a complexity of 60 since the `childComplexity` of posts (`text` 5, `title` 1) is multiplied by the -number of posts (`args.count`). \ No newline at end of file diff --git a/src/estimators/legacy/__tests__/fixtures/schema.ts b/src/estimators/legacy/__tests__/fixtures/schema.ts deleted file mode 100644 index 02b977f..0000000 --- a/src/estimators/legacy/__tests__/fixtures/schema.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Created by Ivo Meißner on 28.07.17. - */ - -import { - GraphQLList, - GraphQLObjectType, - GraphQLNonNull, - GraphQLSchema, - GraphQLString, - GraphQLInt, - GraphQLEnumType, - GraphQLUnionType, - GraphQLInterfaceType, -} from 'graphql'; - -const Item: GraphQLObjectType = new GraphQLObjectType({ - name: 'Item', - fields: () => ({ - variableList: { - type: Item, - complexity: (args: any, childComplexity: number) => childComplexity * (args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, - variableScalar: { - type: Item, - complexity: (args: {[key: string]: any}) => 10 * (args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - list: { type: new GraphQLList(Item) }, - nonNullItem: { - type: new GraphQLNonNull(Item), - resolve: () => ({}), - }, - nonNullList: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Item))), - resolve: () => [], - }, - }), -}); - -const NameInterface = new GraphQLInterfaceType({ - name: 'NameInterface', - fields: { - name: { type: GraphQLString } - }, - resolveType: () => Item -}); - -const SecondItem = new GraphQLObjectType({ - name: 'SecondItem', - fields: () => ({ - name: {type: GraphQLString}, - scalar: {type: GraphQLString} - }), - interfaces: [ NameInterface ] -}); - -const EnumType = new GraphQLEnumType({ - name: 'RGB', - values: { - RED: { value: 0 }, - GREEN: { value: 1 }, - BLUE: { value: 2 } - } -}); - -const Union = new GraphQLUnionType({ - name: 'Union', - types: [ Item, SecondItem ], - resolveType: () => Item -}); - -const Query = new GraphQLObjectType({ - name: 'Query', - fields: () => ({ - name: { type: GraphQLString }, - variableList: { - type: Item, - complexity: (args: {[key: string]: any}, childComplexity: number) => childComplexity * (args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - interface: {type: NameInterface}, - enum: {type: EnumType}, - scalar: { type: GraphQLString }, - complexScalar: { type: GraphQLString, complexity: 20 }, - union: { type: Union }, - variableScalar: { - type: Item, - complexity: (args: {[key: string]: any}) => 10 * (args.count || 10), - args: { - count: { - type: GraphQLInt - } - } - }, - list: { type: new GraphQLList(Item) }, - nonNullItem: { - type: new GraphQLNonNull(Item), - resolve: () => ({}), - }, - nonNullList: { - type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(Item))), - resolve: () => [], - }, - requiredArgs: { - type: Item, - args: { - count: { - type: new GraphQLNonNull(GraphQLInt) - } - } - } - }), -}); - -export default new GraphQLSchema({ query: Query }); diff --git a/src/estimators/legacy/__tests__/legacyEstimator-test.ts b/src/estimators/legacy/__tests__/legacyEstimator-test.ts deleted file mode 100644 index 7df139a..0000000 --- a/src/estimators/legacy/__tests__/legacyEstimator-test.ts +++ /dev/null @@ -1,293 +0,0 @@ -/** - * Created by Ivo Meißner on 28.07.17. - */ - -import { - GraphQLError, - parse, - TypeInfo, - ValidationContext, - visit, - visitWithTypeInfo, -} from 'graphql'; - -import {expect} from 'chai'; - -import schema from './fixtures/schema'; - -import ComplexityVisitor from '../../../QueryComplexity'; -import legacyEstimator from '../index'; -import simpleEstimator from '../../simple'; - -describe('legacy estimator', () => { - const typeInfo = new TypeInfo(schema); - - it('should consider default scalar cost', () => { - const ast = parse(` - query { - scalar - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1); - }); - - it('should consider custom scalar cost', () => { - const ast = parse(` - query { - complexScalar - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(20); - }); - - it('should consider variable scalar cost', () => { - const ast = parse(` - query { - variableScalar(count: 100) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1000); - }); - - it('should not allow negative cost', () => { - const ast = parse(` - query { - variableScalar(count: -100) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(0); - }); - - it('should report error above threshold', () => { - const ast = parse(` - query { - variableScalar(count: 100) - } - `); - - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1000); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( - 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' - ); - }); - - it('should add inline fragments', () => { - const ast = parse(` - query { - variableScalar(count: 5) - ...on Query { - scalar - alias: scalar - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(52); - }); - - it('should add fragments', () => { - const ast = parse(` - query { - scalar - ...QueryFragment - } - - fragment QueryFragment on Query { - variableScalar(count: 2) - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(21); - }); - - it('should add complexity for union types', () => { - const ast = parse(` - query { - union { - ...on Item { - scalar - complexScalar - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(22); - }); - - it('should add complexity for interface types', () => { - const ast = parse(` - query { - interface { - name - ...on NameInterface { - name - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(3); - }); - - it('should add complexity for inline fragments without type condition', () => { - const ast = parse(` - query { - interface { - ... { - name - } - } - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(2); - }); - - it('should add complexity for enum types', () => { - const ast = parse(` - query { - enum - } - `); - - const context = new ValidationContext(schema, ast, typeInfo, () => null); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(visitor.complexity).to.equal(1); - }); - - it('should error on a missing non-null argument', () => { - const ast = parse(` - query { - requiredArgs - } - `); - - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); - const visitor = new ComplexityVisitor(context, { - maximumComplexity: 100, - estimators: [ - legacyEstimator(), - simpleEstimator() - ] - }); - visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); - }); -}); diff --git a/src/estimators/legacy/index.ts b/src/estimators/legacy/index.ts deleted file mode 100644 index a3c3746..0000000 --- a/src/estimators/legacy/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {ComplexityEstimator, ComplexityEstimatorArgs} from '../../QueryComplexity'; - -export default function (): ComplexityEstimator { - return (args: ComplexityEstimatorArgs) => { - // Calculate complexity score - if (typeof args.field.complexity === 'number') { - return args.childComplexity + args.field.complexity; - } else if (typeof args.field.complexity === 'function') { - return args.field.complexity(args.args, args.childComplexity); - } - }; -} From ed7cf16f288c6bb2c2057c741d9feb5e15fb503d Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:26:30 +0100 Subject: [PATCH 4/9] Remove fieldConfigEstimator and legacyEstimator from README --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 49d5b3d..487661e 100644 --- a/README.md +++ b/README.md @@ -83,10 +83,6 @@ or write your own: schema definition (for example via GraphQL SDL) * **[`fieldExtensionsEstimator`](src/estimators/fieldExtensions/README.md):** The field extensions estimator lets you set a numeric value or a custom estimator function in the field config extensions of your schema. -* **[`fieldConfigEstimator`](src/estimators/fieldConfig/README.md):** (DEPRECATED) The field config estimator lets you set a numeric value or a custom estimator - function in the field config of your schema. -* **[`legacyEstimator`](src/estimators/legacy/README.md):** (DEPRECATED) The legacy estimator implements the logic of previous versions. Can be used - to gradually migrate your codebase to new estimators. * PRs welcome... Consult the documentation of each estimator for information about how to use them. From a1e3b7b67bccf7137d494e937622fdc88a873e38 Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:36:10 +0100 Subject: [PATCH 5/9] Dev graphql dependency => same as peer dependency --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 31d95db..e7b8fa3 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@typescript-eslint/parser": "^2.27.0", "chai": "^4.2.0", "eslint": "^6.8.0", - "graphql": "15.0.0", + "graphql": "^14.5.0 || ^15.0.0", "mocha": "^7.1.1", "rimraf": "^3.0.2", "ts-node": "^8.8.2", diff --git a/yarn.lock b/yarn.lock index 344f698..c344d36 100644 --- a/yarn.lock +++ b/yarn.lock @@ -610,7 +610,7 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -graphql@15.0.0: +"graphql@^14.5.0 || ^15.0.0": version "15.0.0" resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.0.0.tgz#042a5eb5e2506a2e2111ce41eb446a8e570b8be9" integrity sha512-ZyVO1xIF9F+4cxfkdhOJINM+51B06Friuv4M66W7HzUOeFd+vNzUn4vtswYINPi6sysjf1M2Ri/rwZALqgwbaQ== From 48a6a6c04453717e9d07f7b6b42d1495fe2fdb82 Mon Sep 17 00:00:00 2001 From: rh389 Date: Sat, 23 May 2020 12:47:22 +0100 Subject: [PATCH 6/9] Make QueryComplexityOptions.estimators mandatory, remove default --- src/QueryComplexity.ts | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/QueryComplexity.ts b/src/QueryComplexity.ts index 6cf0b55..845340f 100644 --- a/src/QueryComplexity.ts +++ b/src/QueryComplexity.ts @@ -29,9 +29,6 @@ import { getNamedType, GraphQLError } from 'graphql'; -import { - simpleEstimator -} from './estimators'; declare module 'graphql/type/definition' { export interface GraphQLField { @@ -71,7 +68,7 @@ export interface QueryComplexityOptions { createError?: (max: number, actual: number) => GraphQLError, // An array of complexity estimators to use for estimating the complexity - estimators?: Array; + estimators: Array; } function queryComplexityMessage(max: number, actual: number): string { @@ -126,16 +123,7 @@ export default class QueryComplexity { this.includeDirectiveDef = this.context.getSchema().getDirective('include'); this.skipDirectiveDef = this.context.getSchema().getDirective('skip'); - - if (!options.estimators) { - console.warn( - 'DEPRECATION WARNING: Estimators should be configured in the queryComplexity options.' - ); - } - - this.estimators = options.estimators || [ - simpleEstimator() - ]; + this.estimators = options.estimators this.OperationDefinition = { enter: this.onOperationDefinitionEnter, From 90d39f44bdb04536c08b87a9a9f1dba0424e8233 Mon Sep 17 00:00:00 2001 From: rh389 Date: Sun, 24 May 2020 15:23:24 +0100 Subject: [PATCH 7/9] Add graphql@~15.0 to CI matrix --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 129f531..2dbb463 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ workflows: # definitions for field extensions in older @types/graphql versions matrix: parameters: - graphql-version: ["~0.13", "~14.0", "~14.5", "~14.6"] + graphql-version: ["~0.13", "~14.0", "~14.5", "~14.6", "~15.0"] - test-and-build: # Leave graphql-version unspecified to respect the lockfile and also run tsc name: test-and-build-with-typecheck From 29df455b92af7b5a4ae4317ee0fb2b8f4ddad867 Mon Sep 17 00:00:00 2001 From: rh389 Date: Mon, 25 May 2020 13:47:07 +0100 Subject: [PATCH 8/9] Add CompatibleValidationContext for use in tests to continue to support the older `getErrors` API. --- src/__tests__/QueryComplexity-test.ts | 45 +++++++++---------- .../fixtures/CompatibleValidationContext.ts | 28 ++++++++++++ .../__tests__/directiveEstimator-test.ts | 30 ++++++------- .../fieldExtensionsEstimator-test.ts | 37 +++++++-------- .../simple/__tests__/simpleEstimator-test.ts | 28 ++++++------ 5 files changed, 92 insertions(+), 76 deletions(-) create mode 100644 src/__tests__/fixtures/CompatibleValidationContext.ts diff --git a/src/__tests__/QueryComplexity-test.ts b/src/__tests__/QueryComplexity-test.ts index d34a5cd..b2bb133 100644 --- a/src/__tests__/QueryComplexity-test.ts +++ b/src/__tests__/QueryComplexity-test.ts @@ -3,10 +3,8 @@ */ import { - GraphQLError, parse, TypeInfo, - ValidationContext, visit, visitWithTypeInfo, } from 'graphql'; @@ -21,6 +19,7 @@ import { directiveEstimator, fieldExtensionsEstimator, } from '../index'; +import { CompatibleValidationContext } from './fixtures/CompatibleValidationContext'; describe('QueryComplexity analysis', () => { const typeInfo = new TypeInfo(schema); @@ -155,7 +154,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -174,8 +173,7 @@ describe('QueryComplexity analysis', () => { } `); - const validationErrors: GraphQLError[] = []; - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -188,8 +186,8 @@ describe('QueryComplexity analysis', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -205,7 +203,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -232,7 +230,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -259,7 +257,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -286,7 +284,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -312,7 +310,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -334,7 +332,7 @@ describe('QueryComplexity analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -355,8 +353,7 @@ describe('QueryComplexity analysis', () => { requiredArgs } `); - const validationErrors: GraphQLError[] = []; - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -367,8 +364,8 @@ describe('QueryComplexity analysis', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); it('should report error when no estimator is configured', () => { @@ -377,15 +374,14 @@ describe('QueryComplexity analysis', () => { scalar } `); - const validationErrors: GraphQLError[] = []; - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal( 'No complexity could be calculated for field Query.scalar. ' + 'At least one complexity estimator has to return a complexity score.' ); @@ -397,8 +393,7 @@ describe('QueryComplexity analysis', () => { scalar } `); - const validationErrors: GraphQLError[] = []; - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -406,8 +401,8 @@ describe('QueryComplexity analysis', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal( 'No complexity could be calculated for field Query.scalar. ' + 'At least one complexity estimator has to return a complexity score.' ); diff --git a/src/__tests__/fixtures/CompatibleValidationContext.ts b/src/__tests__/fixtures/CompatibleValidationContext.ts new file mode 100644 index 0000000..655578c --- /dev/null +++ b/src/__tests__/fixtures/CompatibleValidationContext.ts @@ -0,0 +1,28 @@ +import { GraphQLError, TypeInfo, ValidationContext } from "graphql"; +import { GraphQLSchema } from "graphql/type/schema"; +import { DocumentNode } from "graphql/language/ast"; + +/** + * This class is used to test that validation errors are raised correctly + * + * A compatibility layer is necessary to support graphql versions since 15.0.0 + * *as well as* versions prior to 14.5.0 with the same test, because older + * versions of `ValidationContext` only expose a `getErrors` API and newer + * versions only expose the `onError` API via a fourth constructor argument. + * + * Once we drop support for versions older than 14.5.0 this layer will no + * longer be necessary and tests may use `ValidationContext` directly using the + * `onError` API. + */ +export class CompatibleValidationContext extends ValidationContext { + private errors: GraphQLError[] = [] + + constructor(schema: GraphQLSchema, ast: DocumentNode, typeInfo: TypeInfo) { + super(schema, ast, typeInfo, err => this.errors.push(err)); + } + + getErrors(): ReadonlyArray { + // @ts-ignore + return super.getErrors ? super.getErrors() : this.errors + } +} diff --git a/src/estimators/directive/__tests__/directiveEstimator-test.ts b/src/estimators/directive/__tests__/directiveEstimator-test.ts index a0d7209..b303b9d 100644 --- a/src/estimators/directive/__tests__/directiveEstimator-test.ts +++ b/src/estimators/directive/__tests__/directiveEstimator-test.ts @@ -3,10 +3,8 @@ */ import { - GraphQLError, parse, TypeInfo, - ValidationContext, visit, visitWithTypeInfo, } from 'graphql'; @@ -17,6 +15,7 @@ import schema from './fixtures/schema'; import ComplexityVisitor from '../../../QueryComplexity'; import directiveEstimator from '../index'; +import { CompatibleValidationContext } from '../../../__tests__/fixtures/CompatibleValidationContext'; describe('directiveEstimator analysis', () => { const typeInfo = new TypeInfo(schema); @@ -28,7 +27,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -47,7 +46,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -66,7 +65,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -85,7 +84,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -108,7 +107,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -129,7 +128,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -150,7 +149,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -171,7 +170,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -192,7 +191,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -213,7 +212,7 @@ describe('directiveEstimator analysis', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -232,8 +231,7 @@ describe('directiveEstimator analysis', () => { } `); - const validationErrors: GraphQLError[] = []; - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -242,8 +240,8 @@ describe('directiveEstimator analysis', () => { }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.include( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.include( 'No complexity could be calculated for field Query.noDirective', ); }); diff --git a/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts b/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts index 868409f..6f7bb28 100644 --- a/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts +++ b/src/estimators/fieldExtensions/__tests__/fieldExtensionsEstimator-test.ts @@ -3,10 +3,8 @@ */ import { - GraphQLError, parse, TypeInfo, - ValidationContext, visit, visitWithTypeInfo, } from 'graphql'; @@ -18,6 +16,7 @@ import schema from './fixtures/schema'; import ComplexityVisitor from '../../../QueryComplexity'; import simpleEstimator from '../../simple'; import fieldExtensionsEstimator from '../index'; +import { CompatibleValidationContext } from '../../../__tests__/fixtures/CompatibleValidationContext'; describe('fieldExtensions estimator', () => { const typeInfo = new TypeInfo(schema); @@ -29,7 +28,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -51,7 +50,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -73,7 +72,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -95,7 +94,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -117,8 +116,7 @@ describe('fieldExtensions estimator', () => { } `); - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -131,8 +129,8 @@ describe('fieldExtensions estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -148,7 +146,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -175,7 +173,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -202,7 +200,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -229,7 +227,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -255,7 +253,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -277,7 +275,7 @@ describe('fieldExtensions estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -298,8 +296,7 @@ describe('fieldExtensions estimator', () => { requiredArgs } `); - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -310,7 +307,7 @@ describe('fieldExtensions estimator', () => { ] }); visit(ast, visitWithTypeInfo(typeInfo, visitor)); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal('Argument "count" of required type "Int!" was not provided.'); }); }); diff --git a/src/estimators/simple/__tests__/simpleEstimator-test.ts b/src/estimators/simple/__tests__/simpleEstimator-test.ts index 6085a4d..620a8dd 100644 --- a/src/estimators/simple/__tests__/simpleEstimator-test.ts +++ b/src/estimators/simple/__tests__/simpleEstimator-test.ts @@ -3,10 +3,8 @@ */ import { - GraphQLError, parse, TypeInfo, - ValidationContext, visit, visitWithTypeInfo, } from 'graphql'; @@ -17,6 +15,7 @@ import schema from './fixtures/schema'; import simpleEstimator from '../index'; import ComplexityVisitor from '../../../QueryComplexity'; +import { CompatibleValidationContext } from '../../../__tests__/fixtures/CompatibleValidationContext'; describe('simple estimator', () => { const typeInfo = new TypeInfo(schema); @@ -28,7 +27,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -47,7 +46,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -66,7 +65,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -85,8 +84,7 @@ describe('simple estimator', () => { } `); - const validationErrors: GraphQLError[] = [] - const context = new ValidationContext(schema, ast, typeInfo, err => validationErrors.push(err)); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -96,8 +94,8 @@ describe('simple estimator', () => { visit(ast, visitWithTypeInfo(typeInfo, visitor)); expect(visitor.complexity).to.equal(1000); - expect(validationErrors.length).to.equal(1); - expect(validationErrors[0].message).to.equal( + expect(context.getErrors().length).to.equal(1); + expect(context.getErrors()[0].message).to.equal( 'The query exceeds the maximum complexity of 100. Actual complexity is 1000' ); }); @@ -113,7 +111,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -137,7 +135,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -160,7 +158,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -184,7 +182,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -207,7 +205,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ @@ -226,7 +224,7 @@ describe('simple estimator', () => { } `); - const context = new ValidationContext(schema, ast, typeInfo, () => null); + const context = new CompatibleValidationContext(schema, ast, typeInfo); const visitor = new ComplexityVisitor(context, { maximumComplexity: 100, estimators: [ From bffa43f0c4c9a33c40c583b0fcd7b27cc548f79e Mon Sep 17 00:00:00 2001 From: rh389 Date: Mon, 25 May 2020 13:51:31 +0100 Subject: [PATCH 9/9] Restore peerDepedencies compatibility with graphql <14.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a29ee2c..032f488 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "lodash.get": "^4.4.2" }, "peerDependencies": { - "graphql": "^14.5.0 || ^15.0.0" + "graphql": "^0.13.0 || ^14.0.0 || ^15.0.0" }, "files": [ "dist",