Skip to content

Commit

Permalink
Make it independent from graphql-tools
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilkisiela committed Apr 6, 2020
1 parent f20a46b commit 6d021cc
Show file tree
Hide file tree
Showing 103 changed files with 5,855 additions and 417 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/main.yml
Expand Up @@ -24,6 +24,7 @@ jobs:
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
name: Yarn Cache
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
Expand Down Expand Up @@ -67,11 +68,14 @@ jobs:
- name: Use Node ${{matrix.node_version}}
uses: actions/setup-node@master
with:
version: ${{ matrix.node_version }}
node-version: ${{ matrix.node_version }}
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
if: matrix.os == 'ubuntu-latest'
- name: Yarn Cache
uses: actions/cache@v1
if: matrix.os == 'ubuntu-latest'
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
Expand Down
16 changes: 3 additions & 13 deletions jest.config.js
Expand Up @@ -6,20 +6,10 @@ module.exports = {
'ts-jest': {
diagnostics: false,
tsConfig: {
module: 'commonjs'
}
module: 'commonjs',
},
},
},
reporters: [
'default',
[
'jest-junit',
{
classNameTemplate: '{classname}',
titleTemplate: '{title}',
addFileAttribute: 'true',
},
],
],
reporters: ['default'],
modulePathIgnorePatterns: ['<rootDir>/dist'],
};
9 changes: 7 additions & 2 deletions package.json
Expand Up @@ -32,13 +32,18 @@
]
},
"devDependencies": {
"@types/jest": "25.1.4",
"bob-the-bundler": "0.3.4",
"graphql": "14.6.0",
"husky": "4.2.3",
"jest": "25.2.4",
"lerna": "3.20.2",
"lint-staged": "10.1.1",
"prettier": "2.0.2",
"typescript": "3.8.3",
"tslint": "6.1.0"
"rimraf": "3.0.2",
"tslint": "6.1.0",
"ts-jest": "25.3.0",
"typescript": "3.8.3"
},
"workspaces": [
"packages/*",
Expand Down
15 changes: 5 additions & 10 deletions packages/common/package.json
Expand Up @@ -27,21 +27,16 @@
"input": "./src/index.ts"
},
"devDependencies": {
"@ardatan/bob": "0.2.7",
"@types/aggregate-error": "1.0.1",
"@types/jest": "25.1.4",
"@types/lodash": "4.14.149",
"graphql": "14.6.0",
"graphql-tools-fork": "9.0.1",
"jest": "25.2.4",
"ts-jest": "25.3.0",
"typescript": "3.8.3"
"@types/lodash.get": "4.4.6",
"@types/lodash.set": "4.3.6"
},
"dependencies": {
"@graphql-toolkit/types": "0.9.12",
"aggregate-error": "3.0.1",
"camel-case": "4.1.1",
"graphql-tools-fork": "9.0.1",
"lodash": "4.17.15"
"lodash.get": "4.4.2",
"lodash.set": "4.3.2"
},
"publishConfig": {
"access": "public",
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/extract-resolvers-from-schema.ts
Expand Up @@ -9,8 +9,8 @@ import {
isEnumType,
isUnionType,
} from 'graphql';
import { IResolvers } from 'graphql-tools-fork';
import { extractFieldResolversFromObjectType } from './extract-field-resolvers-from-object-type';
import { IResolvers } from '@graphql-toolkit/types';

export interface ExtractResolversFromSchemaOptions {
selectedTypeDefs?: DocumentNode;
Expand Down
10 changes: 7 additions & 3 deletions packages/common/src/index.ts
@@ -1,14 +1,11 @@
export * from './loaders';
export * from './helpers';
export * from './debug-log';
export * from './extract-field-resolvers-from-object-type';
export * from './extract-resolvers-from-schema';
export * from './fix-windows-path';
export * from './flatten-array';
export * from './get-directives';
export * from './get-fields-with-directives';
export * from './get-implementing-types';
export * from './get-schema-directive-from-directive-resolver';
export * from './print-schema-with-directives';
export * from './get-fields-with-directives';
export * from './validate-documents';
Expand All @@ -19,3 +16,10 @@ export * from './parse-graphql-sdl';
export * from './get-user-types-from-schema';
export * from './create-schema-definition';
export * from './build-operation-for-field';
export * from './schema-error';
export * from './iterate';
export * from './merge';
export * from './stub';
export * from './transport-input';
export * from './extract-field-resolvers-from-object-type';
export * from './extract-resolvers-from-schema';
87 changes: 87 additions & 0 deletions packages/common/src/iterate.ts
@@ -0,0 +1,87 @@
import { getNamedType, GraphQLSchema, isObjectType, isInputObjectType, GraphQLField, GraphQLInputType } from 'graphql';

export type IndexedObject<V> = { [key: string]: V } | ReadonlyArray<V>;
export type IFieldIteratorFn = (fieldDef: GraphQLField<any, any>, typeName: string, fieldName: string) => void;
export type IDefaultValueIteratorFn = (type: GraphQLInputType, value: any) => void;

export function forEachField(schema: GraphQLSchema, fn: IFieldIteratorFn): void {
const typeMap = schema.getTypeMap();
Object.keys(typeMap).forEach((typeName) => {
const type = typeMap[typeName];

// TODO: maybe have an option to include these?
if (!getNamedType(type).name.startsWith('__') && isObjectType(type)) {
const fields = type.getFields();
Object.keys(fields).forEach((fieldName) => {
const field = fields[fieldName];
fn(field, typeName, fieldName);
});
}
});
}

export function forEachDefaultValue(schema: GraphQLSchema, fn: IDefaultValueIteratorFn): void {
const typeMap = schema.getTypeMap();
Object.keys(typeMap).forEach((typeName) => {
const type = typeMap[typeName];

if (!getNamedType(type).name.startsWith('__')) {
if (isObjectType(type)) {
const fields = type.getFields();
Object.keys(fields).forEach((fieldName) => {
const field = fields[fieldName];

field.args.forEach((arg) => {
arg.defaultValue = fn(arg.type, arg.defaultValue);
});
});
} else if (isInputObjectType(type)) {
const fields = type.getFields();
Object.keys(fields).forEach((fieldName) => {
const field = fields[fieldName];
field.defaultValue = fn(field.type, field.defaultValue);
});
}
}
});
}

// A more powerful version of each that has the ability to replace or remove
// array or object keys.
export function updateEachKey<V>(
arrayOrObject: IndexedObject<V>,
// The callback can return nothing to leave the key untouched, null to remove
// the key from the array or object, or a non-null V to replace the value.
updater: (value: V, key: string) => void | null | V
) {
let deletedCount = 0;

Object.keys(arrayOrObject).forEach((key) => {
const result = updater(arrayOrObject[key], key);

if (typeof result === 'undefined') {
return;
}

if (result === null) {
delete arrayOrObject[key];
deletedCount++;
return;
}

arrayOrObject[key] = result;
});

if (deletedCount > 0 && Array.isArray(arrayOrObject)) {
// Remove any holes from the array due to deleted elements.
arrayOrObject.splice(0).forEach((elem) => {
arrayOrObject.push(elem);
});
}
}

export function each<V>(arrayOrObject: IndexedObject<V>, callback: (value: V, key: string) => void) {
Object.keys(arrayOrObject).forEach((key) => {
callback(arrayOrObject[key], key);
});
}
25 changes: 25 additions & 0 deletions packages/common/src/merge.ts
@@ -0,0 +1,25 @@
export function mergeDeep(target: any, ...sources: any): any {
const output = {
...target,
};
sources.forEach((source: any) => {
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach((key) => {
if (isObject(source[key])) {
if (!(key in target)) {
Object.assign(output, { [key]: source[key] });
} else {
output[key] = mergeDeep(target[key], source[key]);
}
} else {
Object.assign(output, { [key]: source[key] });
}
});
}
});
return output;
}

function isObject(item: any): boolean {
return item && typeof item === 'object' && !Array.isArray(item);
}
5 changes: 3 additions & 2 deletions packages/common/src/resolvers-composition.ts
@@ -1,7 +1,8 @@
import { IResolvers, IFieldResolver } from 'graphql-tools-fork';
import { IResolvers, IFieldResolver } from '@graphql-toolkit/types';
import { chainFunctions, asArray } from './helpers';
import { flattenArray } from './flatten-array';
import { get, set } from 'lodash';
import get from 'lodash.get';
import set from 'lodash.set';
import { isScalarType } from 'graphql';

export type ResolversComposition<Resolver extends IFieldResolver<any, any> = IFieldResolver<any, any>> = (
Expand Down
11 changes: 11 additions & 0 deletions packages/common/src/schema-error.ts
@@ -0,0 +1,11 @@
// @schemaDefinition: A GraphQL type schema in shorthand
// @resolvers: Definitions for resolvers to be merged with schema
export class SchemaError extends Error {
public message: string;

constructor(message: string) {
super(message);
this.message = message;
Error.captureStackTrace(this, this.constructor);
}
}
64 changes: 64 additions & 0 deletions packages/common/src/stub.ts
@@ -0,0 +1,64 @@
import {
GraphQLObjectType,
GraphQLInterfaceType,
GraphQLInputObjectType,
GraphQLString,
GraphQLNamedType,
GraphQLInt,
GraphQLFloat,
GraphQLBoolean,
GraphQLID,
isObjectType,
isInterfaceType,
isInputObjectType,
} from 'graphql';

export function createNamedStub(
name: string,
type: 'object' | 'interface' | 'input'
): GraphQLObjectType | GraphQLInputObjectType | GraphQLInterfaceType {
let constructor: any;
if (type === 'object') {
constructor = GraphQLObjectType;
} else if (type === 'interface') {
constructor = GraphQLInterfaceType;
} else {
constructor = GraphQLInputObjectType;
}

return new constructor({
name,
fields: {
__fake: {
type: GraphQLString,
},
},
});
}

export function isStub(type: GraphQLNamedType): boolean {
if (isObjectType(type) || isInterfaceType(type) || isInputObjectType(type)) {
const fields = type.getFields();
const fieldNames = Object.keys(fields);
return fieldNames.length === 1 && fields[fieldNames[0]].name === '__fake';
}

return false;
}

export function getBuiltInForStub(type: GraphQLNamedType): GraphQLNamedType {
switch (type.name) {
case GraphQLInt.name:
return GraphQLInt;
case GraphQLFloat.name:
return GraphQLFloat;
case GraphQLString.name:
return GraphQLString;
case GraphQLBoolean.name:
return GraphQLBoolean;
case GraphQLID.name:
return GraphQLID;
default:
return type;
}
}
46 changes: 46 additions & 0 deletions packages/common/src/transport-input.ts
@@ -0,0 +1,46 @@
import {
GraphQLEnumType,
GraphQLInputType,
GraphQLScalarType,
getNullableType,
isLeafType,
isListType,
isInputObjectType,
} from 'graphql';

type InputValueTransformer = (type: GraphQLEnumType | GraphQLScalarType, originalValue: any) => any;

export function transformInputValue(type: GraphQLInputType, value: any, transformer: InputValueTransformer) {
if (value == null) {
return value;
}

const nullableType = getNullableType(type);

if (isLeafType(nullableType)) {
return transformer(nullableType, value);
} else if (isListType(nullableType)) {
return value.map((listMember: any) => transformInputValue(nullableType.ofType, listMember, transformer));
} else if (isInputObjectType(nullableType)) {
const fields = nullableType.getFields();
const newValue = {};
Object.keys(value).forEach((key) => {
newValue[key] = transformInputValue(fields[key].type, value[key], transformer);
});
return newValue;
}

// unreachable, no other possible return value
}

export function serializeInputValue(type: GraphQLInputType, value: any) {
return transformInputValue(type, value, (t, v) => t.serialize(v));
}

export function parseInputValue(type: GraphQLInputType, value: any) {
return transformInputValue(type, value, (t, v) => t.parseValue(v));
}

export function parseInputValueLiteral(type: GraphQLInputType, value: any) {
return transformInputValue(type, value, (t, v) => t.parseLiteral(v, {}));
}
@@ -1,5 +1,5 @@
import { extractResolversFromSchema } from '../src';
import { makeExecutableSchema } from 'graphql-tools-fork';
import { makeExecutableSchema } from '@graphql-toolkit/schema';
import gql from 'graphql-tag';

describe('extractResolversFromSchema', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/tests/get-directives.spec.ts
@@ -1,5 +1,5 @@
import { GraphQLSchema } from 'graphql';
import { makeExecutableSchema } from 'graphql-tools-fork';
import { makeExecutableSchema } from '@graphql-toolkit/schema';
import { getDirectives } from '../src';

describe('getDirectives', () => {
Expand Down

0 comments on commit 6d021cc

Please sign in to comment.