Repository: FormidableLabs/urql
Pull request #567 (2020-03-03 22:51:27)

Move populateExchange to a package
## Summary

Let's use our new monorepo optimally and start moving some packages, this allows us to install less if it's not needed

## Set of changes

<!--
  Roughly list the changes you've made and which packages are affected.
  Leave some notes on what may be noteworthy files you've changed.
  And lastly, please let us know if you think this is a breaking change.
-->


changeset-bot[bot]: ###  💥  No Changeset

Latest commit: 924b63672882a8b6473e301ab3a22fa6eec521ba

Merging this PR will not cause any packages to be released. If these changes should not cause updates to packages in this repo, this is fine 🙂

**If these changes should be published to npm, you need to add a changeset.**

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/master/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/FormidableLabs/urql/new/chore/move-populate-to-package?filename=.changeset/five-wolves-laugh.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0AUpdate%20the%20package%20info%20above%20to%20the%20changes%20you%20want%2C%20and%20write%20your%20description%20here.%20You%20can%20add%20more%20packages%20on%20new%20lines.%0A)



Patch:
diff --git a/exchanges/graphcache/src/ast/index.ts b/exchanges/graphcache/src/ast/index.ts
index 19123146..2111b254 100644
--- a/exchanges/graphcache/src/ast/index.ts
+++ b/exchanges/graphcache/src/ast/index.ts
@@ -1,4 +1,3 @@
 export { getFieldArguments, normalizeVariables } from './variables';
 export * from './traversal';
-export * from './node';
 export * from './schemaPredicates';
diff --git a/exchanges/graphcache/src/ast/schemaPredicates.ts b/exchanges/graphcache/src/ast/schemaPredicates.ts
index b49ad016..580b3d36 100644
--- a/exchanges/graphcache/src/ast/schemaPredicates.ts
+++ b/exchanges/graphcache/src/ast/schemaPredicates.ts
@@ -9,7 +9,7 @@ import {
   GraphQLUnionType,
 } from 'graphql';
 
