Skip to content
This repository has been archived by the owner on Sep 11, 2019. It is now read-only.

Migrate code to TypeScript #80

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"scripts": {
"prepush": "npm test",
"prebuild": "del-cli ./dist",
"build": "babel src -d dist",
"build": "tsc",
"lint": "eslint src/**/*.js",
"test": "npm run lint --silent && npm run test:unit --silent",
"test:unit": "cross-env NODE_ENV=test LOG4JS_LEVEL='OFF' jest --coverage",
Expand All @@ -28,19 +28,19 @@
"dependencies": {
"chalk": "^2.1.0",
"graphql-tools": "^2.14.1",
"lodash.merge": "^4.6.0"
"lodash.merge": "^4.6.1"
},
"peerDependencies": {
"graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0"
},
"devDependencies": {
"@types/express": "^4.11.1",
"@types/graphql": "^0.12.3",
"@types/jest": "^22.1.1",
"@types/lodash.merge": "^4.6.3",
"@types/node": "^9.4.0",
"apollo-server-express": "^1.1.2",
"babel-cli": "^6.24.1",
"babel-eslint": "^8.0.1",
"babel-jest": "^22.0.1",
"babel-plugin-inline-import": "^2.0.6",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-2": "^6.24.1",
"condition-travis-enterprise": "^1.0.0",
"cpy-cli": "^1.0.1",
"cross-env": "^5.1.1",
Expand All @@ -50,22 +50,36 @@
"eslint-config-prettier": "^2.3.0",
"eslint-plugin-import": "^2.3.0",
"eslint-plugin-prettier": "^2.1.2",
"express": "^4.16.2",
"graphql": "^0.12.3",
"husky": "^0.14.3",
"jest": "^22.0.1",
"nodemon": "^1.11.0",
"prettier": "^1.5.3",
"semantic-release": "^11.0.2",
"supertest": "^3.0.0"
"supertest": "^3.0.0",
"ts-jest": "^22.0.3",
"ts-node": "^4.1.0",
"typescript": "^2.7.1"
},
"jest": {
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "/test/.*\\.(ts|tsx)$",
"coverageReporters": [
"json",
"text",
"lcov"
],
"collectCoverageFrom": [
"{src}/**/*.js"
"{src}/**/*[^d].ts",
"!{src}/**/I*.ts"
],
"coverageThreshold": {
"global": {
Expand Down
89 changes: 65 additions & 24 deletions src/gramps.js → src/gramps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,39 @@ import mapResolvers from './lib/mapResolvers';
import rootSource from './rootSource';
import combineStitchingResolvers from './lib/combineStitchingResolvers';

import { Request, Response, NextFunction } from 'express';
import IDataSource from './lib/IDataSource';
import ILogger from './lib/ILogger';
import IStitching from './lib/IStitching';

/**
* Adds supplied options to the Apollo options object.
* @param {Object} options Apollo options for the methods used in GrAMPS
* @return {Object} Default options, extended with supplied options
* @param options Apollo options for the methods used in GrAMPS
* @return Default options, extended with supplied options
*/
const getDefaultApolloOptions = options => ({
const getDefaultApolloOptions = (options: any) => ({
makeExecutableSchema: {},
addMockFunctionsToSchema: {},
apolloServer: { ...options.graphqlExpress },
...options,
});

const checkTypeDefs = ({ schema, typeDefs, namespace }) => {
interface ICheckTypyDefsOptions {
schema?: string;
typeDefs: any;
namespace: string;
}

interface IStitchedDataSource {
stitching: IStitching;
namespace: string;
}

const checkTypeDefs = ({
schema,
typeDefs,
namespace,
}: ICheckTypyDefsOptions) => {
if (typeof schema === 'string') {
console.warn(
namespace,
Expand All @@ -38,12 +58,16 @@ const checkTypeDefs = ({ schema, typeDefs, namespace }) => {

/**
* Maps data sources and returns array of executable schema
* @param {Array} sources data sources to combine
* @param {Boolean} shouldMock whether or not to mock resolvers
* @param {Object} options additional apollo options
* @return {Array} list of executable schemas
* @param sources data sources to combine
* @param shouldMock whether or not to mock resolvers
* @param options additional apollo options
* @return list of executable schemas
*/
const mapSourcesToExecutableSchemas = (sources, shouldMock, options) =>
const mapSourcesToExecutableSchemas = (
sources: IDataSource[],
shouldMock: boolean,
options: any,
) =>
sources
.map(({ schema, typeDefs, resolvers, mocks, namespace }) => {
const sourceTypeDefs = checkTypeDefs({ schema, typeDefs, namespace });
Expand All @@ -68,7 +92,23 @@ const mapSourcesToExecutableSchemas = (sources, shouldMock, options) =>

return executableSchema;
})
.filter(schema => schema instanceof GraphQLSchema);
.filter<GraphQLSchema>(
(schema): schema is GraphQLSchema => schema instanceof GraphQLSchema,
);

export interface IGrampsInputOptions {
dataSources?: IDataSource[];
enableMockData?: boolean;
extraContext?: (req: Request) => any;
logger?: ILogger;
apollo?: any;
}

export interface IGrampsRequest extends Request {
gramps: {
getContext: (req: Request) => any;
};
}

/**
* Combine schemas, optionally add mocks, and configure `apollo-server-express`.
Expand All @@ -94,20 +134,19 @@ const mapSourcesToExecutableSchemas = (sources, shouldMock, options) =>
* @see http://dev.apollodata.com/tools/graphql-tools/mocking.html#addMockFunctionsToSchema
* @see http://dev.apollodata.com/tools/graphql-tools/generate-schema.html#makeExecutableSchema
*
* @param {Array?} config.dataSources data sources to combine
* @param {boolean?} config.enableMockData whether to add mock resolvers
* @param {Function?} config.extraContext function to add additional context
* @param {Object?} config.logger requires `info` & `error` methods
* @param {Object?} config.apollo options for Apollo functions
* @return {Function} req => options for `graphqlExpress()`
* @param config.dataSources data sources to combine
* @param config.enableMockData whether to add mock resolvers
* @param config.extraContext function to add additional context
* @param config.logger requires `info` & `error` methods
* @param config.apollo options for Apollo functions
*/
export function prepare({
dataSources = [],
enableMockData = process.env.GRAMPS_MODE === 'mock',
extraContext = req => ({}), // eslint-disable-line no-unused-vars
extraContext = (req: Request) => ({}), // eslint-disable-line no-unused-vars
logger = console,
apollo = {},
} = {}) {
}: IGrampsInputOptions = {}) {
// Make sure all Apollo options are set properly to avoid undefined errors.
const apolloOptions = getDefaultApolloOptions(apollo);

Expand All @@ -118,14 +157,16 @@ export function prepare({
logger,
});

const allSources = [rootSource, ...sources];
const allSources: IDataSource[] = [rootSource, ...sources];
const schemas = mapSourcesToExecutableSchemas(
allSources,
enableMockData,
apolloOptions,
);

const sourcesWithStitching = sources.filter(source => source.stitching);
const sourcesWithStitching = sources.filter<IStitchedDataSource>(
(source): source is IStitchedDataSource => !!source.stitching,
);
const linkTypeDefs = sourcesWithStitching.map(
source => source.stitching.linkTypeDefs,
);
Expand All @@ -136,7 +177,7 @@ export function prepare({
resolvers,
});

const getContext = req => {
const getContext = (req: Request) => {
const extra = extraContext(req);
return sources.reduce((allContext, source) => {
const sourceContext =
Expand All @@ -154,7 +195,7 @@ export function prepare({
return {
schema,
context: getContext,
addContext: (req, res, next) => {
addContext: (req: IGrampsRequest, res: Response, next: NextFunction) => {
req.gramps = getContext(req);
next();
},
Expand All @@ -163,9 +204,9 @@ export function prepare({
};
}

export default function gramps(...args) {
export default function gramps(...args: any[]) {
const options = prepare(...args);
return req => ({
return (req?: IGrampsRequest) => ({
...options,
context: options.context(req),
});
Expand Down
File renamed without changes.
11 changes: 11 additions & 0 deletions src/lib/IDataSource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import IStitching from './IStitching';

export default interface IDataSource {
stitching?: IStitching;
schema?: string;
typeDefs?: any;
resolvers?: any;
mocks?: any;
namespace: string;
context?: any;
};
5 changes: 5 additions & 0 deletions src/lib/ILogger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default interface ILogger {
error: (message: string, ...args: any[]) => void;
info: (message: string, ...args: any[]) => void;
warn: (message: string, ...args: any[]) => void;
};
4 changes: 4 additions & 0 deletions src/lib/IStitching.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default interface IStitching {
linkTypeDefs?: any;
resolvers: any;
};
8 changes: 0 additions & 8 deletions src/lib/combineStitchingResolvers.js

This file was deleted.

10 changes: 10 additions & 0 deletions src/lib/combineStitchingResolvers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import IDataSource from './IDataSource';
import { merge } from 'lodash';
import IStitching from './IStitching';

export default (sources: { stitching: IStitching }[]) => (mergeInfo: any) => {
return merge(
{},
...sources.map(source => source.stitching.resolvers(mergeInfo)),
);
};
8 changes: 0 additions & 8 deletions src/lib/defaultLogger.js

This file was deleted.

8 changes: 8 additions & 0 deletions src/lib/defaultLogger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* eslint-disable no-console */
const defaultLogger = {
error: (msg?: any) => console.error(msg),
info: (msg?: any) => console.info(msg),
warn: (msg?: any) => console.warn(msg)
};

export default defaultLogger;
Loading