Repository: kamilkisiela/graphql-inspector
Pull request #14 (2018-11-23 19:28:43)

@graphql-inspector organization


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 50b145f1..9bbb146b 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -20,5 +20,5 @@ jobs:
             - node_modules
           key: v1-dependencies-{{ checksum "package.json" }}
 
-      - run: yarn test
       - run: yarn build
+      - run: yarn test
diff --git a/.gitignore b/.gitignore
index fe4083c5..407c6ef0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,7 @@ node_modules/
 dist/
 yarn.lock
 yarn-error.log
+**/*/node_modules/
+**/*/dist/
+**/*/yarn.lock
+**/*/yarn-error.log
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 00000000..5575c7d1
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,1 @@
+packages/*/dist
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..6a085499
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+  "files.exclude": {
+    "**/dist": true
+  }
+}
diff --git a/README.md b/README.md
index a5646aba..3b18c3c1 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,12 @@
 # GraphQL Inspector
 
 [![CircleCI](https://circleci.com/gh/kamilkisiela/graphql-inspector.svg?style=shield&circle-token=d1cd06aba321ee2b7bf8bd2041104643639463b0)](https://circleci.com/gh/kamilkisiela/graphql-inspector)
-[![npm version](https://badge.fury.io/js/graphql-inspector.svg)](https://npmjs.com/package/graphql-inspector)
 [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
 [![renovate-app badge](https://img.shields.io/badge/renovate-app-blue.svg)](https://renovateapp.com/)
 
 **GraphQL Inspector** ouputs a list of changes between two GraphQL schemas. Every change is precisely explained and marked as breaking, non-breaking or dangerous.
 It helps you validate documents and fragments against a schema and even find similar or duplicated types.
 
-![Example](./demo.gif)
-
 ## Features
 
 Major features:
@@ -26,21 +23,14 @@ GraphQL Inspector has a **CLI** and also a **programatic API**, so you can use i
 ## Installation
 
 ```bash
-yarn add graphql-inspector
-```
+# CLI
+yarn add @graphql-inspector/cli
 
-## CLI Usage
-
-```bash
-graphql-inspector diff     <OLD_SCHEMA> <NEW_SCHEMA>
-graphql-inspector validate <DOCUMENTS>  <SCHEMA>
-graphql-inspector similar  <SCHEMA>
-graphql-inspector serve    <SCHEMA>
-graphql-inspector coverage <DOCUMENTS>  <SCHEMA>
-graphql-inspector --help
+# Core API for programatic usage
+yarn add @graphql-inspector/core
 ```
 
-### Examples
+### CLI Usage
 
 ```bash
 # Compare schemas
@@ -107,7 +97,7 @@ import {
   InvalidDocument,
   SimilarMap,
   SchemaCoverage,
-} from 'graphql-inspector';
+} from '@graphql-inspector/core';
 
 // diff
 const changes: Change[] = diff(schemaA, schemaB);
diff --git a/example/coverage.json b/example/coverage.json
index dfc26df1..6186cdfe 100644
--- a/example/coverage.json
+++ b/example/coverage.json
@@ -68,4 +68,4 @@
       }
     }
   }
-}
\ No newline at end of file
+}
diff --git a/example/package.json b/example/package.json
index 41047f2d..e8153ca5 100644
--- a/example/package.json
+++ b/example/package.json
@@ -1,16 +1,17 @@
 {
   "name": "example",
   "scripts": {
-    "diff": "node ../dist/cli.js diff ./schemas/schema.graphql ./schemas/new.graphql",
-    "diff:same": "node ../dist/cli.js diff ./schemas/schema.graphql ./schemas/schema.graphql",
-    "validate": "node ../dist/cli.js validate ./documents/*.graphql ./schemas/schema.graphql",
-    "validate:none": "node ../dist/cli.js validate ./no-documents/*.graphql ./schemas/schema.graphql",
-    "similar": "node ../dist/cli.js similar ./schemas/similar.graphql",
-    "similar:type": "node ../dist/cli.js similar ./schemas/similar.graphql --type Post",
-    "similar:loose": "node ../dist/cli.js similar ./schemas/similar.graphql --threshold 0.1",
-    "serve": "node ../dist/cli.js serve ./schemas/schema.graphql",
-    "coverage": "node ../dist/cli.js coverage ./documents/*.graphql ./schemas/schema.graphql",
-    "coverage:write": "node ../dist/cli.js coverage ./documents/*.graphql ./schemas/schema.graphql --silent --write ./coverage.json",
-    "open-help": "node ../dist/cli.js --help"
+    "graphql-inspector": "node ../packages/cli/dist/index.js",
+    "diff": "yarn graphql-inspector diff ./schemas/schema.graphql ./schemas/new.graphql",
+    "diff:same": "yarn graphql-inspector diff ./schemas/schema.graphql ./schemas/schema.graphql",
+    "validate": "yarn graphql-inspector validate ./documents/*.graphql ./schemas/schema.graphql",
+    "validate:none": "yarn graphql-inspector validate ./no-documents/*.graphql ./schemas/schema.graphql",
+    "similar": "yarn graphql-inspector similar ./schemas/similar.graphql",
+    "similar:type": "yarn graphql-inspector similar ./schemas/similar.graphql --type Post",
+    "similar:loose": "yarn graphql-inspector similar ./schemas/similar.graphql --threshold 0.1",
+    "serve": "yarn graphql-inspector serve ./schemas/schema.graphql",
+    "coverage": "yarn graphql-inspector coverage ./documents/*.graphql ./schemas/schema.graphql",
+    "coverage:write": "yarn graphql-inspector coverage ./documents/*.graphql ./schemas/schema.graphql --silent --write ./coverage.json",
+    "open-help": "yarn graphql-inspector --help"
   }
 }
diff --git a/lerna.json b/lerna.json
new file mode 100644
index 00000000..b5b604a7
--- /dev/null
+++ b/lerna.json
@@ -0,0 +1,5 @@
+{
+  "npmClient": "yarn",
+  "useWorkspaces": true,
+  "version": "0.6.0-alpha.2"
+}
diff --git a/lint-staged.config.js b/lint-staged.config.js
deleted file mode 100644
index 002932ac..00000000
--- a/lint-staged.config.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
-  '{src,__tests__}/**/*.ts': ['prettier --write', 'git add'],
-};
diff --git a/package.json b/package.json
index 436a9f12..8c89d9db 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "graphql-inspector",
-  "version": "0.5.1",
+  "private": true,
   "description": "Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.",
   "keywords": [
     "graphql",
@@ -9,10 +9,6 @@
     "cli"
   ],
   "sideEffects": false,
-  "main": "dist/index.js",
-  "bin": {
-    "graphql-inspector": "dist/cli.js"
-  },
   "author": {
     "name": "Kamil Kisiela",
     "email": "kamil.kisiela@gmail.com",
@@ -24,43 +20,31 @@
     "url": "kamilkisiela/graphql-inspector"
   },
   "scripts": {
-    "build": "tsc",
-    "test": "jest",
-    "format": "prettier --config .prettierrc --write \"{src,__tests__}/**/*.ts\"",
-    "clean": "rm -rf dist/",
-    "precommit": "lint-staged",
-    "prebuild": "npm run clean",
-    "prepublishOnly": "npm run build"
+    "build": "lerna run build",
+    "test": "lerna run test",
+    "format": "prettier --config .prettierrc --write \"**/*.{js,json,md,ts,graphql}\"",
+    "release": "lerna publish --exact --force-publish=\"*\"",
+    "release:canary": "lerna publish --force-publish=\"*\" --canary --exact",
+    "precommit": "lint-staged"
   },
   "devDependencies": {
-    "@types/figures": "2.0.0",
-    "@types/glob": "7.1.1",
-    "@types/graphql": "14.0.3",
-    "@types/indent-string": "3.0.0",
-    "@types/is-glob": "4.0.0",
-    "@types/jest": "23.3.9",
-    "@types/log-symbols": "2.0.0",
-    "@types/node-fetch": "2.1.3",
-    "@types/opn": "5.1.0",
-    "graphql-tag": "2.10.0",
-    "jest": "23.6.0",
     "lint-staged": "8.0.4",
-    "prettier": "1.15.2",
-    "ts-jest": "23.10.4",
-    "typescript": "3.1.6"
+    "prettier": "1.15.2"
   },
   "dependencies": {
-    "apollo-server": "2.2.2",
-    "chalk": "2.4.1",
-    "commander": "2.19.0",
-    "figures": "2.0.0",
-    "glob": "7.1.3",
-    "graphql": "14.0.2",
-    "indent-string": "3.2.0",
-    "is-glob": "4.0.0",
-    "is-valid-path": "0.1.1",
-    "log-symbols": "2.2.0",
-    "node-fetch": "2.3.0",
-    "opn": "5.4.0"
+    "husky": "1.2.0",
+    "lerna": "3.4.3"
+  },
+  "workspaces": {
+    "packages": [
+      "packages/core",
+      "packages/cli"
+    ]
+  },
+  "lint-staged": {
+    "*.{js,json,md,ts,graphql}": [
+      "prettier --write",
+      "git add"
+    ]
   }
 }
diff --git a/packages/cli/.npmignore b/packages/cli/.npmignore
new file mode 100644
index 00000000..fd1ffd65
--- /dev/null
+++ b/packages/cli/.npmignore
@@ -0,0 +1,5 @@
+__tests__/
+src/
+jest.config.js
+tsconfig.json
+tsconfig.test.json
diff --git a/packages/cli/.npmrc b/packages/cli/.npmrc
new file mode 100644
index 00000000..449691b7
--- /dev/null
+++ b/packages/cli/.npmrc
@@ -0,0 +1,1 @@
+save-exact=true
\ No newline at end of file
diff --git a/packages/cli/LICENSE b/packages/cli/LICENSE
new file mode 100644
index 00000000..af048480
--- /dev/null
+++ b/packages/cli/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Kamil Kisiela
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/cli/README.md b/packages/cli/README.md
new file mode 100644
index 00000000..7f1197cd
--- /dev/null
+++ b/packages/cli/README.md
@@ -0,0 +1,98 @@
+# GraphQL Inspector
+
+[![CircleCI](https://circleci.com/gh/kamilkisiela/graphql-inspector.svg?style=shield&circle-token=d1cd06aba321ee2b7bf8bd2041104643639463b0)](https://circleci.com/gh/kamilkisiela/graphql-inspector)
+[![npm version](https://badge.fury.io/js/@graphql-inspector/cli.svg)](https://npmjs.com/package/@graphql-inspector/cli)
+
+**GraphQL Inspector** ouputs a list of changes between two GraphQL schemas. Every change is precisely explained and marked as breaking, non-breaking or dangerous.
+It helps you validate documents and fragments against a schema and even find similar or duplicated types.
+
+![Example](./demo.gif)
+
+## Features
+
+Major features:
+
+- **Compares schemas**
+- **Finds breaking or dangerous changes**
+- **Validates documents against a schema**
+- **Finds similar / duplicated types**
+- **Schema coverage based on documents**
+- **Serves a GraphQL server with faked data and GraphQL Playground**
+
+GraphQL Inspector has a **CLI** and also a **programatic API**, so you can use it however you want to and even build tools on top of it.
+
+## Installation
+
+```bash
+yarn add @graphql-inspector/cli
+```
+
+## CLI Usage
+
+```bash
+graphql-inspector diff     <OLD_SCHEMA> <NEW_SCHEMA>
+graphql-inspector validate <DOCUMENTS>  <SCHEMA>
+graphql-inspector similar  <SCHEMA>
+graphql-inspector serve    <SCHEMA>
+graphql-inspector coverage <DOCUMENTS>  <SCHEMA>
+graphql-inspector --help
+```
+
+### Examples
+
+```bash
+# Compare schemas
+$ graphql-inspector diff OLD_SCHEMA NEW_SCHEMA
+
+Detected the following changes (4) between schemas:
+
+🛑  Field `name` was removed from object type `Post`
+⚠️  Enum value `ARCHIVED` was added to enum `Status`
+✅  Field `createdAt` was added to object type `Post`
+
+Detected 1 breaking change
+
+
+# Validate documents
+$ graphql-inspector validate DOCUMENTS SCHEMA
+
+Detected 1 invalid document:
+
+🛑  ./documents/post.graphql:
+  - Cannot query field createdAtSomePoint on type Post. Did you mean createdAt?
+
+
+# Find similar types
+$ graphql-inspector similar SCHEMA
+
+✅ Post
+Best match (60%): BlogPost
+
+
+# Serve faked GraphQL API with Playground
+$ graphql-inspector serve SCHEMA
+
+✅ Serving the GraphQL API on http://localhost:4000/
+
+
+# Check coverage
+$ graphql-inspector coverage DOCUMENTS SCHEMA
+
+Schema coverage
+
+type Query {
+  post x 1
+}
+
+type Post {
+  id x 1
+  title x 1
+  🛑 createdAt x 0
+  🛑 modifiedAt x 0
+}
+
+```
+
+## License
+
+[MIT](https://github.com/kamilkisiela/graphql-inspector/blob/master/LICENSE) © Kamil Kisiela
diff --git a/demo.gif b/packages/cli/demo.gif
similarity index 100%
rename from demo.gif
rename to packages/cli/demo.gif
diff --git a/demo.yml b/packages/cli/demo.yml
similarity index 100%
rename from demo.yml
rename to packages/cli/demo.yml
diff --git a/jest.config.js b/packages/cli/jest.config.js
similarity index 100%
rename from jest.config.js
rename to packages/cli/jest.config.js
diff --git a/packages/cli/package.json b/packages/cli/package.json
new file mode 100644
index 00000000..5f315bfb
--- /dev/null
+++ b/packages/cli/package.json
@@ -0,0 +1,66 @@
+{
+  "name": "@graphql-inspector/cli",
+  "version": "0.6.0-alpha.2",
+  "description": "Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.",
+  "keywords": [
+    "graphql",
+    "graphql-inspector",
+    "tools",
+    "cli"
+  ],
+  "sideEffects": false,
+  "main": "dist/index.js",
+  "bin": {
+    "graphql-inspector": "dist/index.js"
+  },
+  "author": {
+    "name": "Kamil Kisiela",
+    "email": "kamil.kisiela@gmail.com",
+    "url": "https://github.com/kamilkisiela"
+  },
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "kamilkisiela/graphql-inspector"
+  },
+  "scripts": {
+    "build": "tsc",
+    "test": "jest",
+    "clean": "rm -rf dist/",
+    "prebuild": "yarn clean",
+    "prepublishOnly": "yarn build"
+  },
+  "devDependencies": {
+    "@types/figures": "2.0.0",
+    "@types/glob": "7.1.1",
+    "@types/graphql": "14.0.3",
+    "@types/indent-string": "3.0.0",
+    "@types/is-glob": "4.0.0",
+    "@types/jest": "23.3.9",
+    "@types/log-symbols": "2.0.0",
+    "@types/node": "10.12.10",
+    "@types/node-fetch": "2.1.3",
+    "@types/opn": "5.1.0",
+    "graphql-tag": "2.10.0",
+    "jest": "23.6.0",
+    "lint-staged": "8.0.4",
+    "prettier": "1.15.2",
+    "ts-jest": "23.10.4",
+    "typescript": "3.1.6"
+  },
+  "dependencies": {
+    "@graphql-inspector/core": "0.6.0-alpha.2",
+    "apollo-server": "2.2.2",
+    "chalk": "2.4.1",
+    "commander": "2.19.0",
+    "figures": "2.0.0",
+    "glob": "7.1.3",
+    "graphql": "14.0.2",
+    "indent-string": "3.2.0",
+    "is-glob": "4.0.0",
+    "is-valid-path": "0.1.1",
+    "log-symbols": "2.2.0",
+    "node-fetch": "2.3.0",
+    "opn": "5.4.0"
+  }
+}
diff --git a/src/cli/commands/coverage.ts b/packages/cli/src/commands/coverage.ts
similarity index 87%
rename from src/cli/commands/coverage.ts
rename to packages/cli/src/commands/coverage.ts
index 660e0b05..eb6d24f3 100644
--- a/src/cli/commands/coverage.ts
+++ b/packages/cli/src/commands/coverage.ts
@@ -1,13 +1,19 @@
 import * as isValidPath from 'is-valid-path';
 import {writeFileSync} from 'fs';
 import {extname} from 'path';
+import {
+  coverage as calculateCoverage,
+  SchemaCoverage,
+} from '@graphql-inspector/core';
 
+import {ensureAbsolute} from '../utils/fs';
 import {loadSchema} from '../loaders/schema';
 import {loadDocuments} from '../loaders/documents';
 import {Renderer, ConsoleRenderer} from '../render';
-import {coverage as calculateCoverage} from '../../coverage';
-import {ensureAbsolute} from '../../utils/fs';
-import {outputJSON} from '../../coverage/output/json';
+
+export function outputJSON(coverage: SchemaCoverage): string {
+  return JSON.stringify(coverage, null, 2);
+}
 
 export async function coverage(
   documentsPointer: string,
diff --git a/src/cli/commands/diff.ts b/packages/cli/src/commands/diff.ts
similarity index 92%
rename from src/cli/commands/diff.ts
rename to packages/cli/src/commands/diff.ts
index 69c3f7a1..eb81e37f 100644
--- a/src/cli/commands/diff.ts
+++ b/packages/cli/src/commands/diff.ts
@@ -1,7 +1,11 @@
+import {
+  diff as diffSchema,
+  Change,
+  CriticalityLevel,
+} from '@graphql-inspector/core';
+
 import {loadSchema} from '../loaders/schema';
-import {diff as diffSchema} from '../../diff/schema';
 import {renderChange, Renderer, ConsoleRenderer} from '../render';
-import {Change, CriticalityLevel} from '../../diff/changes/change';
 
 function hasBreaking(changes: Change[]): boolean {
   return changes.some(c => c.criticality.level === CriticalityLevel.Breaking);
diff --git a/src/cli/commands/serve.ts b/packages/cli/src/commands/serve.ts
similarity index 100%
rename from src/cli/commands/serve.ts
rename to packages/cli/src/commands/serve.ts
diff --git a/src/cli/commands/similar.ts b/packages/cli/src/commands/similar.ts
similarity index 94%
rename from src/cli/commands/similar.ts
rename to packages/cli/src/commands/similar.ts
index 663cd3e4..d115dd39 100644
--- a/src/cli/commands/similar.ts
+++ b/packages/cli/src/commands/similar.ts
@@ -1,11 +1,10 @@
 import chalk from 'chalk';
 import {GraphQLNamedType} from 'graphql';
 import indent = require('indent-string');
+import {similar as findSimilar, getTypePrefix} from '@graphql-inspector/core';
 
 import {loadSchema} from '../loaders/schema';
 import {Renderer, ConsoleRenderer} from '../render';
-import {similar as findSimilar} from '../../similar';
-import {getTypePrefix} from '../../utils/graphql';
 
 export async function similar(
   schemaPointer: string,
diff --git a/src/cli/commands/validate.ts b/packages/cli/src/commands/validate.ts
similarity index 93%
rename from src/cli/commands/validate.ts
rename to packages/cli/src/commands/validate.ts
index dee35ccf..7c893878 100644
--- a/src/cli/commands/validate.ts
+++ b/packages/cli/src/commands/validate.ts
@@ -1,7 +1,8 @@
+import {validate as validateDocuments} from '@graphql-inspector/core';
+
 import {loadSchema} from '../loaders/schema';
 import {loadDocuments} from '../loaders/documents';
 import {Renderer, ConsoleRenderer, renderInvalidDocument} from '../render';
-import {validate as validateDocuments} from '../../validate';
 
 export async function validate(
   documentsPointer: string,
diff --git a/src/cli.ts b/packages/cli/src/index.ts
similarity index 84%
rename from src/cli.ts
rename to packages/cli/src/index.ts
index 220c45fe..abb5dfe2 100644
--- a/src/cli.ts
+++ b/packages/cli/src/index.ts
@@ -2,12 +2,12 @@
 
 import * as commander from 'commander';
 
-import {diff} from './cli/commands/diff';
-import {validate} from './cli/commands/validate';
-import {similar} from './cli/commands/similar';
-import {serve} from './cli/commands/serve';
-import {coverage} from './cli/commands/coverage';
-import {normalizeOptions} from './cli/utils/options';
+import {diff} from './commands/diff';
+import {validate} from './commands/validate';
+import {similar} from './commands/similar';
+import {serve} from './commands/serve';
+import {coverage} from './commands/coverage';
+import {normalizeOptions} from './utils/options';
 
 commander.option('-r, --require <s...>', 'Require modules');
 
diff --git a/src/cli/loaders/documents/from-glob-files.ts b/packages/cli/src/loaders/documents/from-glob-files.ts
similarity index 100%
rename from src/cli/loaders/documents/from-glob-files.ts
rename to packages/cli/src/loaders/documents/from-glob-files.ts
diff --git a/src/cli/loaders/documents/index.ts b/packages/cli/src/loaders/documents/index.ts
similarity index 100%
rename from src/cli/loaders/documents/index.ts
rename to packages/cli/src/loaders/documents/index.ts
diff --git a/src/cli/loaders/documents/loader.ts b/packages/cli/src/loaders/documents/loader.ts
similarity index 100%
rename from src/cli/loaders/documents/loader.ts
rename to packages/cli/src/loaders/documents/loader.ts
diff --git a/src/cli/loaders/schema/from-graphql-file.ts b/packages/cli/src/loaders/schema/from-graphql-file.ts
similarity index 84%
rename from src/cli/loaders/schema/from-graphql-file.ts
rename to packages/cli/src/loaders/schema/from-graphql-file.ts
index 06758150..96222d16 100644
--- a/src/cli/loaders/schema/from-graphql-file.ts
+++ b/packages/cli/src/loaders/schema/from-graphql-file.ts
@@ -2,8 +2,8 @@ import {parse, buildASTSchema} from 'graphql';
 import {existsSync, readFileSync} from 'fs';
 
 import {SchemaHandler} from './loader';
-import {stripBOM} from '../../../utils/string';
-import {ensureAbsolute} from '../../../utils/fs';
+import {stripBOM} from '../../utils/string';
+import {ensureAbsolute} from '../../utils/fs';
 
 function isGraphQLFile(pointer: string): boolean {
   return /\.(graphql|gql|graphqls)$/i.test(pointer);
@@ -11,7 +11,7 @@ function isGraphQLFile(pointer: string): boolean {
 
 export const fromGraphQLFile: SchemaHandler = function fromUrl(pointer) {
   if (isGraphQLFile(pointer)) {
-    const fullPath = ensureAbsolute(pointer)
+    const fullPath = ensureAbsolute(pointer);
     if (existsSync(fullPath)) {
       return async function load() {
         if (existsSync(fullPath)) {
diff --git a/src/cli/loaders/schema/from-json-file.ts b/packages/cli/src/loaders/schema/from-json-file.ts
similarity index 91%
rename from src/cli/loaders/schema/from-json-file.ts
rename to packages/cli/src/loaders/schema/from-json-file.ts
index c41ea43c..038f06fc 100644
--- a/src/cli/loaders/schema/from-json-file.ts
+++ b/packages/cli/src/loaders/schema/from-json-file.ts
@@ -2,8 +2,8 @@ import {buildClientSchema} from 'graphql';
 import {existsSync, readFileSync} from 'fs';
 
 import {SchemaHandler} from './loader';
-import {parseBOM} from '../../../utils/string';
-import {ensureAbsolute} from '../../../utils/fs';
+import {parseBOM} from '../../utils/string';
+import {ensureAbsolute} from '../../utils/fs';
 
 function isJSONFile(pointer: string): boolean {
   return /\.json$/i.test(pointer);
diff --git a/src/cli/loaders/schema/from-url.ts b/packages/cli/src/loaders/schema/from-url.ts
similarity index 100%
rename from src/cli/loaders/schema/from-url.ts
rename to packages/cli/src/loaders/schema/from-url.ts
diff --git a/src/cli/loaders/schema/index.ts b/packages/cli/src/loaders/schema/index.ts
similarity index 100%
rename from src/cli/loaders/schema/index.ts
rename to packages/cli/src/loaders/schema/index.ts
diff --git a/src/cli/loaders/schema/loader.ts b/packages/cli/src/loaders/schema/loader.ts
similarity index 100%
rename from src/cli/loaders/schema/loader.ts
rename to packages/cli/src/loaders/schema/loader.ts
diff --git a/src/cli/render.ts b/packages/cli/src/render.ts
similarity index 92%
rename from src/cli/render.ts
rename to packages/cli/src/render.ts
index 82423d60..13213497 100644
--- a/src/cli/render.ts
+++ b/packages/cli/src/render.ts
@@ -1,11 +1,13 @@
 import * as logSymbols from 'log-symbols';
 import chalk from 'chalk';
 import indent = require('indent-string');
-
-import {Change, CriticalityLevel} from '../diff/changes/change';
-import {InvalidDocument} from '../validate';
-import {getTypePrefix} from '../utils/graphql';
-import {SchemaCoverage} from '../coverage';
+import {
+  Change,
+  CriticalityLevel,
+  InvalidDocument,
+  SchemaCoverage,
+  getTypePrefix,
+} from '@graphql-inspector/core';
 
 export function getSymbol(level: CriticalityLevel): string {
   const symbols = {
diff --git a/packages/cli/src/typings.d.ts b/packages/cli/src/typings.d.ts
new file mode 100644
index 00000000..51759c73
--- /dev/null
+++ b/packages/cli/src/typings.d.ts
@@ -0,0 +1,7 @@
+declare module 'is-valid-path' {
+  namespace isValidPath {
+
+  }
+  function isValidPath(val: string): boolean;
+  export = isValidPath;
+}
diff --git a/src/utils/fs.ts b/packages/cli/src/utils/fs.ts
similarity index 55%
rename from src/utils/fs.ts
rename to packages/cli/src/utils/fs.ts
index 70e35fb3..32b1160d 100644
--- a/src/utils/fs.ts
+++ b/packages/cli/src/utils/fs.ts
@@ -1,5 +1,8 @@
 import {isAbsolute, resolve} from 'path';
 
-export function ensureAbsolute(filepath: string, basepath: string = process.cwd()) {
+export function ensureAbsolute(
+  filepath: string,
+  basepath: string = process.cwd(),
+) {
   return isAbsolute(filepath) ? filepath : resolve(basepath, filepath);
 }
diff --git a/src/cli/utils/options.ts b/packages/cli/src/utils/options.ts
similarity index 88%
rename from src/cli/utils/options.ts
rename to packages/cli/src/utils/options.ts
index 0c324b0c..836bcb61 100644
--- a/src/cli/utils/options.ts
+++ b/packages/cli/src/utils/options.ts
@@ -1,5 +1,5 @@
 import * as isValidPath from 'is-valid-path';
-import {ensureAbsolute} from '../../utils/fs';
+import {ensureAbsolute} from './fs';
 
 export function pipe(...middlewares: any[]) {
   return (value: any) => {
@@ -35,5 +35,8 @@ function normalizeRequire(options: any) {
 }
 
 export function normalizeOptions(options: any) {
-  return pipe(normalizeRequire, useRequire)(options);
+  return pipe(
+    normalizeRequire,
+    useRequire,
+  )(options);
 }
diff --git a/packages/cli/src/utils/string.ts b/packages/cli/src/utils/string.ts
new file mode 100644
index 00000000..fc422456
--- /dev/null
+++ b/packages/cli/src/utils/string.ts
@@ -0,0 +1,15 @@
+export function stripBOM(content: string) {
+  content = content.toString();
+  // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
+  // because the buffer-to-string conversion in `fs.readFileSync()`
+  // translates it to FEFF, the UTF-16 BOM.
+  if (content.charCodeAt(0) === 0xfeff) {
+    content = content.slice(1);
+  }
+
+  return content;
+}
+
+export function parseBOM(content: string) {
+  return JSON.parse(stripBOM(content));
+}
diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json
new file mode 100644
index 00000000..0f57ba05
--- /dev/null
+++ b/packages/cli/tsconfig.json
@@ -0,0 +1,21 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "module": "commonjs",
+    "declaration": true,
+    "sourceMap": true,
+    "outDir": "./dist",
+    "rootDir": "./src",
+
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+
+    "moduleResolution": "node",
+    "allowSyntheticDefaultImports": true,
+    "baseUrl": "./",
+    "types": ["node"],
+    "lib": ["es2015", "esnext.asynciterable", "dom"]
+  },
+  "files": ["src/typings.d.ts", "src/index.ts"]
+}
diff --git a/packages/core/.npmignore b/packages/core/.npmignore
new file mode 100644
index 00000000..fd1ffd65
--- /dev/null
+++ b/packages/core/.npmignore
@@ -0,0 +1,5 @@
+__tests__/
+src/
+jest.config.js
+tsconfig.json
+tsconfig.test.json
diff --git a/packages/core/.npmrc b/packages/core/.npmrc
new file mode 100644
index 00000000..449691b7
--- /dev/null
+++ b/packages/core/.npmrc
@@ -0,0 +1,1 @@
+save-exact=true
\ No newline at end of file
diff --git a/packages/core/LICENSE b/packages/core/LICENSE
new file mode 100644
index 00000000..af048480
--- /dev/null
+++ b/packages/core/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Kamil Kisiela
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/core/README.md b/packages/core/README.md
new file mode 100644
index 00000000..1c1c43b5
--- /dev/null
+++ b/packages/core/README.md
@@ -0,0 +1,55 @@
+# GraphQL Inspector
+
+[![CircleCI](https://circleci.com/gh/kamilkisiela/graphql-inspector.svg?style=shield&circle-token=d1cd06aba321ee2b7bf8bd2041104643639463b0)](https://circleci.com/gh/kamilkisiela/graphql-inspector)
+[![npm version](https://badge.fury.io/js/@graphql-inspector/core.svg)](https://npmjs.com/package/@graphql-inspector/core)
+
+**GraphQL Inspector** ouputs a list of changes between two GraphQL schemas. Every change is precisely explained and marked as breaking, non-breaking or dangerous.
+It helps you validate documents and fragments against a schema and even find similar or duplicated types.
+
+## Features
+
+Major features:
+
+- **Compares schemas**
+- **Finds breaking or dangerous changes**
+- **Validates documents against a schema**
+- **Finds similar / duplicated types**
+- **Schema coverage based on documents**
+- **Serves a GraphQL server with faked data and GraphQL Playground**
+
+GraphQL Inspector has a **CLI** and also a **programatic API**, so you can use it however you want to and even build tools on top of it.
+
+## Installation
+
+```bash
+yarn add @graphql-inspector/core
+```
+
+## Examples
+
+```typescript
+import {
+  diff,
+  validate,
+  similar,
+  coverage,
+  Change,
+  InvalidDocument,
+  SimilarMap,
+  SchemaCoverage,
+} from '@graphql-inspector/core';
+
+// diff
+const changes: Change[] = diff(schemaA, schemaB);
+// validate
+const invalid: InvalidDocument[] = validate(documentsGlob, schema);
+// similar
+const similar: SimilarMap = similar(schema, typename, threshold);
+// coverage
+const schemaCoverage: SchemaCoverage = coverage(schema, documents);
+// ...
+```
+
+## License
+
+[MIT](https://github.com/kamilkisiela/graphql-inspector/blob/master/LICENSE) © Kamil Kisiela
diff --git a/__tests__/coverage/coverage.ts b/packages/core/__tests__/coverage/coverage.ts
similarity index 100%
rename from __tests__/coverage/coverage.ts
rename to packages/core/__tests__/coverage/coverage.ts
diff --git a/__tests__/diff/enum.ts b/packages/core/__tests__/diff/enum.ts
similarity index 100%
rename from __tests__/diff/enum.ts
rename to packages/core/__tests__/diff/enum.ts
diff --git a/__tests__/diff/schema.ts b/packages/core/__tests__/diff/schema.ts
similarity index 100%
rename from __tests__/diff/schema.ts
rename to packages/core/__tests__/diff/schema.ts
diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js
new file mode 100644
index 00000000..f8cd7ace
--- /dev/null
+++ b/packages/core/jest.config.js
@@ -0,0 +1,31 @@
+// For a detailed explanation regarding each configuration property, visit:
+// https://jestjs.io/docs/en/configuration.html
+
+module.exports = {
+  // Automatically clear mock calls and instances between every test
+  clearMocks: true,
+
+  // The directory where Jest should output its coverage files
+  coverageDirectory: 'coverage',
+
+  // A set of global variables that need to be available in all test environments
+  globals: {
+    'ts-jest': {
+      tsConfigFile: 'tsconfig.test.json',
+    },
+  },
+
+  // An array of file extensions your modules use
+  moduleFileExtensions: ['ts', 'tsx', 'js'],
+
+  // The test environment that will be used for testing
+  testEnvironment: 'node',
+
+  // The glob patterns Jest uses to detect test files
+  testMatch: ['**/__tests__/**/*.+(ts|tsx|js)'],
+
+  // A map from regular expressions to paths to transformers
+  transform: {
+    '^.+\\.(ts|tsx)$': 'ts-jest',
+  },
+};
diff --git a/packages/core/package.json b/packages/core/package.json
new file mode 100644
index 00000000..45bd69fd
--- /dev/null
+++ b/packages/core/package.json
@@ -0,0 +1,41 @@
+{
+  "name": "@graphql-inspector/core",
+  "version": "0.6.0-alpha.2",
+  "description": "Tooling for GraphQL. Compare GraphQL Schemas, check documents, find breaking changes, find similar types.",
+  "keywords": [
+    "graphql",
+    "graphql-inspector",
+    "tools"
+  ],
+  "sideEffects": false,
+  "main": "dist/index.js",
+  "author": {
+    "name": "Kamil Kisiela",
+    "email": "kamil.kisiela@gmail.com",
+    "url": "https://github.com/kamilkisiela"
+  },
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "kamilkisiela/graphql-inspector"
+  },
+  "scripts": {
+    "build": "tsc",
+    "test": "jest",
+    "clean": "rm -rf dist/",
+    "prebuild": "yarn clean",
+    "prepublishOnly": "yarn build"
+  },
+  "peerDependencies": {
+    "graphql": "^0.13.0 || ^14.0.0"
+  },
+  "devDependencies": {
+    "@types/graphql": "14.0.3",
+    "@types/jest": "23.3.9",
+    "graphql-tag": "2.10.0",
+    "jest": "23.6.0",
+    "prettier": "1.15.2",
+    "ts-jest": "23.10.4",
+    "typescript": "3.1.6"
+  }
+}
diff --git a/src/ast/document.ts b/packages/core/src/ast/document.ts
similarity index 100%
rename from src/ast/document.ts
rename to packages/core/src/ast/document.ts
diff --git a/src/coverage/index.ts b/packages/core/src/coverage/index.ts
similarity index 100%
rename from src/coverage/index.ts
rename to packages/core/src/coverage/index.ts
diff --git a/src/coverage/output/json.ts b/packages/core/src/coverage/output/json.ts
similarity index 100%
rename from src/coverage/output/json.ts
rename to packages/core/src/coverage/output/json.ts
diff --git a/src/diff/argument.ts b/packages/core/src/diff/argument.ts
similarity index 100%
rename from src/diff/argument.ts
rename to packages/core/src/diff/argument.ts
diff --git a/src/diff/changes/argument.ts b/packages/core/src/diff/changes/argument.ts
similarity index 100%
rename from src/diff/changes/argument.ts
rename to packages/core/src/diff/changes/argument.ts
diff --git a/src/diff/changes/change.ts b/packages/core/src/diff/changes/change.ts
similarity index 100%
rename from src/diff/changes/change.ts
rename to packages/core/src/diff/changes/change.ts
diff --git a/src/diff/changes/directive.ts b/packages/core/src/diff/changes/directive.ts
similarity index 100%
rename from src/diff/changes/directive.ts
rename to packages/core/src/diff/changes/directive.ts
diff --git a/src/diff/changes/enum.ts b/packages/core/src/diff/changes/enum.ts
similarity index 100%
rename from src/diff/changes/enum.ts
rename to packages/core/src/diff/changes/enum.ts
diff --git a/src/diff/changes/field.ts b/packages/core/src/diff/changes/field.ts
similarity index 100%
rename from src/diff/changes/field.ts
rename to packages/core/src/diff/changes/field.ts
diff --git a/src/diff/changes/input.ts b/packages/core/src/diff/changes/input.ts
similarity index 100%
rename from src/diff/changes/input.ts
rename to packages/core/src/diff/changes/input.ts
diff --git a/src/diff/changes/object.ts b/packages/core/src/diff/changes/object.ts
similarity index 100%
rename from src/diff/changes/object.ts
rename to packages/core/src/diff/changes/object.ts
diff --git a/src/diff/changes/schema.ts b/packages/core/src/diff/changes/schema.ts
similarity index 100%
rename from src/diff/changes/schema.ts
rename to packages/core/src/diff/changes/schema.ts
diff --git a/src/diff/changes/type.ts b/packages/core/src/diff/changes/type.ts
similarity index 100%
rename from src/diff/changes/type.ts
rename to packages/core/src/diff/changes/type.ts
diff --git a/src/diff/changes/union.ts b/packages/core/src/diff/changes/union.ts
similarity index 100%
rename from src/diff/changes/union.ts
rename to packages/core/src/diff/changes/union.ts
diff --git a/src/diff/directive.ts b/packages/core/src/diff/directive.ts
similarity index 100%
rename from src/diff/directive.ts
rename to packages/core/src/diff/directive.ts
diff --git a/src/diff/enum.ts b/packages/core/src/diff/enum.ts
similarity index 100%
rename from src/diff/enum.ts
rename to packages/core/src/diff/enum.ts
diff --git a/src/diff/field.ts b/packages/core/src/diff/field.ts
similarity index 100%
rename from src/diff/field.ts
rename to packages/core/src/diff/field.ts
diff --git a/src/diff/input.ts b/packages/core/src/diff/input.ts
similarity index 100%
rename from src/diff/input.ts
rename to packages/core/src/diff/input.ts
diff --git a/src/diff/interface.ts b/packages/core/src/diff/interface.ts
similarity index 100%
rename from src/diff/interface.ts
rename to packages/core/src/diff/interface.ts
diff --git a/src/diff/object.ts b/packages/core/src/diff/object.ts
similarity index 100%
rename from src/diff/object.ts
rename to packages/core/src/diff/object.ts
diff --git a/src/diff/schema.ts b/packages/core/src/diff/schema.ts
similarity index 100%
rename from src/diff/schema.ts
rename to packages/core/src/diff/schema.ts
diff --git a/src/diff/union.ts b/packages/core/src/diff/union.ts
similarity index 100%
rename from src/diff/union.ts
rename to packages/core/src/diff/union.ts
diff --git a/src/index.ts b/packages/core/src/index.ts
similarity index 56%
rename from src/index.ts
rename to packages/core/src/index.ts
index 94432b8f..30bc6872 100644
--- a/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,6 +1,11 @@
-export {Renderer, ConsoleRenderer} from './cli/render';
 export {diff} from './diff/schema';
 export {validate, InvalidDocument} from './validate';
 export {similar, SimilarMap} from './similar';
 export {coverage, SchemaCoverage} from './coverage';
-export {Change, CriticalityLevel, Criticality} from './diff/changes/change';
+export {
+  Change,
+  CriticalityLevel,
+  Criticality,
+  ChangeType,
+} from './diff/changes/change';
+export {getTypePrefix} from './utils/graphql';
diff --git a/src/similar/index.ts b/packages/core/src/similar/index.ts
similarity index 91%
rename from src/similar/index.ts
rename to packages/core/src/similar/index.ts
index d28c38c6..5992f039 100644
--- a/src/similar/index.ts
+++ b/packages/core/src/similar/index.ts
@@ -62,9 +62,11 @@ function similarTo(
 
   return {
     bestMatch: result.bestMatch,
-    ratings: result.ratings.filter(
-      r => r.rating >= threshold && r.target !== result.bestMatch.target,
-    ).sort((a: Rating, b: Rating) => a.rating + b.rating),
+    ratings: result.ratings
+      .filter(
+        r => r.rating >= threshold && r.target !== result.bestMatch.target,
+      )
+      .sort((a: Rating, b: Rating) => a.rating + b.rating),
   };
 }
 
diff --git a/src/utils/arrays.ts b/packages/core/src/utils/arrays.ts
similarity index 100%
rename from src/utils/arrays.ts
rename to packages/core/src/utils/arrays.ts
diff --git a/src/utils/graphql.ts b/packages/core/src/utils/graphql.ts
similarity index 100%
rename from src/utils/graphql.ts
rename to packages/core/src/utils/graphql.ts
diff --git a/src/utils/string.ts b/packages/core/src/utils/string.ts
similarity index 82%
rename from src/utils/string.ts
rename to packages/core/src/utils/string.ts
index 57762d82..81398cff 100644
--- a/src/utils/string.ts
+++ b/packages/core/src/utils/string.ts
@@ -1,19 +1,3 @@
-export function stripBOM(content: string) {
-  content = content.toString();
-  // Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
-  // because the buffer-to-string conversion in `fs.readFileSync()`
-  // translates it to FEFF, the UTF-16 BOM.
-  if (content.charCodeAt(0) === 0xfeff) {
-    content = content.slice(1);
-  }
-
-  return content;
-}
-
-export function parseBOM(content: string) {
-  return JSON.parse(stripBOM(content));
-}
-
 export interface Target {
   typeId: string;
   value: string;
diff --git a/src/validate/index.ts b/packages/core/src/validate/index.ts
similarity index 100%
rename from src/validate/index.ts
rename to packages/core/src/validate/index.ts
diff --git a/tsconfig.json b/packages/core/tsconfig.json
similarity index 70%
rename from tsconfig.json
rename to packages/core/tsconfig.json
index 852304ba..1f72f438 100644
--- a/tsconfig.json
+++ b/packages/core/tsconfig.json
@@ -15,15 +15,7 @@
     "allowSyntheticDefaultImports": true,
     "baseUrl": "./",
     "types": [],
-    "lib": [
-      "es2015",
-      "esnext.asynciterable",
-      "dom"
-    ]
+    "lib": ["es2015", "esnext.asynciterable", "dom"]
   },
-  "files": [
-    "src/typings.d.ts",
-    "src/index.ts",
-    "src/cli.ts"
-  ]
+  "files": ["src/index.ts"]
 }
diff --git a/renovate.json b/renovate.json
index 1c551603..b082d566 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,21 +1,13 @@
 {
-  "extends": [
-    "config:js-lib"
-  ],
+  "extends": ["config:js-lib"],
   "timezone": "Europe/Warsaw",
-  "schedule": [
-    "after 11pm and before 6am on every weekday"
-  ],
+  "schedule": ["after 11pm and before 6am on every weekday"],
   "prCreation": "not-pending",
   "automerge": true,
   "major": {
     "automerge": false
   },
-  "assignees": [
-    "@kamilkisiela"
-  ],
-  "reviewers": [
-    "@kamilkisiela"
-  ],
+  "assignees": ["@kamilkisiela"],
+  "reviewers": ["@kamilkisiela"],
   "enabledManagers": ["yarn"]
-}
\ No newline at end of file
+}
diff --git a/src/typings.d.ts b/src/typings.d.ts
deleted file mode 100644
index c9524934..00000000
--- a/src/typings.d.ts
+++ /dev/null
@@ -1,1 +0,0 @@
-declare module 'is-valid-path';


Test patch:
diff --git a/__tests__/assets/document.graphql b/packages/cli/__tests__/assets/document.graphql
similarity index 100%
rename from __tests__/assets/document.graphql
rename to packages/cli/__tests__/assets/document.graphql
diff --git a/__tests__/assets/new.graphql b/packages/cli/__tests__/assets/new.graphql
similarity index 100%
rename from __tests__/assets/new.graphql
rename to packages/cli/__tests__/assets/new.graphql
diff --git a/__tests__/assets/old.graphql b/packages/cli/__tests__/assets/old.graphql
similarity index 100%
rename from __tests__/assets/old.graphql
rename to packages/cli/__tests__/assets/old.graphql
diff --git a/__tests__/cli/diff.ts b/packages/cli/__tests__/diff.ts
similarity index 88%
rename from __tests__/cli/diff.ts
rename to packages/cli/__tests__/diff.ts
index 5d899f8f..ac1100f4 100644
--- a/__tests__/cli/diff.ts
+++ b/packages/cli/__tests__/diff.ts
@@ -1,14 +1,14 @@
-import {diff} from '../../src/cli/commands/diff';
-import {ConsoleRenderer} from '../../src/cli/render';
+import {diff} from '../src/commands/diff';
+import {ConsoleRenderer} from '../src/render';
 
-const oldSchema = '../assets/old.graphql';
-const newSchema = '../assets/new.graphql';
+const oldSchema = './assets/old.graphql';
+const newSchema = './assets/new.graphql';
 
 function hasMessage(msg: string) {
   return (args: string[]) => args.join('').indexOf(msg) !== -1;
 }
 
-describe('cli/diff', () => {
+describe('diff', () => {
   const renderer = new ConsoleRenderer();
   let spyProcessExit: jest.SpyInstance;
   let spyProcessCwd: jest.SpyInstance;
diff --git a/__tests__/cli/render.ts b/packages/cli/__tests__/render.ts
similarity index 92%
rename from __tests__/cli/render.ts
rename to packages/cli/__tests__/render.ts
index d41ff42f..dbc39f41 100644
--- a/__tests__/cli/render.ts
+++ b/packages/cli/__tests__/render.ts
@@ -1,6 +1,6 @@
 import chalk from 'chalk';
-import {renderChange, getSymbol} from '../../src/cli/render';
-import {Change, CriticalityLevel, ChangeType} from '../../src/diff/changes/change';
+import {Change, CriticalityLevel, ChangeType} from '@graphql-inspector/core';
+import {renderChange, getSymbol} from '../src/render';
 
 test('render dangerous', () => {
   const change: Change = {
diff --git a/__tests__/cli/validate.ts b/packages/cli/__tests__/validate.ts
similarity index 88%
rename from __tests__/cli/validate.ts
rename to packages/cli/__tests__/validate.ts
index 3b0dac04..00ba6158 100644
--- a/__tests__/cli/validate.ts
+++ b/packages/cli/__tests__/validate.ts
@@ -1,5 +1,5 @@
-import {validate} from '../../src/cli/commands/validate';
-import {ConsoleRenderer, bolderize} from '../../src/cli/render';
+import {validate} from '../src/commands/validate';
+import {ConsoleRenderer, bolderize} from '../src/render';
 
 const schema = './__tests__/assets/old.graphql';
 const documents = './__tests__/assets/document.graphql';
@@ -8,7 +8,7 @@ function hasMessage(msg: string) {
   return (args: string[]) => args.join('').indexOf(msg) !== -1;
 }
 
-describe('cli/validate', () => {
+describe('validate', () => {
   const renderer = new ConsoleRenderer();
   let spyProcessExit: jest.SpyInstance;
   let spyEmit: jest.SpyInstance;
@@ -27,7 +27,7 @@ describe('cli/validate', () => {
   test('should load graphql files', async () => {
     await validate(documents, schema, {
       renderer,
-      require: []
+      require: [],
     });
 
     expect(
diff --git a/packages/cli/tsconfig.test.json b/packages/cli/tsconfig.test.json
new file mode 100644
index 00000000..eb6cdacb
--- /dev/null
+++ b/packages/cli/tsconfig.test.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "types": ["jest"]
+  },
+  "include": ["src/typings.d.ts", "__tests__/**/*.ts"]
+}
diff --git a/packages/core/tsconfig.test.json b/packages/core/tsconfig.test.json
new file mode 100644
index 00000000..969de871
--- /dev/null
+++ b/packages/core/tsconfig.test.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "types": ["jest"]
+  },
+  "include": ["__tests__/**/*.ts"]
+}
diff --git a/tsconfig.test.json b/tsconfig.test.json
deleted file mode 100644
index 2b2913a0..00000000
--- a/tsconfig.test.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "compilerOptions": {
-    "types": [
-      "jest"
-    ]
-  },
-  "include": [
-    "src/typings.d.ts",
-    "__tests__/**/*.ts",
-  ]
-}