Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Independence #529

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/main.yml
Expand Up @@ -20,11 +20,12 @@ jobs:
- name: Use Node
uses: actions/setup-node@master
with:
node-version: '13.x'
node-version: 12
- name: Get yarn cache
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 @@ -72,7 +73,8 @@ jobs:
- name: Get yarn cache
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
- uses: actions/cache@v1
- name: Yarn Cache
uses: actions/cache@v1
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/release.yml
@@ -0,0 +1,30 @@
on:
push:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10

name: Create Release

jobs:
build:
name: Create Release on GitHub
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@master
- name: Create Release
id: create_release
uses: actions/create-release@latest
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: ${{ github.ref }}
body: |
> Do you want The Guild to keep your codebase up to date and run your build on each GraphQL Toolkit commit so we will make sure not to break your app?
> Contact us here: [the-guild.dev/connected-build](http://bit.ly/connected-toolkit)
> Chat with us [on discord](http://bit.ly/guild-chat)

List of changes:
draft: false
prerelease: false
11 changes: 5 additions & 6 deletions package.json
Expand Up @@ -10,8 +10,8 @@
"prerelease": "yarn test-and-build",
"prerelease:canary": "yarn test-and-build",
"release": "lerna publish --exact --force-publish=\"*\"",
"release:canary": "lerna publish --force-publish=\"*\" --preid \"alpha-`git rev-parse --short HEAD`\" --canary --exact",
"ci:release:canary": "lerna publish --force-publish=\"*\" --preid \"alpha-`git rev-parse --short HEAD`\" --canary --exact --yes"
"release:canary": "lerna publish --contents dist --force-publish=\"*\" --preid \"alpha-`git rev-parse --short HEAD`\" --canary --exact",
"ci:release:canary": "lerna publish --contents dist --force-publish=\"*\" --preid \"alpha-`git rev-parse --short HEAD`\" --canary --exact --yes"
},
"husky": {
"hooks": {
Expand All @@ -32,20 +32,19 @@
]
},
"devDependencies": {
"@ardatan/bob": "0.2.7",
"@types/jest": "25.2.1",
"@types/lodash": "4.14.149",
"bob-the-bundler": "0.3.4",
"graphql": "15.0.0",
"graphql-tools-fork": "9.0.1",
"husky": "4.2.3",
"jest": "25.2.7",
"lerna": "3.20.2",
"lint-staged": "10.1.2",
"prettier": "2.0.2",
"rimraf": "3.0.2",
"tslint": "6.1.1",
"ts-jest": "25.3.1",
"typescript": "3.8.3",
"tslint": "6.1.1"
"typescript": "3.8.3"
},
"workspaces": [
"packages/*",
Expand Down
9 changes: 6 additions & 3 deletions packages/common/package.json
Expand Up @@ -27,13 +27,16 @@
"input": "./src/index.ts"
},
"devDependencies": {
"@types/aggregate-error": "1.0.1"
"@types/aggregate-error": "1.0.1",
"@types/lodash.get": "4.4.6",
"@types/lodash.set": "4.3.6"
},
"dependencies": {
"@graphql-toolkit/types": "0.10.2",
"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,4 +16,11 @@ 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';
export * from './types';
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, {}));
}