From 46825b31052a2032ba714175f66da4a8c7ae26b6 Mon Sep 17 00:00:00 2001 From: Jonathan Felchlin Date: Thu, 28 Feb 2019 21:35:45 -0800 Subject: [PATCH 01/12] Fixing error when filtering or generating propTypes for fragments with variables --- package-lock.json | 18 +++++----- .../graphql-anywhere/src/__tests__/index.ts | 2 +- .../src/__tests__/utilities.ts | 36 ++++++++++++++++++- packages/graphql-anywhere/src/graphql.ts | 6 ++-- packages/graphql-anywhere/src/utilities.ts | 6 ++-- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 22a0defb185..e68342347cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4352,7 +4352,7 @@ }, "supports-color": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true } @@ -4455,7 +4455,7 @@ }, "babel-plugin-istanbul": { "version": "4.1.6", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz", "integrity": "sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ==", "dev": true, "requires": { @@ -4473,7 +4473,7 @@ }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", + "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=", "dev": true }, @@ -6530,7 +6530,7 @@ "dependencies": { "globby": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "resolved": "http://registry.npmjs.org/globby/-/globby-6.1.0.tgz", "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { @@ -6543,7 +6543,7 @@ "dependencies": { "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true } @@ -8622,7 +8622,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true }, @@ -8753,7 +8753,7 @@ }, "git-config-path": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", + "resolved": "http://registry.npmjs.org/git-config-path/-/git-config-path-1.0.1.tgz", "integrity": "sha1-bTP37WPbDQ4RgTFQO6s6ykfVRmQ=", "dev": true, "requires": { @@ -14127,7 +14127,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -15366,7 +15366,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } diff --git a/packages/graphql-anywhere/src/__tests__/index.ts b/packages/graphql-anywhere/src/__tests__/index.ts index 96cbf4ba924..f09789ac80a 100644 --- a/packages/graphql-anywhere/src/__tests__/index.ts +++ b/packages/graphql-anywhere/src/__tests__/index.ts @@ -214,7 +214,7 @@ const execute = (graphql, r) => () => { } `; - const result = await graphql(resolver, query, null, null, null); + const result = await graphql(resolver, query, null, null); expect(result).toEqual({ a: { diff --git a/packages/graphql-anywhere/src/__tests__/utilities.ts b/packages/graphql-anywhere/src/__tests__/utilities.ts index fa5f28f1fe6..69b996332be 100644 --- a/packages/graphql-anywhere/src/__tests__/utilities.ts +++ b/packages/graphql-anywhere/src/__tests__/utilities.ts @@ -3,7 +3,7 @@ import gql, { disableFragmentWarnings } from 'graphql-tag'; // Turn off warnings for repeated fragment names disableFragmentWarnings(); -import { filter, check } from '../utilities'; +import { filter, check, propType } from '../utilities'; describe('utilities', () => { describe('with a single query', () => { @@ -16,6 +16,24 @@ describe('utilities', () => { } } `; + const fragment = gql` + fragment foo on Foo { + alias: name + height(unit: METERS) + avatar { + square + } + } + `; + const fragmentWithAVariable = gql` + fragment foo on Foo { + alias: name + height(unit: METERS) + avatar @include(if: $foo) { + square + } + } + `; const data = { alias: 'Bob', name: 'Wrong', @@ -80,6 +98,22 @@ describe('utilities', () => { expect(filter(doc, arrayData)).toEqual(filteredArrayData); }); + it('can filter data for fragments ', () => { + expect(filter(fragment, data)).toEqual(filteredData); + }); + + it('can filter data for fragments with variables', () => { + expect(filter(fragmentWithAVariable, data)).toEqual(filteredData); + }); + + it('can generate propTypes for fragments', () => { + expect(propType(fragment)).toEqual(expect.any(Function)); + }); + + it('can generate propTypes for fragments with variables', () => { + expect(propType(fragmentWithAVariable)).toEqual(expect.any(Function)); + }); + it('can check matching data', () => { check(doc, filteredData); }); diff --git a/packages/graphql-anywhere/src/graphql.ts b/packages/graphql-anywhere/src/graphql.ts index da535d5ea72..e8ae62b372b 100644 --- a/packages/graphql-anywhere/src/graphql.ts +++ b/packages/graphql-anywhere/src/graphql.ts @@ -81,7 +81,7 @@ export function graphql( document: DocumentNode, rootValue?: any, contextValue?: any, - variableValues?: VariableMap, + variableValues: VariableMap = {}, execOptions: ExecOptions = {}, ) { const mainDefinition = getMainDefinition(document); @@ -120,8 +120,8 @@ function executeSelectionSet( const result = {}; selectionSet.selections.forEach(selection => { - if (!shouldInclude(selection, variables)) { - // Skip this entirely + if (variables && !shouldInclude(selection, variables)) { + // Skip selection sets which we're able to determine should not be run return; } diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index 8887d6ee9fc..cd2916136ec 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -17,8 +17,8 @@ export function filter( }; return Array.isArray(data) - ? data.map(dataObj => graphql(resolver, doc, dataObj)) - : graphql(resolver, doc, data); + ? data.map(dataObj => graphql(resolver, doc, dataObj, null, null)) + : graphql(resolver, doc, data, null, null); } // TODO: we should probably make check call propType and then throw, @@ -44,7 +44,7 @@ export function check(doc: DocumentNode, data: any): void { doc, data, {}, - {}, + null, { fragmentMatcher: () => false, }, From b1826d7be1e7bae993f79a34afa430784ebad7a3 Mon Sep 17 00:00:00 2001 From: Jonathan Felchlin Date: Mon, 4 Mar 2019 11:14:45 -0800 Subject: [PATCH 02/12] Updating filter function to take a variable mapping --- packages/graphql-anywhere/src/__tests__/utilities.ts | 2 +- packages/graphql-anywhere/src/utilities.ts | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/graphql-anywhere/src/__tests__/utilities.ts b/packages/graphql-anywhere/src/__tests__/utilities.ts index 69b996332be..b32753b4e77 100644 --- a/packages/graphql-anywhere/src/__tests__/utilities.ts +++ b/packages/graphql-anywhere/src/__tests__/utilities.ts @@ -103,7 +103,7 @@ describe('utilities', () => { }); it('can filter data for fragments with variables', () => { - expect(filter(fragmentWithAVariable, data)).toEqual(filteredData); + expect(filter(fragmentWithAVariable, data, {foo: true})).toEqual(filteredData); }); it('can generate propTypes for fragments', () => { diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index cd2916136ec..c3295a33bef 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -1,11 +1,12 @@ import { DocumentNode } from 'graphql'; -import { graphql } from './graphql'; +import { graphql, VariableMap } from './graphql'; export function filter( doc: DocumentNode, data: D, -): FD { + variableValues: VariableMap = {}, + ): FD { const resolver = ( fieldName: string, root: any, @@ -17,8 +18,8 @@ export function filter( }; return Array.isArray(data) - ? data.map(dataObj => graphql(resolver, doc, dataObj, null, null)) - : graphql(resolver, doc, data, null, null); + ? data.map(dataObj => graphql(resolver, doc, dataObj, null, variableValues)) + : graphql(resolver, doc, data, null, variableValues); } // TODO: we should probably make check call propType and then throw, From 443be94a4258454a24154e6c6fae97978f222f2d Mon Sep 17 00:00:00 2001 From: Jonathan Felchlin Date: Mon, 4 Mar 2019 12:05:49 -0800 Subject: [PATCH 03/12] Updating propType function to take a mapPropsToVariables argument --- .../src/__tests__/utilities.ts | 16 ++++++++++- packages/graphql-anywhere/src/utilities.ts | 28 +++++++++---------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/graphql-anywhere/src/__tests__/utilities.ts b/packages/graphql-anywhere/src/__tests__/utilities.ts index b32753b4e77..297e804cb34 100644 --- a/packages/graphql-anywhere/src/__tests__/utilities.ts +++ b/packages/graphql-anywhere/src/__tests__/utilities.ts @@ -103,7 +103,9 @@ describe('utilities', () => { }); it('can filter data for fragments with variables', () => { - expect(filter(fragmentWithAVariable, data, {foo: true})).toEqual(filteredData); + expect(filter(fragmentWithAVariable, data, { foo: true })).toEqual( + filteredData, + ); }); it('can generate propTypes for fragments', () => { @@ -118,6 +120,18 @@ describe('utilities', () => { check(doc, filteredData); }); + it('can check matching data for fragments with variables', () => { + check(doc, filteredData, { foo: true }); + }); + + it('throws when checking non-matching data for fragments with variables', () => { + const badFilteredData = { ...filteredData }; + delete badFilteredData.avatar; + expect(() => { + check(doc, badFilteredData); + }).toThrow(); + }); + // This doesn't throw but potentially it should? it('can check overspecified data', () => { check(doc, data); diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index c3295a33bef..2428a96d7f0 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -6,7 +6,7 @@ export function filter( doc: DocumentNode, data: D, variableValues: VariableMap = {}, - ): FD { +): FD { const resolver = ( fieldName: string, root: any, @@ -26,7 +26,11 @@ export function filter( // rather than the other way round, to avoid constructing stack traces // for things like oneOf uses in React. At this stage I doubt many people // are using this like that, but in the future, who knows? -export function check(doc: DocumentNode, data: any): void { +export function check( + doc: DocumentNode, + data: any, + variables: VariableMap = {}, +): void { const resolver = ( fieldName: string, root: any, @@ -40,16 +44,9 @@ export function check(doc: DocumentNode, data: any): void { return root[info.resultKey]; }; - graphql( - resolver, - doc, - data, - {}, - null, - { - fragmentMatcher: () => false, - }, - ); + graphql(resolver, doc, data, {}, variables, { + fragmentMatcher: () => false, + }); } // Lifted/adapted from @@ -105,12 +102,15 @@ function createChainableTypeChecker(validate) { return chainedCheckType; } -export function propType(doc) { +export function propType( + doc: DocumentNode, + mapPropsToVariables = props => props, +) { return createChainableTypeChecker((props, propName) => { const prop = props[propName]; try { if (!prop.loading) { - check(doc, prop); + check(doc, prop, mapPropsToVariables(props)); } return null; } catch (e) { From 2fb1583dca3a0eee8a01d387a3c03659bbe9257e Mon Sep 17 00:00:00 2001 From: Jonathan Felchlin Date: Mon, 4 Mar 2019 13:26:54 -0800 Subject: [PATCH 04/12] Adding propType checking tests --- packages/graphql-anywhere/package.json | 3 ++ .../__tests__/__snapshots__/utilities.ts.snap | 13 +++++++ .../src/__tests__/utilities.ts | 34 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap diff --git a/packages/graphql-anywhere/package.json b/packages/graphql-anywhere/package.json index 4909ca6e522..5bb57d66b04 100644 --- a/packages/graphql-anywhere/package.json +++ b/packages/graphql-anywhere/package.json @@ -39,5 +39,8 @@ "dependencies": { "apollo-utilities": "file:../apollo-utilities", "tslib": "^1.9.3" + }, + "devDependencies": { + "prop-types": "^15.7.2" } } diff --git a/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap b/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap new file mode 100644 index 00000000000..72ba244116d --- /dev/null +++ b/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap @@ -0,0 +1,13 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`utilities with a single query can check propTypes for fragments 1`] = ` +Array [ + "Warning: Failed prop type: alias missing on {}", +] +`; + +exports[`utilities with a single query can check propTypes for fragments with variables 1`] = ` +Array [ + "Warning: Failed prop type: avatar missing on {\\"alias\\":\\"Bob\\",\\"height\\":1.89}", +] +`; diff --git a/packages/graphql-anywhere/src/__tests__/utilities.ts b/packages/graphql-anywhere/src/__tests__/utilities.ts index 297e804cb34..1dcf1075804 100644 --- a/packages/graphql-anywhere/src/__tests__/utilities.ts +++ b/packages/graphql-anywhere/src/__tests__/utilities.ts @@ -1,4 +1,5 @@ import gql, { disableFragmentWarnings } from 'graphql-tag'; +import {checkPropTypes} from 'prop-types'; // Turn off warnings for repeated fragment names disableFragmentWarnings(); @@ -89,6 +90,16 @@ describe('utilities', () => { }, }, ]; + let consoleSpy; + + beforeEach(() => { + checkPropTypes.resetWarningCache(); + consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + }); + + afterEach(() => { + consoleSpy.mockRestore(); + }); it('can filter data', () => { expect(filter(doc, data)).toEqual(filteredData); @@ -112,10 +123,33 @@ describe('utilities', () => { expect(propType(fragment)).toEqual(expect.any(Function)); }); + it('can check propTypes for fragments', () => { + const propTypes = { + foo: propType(fragment), + }; + checkPropTypes(propTypes, filteredData, 'prop', 'MyComponent'); + expect(consoleSpy).not.toHaveBeenCalled(); + checkPropTypes(propTypes, { foo: {} }, 'prop', 'MyComponent'); + expect(consoleSpy.mock.calls[0]).toMatchSnapshot(); + }); + it('can generate propTypes for fragments with variables', () => { expect(propType(fragmentWithAVariable)).toEqual(expect.any(Function)); }); + it('can check propTypes for fragments with variables', () => { + const mapPropsToVariables = () => ({foo: true}); + const propTypes = { + foo: propType(fragmentWithAVariable, mapPropsToVariables), + }; + checkPropTypes(propTypes, filteredData, 'prop', 'MyComponent'); + expect(consoleSpy).not.toHaveBeenCalled(); + const badProps = { foo: { ...filteredData } }; + delete badProps.foo.avatar; + checkPropTypes(propTypes, badProps, 'prop', 'MyComponent'); + expect(consoleSpy.mock.calls[0]).toMatchSnapshot(); + }); + it('can check matching data', () => { check(doc, filteredData); }); From 05b8c5924fa4ed8bcd8855abe528eb0049de97c2 Mon Sep 17 00:00:00 2001 From: Jonathan Felchlin Date: Tue, 5 Mar 2019 01:51:22 -0800 Subject: [PATCH 05/12] Updating propTypes to make fields with variable inclusions optional, when mapPropsToVariables is not passed --- packages/apollo-utilities/src/directives.ts | 99 ++++++++++++------- packages/graphql-anywhere/package-lock.json | 53 +++++++++- .../__tests__/__snapshots__/utilities.ts.snap | 2 +- .../graphql-anywhere/src/__tests__/index.ts | 8 +- .../src/__tests__/utilities.ts | 32 +++--- packages/graphql-anywhere/src/async.ts | 1 + packages/graphql-anywhere/src/graphql.ts | 2 + packages/graphql-anywhere/src/utilities.ts | 35 +++++-- 8 files changed, 173 insertions(+), 59 deletions(-) diff --git a/packages/apollo-utilities/src/directives.ts b/packages/apollo-utilities/src/directives.ts index 464ed15d453..2fcc1e888c3 100644 --- a/packages/apollo-utilities/src/directives.ts +++ b/packages/apollo-utilities/src/directives.ts @@ -7,6 +7,8 @@ import { BooleanValueNode, DirectiveNode, DocumentNode, + ArgumentNode, + ValueNode, } from 'graphql'; import { visit } from 'graphql/language/visitor'; @@ -44,56 +46,29 @@ export function shouldInclude( return true; } - let res: boolean = true; - selection.directives.forEach(directive => { - // TODO should move this validation to GraphQL validation once that's implemented. - if (directive.name.value !== 'skip' && directive.name.value !== 'include') { - // Just don't worry about directives we don't understand - return; - } + const inclusionDirectives: InclusionDirectives = getInclusionDirectives( + selection.directives, + ); - //evaluate the "if" argument and skip (i.e. return undefined) if it evaluates to true. - const directiveArguments = directive.arguments || []; + if (!inclusionDirectives.length) { + return true; + } + return inclusionDirectives.every(({ directive, ifArgument }) => { const directiveName = directive.name.value; - invariant( - directiveArguments.length === 1, - `Incorrect number of arguments for the @${directiveName} directive.`, - ); - - const ifArgument = directiveArguments[0]; - invariant( - ifArgument.name && ifArgument.name.value === 'if', - `Invalid argument for the @${directiveName} directive.`, - ); - - const ifValue = directiveArguments[0].value; let evaledValue: boolean = false; - if (!ifValue || ifValue.kind !== 'BooleanValue') { - // means it has to be a variable value if this is a valid @skip or @include directive - invariant( - ifValue.kind === 'Variable', - `Argument for the @${directiveName} directive must be a variable or a boolean value.`, - ); - evaledValue = variables[(ifValue as VariableNode).name.value]; + if (ifArgument.value.kind === 'Variable') { + evaledValue = variables[(ifArgument.value as VariableNode).name.value]; invariant( evaledValue !== void 0, `Invalid variable referenced in @${directiveName} directive.`, ); } else { - evaledValue = (ifValue as BooleanValueNode).value; + evaledValue = (ifArgument.value as BooleanValueNode).value; } - if (directiveName === 'skip') { - evaledValue = !evaledValue; - } - - if (!evaledValue) { - res = false; - } + return directiveName === 'skip' ? !evaledValue : evaledValue; }); - - return res; } export function getDirectiveNames(doc: DocumentNode) { @@ -121,3 +96,51 @@ export function hasClientExports(document: DocumentNode) { hasDirectives(['export'], document) ); } + +export type InclusionDirectives = Array<{ + directive: DirectiveNode; + ifArgument: ArgumentNode; +}>; + +export function getInclusionDirectives( + directives: ReadonlyArray, +): InclusionDirectives { + const result: InclusionDirectives = []; + if (!directives || !directives.length) { + return result; + } + directives.forEach(directive => { + if (!isInclusionDirective(directive)) { + return; + } + const directiveArguments = directive.arguments || []; + const directiveName = directive.name.value; + + invariant( + directiveArguments.length === 1, + `Incorrect number of arguments for the @${directiveName} directive.`, + ); + + const ifArgument = directiveArguments[0]; + invariant( + ifArgument.name && ifArgument.name.value === 'if', + `Invalid argument for the @${directiveName} directive.`, + ); + + const ifValue: ValueNode = ifArgument.value; + + // means it has to be a variable value if this is a valid @skip or @include directive + invariant( + ifValue && + (ifValue.kind === 'Variable' || ifValue.kind === 'BooleanValue'), + `Argument for the @${directiveName} directive must be a variable or a boolean value.`, + ); + result.push({ directive, ifArgument }); + }); + + return result; +} + +export function isInclusionDirective(directive: DirectiveNode): boolean { + return directive.name.value === 'skip' || directive.name.value === 'include'; +} diff --git a/packages/graphql-anywhere/package-lock.json b/packages/graphql-anywhere/package-lock.json index a250ba1d229..31f3c67b6e0 100644 --- a/packages/graphql-anywhere/package-lock.json +++ b/packages/graphql-anywhere/package-lock.json @@ -7,7 +7,9 @@ "apollo-utilities": { "version": "file:../apollo-utilities", "requires": { - "fast-json-stable-stringify": "^2.0.0" + "fast-json-stable-stringify": "^2.0.0", + "ts-invariant": "^0.3.0", + "tslib": "^1.9.3" }, "dependencies": { "fast-json-stable-stringify": { @@ -17,9 +19,58 @@ "fclone": { "version": "1.0.11", "bundled": true + }, + "ts-invariant": { + "version": "0.3.0", + "bundled": true, + "requires": { + "tslib": "^1.9.3" + } + }, + "tslib": { + "version": "1.9.3", + "bundled": true } } }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "react-is": { + "version": "16.8.3", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz", + "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==", + "dev": true + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", diff --git a/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap b/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap index 72ba244116d..40c53e9256d 100644 --- a/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap +++ b/packages/graphql-anywhere/src/__tests__/__snapshots__/utilities.ts.snap @@ -8,6 +8,6 @@ Array [ exports[`utilities with a single query can check propTypes for fragments with variables 1`] = ` Array [ - "Warning: Failed prop type: avatar missing on {\\"alias\\":\\"Bob\\",\\"height\\":1.89}", + "Warning: Failed prop type: height missing on {\\"alias\\":\\"Bob\\",\\"avatar\\":{\\"square\\":\\"abc\\"}}", ] `; diff --git a/packages/graphql-anywhere/src/__tests__/index.ts b/packages/graphql-anywhere/src/__tests__/index.ts index f09789ac80a..99247785836 100644 --- a/packages/graphql-anywhere/src/__tests__/index.ts +++ b/packages/graphql-anywhere/src/__tests__/index.ts @@ -423,7 +423,7 @@ const execute = (graphql, r) => () => { }); }); - it('passes info including isLeaf, resultKey and directives', async () => { + it('passes info including isLeaf, resultKey, directives, and field', async () => { const leafMap: { [s: string]: ExecInfo } = {}; const resolver: Resolver = (fieldName, root, args, context, info) => { @@ -450,6 +450,8 @@ const execute = (graphql, r) => () => { isLeaf: false, resultKey: 'alias', + + field: expect.any(Object), }, b: { @@ -458,6 +460,8 @@ const execute = (graphql, r) => () => { isLeaf: true, resultKey: 'b', + + field: expect.any(Object), }, hasDirective: { @@ -470,6 +474,8 @@ const execute = (graphql, r) => () => { isLeaf: true, resultKey: 'hasDirective', + + field: expect.any(Object), }, }); }); diff --git a/packages/graphql-anywhere/src/__tests__/utilities.ts b/packages/graphql-anywhere/src/__tests__/utilities.ts index 1dcf1075804..a993a8edbaa 100644 --- a/packages/graphql-anywhere/src/__tests__/utilities.ts +++ b/packages/graphql-anywhere/src/__tests__/utilities.ts @@ -1,5 +1,5 @@ import gql, { disableFragmentWarnings } from 'graphql-tag'; -import {checkPropTypes} from 'prop-types'; +import { checkPropTypes } from 'prop-types'; // Turn off warnings for repeated fragment names disableFragmentWarnings(); @@ -90,15 +90,14 @@ describe('utilities', () => { }, }, ]; - let consoleSpy; beforeEach(() => { checkPropTypes.resetWarningCache(); - consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + jest.spyOn(global.console, 'error').mockImplementation(() => {}); }); afterEach(() => { - consoleSpy.mockRestore(); + global.console.error.mockRestore(); }); it('can filter data', () => { @@ -128,9 +127,9 @@ describe('utilities', () => { foo: propType(fragment), }; checkPropTypes(propTypes, filteredData, 'prop', 'MyComponent'); - expect(consoleSpy).not.toHaveBeenCalled(); + expect(global.console.error).not.toHaveBeenCalled(); checkPropTypes(propTypes, { foo: {} }, 'prop', 'MyComponent'); - expect(consoleSpy.mock.calls[0]).toMatchSnapshot(); + expect(global.console.error.mock.calls[0]).toMatchSnapshot(); }); it('can generate propTypes for fragments with variables', () => { @@ -138,16 +137,27 @@ describe('utilities', () => { }); it('can check propTypes for fragments with variables', () => { - const mapPropsToVariables = () => ({foo: true}); + const mapPropsToVariables = () => null; const propTypes = { foo: propType(fragmentWithAVariable, mapPropsToVariables), }; - checkPropTypes(propTypes, filteredData, 'prop', 'MyComponent'); - expect(consoleSpy).not.toHaveBeenCalled(); + checkPropTypes(propTypes, { foo: filteredData }, 'prop', 'MyComponent'); + expect(global.console.error).not.toHaveBeenCalled(); const badProps = { foo: { ...filteredData } }; - delete badProps.foo.avatar; + delete badProps.foo.height; checkPropTypes(propTypes, badProps, 'prop', 'MyComponent'); - expect(consoleSpy.mock.calls[0]).toMatchSnapshot(); + expect(global.console.error).toHaveBeenCalled(); + expect(global.console.error.mock.calls[0]).toMatchSnapshot(); + }); + + it('makes variable inclusion props optional, when no variables are passed', () => { + const propTypes = { + foo: propType(fragmentWithAVariable), + }; + const propsWithoutAvatar = { foo: { ...filteredData } }; + delete propsWithoutAvatar.foo.avatar; + checkPropTypes(propTypes, propsWithoutAvatar, 'prop', 'MyComponent'); + expect(global.console.error).not.toHaveBeenCalled(); }); it('can check matching data', () => { diff --git a/packages/graphql-anywhere/src/async.ts b/packages/graphql-anywhere/src/async.ts index f9051b33e4b..0e9d093371d 100644 --- a/packages/graphql-anywhere/src/async.ts +++ b/packages/graphql-anywhere/src/async.ts @@ -157,6 +157,7 @@ async function executeField( isLeaf: !field.selectionSet, resultKey: resultKeyNameFromField(field), directives: getDirectiveInfoFromField(field, variables), + field, }; const result = await resolver(fieldName, rootValue, args, contextValue, info); diff --git a/packages/graphql-anywhere/src/graphql.ts b/packages/graphql-anywhere/src/graphql.ts index e8ae62b372b..3608f81097a 100644 --- a/packages/graphql-anywhere/src/graphql.ts +++ b/packages/graphql-anywhere/src/graphql.ts @@ -53,6 +53,7 @@ export type ExecInfo = { isLeaf: boolean; resultKey: string; directives: DirectiveInfo; + field: FieldNode; }; export type ExecOptions = { @@ -186,6 +187,7 @@ function executeField( isLeaf: !field.selectionSet, resultKey: resultKeyNameFromField(field), directives: getDirectiveInfoFromField(field, variables), + field, }; const result = resolver(fieldName, rootValue, args, contextValue, info); diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index 2428a96d7f0..42f195527f2 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -1,6 +1,8 @@ -import { DocumentNode } from 'graphql'; +import { DocumentNode, DirectiveNode } from 'graphql'; -import { graphql, VariableMap } from './graphql'; +import { getInclusionDirectives, InclusionDirectives } from 'apollo-utilities'; + +import { graphql, VariableMap, ExecInfo, ExecContext } from './graphql'; export function filter( doc: DocumentNode, @@ -10,9 +12,9 @@ export function filter( const resolver = ( fieldName: string, root: any, - args: any, - context: any, - info: any, + args: Object, + context: ExecContext, + info: ExecInfo, ) => { return root[info.resultKey]; }; @@ -39,7 +41,11 @@ export function check( info: any, ) => { if (!{}.hasOwnProperty.call(root, info.resultKey)) { - throw new Error(`${info.resultKey} missing on ${JSON.stringify(root)}`); + // When variables is null, fields with @include/skip directives that + // reference variables are considered optional. + if (variables || !hasVariableInclusions(info.field.directives)) { + throw new Error(`${info.resultKey} missing on ${JSON.stringify(root)}`); + } } return root[info.resultKey]; }; @@ -49,6 +55,21 @@ export function check( }); } +function hasVariableInclusions( + directives: ReadonlyArray, +): boolean { + if (!directives || !directives.length) { + return false; + } + const inclusionDirectives: InclusionDirectives = getInclusionDirectives( + directives, + ); + return inclusionDirectives.some( + ({ ifArgument }) => + ifArgument.value && ifArgument.value.kind === 'Variable', + ); +} + // Lifted/adapted from // https://github.com/facebook/react/blob/master/src/isomorphic/classic/types/ReactPropTypes.js const ANONYMOUS = '<>'; @@ -104,7 +125,7 @@ function createChainableTypeChecker(validate) { export function propType( doc: DocumentNode, - mapPropsToVariables = props => props, + mapPropsToVariables = props => null, ) { return createChainableTypeChecker((props, propName) => { const prop = props[propName]; From 30a2ec17767aa740940a0c02bef31cbb62748792 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Apr 2019 13:04:17 -0400 Subject: [PATCH 06/12] Simplify hasVariableInclusions and getInclusionDirectives a bit. --- packages/apollo-utilities/src/directives.ts | 18 +++++++----------- packages/graphql-anywhere/src/utilities.ts | 13 +++---------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/packages/apollo-utilities/src/directives.ts b/packages/apollo-utilities/src/directives.ts index 2fcc1e888c3..64b69fa6ef9 100644 --- a/packages/apollo-utilities/src/directives.ts +++ b/packages/apollo-utilities/src/directives.ts @@ -105,19 +105,16 @@ export type InclusionDirectives = Array<{ export function getInclusionDirectives( directives: ReadonlyArray, ): InclusionDirectives { - const result: InclusionDirectives = []; if (!directives || !directives.length) { - return result; + return []; } - directives.forEach(directive => { - if (!isInclusionDirective(directive)) { - return; - } - const directiveArguments = directive.arguments || []; + + return directives.filter(isInclusionDirective).map(directive => { + const directiveArguments = directive.arguments; const directiveName = directive.name.value; invariant( - directiveArguments.length === 1, + directiveArguments && directiveArguments.length === 1, `Incorrect number of arguments for the @${directiveName} directive.`, ); @@ -135,10 +132,9 @@ export function getInclusionDirectives( (ifValue.kind === 'Variable' || ifValue.kind === 'BooleanValue'), `Argument for the @${directiveName} directive must be a variable or a boolean value.`, ); - result.push({ directive, ifArgument }); - }); - return result; + return { directive, ifArgument }; + }); } export function isInclusionDirective(directive: DirectiveNode): boolean { diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index 42f195527f2..43563292790 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -1,6 +1,6 @@ import { DocumentNode, DirectiveNode } from 'graphql'; -import { getInclusionDirectives, InclusionDirectives } from 'apollo-utilities'; +import { getInclusionDirectives } from 'apollo-utilities'; import { graphql, VariableMap, ExecInfo, ExecContext } from './graphql'; @@ -58,15 +58,8 @@ export function check( function hasVariableInclusions( directives: ReadonlyArray, ): boolean { - if (!directives || !directives.length) { - return false; - } - const inclusionDirectives: InclusionDirectives = getInclusionDirectives( - directives, - ); - return inclusionDirectives.some( - ({ ifArgument }) => - ifArgument.value && ifArgument.value.kind === 'Variable', + return getInclusionDirectives(directives).some( + ({ ifArgument }) => ifArgument.value && ifArgument.value.kind === 'Variable', ); } From 0919eee48477e6910ca6bbb9ffa2ebc5bd5c4100 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Apr 2019 13:07:26 -0400 Subject: [PATCH 07/12] Simplify shouldInclude. --- packages/apollo-utilities/src/directives.ts | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/packages/apollo-utilities/src/directives.ts b/packages/apollo-utilities/src/directives.ts index 64b69fa6ef9..11c45ee5cce 100644 --- a/packages/apollo-utilities/src/directives.ts +++ b/packages/apollo-utilities/src/directives.ts @@ -42,32 +42,20 @@ export function shouldInclude( selection: SelectionNode, variables: { [name: string]: any } = {}, ): boolean { - if (!selection.directives) { - return true; - } - - const inclusionDirectives: InclusionDirectives = getInclusionDirectives( + return !selection.directives || getInclusionDirectives( selection.directives, - ); - - if (!inclusionDirectives.length) { - return true; - } - return inclusionDirectives.every(({ directive, ifArgument }) => { - const directiveName = directive.name.value; - + ).every(({ directive, ifArgument }) => { let evaledValue: boolean = false; if (ifArgument.value.kind === 'Variable') { evaledValue = variables[(ifArgument.value as VariableNode).name.value]; invariant( evaledValue !== void 0, - `Invalid variable referenced in @${directiveName} directive.`, + `Invalid variable referenced in @${directive.name.value} directive.`, ); } else { evaledValue = (ifArgument.value as BooleanValueNode).value; } - - return directiveName === 'skip' ? !evaledValue : evaledValue; + return directive.name.value === 'skip' ? !evaledValue : evaledValue; }); } From 3b15d9f82144b725cc5b9c646980c77d0bcfac9b Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Apr 2019 13:23:35 -0400 Subject: [PATCH 08/12] Use ts-invariant in graphql-anywhere/src/utilities.ts. --- packages/graphql-anywhere/package-lock.json | 31 ++++++--------------- packages/graphql-anywhere/package.json | 1 + packages/graphql-anywhere/src/utilities.ts | 18 +++++++----- 3 files changed, 21 insertions(+), 29 deletions(-) diff --git a/packages/graphql-anywhere/package-lock.json b/packages/graphql-anywhere/package-lock.json index 31f3c67b6e0..2626006857b 100644 --- a/packages/graphql-anywhere/package-lock.json +++ b/packages/graphql-anywhere/package-lock.json @@ -8,29 +8,8 @@ "version": "file:../apollo-utilities", "requires": { "fast-json-stable-stringify": "^2.0.0", - "ts-invariant": "^0.3.0", + "ts-invariant": "^0.3.2", "tslib": "^1.9.3" - }, - "dependencies": { - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fclone": { - "version": "1.0.11", - "bundled": true - }, - "ts-invariant": { - "version": "0.3.0", - "bundled": true, - "requires": { - "tslib": "^1.9.3" - } - }, - "tslib": { - "version": "1.9.3", - "bundled": true - } } }, "js-tokens": { @@ -71,6 +50,14 @@ "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==", "dev": true }, + "ts-invariant": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.3.2.tgz", + "integrity": "sha512-QsY8BCaRnHiB5T6iE4DPlJMAKEG3gzMiUco9FEt1jUXQf0XP6zi0idT0i0rMTu8A326JqNSDsmlkA9dRSh1TRg==", + "requires": { + "tslib": "^1.9.3" + } + }, "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", diff --git a/packages/graphql-anywhere/package.json b/packages/graphql-anywhere/package.json index 5bb57d66b04..65fa9d2ba3b 100644 --- a/packages/graphql-anywhere/package.json +++ b/packages/graphql-anywhere/package.json @@ -38,6 +38,7 @@ "license": "MIT", "dependencies": { "apollo-utilities": "file:../apollo-utilities", + "ts-invariant": "^0.3.2", "tslib": "^1.9.3" }, "devDependencies": { diff --git a/packages/graphql-anywhere/src/utilities.ts b/packages/graphql-anywhere/src/utilities.ts index 43563292790..732f7e92598 100644 --- a/packages/graphql-anywhere/src/utilities.ts +++ b/packages/graphql-anywhere/src/utilities.ts @@ -4,6 +4,10 @@ import { getInclusionDirectives } from 'apollo-utilities'; import { graphql, VariableMap, ExecInfo, ExecContext } from './graphql'; +import { invariant } from 'ts-invariant'; + +const { hasOwnProperty } = Object.prototype; + export function filter( doc: DocumentNode, data: D, @@ -40,13 +44,13 @@ export function check( context: any, info: any, ) => { - if (!{}.hasOwnProperty.call(root, info.resultKey)) { - // When variables is null, fields with @include/skip directives that - // reference variables are considered optional. - if (variables || !hasVariableInclusions(info.field.directives)) { - throw new Error(`${info.resultKey} missing on ${JSON.stringify(root)}`); - } - } + // When variables is null, fields with @include/skip directives that + // reference variables are considered optional. + invariant( + hasOwnProperty.call(root, info.resultKey) || + (!variables && hasVariableInclusions(info.field.directives)), + `${info.resultKey} missing on ${JSON.stringify(root)}`, + ); return root[info.resultKey]; }; From b003de7fea42f3f745f86ff4dab8954f597c1ae1 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 11 Apr 2019 13:29:32 -0400 Subject: [PATCH 09/12] Avoid unnecessarily exporting isInclusionDirective. Also shaved a few more bytes in getInclusionDirectives and shouldInclude. --- packages/apollo-utilities/src/directives.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/apollo-utilities/src/directives.ts b/packages/apollo-utilities/src/directives.ts index 11c45ee5cce..1364f15fe45 100644 --- a/packages/apollo-utilities/src/directives.ts +++ b/packages/apollo-utilities/src/directives.ts @@ -42,7 +42,7 @@ export function shouldInclude( selection: SelectionNode, variables: { [name: string]: any } = {}, ): boolean { - return !selection.directives || getInclusionDirectives( + return getInclusionDirectives( selection.directives, ).every(({ directive, ifArgument }) => { let evaledValue: boolean = false; @@ -93,11 +93,7 @@ export type InclusionDirectives = Array<{ export function getInclusionDirectives( directives: ReadonlyArray, ): InclusionDirectives { - if (!directives || !directives.length) { - return []; - } - - return directives.filter(isInclusionDirective).map(directive => { + return directives ? directives.filter(isInclusionDirective).map(directive => { const directiveArguments = directive.arguments; const directiveName = directive.name.value; @@ -122,9 +118,9 @@ export function getInclusionDirectives( ); return { directive, ifArgument }; - }); + }) : []; } -export function isInclusionDirective(directive: DirectiveNode): boolean { - return directive.name.value === 'skip' || directive.name.value === 'include'; +function isInclusionDirective({ name: { value } }: DirectiveNode): boolean { + return value === 'skip' || value === 'include'; } From 42c74f10238a2bbec4d24e57c40433126c35e4e4 Mon Sep 17 00:00:00 2001 From: Hugh Willson Date: Wed, 17 Apr 2019 14:44:36 -0400 Subject: [PATCH 10/12] Move prop-types dev dep up to the monorepo root; Slight code tweak --- package-lock.json | 26 ++++++++++++-- package.json | 1 + packages/apollo-utilities/src/directives.ts | 7 ++-- packages/graphql-anywhere/package-lock.json | 38 --------------------- packages/graphql-anywhere/package.json | 3 -- 5 files changed, 28 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index e68342347cf..ad0ac193fa0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3941,6 +3941,9 @@ "apollo-boost": { "version": "file:packages/apollo-boost", "requires": { + "apollo-cache": "file:packages/apollo-cache", + "apollo-cache-inmemory": "file:packages/apollo-cache-inmemory", + "apollo-client": "file:packages/apollo-client", "apollo-link": "^1.0.6", "apollo-link-error": "^1.0.3", "apollo-link-http": "^1.3.1", @@ -3962,12 +3965,15 @@ "apollo-cache": { "version": "file:packages/apollo-cache", "requires": { + "apollo-utilities": "file:packages/apollo-utilities", "tslib": "^1.9.3" } }, "apollo-cache-inmemory": { "version": "file:packages/apollo-cache-inmemory", "requires": { + "apollo-cache": "file:packages/apollo-cache", + "apollo-utilities": "file:packages/apollo-utilities", "optimism": "^0.6.9", "ts-invariant": "^0.3.2", "tslib": "^1.9.3" @@ -3987,8 +3993,10 @@ "version": "file:packages/apollo-client", "requires": { "@types/zen-observable": "^0.8.0", + "apollo-cache": "file:packages/apollo-cache", "apollo-link": "^1.0.0", "apollo-link-dedup": "^1.0.0", + "apollo-utilities": "file:packages/apollo-utilities", "symbol-observable": "^1.0.2", "ts-invariant": "^0.3.2", "tslib": "^1.9.3", @@ -8959,7 +8967,19 @@ "graphql-anywhere": { "version": "file:packages/graphql-anywhere", "requires": { + "apollo-utilities": "file:packages/apollo-utilities", + "ts-invariant": "^0.3.2", "tslib": "^1.9.3" + }, + "dependencies": { + "ts-invariant": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.3.3.tgz", + "integrity": "sha512-UReOKsrJFGC9tUblgSRWo+BsVNbEd77Cl6WiV/XpMlkifXwNIJbknViCucHvVZkXSC/mcWeRnIGdY7uprcwvdQ==", + "requires": { + "tslib": "^1.9.3" + } + } } }, "graphql-tag": { @@ -17192,9 +17212,9 @@ } }, "react-is": { - "version": "16.8.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz", - "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==", + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", + "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==", "dev": true }, "read": { diff --git a/package.json b/package.json index 65326fd8af6..e2aefa7e3e1 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "lodash": "4.17.11", "pre-commit": "1.2.2", "prettier": "1.16.4", + "prop-types": "^15.7.2", "react": "16.8.6", "react-dom": "16.8.6", "rollup": "1.9.0", diff --git a/packages/apollo-utilities/src/directives.ts b/packages/apollo-utilities/src/directives.ts index 1364f15fe45..84c14abaeaa 100644 --- a/packages/apollo-utilities/src/directives.ts +++ b/packages/apollo-utilities/src/directives.ts @@ -90,6 +90,10 @@ export type InclusionDirectives = Array<{ ifArgument: ArgumentNode; }>; +function isInclusionDirective({ name: { value } }: DirectiveNode): boolean { + return value === 'skip' || value === 'include'; +} + export function getInclusionDirectives( directives: ReadonlyArray, ): InclusionDirectives { @@ -121,6 +125,3 @@ export function getInclusionDirectives( }) : []; } -function isInclusionDirective({ name: { value } }: DirectiveNode): boolean { - return value === 'skip' || value === 'include'; -} diff --git a/packages/graphql-anywhere/package-lock.json b/packages/graphql-anywhere/package-lock.json index 2626006857b..ff62eba3ffb 100644 --- a/packages/graphql-anywhere/package-lock.json +++ b/packages/graphql-anywhere/package-lock.json @@ -12,44 +12,6 @@ "tslib": "^1.9.3" } }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "dev": true, - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, - "react-is": { - "version": "16.8.3", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.3.tgz", - "integrity": "sha512-Y4rC1ZJmsxxkkPuMLwvKvlL1Zfpbcu+Bf4ZigkHup3v9EfdYhAlWAaVyA19olXq2o2mGn0w+dFKvk3pVVlYcIA==", - "dev": true - }, "ts-invariant": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.3.2.tgz", diff --git a/packages/graphql-anywhere/package.json b/packages/graphql-anywhere/package.json index 65fa9d2ba3b..452c72dcfc0 100644 --- a/packages/graphql-anywhere/package.json +++ b/packages/graphql-anywhere/package.json @@ -40,8 +40,5 @@ "apollo-utilities": "file:../apollo-utilities", "ts-invariant": "^0.3.2", "tslib": "^1.9.3" - }, - "devDependencies": { - "prop-types": "^15.7.2" } } From fcebb084b9a170aebc2afa3d2ad6408442185253 Mon Sep 17 00:00:00 2001 From: Hugh Willson Date: Wed, 17 Apr 2019 15:12:48 -0400 Subject: [PATCH 11/12] Changelog update --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 204c5bdeada..5a59ff499b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,14 @@ - Allow `IntrospectionFragmentMatcher` to match fragments against the root `Query`, as `HeuristicFragmentMatcher` does.
[@rynobax](https://github.com/rynobax) in [#4620](https://github.com/apollographql/apollo-client/pull/4620) +### GraphQL Anywhere + +- The `graphql` function can now be configured to ignore `@include` and + `@skip` directives (useful when walking a fragment to generate prop types + or filter result data).
+ [@GreenGremlin](https://github.com/GreenGremlin) in [#4373](https://github.com/apollographql/apollo-client/pull/4373) + + ## Apollo Client 2.5.1 ### apollo-client 2.5.1 From 6102cc6e43616e5de08c7da1b67a7247f54530d0 Mon Sep 17 00:00:00 2001 From: Hugh Willson Date: Wed, 17 Apr 2019 15:18:21 -0400 Subject: [PATCH 12/12] Bundlesize limit increase (temporary) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index daf38f9a420..3393a053d50 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ { "name": "apollo-utilities", "path": "./packages/apollo-utilities/lib/bundle.cjs.min.js", - "maxSize": "4.2 kB" + "maxSize": "4.3 kB" } ], "lint-staged": {