diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e20b710 --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +src/generated/* diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..9f45755 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,36 @@ +{ + "env": { + "es6": true, + "node": true + }, + "extends": [ + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 2018, + "sourceType": "module", + "project": "./tsconfig.json", + "tsconfigRootDir": "./" + }, + "rules": { + "indent": ["error", 2], + "max-len": ["error", 150], + "linebreak-style": ["error", "unix"], + "quotes": ["error", "single"], + "semi": ["error", "always"], + "object-curly-spacing": ["error", "always"], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/explicit-function-return-type": ["error", { + "allowExpressions": true, + "allowTypedFunctionExpressions": true, + "allowHigherOrderFunctions": true + }] + } +} diff --git a/.gitignore b/.gitignore index e1d9fa0..385ac50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ dist/ -yarn-error.log \ No newline at end of file +yarn-error.log +.idea/ +.vscode/ diff --git a/README.md b/README.md index 8cc215e..d835335 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ # nimbus-graphql A GraphQL Framework with batteries included + +# Developing + +## VSCode users + +Since `tslint` is being deprecated, we are using `eslint` to make this VSCode extension report issues on typescript files we need to add a setting. +To do that, add the following snippet on `settings.json`: +```json +{ + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ] +} +``` diff --git a/package.json b/package.json index 2845b9c..ac9d1f6 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "author": "Utilitywarehouse", "license": "ISC", "scripts": { - "build": "rm -rf ./dist && tsc -p tsconfig.json", + "build": "rm -rf ./dist && tsc --outDir ./dist -d -p ./", "format": "prettier --write \"src/**/*.ts\"", - "lint": "tslint -p tsconfig.json -c tslint.json", - "lint:fix": "tslint -p tsconfig.json -c tslint.json --fix", + "lint": "eslint 'src/**/*.ts'", + "lint:fix": "eslint 'src/**/*.ts' --fix", "test": "jest", "test:watch": "jest --watch", "test:cov": "jest --coverage", @@ -48,21 +48,26 @@ "@types/bunyan": "^1.8.5", "@types/google-protobuf": "^3.2.7", "@types/graphql": "^14.0.3", - "@types/jest": "^23.3.10", - "@types/node": "^10.7.1", + "@types/graphql-iso-date": "^3.3.3", + "@types/graphql-type-json": "^0.3.2", + "@types/jest": "^24.0.18", + "@types/lodash": "^4.14.137", + "@types/node": "^12.7.2", "@types/node-fetch": "^2.1.4", + "@types/protobufjs": "^6.0.0", "@types/supertest": "^2.0.7", "@types/uuid": "^3.4.4", + "@typescript-eslint/eslint-plugin": "^2.0.0", + "@typescript-eslint/parser": "^2.0.0", + "eslint": "^6.2.2", "glob": "^7.1.3", - "grpc-tools": "^1.6.6", + "grpc-tools": "^1.8.0", "grpc_tools_node_protoc_ts": "^2.4.2", "jest": "^23.6.0", "mockttp": "^0.12.4", - "prettier": "^1.14.2", "supertest": "^3.4.2", "ts-jest": "^23.10.5", "ts-node": "^7.0.1", - "tsconfig-paths": "^3.7.0", - "tslint": "5.11.0" + "tsconfig-paths": "^3.7.0" } } diff --git a/src/__tests__/resolver.decorator.test.ts b/src/__tests__/resolver.decorator.test.ts index ea4f2a6..781becc 100644 --- a/src/__tests__/resolver.decorator.test.ts +++ b/src/__tests__/resolver.decorator.test.ts @@ -1,22 +1,22 @@ import { After, Arg, Before, Context, Mutation, Parent, Query, Resolve, Resolver } from '../resolver.decorators'; import { ResolverRegistry } from '../resolver.registry'; import { makeExecutableSchema } from 'graphql-tools'; -import { graphql } from 'graphql'; +import { graphql, GraphQLSchema } from 'graphql'; import * as assert from 'assert'; import { NullError } from '../errors'; @Resolver('Decorator') class ResolverClass { - id(parent) { + id(parent: any): string { return parent.id + '-1'; } @Before(() => { - throw new NullError('tried to access protected field'); + throw new NullError('tried to access protected field'); }) @Query() - itsAlwaysNull() { + itsAlwaysNull(): string { return 'you\'ll never see this message'; } @@ -24,7 +24,7 @@ class ResolverClass { throw new Error('You hit before hook'); }) @Query() - beforeHook() { + beforeHook(): string { return 'You\'ll never hit this'; } @@ -32,40 +32,40 @@ class ResolverClass { throw new Error('You hit after hook'); }) @Query() - afterHook() { + afterHook(): string { return 'you\'ll never see this message'; } @Resolve('OtherType.id') - field2(parent) { + field2(parent: any): string { return parent.id + '-1'; } @Query() - decorator() { + decorator(): any { return { id: 'id-field' }; } @Query('otherQuery') - other() { + other(): any { return { id: 'id-other' }; } @Mutation() - mutation() { + mutation(): string { return 'mutated'; } @Mutation('otherMutation') - mutation2() { + mutation2(): string { return 'otherMutation'; } methodWithMappedParams( - @Parent parent, - @Context('ctx') context, - @Arg('arg') arg, - ) { + @Parent parent: any, + @Context('ctx') context: any, + @Arg('arg') arg: any, + ): string { assert(parent, 'Parent not present'); assert(context, 'Context not present'); @@ -77,7 +77,7 @@ class ResolverClass { describe.only('GraphQL Decorators', () => { - let schema; + let schema: GraphQLSchema; beforeEach(() => { const schemaSDL = ` type Decorator { diff --git a/src/config/__tests__/coercion.test.ts b/src/config/__tests__/coercion.test.ts index 3a9e25f..1557890 100644 --- a/src/config/__tests__/coercion.test.ts +++ b/src/config/__tests__/coercion.test.ts @@ -1,8 +1,8 @@ -import {StringBoolean} from '../index'; +import { StringBoolean } from '../index'; test('coercion', () => { - expect(StringBoolean('true')).toBe(true); - expect(StringBoolean('false')).toBe(false); - expect(StringBoolean('whatever')).toBe(false); - expect(StringBoolean('TRUE')).toBe(true); + expect(StringBoolean('true')).toBe(true); + expect(StringBoolean('false')).toBe(false); + expect(StringBoolean('whatever')).toBe(false); + expect(StringBoolean('TRUE')).toBe(true); }); diff --git a/src/config/__tests__/fixtures/example.default.config.ts b/src/config/__tests__/fixtures/example.default.config.ts index 4e78c00..bc9b776 100644 --- a/src/config/__tests__/fixtures/example.default.config.ts +++ b/src/config/__tests__/fixtures/example.default.config.ts @@ -1,5 +1,5 @@ export default { - test: 'default-value', - other: 'other-value', - nan: Number('az'), + test: 'default-value', + other: 'other-value', + nan: Number('az'), }; diff --git a/src/config/__tests__/fixtures/example.section.config.ts b/src/config/__tests__/fixtures/example.section.config.ts index 0571425..d9ab8fc 100644 --- a/src/config/__tests__/fixtures/example.section.config.ts +++ b/src/config/__tests__/fixtures/example.section.config.ts @@ -1,7 +1,7 @@ -import {Section} from '../../config.service'; +import { Section } from '../../config.service'; export default { - [Section]: 'test', - test: 'section-value', - nan: Number('az'), + [Section]: 'test', + test: 'section-value', + nan: Number('az'), }; diff --git a/src/config/__tests__/service.test.ts b/src/config/__tests__/service.test.ts index 6d3d6cb..d40bd1d 100644 --- a/src/config/__tests__/service.test.ts +++ b/src/config/__tests__/service.test.ts @@ -1,50 +1,50 @@ -import {Config} from '../config.service'; +import { Config } from '../config.service'; describe('config.service', () => { - let config; - - beforeAll(async () => { - config = await Config.load(__dirname, 'fixtures/*.config.ts'); - }); - - test('getting default value', () => { - expect(config.get('test')).toBe('default-value'); - }); - - test('getting section value', () => { - expect(config.section('test').get('test')).toBe('section-value'); - }); - - test('getting section value with fallback', () => { - expect(config.section('test').get('other')).toBe('other-value'); - }); - - test('exception on unknown section key', () => { - expect(() => { - config.section('test').get('n-a'); - }).toThrow('could not find requested key'); - }); - - test('exception on unknown default key', () => { - expect(() => { - config.get('n-a'); - }).toThrow('could not find requested key'); - }); - - test('exception on NaN section value (bad coercion)', () => { - expect(() => { - config.section('test').get('nan'); - }).toThrow('NaN encountered for key'); - }); - - test('exception on NAN default value (bad coercion)', () => { - expect(() => { - config.get('nan'); - }).toThrow('NaN encountered for key'); - }); - - test('reverting to default on unknown section', () => { - expect(config.section('n-a').get('test')).toBe('default-value'); - }); -}) + let config: Config; + + beforeAll(() => { + config = Config.load(__dirname, 'fixtures/*.config.ts'); + }); + + test('getting default value', () => { + expect(config.get('test')).toBe('default-value'); + }); + + test('getting section value', () => { + expect(config.section('test').get('test')).toBe('section-value'); + }); + + test('getting section value with fallback', () => { + expect(config.section('test').get('other')).toBe('other-value'); + }); + + test('exception on unknown section key', () => { + expect(() => { + config.section('test').get('n-a'); + }).toThrow('could not find requested key'); + }); + + test('exception on unknown default key', () => { + expect(() => { + config.get('n-a'); + }).toThrow('could not find requested key'); + }); + + test('exception on NaN section value (bad coercion)', () => { + expect(() => { + config.section('test').get('nan'); + }).toThrow('NaN encountered for key'); + }); + + test('exception on NAN default value (bad coercion)', () => { + expect(() => { + config.get('nan'); + }).toThrow('NaN encountered for key'); + }); + + test('reverting to default on unknown section', () => { + expect(config.section('n-a').get('test')).toBe('default-value'); + }); +}); diff --git a/src/config/config.getter.ts b/src/config/config.getter.ts index 10a0888..f54e9fd 100644 --- a/src/config/config.getter.ts +++ b/src/config/config.getter.ts @@ -1,32 +1,35 @@ -import {ConfigProvider} from './config.provider'; -import {ConfigContainer} from './config.container'; +import { ConfigProvider } from './config.provider'; +import { ConfigContainer } from './config.container'; export class Getter implements ConfigProvider { - constructor( - private readonly name: string, - private readonly section: ConfigContainer = {}, - private readonly defaults: ConfigContainer = {}) { - } + constructor( + private readonly name: string, + private readonly section: ConfigContainer = {}, + private readonly defaults: ConfigContainer = {}) { + } - get(key: string): any { + get(key: string): any { - let value; + let value; - if (this.section.hasOwnProperty(key)) { - value = this.section[key]; - } + const sectionHasProperty = Object.prototype.hasOwnProperty.call(this.section, key); + const defaultsHasProperty = Object.prototype.hasOwnProperty.call(this.defaults, key); - if (!this.section.hasOwnProperty(key) && this.defaults.hasOwnProperty(key)) { - value = this.defaults[key]; - } + if (sectionHasProperty) { + value = this.section[key]; + } - if (Number.isNaN(value)) { - throw new Error(`NaN encountered for key '${key}' for section '${this.name}' in config`); - } else if (value === undefined) { - throw new Error(`could not find requested key '${key}' for section '${this.name}' in config`); - } + if (!sectionHasProperty && defaultsHasProperty) { + value = this.defaults[key]; + } - return value; + if (Number.isNaN(value)) { + throw new Error(`NaN encountered for key '${key}' for section '${this.name}' in config`); + } else if (value === undefined) { + throw new Error(`could not find requested key '${key}' for section '${this.name}' in config`); } + return value; + } + } diff --git a/src/config/config.service.ts b/src/config/config.service.ts index 4270f21..ca4fe02 100644 --- a/src/config/config.service.ts +++ b/src/config/config.service.ts @@ -1,57 +1,58 @@ import * as path from 'path'; import * as glob from 'fast-glob'; -import {ConfigProvider} from './config.provider'; -import {ConfigContainer} from './config.container'; -import {Getter} from './config.getter'; +import { ConfigProvider } from './config.provider'; +import { ConfigContainer } from './config.container'; +import { Getter } from './config.getter'; export const Section = Symbol.for('config.section'); export class Config implements ConfigProvider { - constructor( + constructor( private readonly defaults: ConfigContainer, private readonly sections: {[key: string]: ConfigContainer}, - ) { + ) { - } - - section(key: string): ConfigProvider { - return new Getter(key, this.sections[key], this.defaults); - } + } - get(key: string): any { - if (this.defaults.hasOwnProperty(key)) { - const value = this.defaults[key]; + section(key: string): ConfigProvider { + return new Getter(key, this.sections[key], this.defaults); + } - if (Number.isNaN(value)) { - throw new Error(`NaN encountered for key '${key}' in config`); - } + get(key: string): any { + const defaultsHasProperty = Object.prototype.hasOwnProperty.call(this.defaults, key); + if (defaultsHasProperty) { + const value = this.defaults[key]; - return value; - } + if (Number.isNaN(value)) { + throw new Error(`NaN encountered for key '${key}' in config`); + } - throw new Error(`could not find requested key '${key}' in config`); + return value; } - static load(base, globPattern) { + throw new Error(`could not find requested key '${key}' in config`); + } - const files = glob.sync(path.resolve(base, globPattern)); + static load(base: string, globPattern: string): Config { - const configs = files.map(f => { - return require(f).default; - }); + const files = glob.sync(path.resolve(base, globPattern)); - let defaults: ConfigContainer = {}; - const sections: {[key: string]: ConfigContainer} = {}; + const configs = files.map(f => { + return require(f).default; + }); - configs.forEach(c => { - if (c[Section]) { - sections[c[Section]] = c; - } else { - defaults = {...defaults, ...c}; - } - }); + let defaults: ConfigContainer = {}; + const sections: {[key: string]: ConfigContainer} = {}; - return new Config(defaults, sections); - } + configs.forEach(c => { + if (c[Section]) { + sections[c[Section]] = c; + } else { + defaults = { ...defaults, ...c }; + } + }); + + return new Config(defaults, sections); + } } diff --git a/src/config/index.ts b/src/config/index.ts index 305dfa0..467da0b 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -1,6 +1,6 @@ export * from './config.service'; export * from './config.provider'; -export const StringBoolean = (value) => { - return value.toLowerCase().trim() === 'true'; +export const StringBoolean = (value: string): boolean => { + return value.toLowerCase().trim() === 'true'; }; diff --git a/src/errors/base.ts b/src/errors/base.ts index e9d2758..6d08bf1 100644 --- a/src/errors/base.ts +++ b/src/errors/base.ts @@ -1,28 +1,28 @@ export class BaseError extends Error { - static wrap(this: new (message?: string, previous?: Error | BaseError) => T, previous: Error, message?: string): T { - return new this(message, previous); - } + static wrap(this: new (message?: string, previous?: Error | BaseError) => T, previous: Error, message?: string): T { + return new this(message, previous); + } private correlationId: string; constructor(message?: string, readonly previous?: Error | BaseError) { - super(message); + super(message); } - setCorrelationId(correlationId: string) { - this.correlationId = correlationId; + setCorrelationId(correlationId: string): void { + this.correlationId = correlationId; } - render() { - return { - message: this.message, - correlationId: this.correlationId, - type: this.constructor.name, - previous: this.previous && (this.previous instanceof BaseError && this.previous.render() || { - type: this.previous.constructor.name, - message: this.previous.message, - }) || null, - }; + render(): any { + return { + message: this.message, + correlationId: this.correlationId, + type: this.constructor.name, + previous: this.previous && (this.previous instanceof BaseError && this.previous.render() || { + type: this.previous.constructor.name, + message: this.previous.message, + }) || null, + }; } } diff --git a/src/errors/forbidden.ts b/src/errors/forbidden.ts index d0b82e1..b191241 100644 --- a/src/errors/forbidden.ts +++ b/src/errors/forbidden.ts @@ -1,3 +1,3 @@ -import {BaseError} from './base'; +import { BaseError } from './base'; export class Forbidden extends BaseError {} diff --git a/src/errors/gql.error.ts b/src/errors/gql.error.ts index 6371fc2..15629b4 100644 --- a/src/errors/gql.error.ts +++ b/src/errors/gql.error.ts @@ -1,47 +1,47 @@ -import {BaseError} from './base'; -import {GraphQLError} from 'graphql'; +import { BaseError } from './base'; +import { GraphQLError } from 'graphql'; export class GQLError extends BaseError { - constructor(message: string, readonly type: string, readonly gql: GraphQLError, readonly previous?: BaseError | Error) { - super(message); + constructor(message: string, readonly type: string, readonly gql: GraphQLError, readonly previous?: BaseError | Error) { + super(message); + } + + static from(error: GraphQLError): GQLError { + + let err: GQLError; + + if (error.originalError instanceof BaseError) { + err = new GQLError(error.originalError.message, error.originalError.constructor.name, error, error.originalError.previous); + } else if (error.originalError) { + err = new GQLError(error.originalError.message, error.originalError.constructor.name, error); + } else { + err = new GQLError(error.message, error.constructor.name, error); } - static from(error: GraphQLError): GQLError { + if (error.extensions && error.extensions.correlationId) { + err.setCorrelationId(error.extensions.correlationId); + } - let err: GQLError; + return err; + } - if (error.originalError instanceof BaseError) { - err = new GQLError(error.originalError.message, error.originalError.constructor.name, error, error.originalError.previous); - } else if (error.originalError) { - err = new GQLError(error.originalError.message, error.originalError.constructor.name, error); - } else { - err = new GQLError(error.message, error.constructor.name, error); - } + render(): any { + const details = super.render(); + details.type = this.type; + details.locations = this.gql.locations; + details.path = this.gql.path; + details.extensions = this.gql.extensions; - if (error.extensions && error.extensions.correlationId) { - err.setCorrelationId(error.extensions.correlationId); - } + details.extensions.exception.type = this.type; + details.extensions.exception.message = this.message; - return err; + if (this.previous && this.previous instanceof BaseError) { + details.extensions.exception.previous = this.previous.render(); + } else if (this.previous && this.previous.message) { + details.extensions.exception.previous = this.previous.message; } - render() { - const details = super.render(); - details.type = this.type; - details.locations = this.gql.locations; - details.path = this.gql.path; - details.extensions = this.gql.extensions; - - details.extensions.exception.type = this.type - details.extensions.exception.message = this.message - - if (this.previous && this.previous instanceof BaseError) { - details.extensions.exception.previous = this.previous.render() - } else if (this.previous && this.previous.message) { - details.extensions.exception.previous = this.previous.message - } - - return details; - } -} \ No newline at end of file + return details; + } +} diff --git a/src/errors/index.ts b/src/errors/index.ts index 27ec871..bdcc97c 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -4,3 +4,5 @@ export * from './not_found'; export * from './forbidden'; export * from './unauthorized'; export * from './internal'; +export * from './null.error'; +export * from './gql.error'; diff --git a/src/errors/internal.ts b/src/errors/internal.ts index 39f3bb2..ec22ddd 100644 --- a/src/errors/internal.ts +++ b/src/errors/internal.ts @@ -1,4 +1,4 @@ -import {BaseError} from './base'; +import { BaseError } from './base'; export class Internal extends BaseError { diff --git a/src/errors/not_found.ts b/src/errors/not_found.ts index be6b931..ae5935d 100644 --- a/src/errors/not_found.ts +++ b/src/errors/not_found.ts @@ -1,3 +1,3 @@ -import {BaseError} from './base'; +import { BaseError } from './base'; export class NotFoundError extends BaseError {} diff --git a/src/errors/transport.ts b/src/errors/transport.ts index 9721e5a..bf8615b 100644 --- a/src/errors/transport.ts +++ b/src/errors/transport.ts @@ -1,3 +1,3 @@ -import {BaseError} from './base'; +import { BaseError } from './base'; export class TransportError extends BaseError {} diff --git a/src/errors/unauthorized.ts b/src/errors/unauthorized.ts index 75920c7..0cb660c 100644 --- a/src/errors/unauthorized.ts +++ b/src/errors/unauthorized.ts @@ -1,3 +1,3 @@ -import {BaseError} from './base'; +import { BaseError } from './base'; export class Unauthorized extends BaseError {} diff --git a/src/framework/application.ts b/src/framework/application.ts index bc8d26a..3aa6542 100644 --- a/src/framework/application.ts +++ b/src/framework/application.ts @@ -1,11 +1,11 @@ import { Container, ContainerInstance } from 'typedi'; -import {createServer as createHttpServer, Server} from 'http'; +import { createServer as createHttpServer, Server } from 'http'; import Logger = require('bunyan'); import { Module } from './module'; import { Config } from '../config'; import { LoggerFactory, Logger as LoggerToken } from '../logger'; -import { Express } from "express"; -import { createExpressApp } from "./express"; +import { Express } from 'express'; +import { createExpressApp } from './express'; /** * Application @@ -24,7 +24,7 @@ export class Application extends ContainerInstance { this.modules = []; this.containerId = containerID; this.express = createExpressApp(); - this.server = createHttpServer(this.express) + this.server = createHttpServer(this.express); } /** @@ -33,11 +33,11 @@ export class Application extends ContainerInstance { * @param modules * @param containerId */ - static async create(basePath: string, modules: Array Module>, containerId?: symbol) { + static async create(basePath: string, modules: Array Module>, containerId?: symbol): Promise { const app = new Application(basePath); - await app.loadConfig(); - await app.defaultLogger(); + app.loadConfig(); + app.defaultLogger(); await app.initModules(modules); return app; @@ -46,15 +46,15 @@ export class Application extends ContainerInstance { /** * Get config Instance */ - config() { + config(): Config { return this.get(Config); } /** * Get Logger Instance */ - logger() { - return this.get(LoggerToken); + logger(): typeof LoggerToken { + return this.get(LoggerToken) as typeof LoggerToken; } /** @@ -62,7 +62,7 @@ export class Application extends ContainerInstance { * @param handle * @param listeningListener */ - listen(handle: any, listeningListener?: Function) { + listen(handle: any, listeningListener?: () => void): Server { return this.server.listen(handle, listeningListener); } @@ -70,7 +70,7 @@ export class Application extends ContainerInstance { * Set a custom logger * @param logger */ - setLogger(logger: Logger) { + setLogger(logger: Logger): void { this.set(LoggerToken, logger); Container.set(LoggerToken, logger); } @@ -78,7 +78,7 @@ export class Application extends ContainerInstance { /** * Init all application modules */ - initModules(modules: Array Module>) { + initModules(modules: Array Module>): Promise { return modules.reduce((promise: Promise, appModule: new (app: Application) => Module) => { return promise.then(() => { const moduleInstance = new appModule(this); @@ -91,8 +91,8 @@ export class Application extends ContainerInstance { /** * Load configurations */ - private async loadConfig() { - const config = await Config.load(this.basePath, '!(node_modules)/**/*.config.!(*.d){js,ts,json}'); + private loadConfig(): Config { + const config = Config.load(this.basePath, '!(node_modules)/**/*.config.!(*.d){js,ts,json}'); Container.set({ type: Config, value: config, global: true }); return config; } @@ -100,11 +100,11 @@ export class Application extends ContainerInstance { /** * Default logger */ - private defaultLogger() { + private defaultLogger(): void { const config = Container.get(Config); - return this.setLogger(LoggerFactory.new( - config.get('log.name'), - config.get('log.level'), + this.setLogger(LoggerFactory.new( + config.get('log.name'), + config.get('log.level'), )); } } diff --git a/src/framework/express.ts b/src/framework/express.ts index b09e7f6..c67ee13 100644 --- a/src/framework/express.ts +++ b/src/framework/express.ts @@ -1,15 +1,15 @@ import * as express from 'express'; -import {Request} from 'express'; -import {v4 as uuid} from 'uuid'; +import { Request } from 'express'; +import { v4 as uuid } from 'uuid'; -export const createExpressApp = () => { +export const createExpressApp = (): express.Express => { - const app = express(); + const app = express(); - app.use((req: Request, _, next) => { - req.headers['X-Correlation-ID'] = req.headers['X-Correlation-ID'] || uuid(); - next(); - }); + app.use((req: Request, _, next) => { + req.headers['X-Correlation-ID'] = req.headers['X-Correlation-ID'] || uuid(); + next(); + }); - return app; + return app; }; diff --git a/src/framework/module.ts b/src/framework/module.ts index c2605a0..457122b 100644 --- a/src/framework/module.ts +++ b/src/framework/module.ts @@ -1,11 +1,12 @@ -import { Container } from 'typedi'; +import { Container, ObjectType } from 'typedi'; import { Application } from './application'; +import { Config } from '../config'; -export interface IModule { - register(); +export interface Module { + register(): void; } -export abstract class Module implements IModule { +export abstract class Module implements Module { app: Application; @@ -24,14 +25,14 @@ export abstract class Module implements IModule { return this as any; } - abstract register(); + // abstract register(): void; /** * Bind an abstract type to a resolved type * @param abstract * @param concrete */ - bind(abstract: any, concrete: any) { + bind(abstract: any, concrete: any): Application { if (this.app.has(concrete) || typeof concrete === 'function') { return this.app.set(abstract, this.get(concrete)); } @@ -45,7 +46,7 @@ export abstract class Module implements IModule { * @param abstract * @param concrete */ - bindIf(condition, abstract: any, concrete: any) { + bindIf(condition: boolean, abstract: any, concrete: any): any { if (condition) { return this.bind(abstract, concrete); } @@ -56,12 +57,12 @@ export abstract class Module implements IModule { * @param abstract * @param concrete */ - bindIfDev(abstract: any, concrete: any) { + bindIfDev(abstract: any, concrete: any): any { const parentClass = this.constructor as typeof Module; return this.bindIf( - parentClass.dev && this.config().get('service.isDev'), - abstract, - concrete, + parentClass.dev && this.config().get('service.isDev'), + abstract, + concrete, ); } @@ -69,7 +70,7 @@ export abstract class Module implements IModule { * Import classes into the container * @param factories */ - import(factories) { + import(factories: Function[]): void { Container.import(factories); } @@ -77,14 +78,14 @@ export abstract class Module implements IModule { * Retrieve dependency bound to the container * @param service */ - get(service) { + get(service: ObjectType): T { return this.app.get(service); } /** * Return global configuration object */ - config() { + config(): Config { return this.app.config(); } } diff --git a/src/graphql.builder.ts b/src/graphql.builder.ts index fc0672b..982cede 100644 --- a/src/graphql.builder.ts +++ b/src/graphql.builder.ts @@ -1,22 +1,21 @@ -import { GraphQLError } from "graphql"; +import { GraphQLError } from 'graphql'; import * as fs from 'fs'; -import * as merge from 'lodash.merge'; +import { merge } from 'lodash'; import { Container } from 'typedi'; import { GraphQLDate, GraphQLDateTime, GraphQLTime } from 'graphql-iso-date'; import { SubscriptionServerOptions } from 'apollo-server-core'; import * as GraphQLJSON from 'graphql-type-json'; import { GraphQLUUID } from 'graphql-custom-types'; import { ApolloServer, Config, CorsOptions } from 'apollo-server-express'; -import { Server } from 'http'; import { ResolverRegistry } from './resolver.registry'; import { ResolverInterface } from './resolver.interface'; import { ResolverToken } from './resolver.token'; import { Application } from './framework'; -import { GQLError } from "./errors/gql.error"; +import { GQLError } from './errors'; export interface GraphQLOperations { - onResponse(response: any); + onResponse(response: any): void; onError(error: GQLError): void; } @@ -26,7 +25,7 @@ export interface GraphQLContextBuilder { } const ExtensionInjectCorrelationIdToError = { - willSendResponse(o) { + willSendResponse(o: any): GraphQLError | any { const { context, graphqlResponse } = o; @@ -41,13 +40,13 @@ const ExtensionInjectCorrelationIdToError = { ext.correlationId = context.req.headers['X-Correlation-ID']; return new GraphQLError( - e.message, - e.nodes, - e.source, - e.positions, - e.path, - e.originalError, - ext, + e.message, + e.nodes, + e.source, + e.positions, + e.path, + e.originalError, + ext, ); }); @@ -67,12 +66,12 @@ export class GraphQLBuilder { this.app = container; } - metrics(operations: GraphQLOperations) { + metrics(operations: GraphQLOperations): GraphQLBuilder { this.gqlMetrics = operations; return this; } - context(graphqlContext: GraphQLContextBuilder) { + context(graphqlContext: GraphQLContextBuilder): GraphQLBuilder { this.gqlContext = graphqlContext; return this; } @@ -87,18 +86,18 @@ export class GraphQLBuilder { } { const typeDefs = this.schemaPath ? - JSON.parse(fs.readFileSync(this.schemaPath, 'utf8')) : - customConfig.typeDefs; + JSON.parse(fs.readFileSync(this.schemaPath, 'utf8')) : + customConfig.typeDefs; return merge({ typeDefs, - extensions: [() => ExtensionInjectCorrelationIdToError], - context: (args) => this.gqlContext.build(args), + extensions: [(): any => ExtensionInjectCorrelationIdToError], + context: (args: any) => this.gqlContext.build(args), // all resolvers are registered in the resolver builder, it will return the typical resolver // structure which it works out via decorators resolvers: this.app.get(ResolverRegistry).register( - ...Container.getMany(ResolverToken), + ...Container.getMany(ResolverToken), ).scalars({ JSON: GraphQLJSON, Date: GraphQLDate, @@ -114,7 +113,7 @@ export class GraphQLBuilder { return error.render(); }, tracing: true, - formatResponse: (response) => { + formatResponse: (response: any) => { if (this.gqlMetrics) { this.gqlMetrics.onResponse(response); } @@ -124,7 +123,7 @@ export class GraphQLBuilder { }, customConfig || {}); } - server(customConfig?: Config) { + server(customConfig?: Config): ApolloServer { const config = this.serverConfig(customConfig); const apollo = new ApolloServer(config); @@ -132,7 +131,7 @@ export class GraphQLBuilder { if (this.subOpts) { apollo.installSubscriptionHandlers( - this.app.server + this.app.server, ); } diff --git a/src/grpc/client.ts b/src/grpc/client.ts index 9088a7e..579ca51 100644 --- a/src/grpc/client.ts +++ b/src/grpc/client.ts @@ -1,8 +1,7 @@ -/// import * as grpc from 'grpc'; -import {Pool, PoolStatus} from './pool'; -import {CheckerReporter} from '../operational'; -import {RepositoryContext} from '../repository'; +import { Pool, PoolStatus } from './pool'; +import { CheckerReporter } from '../operational'; +import { RepositoryContext } from '../repository'; export class GrpcClient { @@ -14,54 +13,54 @@ export class GrpcClient { withContext(context: RepositoryContext): this { - const constructor = this.constructor as new (clientProvider: Client | Pool) => this; + const constructor = this.constructor as new (clientProvider: Client | Pool) => this; - const scopedInstance = new constructor(this.clientProvider); - scopedInstance.setDefaultMetadata({ - authorization: context.authToken && context.authToken.asHeader(), - correlationId: context.correlationId, - }); + const scopedInstance = new constructor(this.clientProvider); + scopedInstance.setDefaultMetadata({ + authorization: context.authToken && context.authToken.asHeader(), + correlationId: context.correlationId, + }); - return scopedInstance; + return scopedInstance; } - checkHealth(cr: CheckerReporter) { - if (this.clientProvider instanceof Pool) { + checkHealth(cr: CheckerReporter): void { + if (this.clientProvider instanceof Pool) { - switch (this.clientProvider.status) { - case PoolStatus.AllConnected: - cr.healthy('all clients connected'); - break; - case PoolStatus.SomeConnected: - cr.degraded('only some clients connected', 'check upstream pods health'); - break; - case PoolStatus.AllDisconnected: - cr.unhealthy('all clients disconnected', 'check upstream pods health or address config', 'unable to data'); - break; - } - } else { - throw new Error('connection watching on non pool grpc connections is not imlemented'); + switch (this.clientProvider.status) { + case PoolStatus.AllConnected: + cr.healthy('all clients connected'); + break; + case PoolStatus.SomeConnected: + cr.degraded('only some clients connected', 'check upstream pods health'); + break; + case PoolStatus.AllDisconnected: + cr.unhealthy('all clients disconnected', 'check upstream pods health or address config', 'unable to data'); + break; } + } else { + throw new Error('connection watching on non pool grpc connections is not imlemented'); + } } - setDefaultMetadata(data: {[key: string]: string}) { + setDefaultMetadata(data: {[key: string]: string}): void { - const md = new grpc.Metadata(); + const md = new grpc.Metadata(); - for (const key in data) { - if (data.hasOwnProperty(key) && data[key]) { - md.set(key, data[key]); - } + for (const key in data) { + if (Object.prototype.hasOwnProperty.call(data, key) && data[key]) { + md.set(key, data[key]); } + } - this.defaultMetadata = md; + this.defaultMetadata = md; } get client(): Client { - if (this.clientProvider instanceof Pool) { - return this.clientProvider.get(); - } else { - return this.clientProvider; - } + if (this.clientProvider instanceof Pool) { + return this.clientProvider.get(); + } else { + return this.clientProvider; + } } } diff --git a/src/grpc/interceptors.ts b/src/grpc/interceptors.ts index a9dbbce..166885a 100644 --- a/src/grpc/interceptors.ts +++ b/src/grpc/interceptors.ts @@ -8,7 +8,7 @@ export enum InterceptorType { BidiStreaming, } -export type InterceptorFactory = (options, nextCall) => grpc.InterceptingCall; +export type InterceptorFactory = (options: any, nextCall: Function) => grpc.InterceptingCall; export type InterceptorFactorySelector = (methodDefinition: grpc.MethodDefinition) => InterceptorFactory; @@ -18,152 +18,152 @@ export interface Interceptor { } export function interceptorChain(interceptors: Interceptor[]): InterceptorFactorySelector[] { - return interceptors.map(i => { - return (methodDefinition: grpc.MethodDefinition): InterceptorFactory => { - switch (i.type) { - case InterceptorType.Unary: - if (!methodDefinition.requestStream && !methodDefinition.responseStream) { - return i.interceptorFn; - } - break; - case InterceptorType.ClientStreaming: - if (methodDefinition.requestStream && !methodDefinition.responseStream) { - return i.interceptorFn; - } - break; - case InterceptorType.ServerStreaming: - if (!methodDefinition.requestStream && methodDefinition.responseStream) { - return i.interceptorFn; - } - break; - case InterceptorType.BidiStreaming: - if (methodDefinition.requestStream && methodDefinition.responseStream) { - return i.interceptorFn; - } - break; - } - return; - }; - }); + return interceptors.map(i => { + return (methodDefinition: grpc.MethodDefinition): InterceptorFactory => { + switch (i.type) { + case InterceptorType.Unary: + if (!methodDefinition.requestStream && !methodDefinition.responseStream) { + return i.interceptorFn; + } + break; + case InterceptorType.ClientStreaming: + if (methodDefinition.requestStream && !methodDefinition.responseStream) { + return i.interceptorFn; + } + break; + case InterceptorType.ServerStreaming: + if (!methodDefinition.requestStream && methodDefinition.responseStream) { + return i.interceptorFn; + } + break; + case InterceptorType.BidiStreaming: + if (methodDefinition.requestStream && methodDefinition.responseStream) { + return i.interceptorFn; + } + break; + } + return; + }; + }); } const grpcHistogram = new prom.Histogram({ - name: 'grpc_requests_seconds', - help: 'measures grpc request duration', - labelNames: ['status', 'service', 'method'], - buckets: [0.2, 0.5, 1, 1.5, 3, 5, 10], + name: 'grpc_requests_seconds', + help: 'measures grpc request duration', + labelNames: ['status', 'service', 'method'], + buckets: [0.2, 0.5, 1, 1.5, 3, 5, 10], }); -const statusMap = {}; +const statusMap: any = {}; -Object.keys(grpc.status).forEach(key => { - statusMap[grpc.status[key]] = key; +Object.keys(grpc.status).forEach((key: keyof typeof grpc.status) => { + statusMap[grpc.status[key]] = key; }); -export function prometheusInterceptor(options, nextCall): grpc.InterceptingCall { - return new grpc.InterceptingCall(nextCall(options), { - start(metadata, listener, next) { +export const prometheusInterceptor: InterceptorFactory = (options, nextCall) => { + return new grpc.InterceptingCall(nextCall(options), { + start(metadata, listener, next): void { - const [service, method] = options.method_definition.path.split('/').splice(1, 2); + const [service, method] = options.method_definition.path.split('/').splice(1, 2); - const labels = { - status: statusMap[grpc.status.UNKNOWN], - service, - method, - }; + const labels = { + status: statusMap[grpc.status.UNKNOWN], + service, + method, + }; - const timeRequest = grpcHistogram.startTimer(labels); + const timeRequest = grpcHistogram.startTimer(labels); - const newListener = { - onReceiveStatus(status, nextStatus) { - labels.status = statusMap[status.code]; - timeRequest(); - nextStatus(status); - }, - }; - next(metadata, newListener); + const newListener = { + onReceiveStatus(status: grpc.StatusObject, nextStatus: Function): void { + labels.status = statusMap[status.code]; + timeRequest(); + nextStatus(status); }, - }); -} + }; + next(metadata, newListener); + }, + }); +}; export function retryInterceptorFactory( - maxRetries = 1, - codeMap: grpc.status[] = [grpc.status.UNAVAILABLE, grpc.status.UNKNOWN], -): (options, nextCall) => grpc.InterceptingCall { - return (options, mainChainNext) => { - - let originMetadata; - let originMessage; - let lastReceivedMessage; - let receivedMessageCallback; - let lastReceivedStatus; - - return new grpc.InterceptingCall(mainChainNext(options), { - sendMessage(message, next) { - originMessage = message; - next(message); - }, - start(metadata, listener, next) { - - originMetadata = metadata; - - const newListener = { - onReceiveMessage(message, onReceiveNext) { - lastReceivedMessage = message; - receivedMessageCallback = onReceiveNext; - }, - onReceiveStatus(status, statusChainNext) { - - let currentRetries = 0; - - function retry() { - - if (currentRetries >= maxRetries) { - receivedMessageCallback(lastReceivedMessage); - statusChainNext(lastReceivedStatus); - return; // no more retries allowed - } - - currentRetries++; - - // trigger the interceptor chain manually for retry - - const retryCall = mainChainNext(options); - - retryCall.start(originMetadata, { - onReceiveMessage(message) { - lastReceivedMessage = message; - }, - onReceiveStatus(retryStatus) { - - lastReceivedStatus = retryStatus; - if (codeMap.includes(retryStatus.code)) { - retry(); - } else { - receivedMessageCallback(lastReceivedMessage); - statusChainNext(lastReceivedStatus); - } - }, - }); - - retryCall.sendMessage(originMessage); - retryCall.halfClose(); - } - - lastReceivedStatus = status; - - if (codeMap.includes(status.code)) { - retry(); - } else { - // no need to retry, just return what was originally cached - receivedMessageCallback(lastReceivedMessage); - statusChainNext(lastReceivedStatus); - } - }, - }; - - next(metadata, newListener); - }, - }); - }; + maxRetries = 1, + codeMap: grpc.status[] = [grpc.status.UNAVAILABLE, grpc.status.UNKNOWN], +): InterceptorFactory { + return (options, mainChainNext): grpc.InterceptingCall => { + + let originMetadata: grpc.Metadata; + let originMessage: any; + let lastReceivedMessage: any; + let receivedMessageCallback: Function; + let lastReceivedStatus: grpc.StatusObject; + + return new grpc.InterceptingCall(mainChainNext(options), { + sendMessage(message, next) { + originMessage = message; + next(message); + }, + start(metadata, listener, next) { + + originMetadata = metadata; + + const newListener: grpc.Listener = { + onReceiveMessage(message, onReceiveNext) { + lastReceivedMessage = message; + receivedMessageCallback = onReceiveNext; + }, + onReceiveStatus(status, statusChainNext) { + + let currentRetries = 0; + + function retry(): void { + + if (currentRetries >= maxRetries) { + receivedMessageCallback(lastReceivedMessage); + statusChainNext(lastReceivedStatus); + return; // no more retries allowed + } + + currentRetries++; + + // trigger the interceptor chain manually for retry + + const retryCall = mainChainNext(options); + + retryCall.start(originMetadata, { + onReceiveMessage(message: any) { + lastReceivedMessage = message; + }, + onReceiveStatus(retryStatus: grpc.StatusObject) { + + lastReceivedStatus = retryStatus; + if (codeMap.includes(retryStatus.code)) { + retry(); + } else { + receivedMessageCallback(lastReceivedMessage); + statusChainNext(lastReceivedStatus); + } + }, + }); + + retryCall.sendMessage(originMessage); + retryCall.halfClose(); + } + + lastReceivedStatus = status; + + if (codeMap.includes(status.code)) { + retry(); + } else { + // no need to retry, just return what was originally cached + receivedMessageCallback(lastReceivedMessage); + statusChainNext(lastReceivedStatus); + } + }, + }; + + next(metadata, newListener); + }, + } as grpc.Requester); + }; } diff --git a/src/grpc/options.ts b/src/grpc/options.ts index 823c8c8..bc316af 100644 --- a/src/grpc/options.ts +++ b/src/grpc/options.ts @@ -6,13 +6,13 @@ interface CallOptions { } export function options(opt: CallOptions): Partial { - const opts = { - ...opt, - }; + const opts = { + ...opt, + }; - if (opt.timeout) { - opts.deadline = new Date().setSeconds(new Date().getSeconds() + (opt.timeout / 1000)); - } + if (opt.timeout) { + opts.deadline = new Date().setSeconds(new Date().getSeconds() + (opt.timeout / 1000)); + } - return opts; + return opts; } diff --git a/src/grpc/pool.ts b/src/grpc/pool.ts index 308b247..47bdbd9 100644 --- a/src/grpc/pool.ts +++ b/src/grpc/pool.ts @@ -1,11 +1,12 @@ import * as grpc from 'grpc'; import { - interceptorChain, - InterceptorFactorySelector, - InterceptorType, - prometheusInterceptor, - retryInterceptorFactory, + interceptorChain, + InterceptorFactorySelector, + InterceptorType, + prometheusInterceptor, + retryInterceptorFactory, } from './interceptors'; +import { ObjectType } from 'typedi'; interface ClientOptions { interceptor_providers?: InterceptorFactorySelector[]; @@ -20,8 +21,8 @@ interface PoolOptions { } const defaultInterceptors = interceptorChain([ - {type: InterceptorType.Unary, interceptorFn: prometheusInterceptor}, - {type: InterceptorType.Unary, interceptorFn: retryInterceptorFactory()}, + { type: InterceptorType.Unary, interceptorFn: prometheusInterceptor }, + { type: InterceptorType.Unary, interceptorFn: retryInterceptorFactory() }, ]); export enum PoolStatus { @@ -36,61 +37,62 @@ export class Pool { status: PoolStatus = PoolStatus.AllDisconnected; constructor(clientProto: { new (...args: any[]): Client }, options: PoolOptions) { - for (let i = 1; i <= options.size; i++) { - this.clients.push(this.make(i, clientProto, options)); - } - this.provider = this.startProvider(); - this.watchConnections(); + for (let i = 1; i <= options.size; i++) { + this.clients.push(this.make(i, clientProto, options)); + } + this.provider = this.startProvider(); + this.watchConnections(); } - private watchConnections() { - - const result: boolean[] = []; + private watchConnections(): void { - this.clients.forEach((client, index) => { - const channel = grpc.getClientChannel(client); + const result: boolean[] = []; - setInterval(() => { - const connectivityState = channel.getConnectivityState(true); - switch (connectivityState) { - case grpc.connectivityState.READY: - result[index] = true; - break; - default: - result[index] = false; - } - }, 2000); - }); + this.clients.forEach((client, index) => { + const channel = grpc.getClientChannel(client); - setInterval( () => { - if (result.every(s => s === true)) { - this.status = PoolStatus.AllConnected; - } else if (result.every(s => s === false)) { - this.status = PoolStatus.AllDisconnected; - } else { - this.status = PoolStatus.SomeConnected; - } + setInterval(() => { + const connectivityState = channel.getConnectivityState(true); + switch (connectivityState) { + case grpc.connectivityState.READY: + result[index] = true; + break; + default: + result[index] = false; + } }, 2000); + }); + + setInterval( () => { + if (result.every(s => s === true)) { + this.status = PoolStatus.AllConnected; + } else if (result.every(s => s === false)) { + this.status = PoolStatus.AllDisconnected; + } else { + this.status = PoolStatus.SomeConnected; + } + }, 2000); } - private make(index, clientProto, options: PoolOptions): Client { - const grpcOptions: ClientOptions = Object.assign( - {interceptor_providers: defaultInterceptors}, - options.options, - {'connection.index': index}, - ); - return new clientProto(options.address, options.credentials, grpcOptions); + private make(index: number, clientProto: ObjectType, options: PoolOptions): Client { + const grpcOptions: ClientOptions = Object.assign( + // eslint-disable-next-line + { interceptor_providers: defaultInterceptors }, + options.options, + { 'connection.index': index }, + ); + return new clientProto(options.address, options.credentials, grpcOptions); } - private *startProvider() { - let index = 0; - while (true) { - yield this.clients[index]; - index = (index + 1) % this.clients.length; - } + private *startProvider(): IterableIterator { + let index = 0; + while (true) { + yield this.clients[index]; + index = (index + 1) % this.clients.length; + } } get(): Client { - return this.provider.next().value; + return this.provider.next().value; } } diff --git a/src/grpc/utils.ts b/src/grpc/utils.ts index 0c7e091..3c5422e 100644 --- a/src/grpc/utils.ts +++ b/src/grpc/utils.ts @@ -15,18 +15,19 @@ export type PromisedGRPCResponse = Promise<{ */ export function promisify(grpcClientCall: (callback: gRPCHandler) => Call): PromisedGRPCResponse { function handleGRPC(resolve: (data: T) => void, reject: (error: Error) => void): gRPCHandler { - return (error: grpc.ServiceError | null, response: T) => { + return (error: grpc.ServiceError | null, response: T): void => { if (error) { - return reject(TransportError.wrap(error)); + reject(TransportError.wrap(error)); } - return resolve(response); + resolve(response); }; } - return new Promise(async (enhancedResolve, enhancedReject) => { + // eslint-disable-next-line + return new Promise(async (enhancedResolve: Function, enhancedReject: Function) => { try { let call: Call; - const response = await new Promise((resolve: (data: T) => void, reject) => { + const response = await new Promise((resolve: (data: T) => void, reject): void => { call = grpcClientCall(handleGRPC(resolve, reject)); }); diff --git a/src/http/__tests__/client.test.ts b/src/http/__tests__/client.test.ts index 1563811..c251597 100644 --- a/src/http/__tests__/client.test.ts +++ b/src/http/__tests__/client.test.ts @@ -1,6 +1,6 @@ import axios from 'axios'; -import {createClient} from '../http.client'; -import {TransportError} from '../../errors'; +import { createClient } from '../http.client'; +import { TransportError } from '../../errors'; const mockRequest = jest.fn(); mockRequest.mockResolvedValue('return'); @@ -9,101 +9,103 @@ jest.mock('axios'); const mockAxios = axios as jest.Mocked; -mockAxios.create.mockReturnValue(() => ({ - request: mockRequest, -})); +mockAxios.create.mockReturnValue({ + request: mockRequest, +} as any); describe('http client', () => { - test('create adds default timeout', () => { - createClient(); - expect(mockAxios.create).toHaveBeenCalledWith({timeout: 3000}); - }); + test('create adds default timeout', () => { + createClient(); + // eslint-disable-next-line + expect(mockAxios.create).toHaveBeenCalledWith({ timeout: 3000 }); + }); - test('create passes axios options', () => { - createClient({ - timeout: 10, - method: 'post', - }); - expect(mockAxios.create).toHaveBeenCalledWith({timeout: 10, method: 'post'}); + test('create passes axios options', () => { + createClient({ + timeout: 10, + method: 'post', }); + // eslint-disable-next-line + expect(mockAxios.create).toHaveBeenCalledWith({ timeout: 10, method: 'post' }); + }); - test('get', async () => { - const client = createClient(); + test('get', async () => { + const client = createClient(); - await client.get('/url', {timeout: 10}); + await client.get('/url', { timeout: 10 }); - expect(mockRequest).toHaveBeenCalledWith({ - url: '/url', - method: 'get', - data: undefined, - validateStatus: null, - timeout: 10, - }); + expect(mockRequest).toHaveBeenCalledWith({ + url: '/url', + method: 'get', + data: undefined, + validateStatus: null, + timeout: 10, }); + }); - test('post', async () => { - const client = createClient(); + test('post', async () => { + const client = createClient(); - await client.post('/url', {a: 1}, {timeout: 10}); + await client.post('/url', { a: 1 }, { timeout: 10 }); - expect(mockRequest).toHaveBeenCalledWith({ - url: '/url', - method: 'post', - validateStatus: null, - timeout: 10, - data: {a: 1}, - }); + expect(mockRequest).toHaveBeenCalledWith({ + url: '/url', + method: 'post', + validateStatus: null, + timeout: 10, + data: { a: 1 }, }); + }); - test('put', async () => { - const client = createClient(); + test('put', async () => { + const client = createClient(); - await client.put('/url', {a: 1}, {timeout: 10}); + await client.put('/url', { a: 1 }, { timeout: 10 }); - expect(mockRequest).toHaveBeenCalledWith({ - url: '/url', - method: 'put', - validateStatus: null, - timeout: 10, - data: {a: 1}, - }); + expect(mockRequest).toHaveBeenCalledWith({ + url: '/url', + method: 'put', + validateStatus: null, + timeout: 10, + data: { a: 1 }, }); + }); - test('patch', async () => { - const client = createClient(); + test('patch', async () => { + const client = createClient(); - await client.patch('/url', {a: 1}, {timeout: 10}); + await client.patch('/url', { a: 1 }, { timeout: 10 }); - expect(mockRequest).toHaveBeenCalledWith({ - url: '/url', - method: 'patch', - validateStatus: null, - timeout: 10, - data: {a: 1}, - }); + expect(mockRequest).toHaveBeenCalledWith({ + url: '/url', + method: 'patch', + validateStatus: null, + timeout: 10, + data: { a: 1 }, }); + }); - test('delete', async () => { - const client = createClient(); + test('delete', async () => { + const client = createClient(); - await client.delete('/url', {timeout: 10}); + await client.delete('/url', { timeout: 10 }); - expect(mockRequest).toHaveBeenCalledWith({ - url: '/url', - method: 'delete', - validateStatus: null, - timeout: 10, - data: undefined, - }); + expect(mockRequest).toHaveBeenCalledWith({ + url: '/url', + method: 'delete', + validateStatus: null, + timeout: 10, + data: undefined, }); + }); - test('throws transport error on failed request', async () => { - mockRequest.mockRejectedValue(new Error('err msg')); + test('throws transport error on failed request', () => { + mockRequest.mockRejectedValue(new Error('err msg')); - const client = createClient(); + const client = createClient(); - expect(client.delete('/url', {timeout: 10})).rejects.toThrow(TransportError); + expect(client.delete('/url', { timeout: 10 })).rejects.toThrow(TransportError); - }); + }); }); diff --git a/src/http/__tests__/url.test.ts b/src/http/__tests__/url.test.ts index 8d1635c..380b3bb 100644 --- a/src/http/__tests__/url.test.ts +++ b/src/http/__tests__/url.test.ts @@ -1,8 +1,8 @@ -import {URL} from '../http.url'; +import { URL } from '../http.url'; test('creates URL with both template and parsed string', () => { - const address = URL.template('/{template}', {template: 'asd'}); + const address = URL.template('/{template}', { template: 'asd' }); - expect(address.urlTemplate()).toEqual('/{template}'); - expect(address.toString()).toEqual('/asd'); + expect(address.urlTemplate()).toEqual('/{template}'); + expect(address.toString()).toEqual('/asd'); }); diff --git a/src/http/http.client.ts b/src/http/http.client.ts index 7428b51..ff51355 100644 --- a/src/http/http.client.ts +++ b/src/http/http.client.ts @@ -1,13 +1,13 @@ -import axios, {AxiosInstance, AxiosPromise, AxiosRequestConfig, AxiosResponse} from 'axios'; +import axios, { AxiosInstance, AxiosPromise, AxiosRequestConfig, AxiosResponse } from 'axios'; import * as prom from 'prom-client'; -import {URL} from './http.url'; -import {TransportError} from '../errors'; +import { URL } from './http.url'; +import { TransportError } from '../errors'; const httpHistogram = new prom.Histogram({ - name: 'http_client_requests_seconds', - help: 'measures http client request duration', - labelNames: ['url', 'status', 'method'], - buckets: [0.2, 0.5, 1, 1.5, 3, 5, 10], + name: 'http_client_requests_seconds', + help: 'measures http client request duration', + labelNames: ['url', 'status', 'method'], + buckets: [0.2, 0.5, 1, 1.5, 3, 5, 10], }); enum Method { @@ -23,75 +23,75 @@ interface Data { } class Client { - constructor(private readonly transport: AxiosInstance) { + constructor(private readonly transport: AxiosInstance) { + } + + private endpoint(url: URL | string): string { + if (url instanceof URL) { + return url.toString(); + } else { + return url; } + } - private endpoint(url: URL | string): string { - if (url instanceof URL) { - return url.toString(); - } else { - return url; - } - } - - private execute(method: Method, url: URL | string, data?: Data, options?: AxiosRequestConfig): AxiosPromise { - if (!options) { - options = {}; - } - - const labels = { - url: url instanceof URL ? url.urlTemplate() : url, - status: 0, - method: method.toString(), - }; - - options.method = method; - options.url = this.endpoint(url); - options.data = data; - options.validateStatus = null; - - const timeRequest = httpHistogram.startTimer(labels); - - // add catch for instrumentation - return this.transport.request(options).then((response: AxiosResponse) => { - labels.status = response.status; - timeRequest(); - return response; - }).catch((error) => { - timeRequest(); - throw new TransportError(error.message); - }); - } - - get(url: URL | string, options?: AxiosRequestConfig): AxiosPromise { - return this.execute(Method.GET, url, undefined, options); - } - - delete(url: URL | string, options?: AxiosRequestConfig): AxiosPromise { - return this.execute(Method.DELETE, url, undefined, options); - } - - post(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { - return this.execute(Method.POST, url, data, options); - } - - put(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { - return this.execute(Method.PUT, url, data, options); + private execute(method: Method, url: URL | string, data?: Data, options?: AxiosRequestConfig): AxiosPromise { + if (!options) { + options = {}; } - patch(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { - return this.execute(Method.PATCH, url, data, options); - } + const labels = { + url: url instanceof URL ? url.urlTemplate() : url, + status: 0, + method: method.toString(), + }; + + options.method = method; + options.url = this.endpoint(url); + options.data = data; + options.validateStatus = null; + + const timeRequest = httpHistogram.startTimer(labels); + + // add catch for instrumentation + return this.transport.request(options).then((response: AxiosResponse) => { + labels.status = response.status; + timeRequest(); + return response; + }).catch((error) => { + timeRequest(); + throw new TransportError(error.message); + }); + } + + get(url: URL | string, options?: AxiosRequestConfig): AxiosPromise { + return this.execute(Method.GET, url, undefined, options); + } + + delete(url: URL | string, options?: AxiosRequestConfig): AxiosPromise { + return this.execute(Method.DELETE, url, undefined, options); + } + + post(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { + return this.execute(Method.POST, url, data, options); + } + + put(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { + return this.execute(Method.PUT, url, data, options); + } + + patch(url: URL | string, data: Data, options?: AxiosRequestConfig): AxiosPromise { + return this.execute(Method.PATCH, url, data, options); + } } export const createClient = (options?: AxiosRequestConfig): Client => { - if (!options) { - options = {}; - } + if (!options) { + options = {}; + } - if (!options.timeout) { - options.timeout = 3000; - } + if (!options.timeout) { + options.timeout = 3000; + } - return new Client(axios.create(options)); + return new Client(axios.create(options)); }; diff --git a/src/http/http.url.ts b/src/http/http.url.ts index 41d712a..a911331 100644 --- a/src/http/http.url.ts +++ b/src/http/http.url.ts @@ -5,22 +5,22 @@ interface Parameters { } export class URL { - private constructor(private readonly template: string, private readonly parsed: string) { + private constructor(private readonly template: string, private readonly parsed: string) { - } + } - static template(template: string, parameters?: Parameters): URL { + static template(template: string, parameters?: Parameters): URL { - const tpl = templates.parse(template); + const tpl = templates.parse(template); - return new URL(template, tpl.expand(parameters)); - } + return new URL(template, tpl.expand(parameters)); + } - urlTemplate() { - return this.template; - } + urlTemplate(): string { + return this.template; + } - toString() { - return this.parsed; - } + toString(): string { + return this.parsed; + } } diff --git a/src/http/index.ts b/src/http/index.ts index 464d6b1..4860abd 100644 --- a/src/http/index.ts +++ b/src/http/index.ts @@ -1,2 +1,2 @@ -export {createClient} from './http.client'; -export {URL} from './http.url'; +export { createClient } from './http.client'; +export { URL } from './http.url'; diff --git a/src/logger/logger.ts b/src/logger/logger.ts index f3536fa..2520b68 100644 --- a/src/logger/logger.ts +++ b/src/logger/logger.ts @@ -1,42 +1,42 @@ import * as bunyan from 'bunyan'; -import {Token} from 'typedi'; -import {RecordWriter} from './writer'; -import {LogLevelString} from 'bunyan'; +import { Token } from 'typedi'; +import { RecordWriter } from './writer'; +import { LogLevelString } from 'bunyan'; export type LoggerEntry = bunyan; export const Logger = new Token('logger'); export class LoggerFactory { - static new(name: string, level: LogLevelString = 'info'): LoggerEntry { - const logger = bunyan.createLogger({ - name, - streams: [ - { - type: 'raw', - stream: new RecordWriter( - [bunyan.ERROR, bunyan.FATAL], - process.stderr, - ), - level: bunyan.ERROR, - }, - { - type: 'raw', - stream: new RecordWriter( - [bunyan.TRACE, bunyan.INFO, bunyan.DEBUG, bunyan.WARN], - process.stdout, - ), - level: bunyan.TRACE, - }, - ], - level, - }); + static new(name: string, level: LogLevelString = 'info'): LoggerEntry { + const logger = bunyan.createLogger({ + name, + streams: [ + { + type: 'raw', + stream: new RecordWriter( + [bunyan.ERROR, bunyan.FATAL], + process.stderr, + ), + level: bunyan.ERROR, + }, + { + type: 'raw', + stream: new RecordWriter( + [bunyan.TRACE, bunyan.INFO, bunyan.DEBUG, bunyan.WARN], + process.stdout, + ), + level: bunyan.TRACE, + }, + ], + level, + }); - logger.addSerializers({ - err: (error) => error.render ? error.render() : error.message, - error: (error) => error.render ? error.render() : error.message, - }); + logger.addSerializers({ + err: (error) => error.render ? error.render() : error.message, + error: (error) => error.render ? error.render() : error.message, + }); - return logger; - } + return logger; + } } diff --git a/src/logger/writer.ts b/src/logger/writer.ts index 03bf28e..3544d00 100644 --- a/src/logger/writer.ts +++ b/src/logger/writer.ts @@ -4,26 +4,26 @@ import * as bunyan from 'bunyan'; import WritableStream = NodeJS.WritableStream; export class RecordWriter { - public levels: {[k: string]: boolean}; - public stream: WritableStream; + public levels: { [k: string]: boolean }; + public stream: WritableStream; - constructor(levels, stream) { - this.levels = {}; - levels.forEach((lvl) => { - this.levels[bunyan.resolveLevel(lvl)] = true; - }); - this.stream = stream; - } + constructor(levels: bunyan.LogLevel[], stream: WritableStream) { + this.levels = {}; + levels.forEach((lvl: bunyan.LogLevel) => { + this.levels[bunyan.resolveLevel(lvl)] = true; + }); + this.stream = stream; + } - mapLevelToString(lvl) { - return bunyan.nameFromLevel[lvl]; - } + mapLevelToString(lvl: number): string { + return bunyan.nameFromLevel[lvl]; + } - write(record) { - if (this.levels[record.level] !== undefined) { - record.severity = this.mapLevelToString(record.level); - const str = JSON.stringify(record, bunyan.safeCycles()) + '\n'; - this.stream.write(str); - } + write(record: any): void { + if (this.levels[record.level] !== undefined) { + record.severity = this.mapLevelToString(record.level); + const str = JSON.stringify(record, bunyan.safeCycles()) + '\n'; + this.stream.write(str); } + } } diff --git a/src/operational/checker.ts b/src/operational/checker.ts index becaaf9..6a4ffe6 100644 --- a/src/operational/checker.ts +++ b/src/operational/checker.ts @@ -1,4 +1,4 @@ -import {Health} from './module'; +import { Health } from './module'; export interface Checker { name: string; @@ -19,21 +19,21 @@ export class CheckerReporter { action?: string; impact?: string; - healthy(output: string) { - this.output = output; - this.health = Health.Healthy; + healthy(output: string): void { + this.output = output; + this.health = Health.Healthy; } - degraded(output: string, action: string) { - this.output = output; - this.action = action; - this.health = Health.Degraded; + degraded(output: string, action: string): void { + this.output = output; + this.action = action; + this.health = Health.Degraded; } - unhealthy(output: string, action: string, impact: string) { - this.output = output; - this.action = action; - this.impact = impact; - this.health = Health.Unhealthy; + unhealthy(output: string, action: string, impact: string): void { + this.output = output; + this.action = action; + this.impact = impact; + this.health = Health.Unhealthy; } } diff --git a/src/operational/handlers.ts b/src/operational/handlers.ts index 54ca0e3..829a9e6 100644 --- a/src/operational/handlers.ts +++ b/src/operational/handlers.ts @@ -1,56 +1,56 @@ -import {Response} from 'express'; +import { Response } from 'express'; import * as HttpStatus from 'http-status-codes'; -import {ApplicationInformation, OperationalModule, Ready} from './module'; +import { ApplicationInformation, OperationalModule, Ready } from './module'; export class Handlers { applicationInformation: ApplicationInformation; constructor(private readonly operational: OperationalModule) { - this.applicationInformation = operational.about(); + this.applicationInformation = operational.about(); } - about = (_, res: Response) => { - res.status(200); - res.json(this.applicationInformation); - res.end(); - } - - ready = (_, res: Response) => { - switch (this.operational.ready()) { - case Ready.No: - res.status(HttpStatus.SERVICE_UNAVAILABLE); - res.end(); - return; - case Ready.None: - res.status(HttpStatus.NOT_FOUND); - res.end(); - return; - default: - res.set('Content-Type', 'text/plain'); - res.status(HttpStatus.OK); - res.send('ready\n'); - } - } - - health = (_, res: Response) => { - const health = this.operational.health(); + about = (_: any, res: Response) => { + res.status(200); + res.json(this.applicationInformation); + res.end(); + }; - if (!health.checks.length) { - res.status(HttpStatus.NOT_FOUND); - res.end(); - return; - } - res.json(this.operational.health()); - } + ready = (_: any, res: Response) => { + switch (this.operational.ready()) { + case Ready.No: + res.status(HttpStatus.SERVICE_UNAVAILABLE); + res.end(); + return; + case Ready.None: + res.status(HttpStatus.NOT_FOUND); + res.end(); + return; + default: + res.set('Content-Type', 'text/plain'); + res.status(HttpStatus.OK); + res.send('ready\n'); + } + }; + + health = (_: any, res: Response) => { + const health = this.operational.health(); + + if (!health.checks.length) { + res.status(HttpStatus.NOT_FOUND); + res.end(); + return; + } + res.json(this.operational.health()); + }; - metrics = (_, res: Response) => { - const metrics = this.operational.metrics(); + metrics = (_: any, res: Response) => { + const metrics = this.operational.metrics(); - if (!metrics) { - res.status(HttpStatus.NOT_FOUND); - res.end(); - return; - } + if (!metrics) { + res.status(HttpStatus.NOT_FOUND); + res.end(); + return; + } - res.send(metrics); - } + res.send(metrics); + }; } diff --git a/src/operational/module.ts b/src/operational/module.ts index 1537711..6571b92 100644 --- a/src/operational/module.ts +++ b/src/operational/module.ts @@ -1,5 +1,5 @@ import * as prom from 'prom-client'; -import {Checker, CheckerReporter, CheckerResult} from './checker'; +import { Checker, CheckerReporter, CheckerResult } from './checker'; export enum Ready { None, @@ -48,7 +48,7 @@ export class OperationalModule { private revision: string; private checkers: Checker[] = []; private readyFn: () => boolean; - private provideMetrics: boolean = false; + private provideMetrics = false; constructor( private readonly name: string, @@ -57,151 +57,151 @@ export class OperationalModule { } enableMetrics(): OperationalModule { - this.provideMetrics = true; - prom.collectDefaultMetrics(); - return this; + this.provideMetrics = true; + prom.collectDefaultMetrics(); + return this; } addOwner(name: string, slack?: string): OperationalModule { - this.owners.push({name, slack}); - return this; + this.owners.push({ name, slack }); + return this; } addLink(description: string, url: string): OperationalModule { - this.links.push({description, url}); - return this; + this.links.push({ description, url }); + return this; } setRevision(revision: string): OperationalModule { - this.revision = revision; - return this; + this.revision = revision; + return this; } readyNone(): OperationalModule { - this.readyFn = null; - return this; + this.readyFn = null; + return this; } readyAlways(): OperationalModule { - this.readyFn = () => true; - return this; + this.readyFn = () => true; + return this; } readyNever(): OperationalModule { - this.readyFn = () => false; - return this; + this.readyFn = () => false; + return this; } readyCallback(fn: () => boolean): OperationalModule { - this.readyFn = fn; - return this; + this.readyFn = fn; + return this; } addCheck(name: string, checkFn: (cr: CheckerReporter) => void): OperationalModule { - this.checkers.push({name, checkFn}); - return this; + this.checkers.push({ name, checkFn }); + return this; } readyUseHealthCheck(): OperationalModule { - this.readyFn = () => { - - switch (this.health().health) { - case Health.Degraded: - case Health.Healthy: - return true; - default: - return false; - } - }; - return this; + this.readyFn = () => { + + switch (this.health().health) { + case Health.Degraded: + case Health.Healthy: + return true; + default: + return false; + } + }; + return this; } about(): ApplicationInformation { - const about = { - name: this.name, - description: this.description, - owners: this.owners, - links: this.links, - build: null, + const about: ApplicationInformation = { + name: this.name, + description: this.description, + owners: this.owners, + links: this.links, + build: null, + }; + + if (this.revision) { + about.build = { + revision: this.revision, }; + } - if (this.revision) { - about.build = { - revision: this.revision, - }; - } - - return about; + return about; } ready(): Ready { - if (!this.readyFn) { - return Ready.None; - } + if (!this.readyFn) { + return Ready.None; + } - return this.readyFn() ? Ready.Yes : Ready.No; + return this.readyFn() ? Ready.Yes : Ready.No; } metrics(): string { - if (!this.provideMetrics) { - return ''; - } + if (!this.provideMetrics) { + return ''; + } - return prom.register.metrics(); + return prom.register.metrics(); } health(): ApplicationHealth { - const result: CheckerResult[] = []; - - let seenHealthy; - let seenDegraded; - let seenUnhealthy; - - this.checkers.forEach((checker => { - const checkerResult = new CheckerReporter(); - checker.checkFn(checkerResult); - result.push({ // should checkFn be async? - name: checker.name, - health: checkerResult.health, - output: checkerResult.output, - action: checkerResult.action, - impact: checkerResult.impact, - }); - - switch (checkerResult.health) { - case Health.Unhealthy: - seenUnhealthy = true; - break; - case Health.Degraded: - seenDegraded = true; - break; - case Health.Healthy: - seenHealthy = true; - break; - } - })); - - let health = Health.Unhealthy; - - switch (true) { - case seenUnhealthy: - health = Health.Unhealthy; - break; - case seenDegraded: - health = Health.Degraded; - break; - case seenHealthy: - health = Health.Healthy; - break; + const result: CheckerResult[] = []; + + let seenHealthy; + let seenDegraded; + let seenUnhealthy; + + this.checkers.forEach((checker => { + const checkerResult = new CheckerReporter(); + checker.checkFn(checkerResult); + result.push({ // should checkFn be async? + name: checker.name, + health: checkerResult.health, + output: checkerResult.output, + action: checkerResult.action, + impact: checkerResult.impact, + }); + + switch (checkerResult.health) { + case Health.Unhealthy: + seenUnhealthy = true; + break; + case Health.Degraded: + seenDegraded = true; + break; + case Health.Healthy: + seenHealthy = true; + break; } - - return { - name: this.name, - description: this.description, - health, - checks: result, - }; + })); + + let health = Health.Unhealthy; + + switch (true) { + case seenUnhealthy: + health = Health.Unhealthy; + break; + case seenDegraded: + health = Health.Degraded; + break; + case seenHealthy: + health = Health.Healthy; + break; + } + + return { + name: this.name, + description: this.description, + health, + checks: result, + }; } } diff --git a/src/repository.decorators.ts b/src/repository.decorators.ts index bc07e69..1478482 100644 --- a/src/repository.decorators.ts +++ b/src/repository.decorators.ts @@ -1,13 +1,13 @@ import { AbstractRepository, RepositoryContext, RepositoryLocator } from './repository'; -import { PullValue } from "./resolver.decorators"; +import { PullValue } from './resolver.decorators'; interface RepositoryGraphQLContext { repositoryLocator: RepositoryLocator; } export const InjectRepo = PullValue((paramType: typeof AbstractRepository) => { - return (source: any, args: any, context: RepositoryGraphQLContext): AbstractRepository => { - const provider = context.repositoryLocator; - return provider.getWithContext(paramType.prototype, RepositoryContext.fromGQLContext(context)); - }; + return (source: any, args: any, context: RepositoryGraphQLContext): AbstractRepository => { + const provider = context.repositoryLocator; + return provider.getWithContext(paramType.prototype, RepositoryContext.fromGQLContext(context)); + }; }); diff --git a/src/repository/__tests__/context.test.ts b/src/repository/__tests__/context.test.ts index aef0d21..c7f3d35 100644 --- a/src/repository/__tests__/context.test.ts +++ b/src/repository/__tests__/context.test.ts @@ -7,23 +7,30 @@ test('building from GQL context', () => { const req = reqOnj as Request; const authToken: AuthToken = { - asScopes(scopes: string[]): boolean { + asHeader(): string { + return ''; + }, + payload(): T { + return undefined; + }, + asScopes(): boolean { return true; }, isValid(): boolean { return false; }, asString(): string { - return ""; + return ''; } - } + }; const gqlContext = { authToken, req, + correlationId: 'id', }; - const repoContext = RepositoryContext.fromGQLContext(gqlContext); + const repoContext = RepositoryContext.fromGQLContext(gqlContext as any); expect(repoContext.authToken).toBe(authToken); expect(repoContext.correlationId).toBe('id'); diff --git a/src/repository/__tests__/decorators.test.ts b/src/repository/__tests__/decorators.test.ts index 4a6df30..d62cfc9 100644 --- a/src/repository/__tests__/decorators.test.ts +++ b/src/repository/__tests__/decorators.test.ts @@ -1,8 +1,9 @@ -import {Repository, RepositoryFactory} from '../repository.decorators'; -import {RepositoryMetadata} from '../repository.metadata'; +import { Repository, RepositoryFactory } from '../repository.decorators'; +import { RepositoryMetadata } from '../repository.metadata'; -const factory = () => 'factored'; +const factory = (): string => 'factored'; +// eslint-disable-next-line @Repository(Repo) class Repo { @@ -13,6 +14,7 @@ class RepoTypeDerived { } +// eslint-disable-next-line @RepositoryFactory(factory, RepoWithFactory) class RepoWithFactory { @@ -24,8 +26,8 @@ class RepoDerivedWithFactory { } test('decorators', () => { - expect(RepositoryMetadata.for(new Repo()).type).toBe(Repo.prototype); - expect(RepositoryMetadata.for(new RepoTypeDerived()).type).toBe(RepoTypeDerived.prototype); - expect(RepositoryMetadata.for(new RepoWithFactory()).type).toBe(RepoWithFactory.prototype); - expect(RepositoryMetadata.for(new RepoDerivedWithFactory()).type).toBe(RepoDerivedWithFactory.prototype); + expect(RepositoryMetadata.for(new Repo()).type).toBe(Repo.prototype); + expect(RepositoryMetadata.for(new RepoTypeDerived()).type).toBe(RepoTypeDerived.prototype); + expect(RepositoryMetadata.for(new RepoWithFactory()).type).toBe(RepoWithFactory.prototype); + expect(RepositoryMetadata.for(new RepoDerivedWithFactory()).type).toBe(RepoDerivedWithFactory.prototype); }); diff --git a/src/repository/__tests__/locator.test.ts b/src/repository/__tests__/locator.test.ts index 86dc2c9..614dcfc 100644 --- a/src/repository/__tests__/locator.test.ts +++ b/src/repository/__tests__/locator.test.ts @@ -1,20 +1,21 @@ +// tslint:disable:max-classes-per-file import { RepositoryLocator } from '../repository.locator'; import { AbstractRepository } from '../abstract.repository'; -import { RepositoryContext } from '../repository.context'; import { RepositoryFactory } from '../repository.decorators'; -import { Container } from "typedi"; +import { Container } from 'typedi'; abstract class AbstractRepo extends AbstractRepository {} @RepositoryFactory(() => { + // eslint-disable-next-line return new ConcreteRepo(); }, AbstractRepo) class ConcreteRepo extends AbstractRepository { - checkHealth(cr: any) { + checkHealth(): boolean { return true; } - withContext(context: RepositoryContext): AbstractRepository { + withContext(): AbstractRepository { return this; } } diff --git a/src/repository/__tests__/metadata.test.ts b/src/repository/__tests__/metadata.test.ts index 0f2e438..2e04e15 100644 --- a/src/repository/__tests__/metadata.test.ts +++ b/src/repository/__tests__/metadata.test.ts @@ -1,4 +1,4 @@ -import {RepositoryMetadata} from '../repository.metadata'; +import { RepositoryMetadata } from '../repository.metadata'; class TestClass { @@ -6,12 +6,12 @@ class TestClass { test('setting for class object and constructor', () => { - const expected = TestClass.prototype; + const expected = TestClass.prototype; - const classInstance = new TestClass(); + const classInstance = new TestClass(); - expect(RepositoryMetadata.getType(TestClass)).toBe(expected); - expect(RepositoryMetadata.getType(classInstance)).toBe(classInstance); - expect(RepositoryMetadata.getType(new TestClass().constructor)).toBe(expected); + expect(RepositoryMetadata.getType(TestClass)).toBe(expected); + expect(RepositoryMetadata.getType(classInstance)).toBe(classInstance); + expect(RepositoryMetadata.getType(new TestClass().constructor)).toBe(expected); }); diff --git a/src/repository/abstract.repository.ts b/src/repository/abstract.repository.ts index 209ce69..820908d 100644 --- a/src/repository/abstract.repository.ts +++ b/src/repository/abstract.repository.ts @@ -1,7 +1,7 @@ -import {RepositoryContext} from './repository.context'; -import {CheckerReporter} from '../operational'; +import { RepositoryContext } from './repository.context'; +import { CheckerReporter } from '../operational'; export abstract class AbstractRepository { abstract withContext(context: RepositoryContext): AbstractRepository; - abstract checkHealth(cr: CheckerReporter); + abstract checkHealth(cr: CheckerReporter): void; } diff --git a/src/repository/repository.context.ts b/src/repository/repository.context.ts index 96c00a4..b06d6e3 100644 --- a/src/repository/repository.context.ts +++ b/src/repository/repository.context.ts @@ -10,7 +10,7 @@ export class RepositoryContext { authToken?: AuthToken; correlationId?: string; - static fromGQLContext(context: T & { authToken?: AuthToken, correlationId }): RepositoryContext { + static fromGQLContext(context: T & { authToken?: AuthToken; correlationId: string }): RepositoryContext { const ctx = new RepositoryContext(); ctx.authToken = context.authToken; ctx.correlationId = context.correlationId; diff --git a/src/repository/repository.decorators.ts b/src/repository/repository.decorators.ts index b87750e..1407191 100644 --- a/src/repository/repository.decorators.ts +++ b/src/repository/repository.decorators.ts @@ -1,26 +1,26 @@ -import {Service} from 'typedi'; -import {RepositoryMetadata, RepositoryToken} from './index'; +import { Service } from 'typedi'; +import { RepositoryMetadata, RepositoryToken } from './index'; -export const Repository = (type?) => (target) => { - RepositoryMetadata.for(target).setType(type || target); - return Service({ - id: RepositoryToken, - multiple: true, - })(target); +export const Repository = (type?: any) => (target: any): any => { + RepositoryMetadata.for(target).setType(type || target); + return Service({ + id: RepositoryToken, + multiple: true, + })(target); }; -export const RepositoryFactory = (factory, type?) => (target) => { - RepositoryMetadata.for(target).setType(type || target); +export const RepositoryFactory = (factory: () => any, type?: any) => (target: any): any => { + RepositoryMetadata.for(target).setType(type || target); - // Register interface to concrete repository - if (type) { - Service({ factory, id: type })(target); - } + // Register interface to concrete repository + if (type) { + Service({ factory, id: type })(target); + } - return Service({ - id: RepositoryToken, - multiple: true, - // global: true, - factory, - })(target); + return Service({ + id: RepositoryToken, + multiple: true, + // global: true, + factory, + })(target); }; diff --git a/src/repository/repository.locator.ts b/src/repository/repository.locator.ts index dadc717..146c4fc 100644 --- a/src/repository/repository.locator.ts +++ b/src/repository/repository.locator.ts @@ -7,7 +7,7 @@ export class RepositoryLocator { constructor(private readonly container: ContainerInstance) {} - private repositories: AbstractRepository[] = [] + private repositories: AbstractRepository[] = []; getWithContext(repoKey: typeof AbstractRepository | AbstractRepository, context: T): AbstractRepository { @@ -18,14 +18,14 @@ export class RepositoryLocator { const repo = this.container.get(interfaceType.constructor); if (interfaceType.constructor === repoKey.constructor || repo.constructor === repoKey.constructor) { - const cached = this.repositories.find((cachedRepo) => cachedRepo.constructor === repo.constructor) + const cached = this.repositories.find((cachedRepo) => cachedRepo.constructor === repo.constructor); if (cached) { return cached; } - const newRepoWithContext = repo.withContext(context) - this.repositories.push(newRepoWithContext) - return newRepoWithContext + const newRepoWithContext = repo.withContext(context); + this.repositories.push(newRepoWithContext); + return newRepoWithContext; } } diff --git a/src/repository/repository.metadata.ts b/src/repository/repository.metadata.ts index 6ee7897..f06356f 100644 --- a/src/repository/repository.metadata.ts +++ b/src/repository/repository.metadata.ts @@ -5,37 +5,37 @@ export class RepositoryMetadata { public type: any; - setType(type: any) { - this.type = RepositoryMetadata.getType(type); + setType(type: any): void { + this.type = RepositoryMetadata.getType(type); } - static getType(target: any) { + static getType(target: any): any { - let returnType = target; + let returnType = target; - if (typeof target === 'function') { - // probably constructor - returnType = target.prototype; - } else { - // probably an instance - returnType = target; - } + if (typeof target === 'function') { + // probably constructor + returnType = target.prototype; + } else { + // probably an instance + returnType = target; + } - return returnType; + return returnType; } static for(target: any): RepositoryMetadata { - let meta = Reflect.getMetadata(RepositoryMetadataKey, RepositoryMetadata.getType(target)); + let meta = Reflect.getMetadata(RepositoryMetadataKey, RepositoryMetadata.getType(target)); - if (meta) { - return meta; - } + if (meta) { + return meta; + } - meta = new RepositoryMetadata(); + meta = new RepositoryMetadata(); - Reflect.defineMetadata(RepositoryMetadataKey, meta, RepositoryMetadata.getType(target)); + Reflect.defineMetadata(RepositoryMetadataKey, meta, RepositoryMetadata.getType(target)); - return meta; + return meta; } } diff --git a/src/repository/repository.token.ts b/src/repository/repository.token.ts index 9fa160b..56c2992 100644 --- a/src/repository/repository.token.ts +++ b/src/repository/repository.token.ts @@ -1,4 +1,4 @@ -import {Token} from 'typedi'; -import {AbstractRepository} from './index'; +import { Token } from 'typedi'; +import { AbstractRepository } from './index'; export const RepositoryToken = new Token('repositories'); diff --git a/src/resolver.decorators.ts b/src/resolver.decorators.ts index e40b8e2..8f6334d 100644 --- a/src/resolver.decorators.ts +++ b/src/resolver.decorators.ts @@ -2,67 +2,74 @@ import { Service } from 'typedi'; import { IFieldResolver } from 'graphql-tools'; import { ResolverToken } from './resolver.token'; import { ResolverMetadata } from './resolver.metadata'; -import { NullError } from "./errors/null.error"; +import { NullError } from './errors'; -export const Resolver = (type?: string): ClassDecorator => (target) => { +export const Resolver = (type?: string): ClassDecorator => (target): void => { if (type) { ResolverMetadata.for(target.prototype).setType(type); } Service({ id: ResolverToken, multiple: true })(target); }; -export const Resolve = (path?: string) => (target, propertyKey: string) => { +export const Resolve = (path?: string) => (target: any, propertyKey: string): void => { ResolverMetadata.for(target).addResolver(path || propertyKey, propertyKey); }; -export const Query = (query?: string) => (target, propertyKey: string) => { +export const Query = (query?: string) => (target: any, propertyKey: string): any => { ResolverMetadata.for(target).addQuery(query || propertyKey, propertyKey); return target; }; -export const Mutation = (mutation?: string) => (target, propertyKey: string) => { +export const Mutation = (mutation?: string) => (target: any, propertyKey: string): any => { ResolverMetadata.for(target).addMutation(mutation || propertyKey, propertyKey); return target; }; -export const Subscription = (subscription?: string) => (target, propertyKey: string) => { +export const Subscription = (subscription?: string) => (target: any, propertyKey: string): any => { ResolverMetadata.for(target).addSubscription(subscription || propertyKey, propertyKey); return target; }; +export const Before = (beforeFn: IFieldResolver): MethodDecorator => (target: any, propertyKey: string): void => { + ResolverMetadata.for(target).addBeforeHook(propertyKey, beforeFn); + }; + + export const PullValue = ( - pullFn: (paramType: TParamType) - => IFieldResolver, -): ParameterDecorator => (target, key, index) => { - const params = Reflect.getMetadata('design:paramtypes', target, key); + pullFn: (paramType: TParamType) + => IFieldResolver, +): ParameterDecorator => (target, key, index): void => { + const params = Reflect.getMetadata('design:paramtypes', target, key); - ResolverMetadata.for(target).addMethodParamOverride( - key, + ResolverMetadata.for(target).addMethodParamOverride( + key as string, index, pullFn(params[index]), - ).addMethodParamNumber(key, params.length); -}; + ).addMethodParamNumber(key as string, params.length); + }; export const Parent = PullValue(() => { - return (parent) => { + return (parent: any): any => { return parent; }; }); -export const Arg = (name: string) => PullValue(() => { - return (parent, args: object) => { +export const Arg = (name: string): Function => PullValue(() => { + return (parent: any, args: any): any => { return args[name]; }; }); -export const Context = (name: string) => PullValue(() => { - return (parent, args, context) => { +export const Context = (name: string): Function => PullValue(() => { + return (parent: any, args: any, context: any): any => { return context[name]; }; }); export const IfAuth = (...scopes: string[]): any => { - return Before((source, args, context, _) => { + return Before((source, args, context) => { if (!context.config.get('auth.bypass')) { if (!context.authValidator.willPass(context.authToken, scopes)) { throw new NullError(); @@ -72,19 +79,13 @@ export const IfAuth = (...scopes: string[]): any => { }; export const MustAuth = (...scopes: string[]): any => { - return Before((source, args, context, _) => { + return Before((source, args, context) => { if (!context.config.get('auth.bypass')) { context.authValidator.mustPass(context.authToken, scopes); } }); }; -export const Before = (beforeFn: IFieldResolver): MethodDecorator => (target, propertyKey: string) => { - ResolverMetadata.for(target).addBeforeHook(propertyKey, beforeFn); -}; - -export const After = (afterFn: (result) => T) => (target, propertyKey: string) => { +export const After = (afterFn: (result: any) => T) => (target: any, propertyKey: string): void => { ResolverMetadata.for(target).addAfterHook(propertyKey, afterFn); }; diff --git a/src/resolver.metadata.ts b/src/resolver.metadata.ts index 50ad0d0..3318b36 100644 --- a/src/resolver.metadata.ts +++ b/src/resolver.metadata.ts @@ -7,56 +7,56 @@ export class ResolverMetadata { public methodParamNumbers: { [k: string]: number } = {}; public methodParamOverrides: { [k: string]: any } = {}; public type: string; - public queries: Array<{ name: string, method: string }> = []; - public subscriptions: Array<{name: string, method: string}> = []; - public mutations: Array<{ name: string, method: string }> = []; - public mappedResolvers: Array<{ name: string, method: string }> = []; + public queries: Array<{ name: string; method: string }> = []; + public subscriptions: Array<{name: string; method: string}> = []; + public mutations: Array<{ name: string; method: string }> = []; + public mappedResolvers: Array<{ name: string; method: string }> = []; - public beforeHooks: Array<{ method: string, hook: IFieldResolver }> = []; - public afterHooks: Array<{ method: string, hook: (result: any) => any }> = []; + public beforeHooks: Array<{ method: string; hook: IFieldResolver }> = []; + public afterHooks: Array<{ method: string; hook: (result: any) => any }> = []; - addSubscription(name: string, method: string) { - this.subscriptions.push({name, method}); + addSubscription(name: string, method: string): ResolverMetadata { + this.subscriptions.push({ name, method }); return this; } - addMutation(name: string, method: string) { + addMutation(name: string, method: string): ResolverMetadata { this.mutations.push({ name, method }); return this; } - addQuery(name: string, method: string) { + addQuery(name: string, method: string): ResolverMetadata { this.queries.push({ name, method }); return this; } - addResolver(name: string, method: string) { + addResolver(name: string, method: string): ResolverMetadata { this.mappedResolvers.push({ name, method }); return this; } addBeforeHook(method: string, hook: IFieldResolver) { + }>(method: string, hook: IFieldResolver): ResolverMetadata { this.beforeHooks.push({ method, hook }); return this; } - addAfterHook(method: string, hook: (result: any) => void) { + addAfterHook(method: string, hook: (result: any) => void): ResolverMetadata { this.afterHooks.push({ method, hook }); return this; } - setType(name: string) { + setType(name: string): ResolverMetadata { this.type = name; return this; } - addMethodParamNumber(key, noOfParameters) { + addMethodParamNumber(key: string, noOfParameters: number): void { this.methodParamNumbers[key] = noOfParameters; } - addMethodParamOverride(key, index, fn) { + addMethodParamOverride(key: string, index: number, fn: Function): ResolverMetadata { this.methodParamOverrides[key] = this.methodParamOverrides[key] || []; this.methodParamOverrides[key][index] = fn; return this; diff --git a/src/resolver.registry.ts b/src/resolver.registry.ts index 2830c50..ac71757 100644 --- a/src/resolver.registry.ts +++ b/src/resolver.registry.ts @@ -1,9 +1,8 @@ import { Service } from 'typedi'; import { ResolverInterface } from './resolver.interface'; import { ResolverMetadata } from './resolver.metadata'; -import * as set from 'lodash.set'; -import * as get from 'lodash.get'; -import { NullError } from "./errors/null.error"; +import { get, set } from 'lodash'; +import { NullError } from './errors'; @Service() export class ResolverRegistry { @@ -16,15 +15,15 @@ export class ResolverRegistry { return this; } - method(meta: ResolverMetadata, r, method) { + method(meta: ResolverMetadata, r: any, method: string): any { return this.withHooks(meta, method, this.remapMethodParameters(meta, r, method)); } - remapMethodParameters(meta: ResolverMetadata, r, method) { + remapMethodParameters(meta: ResolverMetadata, r: any, method: string): Function { if (meta.methodParamOverrides[method]) { const argSpec = meta.methodParamOverrides[method]; - return (...args) => { + return (...args: any[]): any => { const mappedArgs = []; @@ -39,14 +38,14 @@ export class ResolverRegistry { return r[method](...mappedArgs); }; } - return (...args) => r[method](...args); + return (...args: any): any => r[method](...args); } - withHooks(meta: ResolverMetadata, method: string, fn: any) { + withHooks(meta: ResolverMetadata, method: string, fn: any): Function { const beforeHooks = meta.beforeHooks.filter((s) => s.method === method); const afterHooks = meta.afterHooks.filter((s) => s.method === method); - return async (...args) => { + return async (...args: any[]): Promise => { const promisedBeforeHooks = beforeHooks.map((hookDef: any) => Promise.resolve(hookDef.hook(...args))); try { @@ -76,13 +75,13 @@ export class ResolverRegistry { resolverMap(): {} { - const usedProps = []; + const usedProps: any[] = []; const resolvers = {}; - this.resolvers.forEach(r => { + this.resolvers.forEach((r: any) => { - const safeSet = (path, fn) => { + const safeSet = (path: any, fn: any): void => { if (get(resolvers, path)) { throw new Error(`${path} resolver already set, attempting to set from ${r.constructor.name}`); } @@ -101,8 +100,8 @@ export class ResolverRegistry { usedProps.push(method); }); - meta.subscriptions.forEach(({name, method}) => { - safeSet(`Subscription.${name}`, {subscribe: this.method(meta, r, method)}); + meta.subscriptions.forEach(({ name, method }) => { + safeSet(`Subscription.${name}`, { subscribe: this.method(meta, r, method) }); usedProps.push(method); }); @@ -114,7 +113,7 @@ export class ResolverRegistry { const typePrefix = meta.type ? `${meta.type}.` : ''; Object.getOwnPropertyNames(Object.getPrototypeOf(r)).filter(prop => { - return typeof r[prop] === 'function' && prop !== 'constructor' && usedProps.indexOf(prop) === -1; + return typeof r[prop] === 'function' && prop !== 'constructor' && !usedProps.includes(prop); }).forEach(method => { safeSet(`${typePrefix}${method}`, this.method(meta, r, method)); }); diff --git a/src/resolver.token.ts b/src/resolver.token.ts index 5b2df1a..81d9e51 100644 --- a/src/resolver.token.ts +++ b/src/resolver.token.ts @@ -1,4 +1,4 @@ -import {Token} from 'typedi'; -import {ResolverInterface} from './resolver.interface'; +import { Token } from 'typedi'; +import { ResolverInterface } from './resolver.interface'; export const ResolverToken = new Token('resolvers'); diff --git a/src/utils.ts b/src/utils.ts index afe1ba3..4f3c271 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,10 +1,10 @@ import * as fg from 'fast-glob'; import * as path from 'path'; import * as fs from 'fs'; -import {gql} from 'apollo-server-express'; +import { gql } from 'apollo-server-express'; -export function generateSchema(basePath: string, glob: string, outputPath: string) { - const grpahqlFiles = fg.sync([glob], {cwd: basePath}); +export function generateSchema(basePath: string, glob: string, outputPath: string): void { + const grpahqlFiles = fg.sync([glob], { cwd: basePath }); const schema: string[] = []; @@ -12,8 +12,9 @@ export function generateSchema(basePath: string, glob: string, outputPath: strin schema.push(fs.readFileSync(path.join(basePath, file), 'utf8')); }); - fs.writeFileSync(path.join(basePath, outputPath), JSON.stringify( - gql(schema.join('\n'), - ))); + fs.writeFileSync( + path.join(basePath, outputPath), + JSON.stringify(gql(schema.join('\n'))) + ); } diff --git a/tsconfig.json b/tsconfig.json index 68e3a0d..e4d326d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "module": "commonjs", "declaration": true, - "noImplicitAny": false, + "noImplicitAny": true, "removeComments": true, "noLib": false, "allowSyntheticDefaultImports": true, @@ -10,11 +10,22 @@ "experimentalDecorators": true, "target": "es6", "sourceMap": true, - "lib": ["es6", "es7", "esnext.asynciterable", "dom"], + "lib": [ + "es6", + "es7", + "esnext.asynciterable", + "dom" + ], "outDir": "./dist", - "baseUrl": "./src", + "baseUrl": "./", "moduleResolution": "node", - "types": ["graphql"] + "types": [ + "node", + "graphql", + "jest" + ] }, - "exclude": ["node_modules", "**/__tests__/**/*.ts"] + "exclude": [ + "node_modules" + ] } diff --git a/tslint.json b/tslint.json deleted file mode 100644 index 6be1209..0000000 --- a/tslint.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": ["tslint:recommended"], - "jsRules": { - "no-unused-expression": true - }, - "rules": { - "quotemark": [true, "single"], - "member-access": [false], - "ordered-imports": [false], - "max-line-length": [true, 150], - "member-ordering": [false], - "interface-name": [false], - "arrow-parens": false, - "object-literal-sort-keys": false, - "no-empty-interface": false - }, - "rulesDirectory": [], - "linterOptions": { - "exclude": [ - "src/generated/**/*.ts", - "src/**/__tests__/**/*.ts" - ] - } -} diff --git a/typings/uri-template/index.d.ts b/typings/uri-template/index.d.ts new file mode 100644 index 0000000..8919195 --- /dev/null +++ b/typings/uri-template/index.d.ts @@ -0,0 +1,9 @@ +declare module 'uri-template' { + export function parse(template: string): ParsedTemplate; + + interface ParsedTemplate { + expand(parameters: any): string; + toString(): string; + toJSON(): string; + } +} diff --git a/yarn.lock b/yarn.lock index 2c845e4..4e77428 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,6 +14,13 @@ resolved "https://registry.yarnpkg.com/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.6.tgz#022209e28a2b547dcde15b219f0c50f47aa5beb3" integrity sha512-lqK94b+caNtmKFs5oUVXlSpN3sm5IXZ+KfhMxOtr0LR2SqErzkoJilitjDvJ1WbjHlxLI7WtCjRmOLdOGJqtMQ== +"@babel/code-frame@^7.0.0": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + "@babel/code-frame@^7.0.0-beta.35": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" @@ -137,6 +144,11 @@ dependencies: "@types/express" "*" +"@types/eslint-visitor-keys@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" + integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -164,21 +176,52 @@ resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.2.7.tgz#9576ed5dd62cdb1c9f952522028a03b7cb2b69b5" integrity sha512-Pb9wl5qDEwfnJeeu6Zpn5Y+waLrKETStqLZXHMGCTbkNuBBudPy4qOGN6veamyeoUBwTm2knOVeP/FlHHhhmzA== +"@types/graphql-iso-date@^3.3.3": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@types/graphql-iso-date/-/graphql-iso-date-3.3.3.tgz#a368aa7370512a9cc87a5035c3701949ed7db9e2" + integrity sha512-lchvlAox/yqk2Rcrgqh+uvwc1UC9i1hap+0tqQqyYYcAica6Uw2D4mUkCNcw+WeZ8dvSS5QdtIlJuDYUf4nLXQ== + dependencies: + graphql "^14.5.3" + +"@types/graphql-type-json@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@types/graphql-type-json/-/graphql-type-json-0.3.2.tgz#1a7105e6546fc1630a5db4834bfbc0eb554986e4" + integrity sha512-c1cq4o8EhY0Z39ua8UXwG8uBs23xBYA/Uw0tXFl6SuTUpkVv/IJqf6pHQbfdC7nwFRhX2ifTOV/UIg0Q/IJsbg== + dependencies: + graphql "^14.5.3" + "@types/graphql@^14.0.3": version "14.0.7" resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-14.0.7.tgz#daa09397220a68ce1cbb3f76a315ff3cd92312f6" integrity sha512-BoLDjdvLQsXPZLJux3lEZANwGr3Xag56Ngy0U3y8uoRSDdeLcn43H3oBcgZlnd++iOQElBpaRVDHPzEDekyvXQ== -"@types/jest@^23.3.10": - version "23.3.14" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.14.tgz#37daaf78069e7948520474c87b80092ea912520a" - integrity sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug== +"@types/jest-diff@*": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" + integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== + +"@types/jest@^24.0.18": + version "24.0.18" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.18.tgz#9c7858d450c59e2164a8a9df0905fc5091944498" + integrity sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ== + dependencies: + "@types/jest-diff" "*" + +"@types/json-schema@^7.0.3": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" + integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/lodash@^4.14.137": + version "4.14.137" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.137.tgz#8a4804937dc6462274ffcc088df8f14fc1b368e2" + integrity sha512-g4rNK5SRKloO+sUGbuO7aPtwbwzMgjK+bm9BBhLD7jGUiGR7zhwYEhSln/ihgYQBeIJ5j7xjyaYzrWTcu3UotQ== + "@types/long@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" @@ -201,11 +244,23 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-11.11.3.tgz#7c6b0f8eaf16ae530795de2ad1b85d34bf2f5c58" integrity sha512-wp6IOGu1lxsfnrD+5mX6qwSwWuqsdkKKxTN4aQc4wByHAKZJf9/D4KXPQ1POUjEbnCP5LMggB0OEFNY9OTsMqg== -"@types/node@^10.1.0", "@types/node@^10.12.9", "@types/node@^10.7.1": +"@types/node@^10.1.0", "@types/node@^10.12.9": version "10.14.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.1.tgz#8701cd760acc20beba5ffe0b7a1b879f39cb8c41" integrity sha512-Rymt08vh1GaW4vYB6QP61/5m/CFLGnFZP++bJpWbiNxceNa6RBipDmb413jvtSf/R1gg5a/jQVl2jY4XVRscEA== +"@types/node@^12.7.2": + version "12.7.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" + integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg== + +"@types/protobufjs@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/protobufjs/-/protobufjs-6.0.0.tgz#aeabb43f9507bb19c8adfb479584c151082353e4" + integrity sha512-A27RDExpAf3rdDjIrHKiJK6x8kqqJ4CmoChwtipfhVAn1p7+wviQFFP7dppn8FslSbHtQeVPvi8wNKkDjSYjHw== + dependencies: + protobufjs "*" + "@types/range-parser@*": version "1.2.3" resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" @@ -249,6 +304,44 @@ "@types/events" "*" "@types/node" "*" +"@typescript-eslint/eslint-plugin@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.0.0.tgz#609a5d7b00ce21a6f94d7ef282eba9da57ca1e42" + integrity sha512-Mo45nxTTELODdl7CgpZKJISvLb+Fu64OOO2ZFc2x8sYSnUpFrBUW3H+H/ZGYmEkfnL6VkdtOSxgdt+Av79j0sA== + dependencies: + "@typescript-eslint/experimental-utils" "2.0.0" + eslint-utils "^1.4.0" + functional-red-black-tree "^1.0.1" + regexpp "^2.0.1" + tsutils "^3.14.0" + +"@typescript-eslint/experimental-utils@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.0.0.tgz#f3d298bb411357f35c4184e24280b256b6321949" + integrity sha512-XGJG6GNBXIEx/mN4eTRypN/EUmsd0VhVGQ1AG+WTgdvjHl0G8vHhVBHrd/5oI6RRYBRnedNymSYWW1HAdivtmg== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.0.0" + eslint-scope "^4.0.0" + +"@typescript-eslint/parser@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.0.0.tgz#4273bb19d03489daf8372cdaccbc8042e098178f" + integrity sha512-ibyMBMr0383ZKserIsp67+WnNVoM402HKkxqXGlxEZsXtnGGurbnY90pBO3e0nBUM7chEEOcxUhgw9aPq7fEBA== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.0.0" + "@typescript-eslint/typescript-estree" "2.0.0" + eslint-visitor-keys "^1.0.0" + +"@typescript-eslint/typescript-estree@2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.0.0.tgz#c9f6c0efd1b11475540d6a55dc973cc5b9a67e77" + integrity sha512-NXbmzA3vWrSgavymlzMWNecgNOuiMMp62MO3kI7awZRLRcsA1QrYWo6q08m++uuAGVbXH/prZi2y1AWuhSu63w== + dependencies: + lodash.unescape "4.0.1" + semver "^6.2.0" + abab@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f" @@ -275,6 +368,11 @@ acorn-globals@^4.1.0: acorn "^6.0.1" acorn-walk "^6.0.1" +acorn-jsx@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== + acorn-walk@^6.0.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" @@ -290,6 +388,21 @@ acorn@^6.0.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + +ajv@^6.10.0, ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ajv@^6.5.5: version "6.10.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" @@ -424,7 +537,7 @@ ansi-dim@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^3.0.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -495,6 +608,11 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-reset@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ansi-reset/-/ansi-reset-0.1.1.tgz#e7e71292c3c7ddcd4d62ef4a6c7c05980911c3b7" @@ -917,7 +1035,7 @@ axios@^0.18.0: follow-redirects "^1.3.0" is-buffer "^1.1.5" -babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= @@ -1215,11 +1333,6 @@ buffer-from@1.x, buffer-from@^1.0.0, buffer-from@^1.1.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - bunyan@^1.8.12: version "1.8.12" resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" @@ -1274,6 +1387,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -1307,7 +1425,7 @@ chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1316,6 +1434,11 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + chownr@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" @@ -1336,6 +1459,18 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-width@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" + integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + cliui@^3.0.3: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -1396,7 +1531,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@^2.12.1, commander@~2.19.0: +commander@~2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== @@ -1500,6 +1635,17 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": version "0.3.6" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.6.tgz#f85206cee04efa841f3c5982a74ba96ab20d65ad" @@ -1549,6 +1695,13 @@ debug@^3.1.0, debug@^3.2.6: dependencies: ms "^2.1.1" +debug@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + debug@~3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" @@ -1678,6 +1831,13 @@ diff@^3.1.0, diff@^3.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -1727,6 +1887,11 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -1806,6 +1971,86 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-scope@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.4.0, eslint-utils@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== + dependencies: + eslint-visitor-keys "^1.0.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.2.2.tgz#03298280e7750d81fcd31431f3d333e43d93f24f" + integrity sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.4.1" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== + dependencies: + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" + esprima@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" @@ -1816,6 +2061,25 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" + integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -1961,6 +2225,15 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2040,6 +2313,20 @@ fetch-ponyfill@^4.1.0: dependencies: node-fetch "~1.7.1" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -2102,6 +2389,20 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + follow-redirects@^1.3.0: version "1.7.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" @@ -2199,6 +2500,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2266,6 +2572,13 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" @@ -2294,6 +2607,11 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2404,15 +2722,24 @@ graphql@^14.0.2: dependencies: iterall "^1.2.2" +graphql@^14.5.3: + version "14.5.3" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.5.3.tgz#e025851cc413e153220f4edbbb25d49f55104fa0" + integrity sha512-W8A8nt9BsMg0ZK2qA3DJIVU6muWhxZRYLTmc+5XGwzWzVdUdPVlAAg5hTBjiTISEnzsKL/onasu6vl3kgGTbYg== + dependencies: + iterall "^1.2.2" + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= -grpc-tools@^1.6.6: - version "1.7.1" - resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.7.1.tgz#f353812fd21df057d09cf94d06134c19834ad67c" - integrity sha512-mK2AvaWhr6nfthLs2igXxo8c3jjOkr5fra+ifJ6LGgIT+iyJTb4AZOA09s86wDVyBpodqF9XCT1HsXVV6OJIAg== +grpc-tools@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.8.0.tgz#db438dbd0cfb43d412dc02a767d5fb2193636847" + integrity sha512-GzYHjPQ/sbV/DmnNRksapMlLj26Tvq2Qppmzjmd+lHYZNeWM1feiGsYCduzJLyy295P+3uYIPy2/w/1thAnOow== + dependencies: + node-pre-gyp "^0.12.0" grpc@^1.16.0, grpc@^1.16.1: version "1.19.0" @@ -2682,7 +3009,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.13: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -2696,6 +3023,19 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" @@ -2732,6 +3072,25 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +inquirer@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" @@ -2908,6 +3267,13 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-number@^2.0.2, is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -2956,6 +3322,11 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -3436,6 +3807,14 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= +js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^3.7.0: version "3.12.2" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.2.tgz#ef1d067c5a9d9cb65bd72f285b5d8105c77f14fc" @@ -3496,6 +3875,11 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -3616,7 +4000,7 @@ leven@^2.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= -levn@~0.3.0: +levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= @@ -3708,11 +4092,21 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + lodash@^4.16.4, lodash@^4.17.11, lodash@^4.17.4: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== +lodash@^4.17.12, lodash@^4.17.14: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + log-ok@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/log-ok/-/log-ok-0.1.1.tgz#bea3dd36acd0b8a7240d78736b5b97c65444a334" @@ -4004,6 +4398,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + mv@~2: version "2.1.1" resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" @@ -4064,6 +4463,11 @@ neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + node-fetch@^2.1.2, node-fetch@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" @@ -4278,6 +4682,13 @@ once@^1.3.0, once@^1.4.0: dependencies: wrappy "1" +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -4286,7 +4697,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1: +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= @@ -4324,7 +4735,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= @@ -4361,6 +4772,13 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4415,7 +4833,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.0: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= @@ -4507,11 +4925,6 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= -prettier@^1.14.2: - version "1.16.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" - integrity sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g== - pretty-format@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" @@ -4530,6 +4943,11 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + prom-client@^11.2.0: version "11.2.1" resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-11.2.1.tgz#486e7817de9b1d43c0a12aee26fc68830f4d1b16" @@ -4545,17 +4963,7 @@ prompts@^0.1.9: kleur "^2.0.1" sisteransi "^0.1.1" -protobufjs@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" - integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA== - dependencies: - ascli "~1" - bytebuffer "~5" - glob "^7.0.5" - yargs "^3.10.0" - -protobufjs@^6.8.6: +protobufjs@*, protobufjs@^6.8.6: version "6.8.8" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== @@ -4574,6 +4982,16 @@ protobufjs@^6.8.6: "@types/node" "^10.1.0" long "^4.0.0" +protobufjs@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17" + integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA== + dependencies: + ascli "~1" + bytebuffer "~5" + glob "^7.0.5" + yargs "^3.10.0" + proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -4716,6 +5134,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + relative@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" @@ -4817,6 +5240,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -4827,13 +5255,21 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.x, resolve@^1.10.0, resolve@^1.3.2: +resolve@1.x, resolve@^1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.0.tgz#3bdaaeaf45cc07f375656dfd2e54ed0810b101ba" integrity sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg== dependencies: path-parse "^1.0.6" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -4844,7 +5280,7 @@ retry@0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -rimraf@^2.5.4, rimraf@^2.6.1: +rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -4863,6 +5299,20 @@ rsvp@^3.3.3: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= + dependencies: + is-promise "^2.1.0" + +rxjs@^6.4.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" + integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -4916,6 +5366,11 @@ self-closing-tags@^1.0.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^6.1.2, semver@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" @@ -5027,6 +5482,15 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -5218,7 +5682,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -5226,6 +5690,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -5247,6 +5720,13 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom@3.0.0, strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -5264,6 +5744,11 @@ strip-eof@^1.0.0: resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -5343,6 +5828,16 @@ symbol-tree@^3.2.2: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" integrity sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tar@^4: version "4.4.8" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" @@ -5374,16 +5869,33 @@ test-exclude@^4.2.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + throat@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + time-stamp@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -5511,33 +6023,20 @@ tsconfig-paths@^3.7.0: minimist "^1.2.0" strip-bom "^3.0.0" -tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.7.1, tslib@^1.8.1, tslib@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslint@5.11.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" - integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= - dependencies: - babel-code-frame "^6.22.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^3.2.0" - glob "^7.1.1" - js-yaml "^3.7.0" - minimatch "^3.0.4" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.8.0" - tsutils "^2.27.2" +tslib@^1.9.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" + integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== -tsutils@^2.27.2: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== +tsutils@^3.14.0: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== dependencies: tslib "^1.8.1" @@ -5692,6 +6191,11 @@ uuid@^3.1.0, uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -5844,6 +6348,13 @@ write-file-atomic@^2.1.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + ws@^3.2.0, ws@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"