diff --git a/.circleci/config.yml b/.circleci/config.yml index e4292c3..159d1de 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: ['~14.6', '~14.7', '~15.0'] + graphql-version: ['~14.6', '~14.7', '~15.0', '~16.0'] - test-and-build: # Leave graphql-version unspecified to respect the lockfile and also run tsc name: test-and-build-with-typecheck diff --git a/package.json b/package.json index efc5acd..ed51ab8 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build:test:esm": "tsc -p ./tsconfig.test.esm.json && ./fix-hybrid-module.test.esm.sh", "test": "npm run lint && npm run build:test:cjs && npm run testonly:cjs && npm run build:test:esm && npm run testonly:esm", "testonly:cjs": "mocha --check-leaks --exit --full-trace 'dist/test/cjs/**/__tests__/**/*-test.js'", - "testonly:esm": "mocha --check-leaks --exit --full-trace 'dist/test/esm/**/__tests__/**/*-test.js'", + "testonly:esm": "mocha -n experimental-json-modules --check-leaks --exit --full-trace 'dist/test/esm/**/__tests__/**/*-test.js'", "dist": "npm run clean && npm run build", "prepare": "npm run clean && npm run dist" }, @@ -27,7 +27,7 @@ "lodash.get": "^4.4.2" }, "peerDependencies": { - "graphql": "^14.6.0 || ^15.0.0" + "graphql": "^14.6.0 || ^15.0.0 || ^16.0.0" }, "files": [ "dist", @@ -56,14 +56,16 @@ "@types/chai": "^4.2.22", "@types/lodash.get": "^4.4.6", "@types/mocha": "^9.0.0", + "@types/semver": "^7.3.9", "@typescript-eslint/eslint-plugin": "^5.1.0", "@typescript-eslint/parser": "^5.1.0", "chai": "^4.3.4", "eslint": "^8.0.1", - "graphql": "14.6.0", + "graphql": "~14.6.0 || ~15.0.0 || ~16.0.0", "mocha": "^9.1.3", "prettier": "^2.4.1", "rimraf": "^3.0.2", + "semver": "^7.3.5", "typescript": "^4.4.4" } } diff --git a/src/QueryComplexity.ts b/src/QueryComplexity.ts index 4078ba2..348c4f5 100644 --- a/src/QueryComplexity.ts +++ b/src/QueryComplexity.ts @@ -201,7 +201,7 @@ export default class QueryComplexity { onOperationDefinitionLeave( operation: OperationDefinitionNode - ): GraphQLError | undefined { + ): GraphQLError | void { if ( typeof this.options.operationName === 'string' && this.options.operationName !== operation.name.value @@ -268,7 +268,9 @@ export default class QueryComplexity { childNode, this.variableValues || {} ); - includeNode = values.if; + if (typeof values.if === 'boolean') { + includeNode = values.if; + } break; } case 'skip': { @@ -277,7 +279,9 @@ export default class QueryComplexity { childNode, this.variableValues || {} ); - skipNode = values.if; + if (typeof values.if === 'boolean') { + skipNode = values.if; + } break; } } diff --git a/src/__tests__/fixtures/schema.ts b/src/__tests__/fixtures/schema.ts index e7fca70..5a2d30b 100644 --- a/src/__tests__/fixtures/schema.ts +++ b/src/__tests__/fixtures/schema.ts @@ -15,6 +15,7 @@ import { } from 'graphql'; import { ComplexityEstimatorArgs } from '../../QueryComplexity.js'; +import { compatResolveType } from '../utils/compatResolveType.js'; const Item: GraphQLObjectType = new GraphQLObjectType({ name: 'Item', @@ -62,7 +63,7 @@ const NameInterface = new GraphQLInterfaceType({ fields: { name: { type: GraphQLString }, }, - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const SecondItem = new GraphQLObjectType({ @@ -86,7 +87,7 @@ const EnumType = new GraphQLEnumType({ const Union = new GraphQLUnionType({ name: 'Union', types: [Item, SecondItem], - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const UnionInterface = new GraphQLInterfaceType({ @@ -94,7 +95,7 @@ const UnionInterface = new GraphQLInterfaceType({ fields: () => ({ union: { type: Union }, }), - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const SDLInterface = new GraphQLInterfaceType({ diff --git a/src/__tests__/utils/compatResolveType.ts b/src/__tests__/utils/compatResolveType.ts new file mode 100644 index 0000000..26d229c --- /dev/null +++ b/src/__tests__/utils/compatResolveType.ts @@ -0,0 +1,19 @@ +import { GraphQLType } from 'graphql'; + +import graphqlPackage from 'graphql/package.json'; +import semver from 'semver'; + +/** + * GraphQL v16 changed how types are resolved, so we need to return a string + * for the type name for newer version, and the type itself to be compatible with older versions. + * + * @param type + * @returns + */ +export function compatResolveType(type: GraphQLType): any { + if (semver.gte(graphqlPackage.version, '16.0.0')) { + return () => type.toString(); + } else { + return () => type; + } +} diff --git a/src/estimators/directive/index.ts b/src/estimators/directive/index.ts index e64ed6d..0d727e7 100644 --- a/src/estimators/directive/index.ts +++ b/src/estimators/directive/index.ts @@ -61,7 +61,7 @@ export default function ( // Get multipliers let totalMultiplier = 1; - if (values.multipliers) { + if (values.multipliers && Array.isArray(values.multipliers)) { totalMultiplier = values.multipliers.reduce( (aggregated: number, multiplier: string) => { const multiplierValue = get(args.args, multiplier); @@ -78,6 +78,6 @@ export default function ( ); } - return (values.value + args.childComplexity) * totalMultiplier; + return (Number(values.value) + args.childComplexity) * totalMultiplier; }; } diff --git a/src/estimators/fieldExtensions/__tests__/fixtures/schema.ts b/src/estimators/fieldExtensions/__tests__/fixtures/schema.ts index fdc2a36..9c16666 100644 --- a/src/estimators/fieldExtensions/__tests__/fixtures/schema.ts +++ b/src/estimators/fieldExtensions/__tests__/fixtures/schema.ts @@ -14,6 +14,7 @@ import { GraphQLUnionType, GraphQLInterfaceType, } from 'graphql'; +import { compatResolveType } from '../../../../__tests__/utils/compatResolveType.js'; import { ComplexityEstimatorArgs } from '../../../../QueryComplexity.js'; @@ -68,7 +69,7 @@ const NameInterface = new GraphQLInterfaceType({ fields: { name: { type: GraphQLString }, }, - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const SecondItem = new GraphQLObjectType({ @@ -92,7 +93,7 @@ const EnumType = new GraphQLEnumType({ const Union = new GraphQLUnionType({ name: 'Union', types: [Item, SecondItem], - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const Query = new GraphQLObjectType({ diff --git a/src/estimators/simple/__tests__/fixtures/schema.ts b/src/estimators/simple/__tests__/fixtures/schema.ts index dcc67b4..590bd7b 100644 --- a/src/estimators/simple/__tests__/fixtures/schema.ts +++ b/src/estimators/simple/__tests__/fixtures/schema.ts @@ -13,6 +13,7 @@ import { GraphQLUnionType, GraphQLInterfaceType, } from 'graphql'; +import { compatResolveType } from '../../../../__tests__/utils/compatResolveType.js'; const Item: GraphQLObjectType = new GraphQLObjectType({ name: 'Item', @@ -43,7 +44,7 @@ const NameInterface = new GraphQLInterfaceType({ fields: { name: { type: GraphQLString }, }, - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const SecondItem = new GraphQLObjectType({ @@ -67,7 +68,7 @@ const EnumType = new GraphQLEnumType({ const Union = new GraphQLUnionType({ name: 'Union', types: [Item, SecondItem], - resolveType: () => Item, + resolveType: compatResolveType(Item), }); const Query = new GraphQLObjectType({ diff --git a/tsconfig.json b/tsconfig.json index 29cbaaf..b000795 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "module": "commonjs", "esModuleInterop": true, + "resolveJsonModule": true, "target": "es6", "noImplicitAny": true, "moduleResolution": "node", diff --git a/yarn.lock b/yarn.lock index d5d8adb..40c8db9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -84,6 +84,11 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.0.0.tgz#3205bcd15ada9bc681ac20bef64e9e6df88fd297" integrity sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA== +"@types/semver@^7.3.9": + version "7.3.9" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" + integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== + "@typescript-eslint/eslint-plugin@^5.1.0": version "5.3.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.3.1.tgz#d8ff412f10f54f6364e7fd7c1e70eb6767f434c3" @@ -669,12 +674,10 @@ globby@^11.0.4: merge2 "^1.3.0" slash "^3.0.0" -graphql@14.6.0: - version "14.6.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.6.0.tgz#57822297111e874ea12f5cd4419616930cd83e49" - integrity sha512-VKzfvHEKybTKjQVpTFrA5yUq2S9ihcZvfJAtsDBBCuV6wauPu1xl/f9ehgVf0FcEJJs4vz6ysb/ZMkGigQZseg== - dependencies: - iterall "^1.2.2" +"graphql@~14.6.0 || ~15.0.0 || ~16.0.0": + version "16.0.1" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.0.1.tgz#93a13cd4e0e38ca8d0832e79614c8578bfd34f10" + integrity sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg== growl@1.10.5: version "1.10.5" @@ -771,11 +774,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -iterall@^1.2.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.3.0.tgz#afcb08492e2915cbd8a0884eb93a8c94d0d72fea" - integrity sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg== - js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"