-import { invariant, warn } from '../helpers/help';
+import { warn, invariant } from 'shared';
 
 export const isFieldNullable = (
   schema: GraphQLSchema,
diff --git a/exchanges/graphcache/src/ast/traversal.ts b/exchanges/graphcache/src/ast/traversal.ts
index 5d97cbed..b75a8959 100644
--- a/exchanges/graphcache/src/ast/traversal.ts
+++ b/exchanges/graphcache/src/ast/traversal.ts
@@ -7,9 +7,8 @@ import {
   valueFromASTUntyped,
   Kind,
 } from 'graphql';
+import { invariant, getName } from 'shared';
 
-import { invariant } from '../helpers/help';
-import { getName } from './node';
 import { Fragments, Variables } from '../types';
 
 const isFragmentNode = (node: DefinitionNode): node is FragmentDefinitionNode =>
diff --git a/exchanges/graphcache/src/ast/variables.ts b/exchanges/graphcache/src/ast/variables.ts
index f8c04a89..8298e7b9 100644
--- a/exchanges/graphcache/src/ast/variables.ts
+++ b/exchanges/graphcache/src/ast/variables.ts
@@ -3,8 +3,8 @@ import {
   OperationDefinitionNode,
   valueFromASTUntyped,
 } from 'graphql';
+import { getName } from 'shared';
 
-import { getName } from './node';
 import { makeDict } from '../helpers/dict';
 import { Variables } from '../types';
 
diff --git a/exchanges/graphcache/src/index.ts b/exchanges/graphcache/src/index.ts
index fc0f3f74..9217895e 100644
--- a/exchanges/graphcache/src/index.ts
+++ b/exchanges/graphcache/src/index.ts
@@ -2,4 +2,4 @@ export * from './operations';
 export * from './types';
 export { Store, initDataState, clearDataState } from './store';
 export { cacheExchange } from './cacheExchange';
-export { populateExchange } from './populateExchange';
+export { populateExchange } from '@urql/exchange-populate';
diff --git a/exchanges/graphcache/src/operations/invalidate.ts b/exchanges/graphcache/src/operations/invalidate.ts
index 32a4c93e..42df0aaa 100644
--- a/exchanges/graphcache/src/operations/invalidate.ts
+++ b/exchanges/graphcache/src/operations/invalidate.ts
@@ -1,21 +1,14 @@
 import { FieldNode } from 'graphql';
+import { getSelectionSet, getName, SelectionSet } from 'shared';
 
 import {
   getMainOperation,
   normalizeVariables,
   getFragments,
-  getSelectionSet,
-  getName,
   getFieldArguments,
 } from '../ast';
 
-import {
-  EntityField,
-  OperationRequest,
-  Variables,
-  Fragments,
-  SelectionSet,
-} from '../types';
+import { EntityField, OperationRequest, Variables, Fragments } from '../types';
 
 import * as InMemoryData from '../store/data';
 import { Store, keyOfField } from '../store';
diff --git a/exchanges/graphcache/src/operations/query.ts b/exchanges/graphcache/src/operations/query.ts
index f7bff0f6..48c7590d 100644
--- a/exchanges/graphcache/src/operations/query.ts
+++ b/exchanges/graphcache/src/operations/query.ts
@@ -1,14 +1,19 @@
 import { FieldNode, DocumentNode, FragmentDefinitionNode } from 'graphql';
+import {
+  getSelectionSet,
+  getName,
+  SelectionSet,
+  getFragmentTypeName,
+  getFieldAlias,
+  warn,
+  pushDebugNode,
+} from 'shared';
 
 import {
   getFragments,
   getMainOperation,
-  getSelectionSet,
   normalizeVariables,
-  getName,
   getFieldArguments,
-  getFieldAlias,
-  getFragmentTypeName,
 } from '../ast';
 
 import {
@@ -17,7 +22,6 @@ import {
   Data,
   DataField,
   Link,
-  SelectionSet,
   OperationRequest,
   NullArray,
 } from '../types';
@@ -33,7 +37,6 @@ import {
 
 import * as InMemoryData from '../store/data';
 import { makeDict } from '../helpers/dict';
-import { warn, pushDebugNode } from '../helpers/help';
 import { SelectionIterator, ensureData } from './shared';
 
 import {
diff --git a/exchanges/graphcache/src/operations/shared.ts b/exchanges/graphcache/src/operations/shared.ts
index 9a2531e4..d8030714 100644
--- a/exchanges/graphcache/src/operations/shared.ts
+++ b/exchanges/graphcache/src/operations/shared.ts
@@ -1,28 +1,21 @@
 import { FieldNode, InlineFragmentNode, FragmentDefinitionNode } from 'graphql';
+import {
+  warn,
+  pushDebugNode,
+  isInlineFragment,
+  getTypeCondition,
+  getSelectionSet,
+  getName,
+  SelectionSet,
+  isFieldNode,
+} from 'shared';
 
-import { warn, pushDebugNode } from '../helpers/help';
 import { hasField } from '../store/data';
 import { Store, keyOfField } from '../store';
 
-import {
-  Fragments,
-  Variables,
-  SelectionSet,
-  DataField,
-  NullArray,
-  Data,
-} from '../types';
+import { Fragments, Variables, DataField, NullArray, Data } from '../types';
 
-import {
-  getTypeCondition,
-  getFieldArguments,
-  shouldInclude,
-  isInterfaceOfType,
-  isFieldNode,
-  isInlineFragment,
-  getSelectionSet,
-  getName,
-} from '../ast';
+import { getFieldArguments, shouldInclude, isInterfaceOfType } from '../ast';
 
 interface Context {
   store: Store;
diff --git a/exchanges/graphcache/src/operations/write.ts b/exchanges/graphcache/src/operations/write.ts
index 5a9a4713..64edc2f3 100644
--- a/exchanges/graphcache/src/operations/write.ts
+++ b/exchanges/graphcache/src/operations/write.ts
@@ -1,16 +1,22 @@
 import { FieldNode, DocumentNode, FragmentDefinitionNode } from 'graphql';
 
 import {
-  getFieldAlias,
   getFragments,
   getMainOperation,
-  getSelectionSet,
   normalizeVariables,
-  getFragmentTypeName,
-  getName,
   getFieldArguments,
   isFieldAvailableOnType,
 } from '../ast';
+import {
+  getSelectionSet,
+  getName,
+  SelectionSet,
+  getFragmentTypeName,
+  getFieldAlias,
+  invariant,
+  warn,
+  pushDebugNode,
+} from 'shared';
 
 import {
   NullArray,
@@ -18,7 +24,6 @@ import {
   Variables,
   Data,
   Link,
-  SelectionSet,
   OperationRequest,
 } from '../types';
 
@@ -33,7 +38,6 @@ import {
 
 import * as InMemoryData from '../store/data';
 import { makeDict } from '../helpers/dict';
-import { invariant, warn, pushDebugNode } from '../helpers/help';
 import { SelectionIterator, ensureData } from './shared';
 
 export interface WriteResult {
diff --git a/exchanges/graphcache/src/store/data.ts b/exchanges/graphcache/src/store/data.ts
index 402e8078..bf1e418a 100644
--- a/exchanges/graphcache/src/store/data.ts
+++ b/exchanges/graphcache/src/store/data.ts
@@ -7,7 +7,7 @@ import {
 } from '../types';
 
 import { makeDict } from '../helpers/dict';
-import { invariant, currentDebugStack } from '../helpers/help';
+import { invariant, currentDebugStack } from 'shared';
 import { fieldInfoOfKey, joinKeys, prefixKey } from './keys';
 import { defer } from './timing';
 
diff --git a/exchanges/graphcache/src/store/store.ts b/exchanges/graphcache/src/store/store.ts
index 94866520..8bbb7b36 100644
--- a/exchanges/graphcache/src/store/store.ts
+++ b/exchanges/graphcache/src/store/store.ts
@@ -20,7 +20,7 @@ import {
   KeyingConfig,
   DataFields,
 } from '../types';
-import { invariant } from '../helpers/help';
+import { invariant } from 'shared';
 
 import { read, readFragment } from '../operations/query';
 import { writeFragment, startWrite } from '../operations/write';
diff --git a/exchanges/graphcache/src/types.ts b/exchanges/graphcache/src/types.ts
index 49f770f3..72e93a16 100644
--- a/exchanges/graphcache/src/types.ts
+++ b/exchanges/graphcache/src/types.ts
@@ -1,17 +1,8 @@
-import {
-  DocumentNode,
-  FragmentDefinitionNode,
-  SelectionNode,
-  GraphQLOutputType,
-  GraphQLWrappingType,
-} from 'graphql';
+import { DocumentNode, FragmentDefinitionNode } from 'graphql';
 
 // Helper types
 export type NullArray<T> = Array<null | T>;
 
-// GraphQL helper types
-export type SelectionSet = ReadonlyArray<SelectionNode>;
-export type GraphQLFlatType = Exclude<GraphQLOutputType, GraphQLWrappingType>;
 export interface Fragments {
   [fragmentName: string]: void | FragmentDefinitionNode;
 }
@@ -102,6 +93,9 @@ export interface Cache {
   /** invalidateQuery() invalidates all data of a given query */
   invalidateQuery(query: DocumentNode, variables?: Variables): void;
 
+  /** invalidate() invalidates an entity */
+  invalidate(entity: Data | string): void;
+
   /** updateQuery() can be used to update the data of a given query using an updater function */
   updateQuery(
     input: QueryInput,
@@ -182,23 +176,3 @@ export interface StorageAdapter {
   read(): Promise<SerializedEntries>;
   write(data: SerializedEntries): Promise<void>;
 }
-
-export type ErrorCode =
-  | 1
-  | 2
-  | 3
-  | 4
-  | 5
-  | 6
-  | 7
-  | 8
-  | 9
-  | 10
-  | 11
-  | 12
-  | 13
-  | 15
-  | 16
-  | 17
-  | 18
-  | 19;
diff --git a/exchanges/graphcache/tsconfig.json b/exchanges/graphcache/tsconfig.json
index cd80aea8..1cc933ea 100644
--- a/exchanges/graphcache/tsconfig.json
+++ b/exchanges/graphcache/tsconfig.json
@@ -2,11 +2,13 @@
   "extends": "../../tsconfig.json",
   "include": ["src"],
   "compilerOptions": {
+    "rootDirs": ["./", "../shared", "../populate"],
     "baseUrl": "./",
     "paths": {
       "urql": ["../../node_modules/urql/src"],
       "*-urql": ["../../node_modules/*-urql/src"],
-      "@urql/*": ["../../node_modules/@urql/*/src"]
+      "@urql/*": ["../../node_modules/@urql/*/src"],
+      "shared": ["../../node_modules/shared/src"]
     }
   }
 }
diff --git a/exchanges/populate/CHANGELOG.md b/exchanges/populate/CHANGELOG.md
new file mode 100644
index 00000000..85ee9506
--- /dev/null
+++ b/exchanges/populate/CHANGELOG.md
@@ -0,0 +1,7 @@
+# @urql/exchange-populate
+
+## 0.1.0
+
+### Initial release
+
+- Moved the `populateExchange` from `@urql/exchange-graphcache` to its own package.
diff --git a/exchanges/populate/README.md b/exchanges/populate/README.md
new file mode 100644
index 00000000..54f469a5
--- /dev/null
+++ b/exchanges/populate/README.md
@@ -0,0 +1,77 @@
+# @urql/exchange-populate
+
+`populate` is an exchange for auto-populating fields in your mutations.
+
+## Quick Start Guide
+
+First install `@urql/exchange-populate` alongside `urql`:
+
+```sh
+yarn add @urql/exchange-populate
+# or
+npm install --save @urql/exchange-populate
+```
+
+You'll then need to add the `populateExchange`, that this package exposes.
+
+```js
+import { createClient, dedupExchange, cacheExchange, fetchExchange } from 'urql';
+import { populateExchange } from '@urql/exchange-populate';
+
+const client = createClient({
+  url: 'http://localhost:1234/graphql',
+  exchanges: [
+    dedupExchange,
+    populateExchange,
+    cacheExchange,
+    fetchExchange,
+  ],
+});
+```
+
+## Example usage
+
+Consider the following queries which have been requested in other parts of your application:
+
+
+```graphql
+# Query 1
+{
+  todos {
+    id
+    name
+  }
+}
+
+# Query 2
+{
+  todos {
+    id
+    createdAt
+  }
+}
+```
+
+Without the `populateExchange` you may write a mutation like the following which returns a newly created todo item:
+
+```graphql
+# Without populate
+mutation addTodo(id: ID!) {
+  addTodo(id: $id) {
+    id        # To update Query 1 & 2
+    name      # To update Query 1
+    createdAt # To update Query 2
+  }
+}
+```
+
+By using `populateExchange`, you no longer need to manually specify the selection set required to update your other queries. Instead you can just add the `@populate` directive.
+
+```graphql
+# With populate
+mutation addTodo(id: ID!) {
+  addTodo(id: $id) @populate
+}
+```
+
+> Note: The above two mutations produce an identical GraphQL request.
diff --git a/exchanges/populate/package.json b/exchanges/populate/package.json
new file mode 100644
index 00000000..123ee060
--- /dev/null
+++ b/exchanges/populate/package.json
@@ -0,0 +1,61 @@
+{
+  "name": "@urql/exchange-populate",
+  "version": "0.1.0",
+  "description": "An exchange that automaticcally populates the mutation selection body",
+  "sideEffects": false,
+  "homepage": "https://formidable.com/open-source/urql/docs/",
+  "bugs": "https://github.com/FormidableLabs/urql/issues",
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/FormidableLabs/urql.git",
+    "directory": "exchanges/populate"
+  },
+  "keywords": [
+    "urql",
+    "formidablelabs",
+    "exchanges"
+  ],
+  "main": "dist/urql-exchange-populate.cjs.js",
+  "module": "dist/urql-exchange-populate.esm.js",
+  "types": "dist/types/index.d.ts",
+  "source": "src/index.ts",
+  "exports": {
+    ".": {
+      "import": "dist/urql-exchange-populate.esm.js",
+      "require": "dist/urql-exchange-populate.cjs.js",
+      "types": "dist/types/index.d.ts",
+      "source": "src/index.ts"
+    }
+  },
+  "files": [
+    "LICENSE",
+    "CHANGELOG.md",
+    "README.md",
+    "dist/",
+    "extras/"
+  ],
+  "scripts": {
+    "test": "jest",
+    "clean": "rimraf dist extras",
+    "check": "tsc --noEmit",
+    "lint": "eslint --ext=js,jsx,ts,tsx .",
+    "build": "rollup -c ../../scripts/rollup/config.js",
+    "prepare": "../../scripts/prepare/index.js",
+    "prepublishOnly": "run-s clean test build"
+  },
+  "jest": {
+    "preset": "../../scripts/jest/preset"
+  },
+  "dependencies": {
+    "wonka": "^3.2.1 || ^4.0.0",
+    "@urql/core": ">=1.9.0"
+  },
+  "peerDependencies": {
+    "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0"
+  },
+  "devDependencies": {
+    "graphql": "^14.5.8",
+    "graphql-tag": "^2.10.1"
+  }
+}
diff --git a/exchanges/populate/src/index.ts b/exchanges/populate/src/index.ts
new file mode 100644
index 00000000..75dee05f
--- /dev/null
+++ b/exchanges/populate/src/index.ts
@@ -0,0 +1,1 @@
+export * from './populateExchange';
diff --git a/exchanges/graphcache/src/populateExchange.test.ts b/exchanges/populate/src/populateExchange.test.ts
similarity index 100%
rename from exchanges/graphcache/src/populateExchange.test.ts
rename to exchanges/populate/src/populateExchange.test.ts
diff --git a/exchanges/graphcache/src/populateExchange.ts b/exchanges/populate/src/populateExchange.ts
similarity index 98%
rename from exchanges/graphcache/src/populateExchange.ts
rename to exchanges/populate/src/populateExchange.ts
index 84474f09..67f3a293 100644
--- a/exchanges/graphcache/src/populateExchange.ts
+++ b/exchanges/populate/src/populateExchange.ts
@@ -14,18 +14,17 @@ import {
   Kind,
   visit,
 } from 'graphql';
+import { getName, getSelectionSet, unwrapType, invariant, warn } from 'shared';
 
 import { pipe, tap, map } from 'wonka';
 import { Exchange, Operation } from '@urql/core';
 
-import { getName, getSelectionSet, unwrapType } from './ast';
-import { makeDict } from './helpers/dict';
-import { invariant, warn } from './helpers/help';
-
 interface PopulateExchangeOpts {
   schema: IntrospectionQuery;
 }
 
+const makeDict = (): any => Object.create(null);
+
 /** An exchange for auto-populating mutations with a required response body. */
 export const populateExchange = ({
   schema: ogSchema,
diff --git a/exchanges/populate/tsconfig.json b/exchanges/populate/tsconfig.json
new file mode 100644
index 00000000..e713330c
--- /dev/null
+++ b/exchanges/populate/tsconfig.json
@@ -0,0 +1,14 @@
+{
+  "extends": "../../tsconfig.json",
+  "include": ["src"],
+  "compilerOptions": {
+    "baseUrl": "./",
+    "rootDirs": ["./", "../shared", "../populate"],
+    "paths": {
+      "urql": ["../../node_modules/urql/src"],
+      "*-urql": ["../../node_modules/*-urql/src"],
+      "@urql/*": ["../../node_modules/@urql/*/src"],
+      "shared": ["../../node_modules/shared/src"]
+    }
+  }
+}
diff --git a/exchanges/shared/package.json b/exchanges/shared/package.json
new file mode 100644
index 00000000..fc3e9f97
--- /dev/null
+++ b/exchanges/shared/package.json
@@ -0,0 +1,11 @@
+{
+  "private": true,
+  "name": "shared",
+  "version": "1.0.0",
+  "scripts": {
+    "build": "echo 'not building shared'"
+  },
+  "jest": {
+    "preset": "../../scripts/jest/preset"
+  }
+}
diff --git a/exchanges/shared/src/ast/index.ts b/exchanges/shared/src/ast/index.ts
new file mode 100644
index 00000000..d0dddb69
--- /dev/null
+++ b/exchanges/shared/src/ast/index.ts
@@ -0,0 +1,1 @@
+export * from './node';
diff --git a/exchanges/graphcache/src/ast/node.ts b/exchanges/shared/src/ast/node.ts
similarity index 90%
rename from exchanges/graphcache/src/ast/node.ts
rename to exchanges/shared/src/ast/node.ts
index ea8f7f47..d773f86b 100644
--- a/exchanges/graphcache/src/ast/node.ts
+++ b/exchanges/shared/src/ast/node.ts
@@ -9,9 +9,11 @@ import {
   GraphQLOutputType,
   Kind,
   isWrappingType,
+  GraphQLWrappingType,
 } from 'graphql';
 
-import { SelectionSet, GraphQLFlatType } from '../types';
+export type SelectionSet = ReadonlyArray<SelectionNode>;
+export type GraphQLFlatType = Exclude<GraphQLOutputType, GraphQLWrappingType>;
 
 /** Returns the name of a given node */
 export const getName = (node: { name: NameNode }): string => node.name.value;
diff --git a/exchanges/graphcache/src/helpers/help.ts b/exchanges/shared/src/helpers/help.ts
similarity index 92%
rename from exchanges/graphcache/src/helpers/help.ts
rename to exchanges/shared/src/helpers/help.ts
index 9d172460..96344d53 100644
--- a/exchanges/graphcache/src/helpers/help.ts
+++ b/exchanges/shared/src/helpers/help.ts
@@ -4,7 +4,26 @@
 // You can read more about the messages themselves in `docs/help.md`
 
 import { Kind, ExecutableDefinitionNode, InlineFragmentNode } from 'graphql';
-import { ErrorCode } from '../types';
+
+export type ErrorCode =
+  | 1
+  | 2
+  | 3
+  | 4
+  | 5
+  | 6
+  | 7
+  | 8
+  | 9
+  | 10
+  | 11
+  | 12
+  | 13
+  | 15
+  | 16
+  | 17
+  | 18
+  | 19;
 
 type DebugNode = ExecutableDefinitionNode | InlineFragmentNode;
 
diff --git a/exchanges/shared/src/helpers/index.ts b/exchanges/shared/src/helpers/index.ts
new file mode 100644
index 00000000..b6588483
--- /dev/null
+++ b/exchanges/shared/src/helpers/index.ts
@@ -0,0 +1,1 @@
+export * from './help';
diff --git a/exchanges/shared/src/index.ts b/exchanges/shared/src/index.ts
new file mode 100644
index 00000000..2cb11bca
--- /dev/null
+++ b/exchanges/shared/src/index.ts
@@ -0,0 +1,2 @@
+export * from './ast';
+export * from './helpers';
diff --git a/exchanges/shared/tsconfig.json b/exchanges/shared/tsconfig.json
new file mode 100644
index 00000000..cd80aea8
--- /dev/null
+++ b/exchanges/shared/tsconfig.json
@@ -0,0 +1,12 @@
+{
+  "extends": "../../tsconfig.json",
+  "include": ["src"],
+  "compilerOptions": {
+    "baseUrl": "./",
+    "paths": {
+      "urql": ["../../node_modules/urql/src"],
+      "*-urql": ["../../node_modules/*-urql/src"],
+      "@urql/*": ["../../node_modules/@urql/*/src"]
+    }
+  }
+}
diff --git a/package.json b/package.json
index 4c0ea5f4..434e1967 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
     "test": "jest",
     "check": "tsc",
     "lint": "eslint --ext=js,jsx,ts,tsx .",
-    "build": "./scripts/rollup/build.js"
+    "build": "node ./scripts/rollup/build.js"
   },
   "jest": {
     "projects": [
diff --git a/scripts/jest/preset.js b/scripts/jest/preset.js
index e20a2f7c..eafa23ce 100644
--- a/scripts/jest/preset.js
+++ b/scripts/jest/preset.js
@@ -10,6 +10,7 @@ module.exports = {
     "^urql$": "<rootDir>/../../node_modules/urql/src",
     "^(.*-urql)$": "<rootDir>/../../node_modules/$1/src",
     "^@urql/(.*)$": "<rootDir>/../../node_modules/@urql/$1/src",
+    "^shared$": "<rootDir>/../../node_modules/shared/src",
   },
   watchPlugins: ['jest-watch-yarn-workspaces'],
   testRegex: '(src/.*(\\.|/)(test|spec))\\.tsx?$',
diff --git a/tsconfig.json b/tsconfig.json
index b5b2fabc..9d018e0f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,7 +5,8 @@
       "urql": ["packages/react-urql/src"],
       "*-urql": ["packages/*-urql/src"],
       "@urql/exchange-*": ["exchanges/*/src"],
-      "@urql/*": ["packages/*-urql/src", "packages/*/src"]
+      "@urql/*": ["packages/*-urql/src", "packages/*/src"],
+      "shared": ["exchanges/shared/src"]
     },
     "esModuleInterop": true,
     "forceConsistentCasingInFileNames": true,


Test patch:
diff --git a/exchanges/graphcache/src/ast/traversal.test.ts b/exchanges/graphcache/src/ast/traversal.test.ts
index 5c025831..e5e58bba 100644
--- a/exchanges/graphcache/src/ast/traversal.test.ts
+++ b/exchanges/graphcache/src/ast/traversal.test.ts
@@ -1,5 +1,6 @@
 import gql from 'graphql-tag';
-import { getSelectionSet } from './node';
+import { getSelectionSet } from 'shared';
+
 import { getMainOperation, shouldInclude } from './traversal';
 
 describe('getMainOperation', () => {
diff --git a/exchanges/graphcache/src/ast/node.test.ts b/exchanges/shared/src/ast/node.test.ts
similarity index 96%
rename from exchanges/graphcache/src/ast/node.test.ts
rename to exchanges/shared/src/ast/node.test.ts
index a67a68a8..eeef258e 100644
--- a/exchanges/graphcache/src/ast/node.test.ts
+++ b/exchanges/shared/src/ast/node.test.ts
@@ -1,4 +1,4 @@
-import { unwrapType } from './';
+import { unwrapType } from './node';
 import { GraphQLScalarType, GraphQLNonNull, GraphQLList } from 'graphql';
 
 describe('unwrapType', () => {