From 58dbe2edf5748ca40ddfbfe67aabc849fef737a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Sun, 26 Apr 2020 23:13:58 +0200 Subject: [PATCH] feat: switch to json-schema-ref-parser --- .gitignore | 2 + README.md | 17 +++-- package.json | 12 +++- src/__tests__/file.spec.ts | 16 ----- src/__tests__/http.spec.ts | 56 ---------------- src/file.ts | 11 ---- src/http.ts | 27 -------- src/index.ts | 4 +- src/parsers/__tests__/json.spec.ts | 87 +++++++++++++++++++++++++ src/parsers/__tests__/yaml.spec.ts | 83 ++++++++++++++++++++++++ src/parsers/error.ts | 61 ++++++++++++++++++ src/parsers/generic.ts | 36 +++++++++++ src/parsers/index.ts | 4 ++ src/parsers/json.ts | 4 ++ src/parsers/yaml.ts | 4 ++ src/resolvers/__tests__/file.spec.ts | 37 +++++++++++ src/resolvers/__tests__/http.spec.ts | 87 +++++++++++++++++++++++++ src/resolvers/file.ts | 25 ++++++++ src/resolvers/http.ts | 28 ++++++++ src/resolvers/index.ts | 6 ++ yarn.lock | 95 ++++++++++++++++++++++++---- 21 files changed, 564 insertions(+), 138 deletions(-) delete mode 100644 src/__tests__/file.spec.ts delete mode 100644 src/__tests__/http.spec.ts delete mode 100644 src/file.ts delete mode 100644 src/http.ts create mode 100644 src/parsers/__tests__/json.spec.ts create mode 100644 src/parsers/__tests__/yaml.spec.ts create mode 100644 src/parsers/error.ts create mode 100644 src/parsers/generic.ts create mode 100644 src/parsers/index.ts create mode 100644 src/parsers/json.ts create mode 100644 src/parsers/yaml.ts create mode 100644 src/resolvers/__tests__/file.spec.ts create mode 100644 src/resolvers/__tests__/http.spec.ts create mode 100644 src/resolvers/file.ts create mode 100644 src/resolvers/http.ts create mode 100644 src/resolvers/index.ts diff --git a/.gitignore b/.gitignore index 8191cdd..9053dac 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ # misc .idea + +coverage/ diff --git a/README.md b/README.md index af5484d..85f9062 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,16 @@ yarn add @stoplight/json-ref-readers ## Usage -The library exports two functions: `resolveHttp` and `resolveFile`. Both take `uri.URI` and resolve to a string containing requested resource. - ```ts -import { Resolver } from '@stoplight/json-ref-resolver'; -import { resolveFile, resolveHttp } from '@stoplight/json-ref-readers'; +import $RefParser from '@apidevtools/json-schema-ref-parser'; +import { jsonParser, yamlParser } from '@stoplight/json-ref-readers'; + +const parser = new $RefParser(); -const httpAndFileResolver = new Resolver({ - resolvers: { - https: { resolve: resolveHttp }, - http: { resolve: resolveHttp }, - file: { resolve: resolveFile }, +parser.dereference(filePath, { + parse: { + json: jsonParser, + yaml: yamlParser, }, }); ``` diff --git a/package.json b/package.json index 6f4f38c..828918c 100644 --- a/package.json +++ b/package.json @@ -27,21 +27,27 @@ "test.prod": "yarn lint && yarn test --coverage --no-cache", "test.update": "yarn test --updateSnapshot" }, + "peerDependencies": { + "@apidevtools/json-schema-ref-parser": ">=9.0.2" + }, "dependencies": { + "@stoplight/json": "^3.7.1", + "@stoplight/path": "^1.3.1", + "@stoplight/yaml": "^3.8.1", "node-fetch": "^2.6.0" }, "devDependencies": { + "@apidevtools/json-schema-ref-parser": "https://github.com/stoplightio/json-schema-ref-parser#03462047af4e62e889038f5e4ce53c552fbefaee", "@stoplight/scripts": "^7.0.3", + "@stoplight/types": "^11.6.0", "@types/jest": "^24.0.18", "@types/nock": "^11.1.0", "@types/node-fetch": "^2.5.2", - "@types/urijs": "^1.19.4", "jest": "^24.9.0", "nock": "^11.7.0", "ts-jest": "^24.1.0", "tslint": "^5.20.0", "tslint-config-stoplight": "^1.3.0", - "typescript": "^3.6.3", - "urijs": "^1.19.2" + "typescript": "^3.8.3" } } diff --git a/src/__tests__/file.spec.ts b/src/__tests__/file.spec.ts deleted file mode 100644 index 4d0995b..0000000 --- a/src/__tests__/file.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { readFile } from 'fs'; -import { resolveFile } from '../file'; - -jest.mock('fs'); - -describe('resolveFile()', () => { - it('works', async () => { - ((readFile as unknown) as jest.Mock).mockImplementation((_, __, cb) => cb(undefined, 'root:*')); - await expect(resolveFile({ path: () => '/etc/passwd' } as uri.URI)).resolves.toEqual('root:*'); - }); - - it('handles failures', async () => { - ((readFile as unknown) as jest.Mock).mockImplementation((_, __, cb) => cb(new Error('Using shadow, ha, ha'))); - await expect(resolveFile({ path: () => '/etc/passwd' } as uri.URI)).rejects.toThrowError('Using shadow, ha, ha'); - }); -}); diff --git a/src/__tests__/http.spec.ts b/src/__tests__/http.spec.ts deleted file mode 100644 index adb696e..0000000 --- a/src/__tests__/http.spec.ts +++ /dev/null @@ -1,56 +0,0 @@ -import * as nock from 'nock'; -import * as URI from 'urijs'; -import { createResolveHttp, NetworkError, OpenError, resolveHttp } from '../http'; - -describe('resolveHttp()', () => { - afterAll(() => { - nock.cleanAll(); - }); - - it('works', () => { - nock('https://stoplight.io') - .get('/') - .reply(200, 'test'); - - return expect(resolveHttp(new URI('http://stoplight.io'))).resolves.toEqual('test'); - }); - - it('given a 404 network error, throws OpenError', () => { - nock('https://stoplight.io') - .get('/') - .reply(404); - - return expect(resolveHttp(new URI('http://stoplight.io'))).rejects.toStrictEqual( - new OpenError('Page not found: http://stoplight.io/'), - ); - }); - - it('given a network error, throws NetworkError', () => { - nock('https://stoplight.io') - .get('/') - .reply(500); - - return expect(resolveHttp(new URI('http://stoplight.io'))).rejects.toStrictEqual( - new NetworkError('500 Internal Server Error'), - ); - }); -}); - -describe('createResolveHttp()', () => { - afterAll(() => { - nock.cleanAll(); - }); - - it('allows to pass custom RequestInit', () => { - nock('https://stoplight.io') - .get('/') - .basicAuth({ user: 'john', pass: 'doe' }) - .reply(200, 'test'); - - const resolve = createResolveHttp({ - headers: { Authorization: `Basic ${Buffer.from('john:doe').toString('base64')}` }, - }); - - return expect(resolve(new URI('http://stoplight.io'))).resolves.toEqual('test'); - }); -}); diff --git a/src/file.ts b/src/file.ts deleted file mode 100644 index 5069da8..0000000 --- a/src/file.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { readFile } from 'fs'; - -export function resolveFile(ref: uri.URI) { - return new Promise((resolve, reject) => { - const path = ref.path(); - readFile(path, 'utf8', (err, data) => { - if (err) reject(err); - resolve(data); - }); - }); -} diff --git a/src/http.ts b/src/http.ts deleted file mode 100644 index 2fcdde6..0000000 --- a/src/http.ts +++ /dev/null @@ -1,27 +0,0 @@ -import fetch, { RequestInit } from 'node-fetch'; - -export class OpenError extends Error { - public readonly name = 'OpenError'; -} - -export class NetworkError extends Error { - public readonly name = 'ReadError'; -} - -export async function resolveHttp(ref: uri.URI, opts: RequestInit = {}) { - const uri = ref.href(); - const response = await fetch(uri, opts); - if (response.ok) { - return response.text(); - } - - if (response.status === 404) { - throw new OpenError(`Page not found: ${uri}`); - } - - throw new NetworkError(`${response.status} ${response.statusText}`); -} - -export function createResolveHttp(defaultRequestOptions: RequestInit = {}): typeof resolveHttp { - return ref => resolveHttp(ref, defaultRequestOptions); -} diff --git a/src/index.ts b/src/index.ts index 26bdc6c..97b410b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,2 @@ -export { createResolveHttp, resolveHttp, NetworkError, OpenError } from './http'; -export { resolveFile } from './file'; +export * from './parsers'; +export * from './resolvers'; diff --git a/src/parsers/__tests__/json.spec.ts b/src/parsers/__tests__/json.spec.ts new file mode 100644 index 0000000..2fec2cf --- /dev/null +++ b/src/parsers/__tests__/json.spec.ts @@ -0,0 +1,87 @@ +import { readFile } from 'fs'; +import $RefParser = require('@apidevtools/json-schema-ref-parser'); +import { jsonParser } from '../index'; +import { resolveFile } from '../../resolvers'; + +jest.mock('fs'); + +describe('JSON Parser', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('works', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo":true}')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.json' }, { + resolve: { + file: resolveFile, + }, + parse: { + json: jsonParser, + yaml: false, + } + }); + + return expect(deref).resolves.toStrictEqual({ foo: true }); + }); + + it('retains the order of keys', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo":true,"0": false}')); + + const parser = new $RefParser(); + const deref = await parser.dereference({ $ref: './baz.json' }, { + resolve: { + file: resolveFile, + }, + parse: { + json: jsonParser, + yaml: false, + } + }); + + expect(Object.keys(deref)).toEqual(['foo', '0']) + }); + + it('handles failures', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{bar zx;cxz"":true}')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.json' }, { + resolve: { + file: resolveFile, + }, + parse: { + json: jsonParser, + yaml: false, + } + }); + + return expect(deref).rejects.toThrow($RefParser.ParserError); + }); + + it('integrates with continueOnError', () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo": true,}')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.json' }, { + resolve: { + file: resolveFile, + }, + parse: { + json: jsonParser, + yaml: false, + }, + continueOnError: true, + }); + + return Promise.all([ + expect(deref).rejects.toThrow($RefParser.JSONParserErrorGroup), + expect(deref).rejects.toHaveProperty('errors', [ + expect.objectContaining({ name: 'ParserError', message: 'PropertyNameExpected' }), + expect.objectContaining({ name: 'ParserError', message: 'ValueExpected' }), + ]), + ]); + }) +}); diff --git a/src/parsers/__tests__/yaml.spec.ts b/src/parsers/__tests__/yaml.spec.ts new file mode 100644 index 0000000..1e76957 --- /dev/null +++ b/src/parsers/__tests__/yaml.spec.ts @@ -0,0 +1,83 @@ +import { readFile } from 'fs'; +import $RefParser = require('@apidevtools/json-schema-ref-parser'); +import { yamlParser } from '../index'; +import { resolveFile } from '../../resolvers'; + +jest.mock('fs'); + +describe('YAML Parser', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('works', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo":true}')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.yaml' }, { + resolve: { + file: resolveFile, + }, + parse: { + yaml: yamlParser, + } + }); + + return expect(deref).resolves.toStrictEqual({ foo: true }); + }); + + it('retains the order of keys', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo":true,"0": false}')); + + const parser = new $RefParser(); + const deref = await parser.dereference({ $ref: './baz.yaml' }, { + resolve: { + file: resolveFile, + }, + parse: { + yaml: yamlParser, + } + }); + + expect(Object.keys(deref)).toEqual(['foo', '0']) + }); + + it('handles failures', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, 'foo:\n d\na')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.yaml' }, { + resolve: { + file: resolveFile, + }, + parse: { + yaml: yamlParser, + } + }); + + return expect(deref).rejects.toThrow($RefParser.ParserError); + }); + + it('integrates with continueOnError', () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, 'foo:\n d\na')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz.yaml' }, { + resolve: { + file: resolveFile, + }, + parse: { + yaml: yamlParser, + }, + continueOnError: true, + }); + + return Promise.all([ + expect(deref).rejects.toThrow($RefParser.JSONParserErrorGroup), + expect(deref).rejects.toHaveProperty('errors', [ + expect.objectContaining({ name: 'ParserError', message: 'can not read a block mapping entry; a multiline key may not be an implicit key' }), + expect.objectContaining({ name: 'ParserError', message: 'can not read an implicit mapping pair; a colon is missed' }), + ]), + ]); + }) +}); diff --git a/src/parsers/error.ts b/src/parsers/error.ts new file mode 100644 index 0000000..a3fd1ca --- /dev/null +++ b/src/parsers/error.ts @@ -0,0 +1,61 @@ +import { JSONParserError, ParserError } from '@apidevtools/json-schema-ref-parser'; +import { Dictionary, IDiagnostic, JsonPath } from '@stoplight/types'; + +// Vincenzo loves it. +type WritableJSONParserError = Dictionary; + +export default class StoplightParserError extends ParserError { + protected _path: JsonPath; + protected _source: string; + public errors: JSONParserError[]; + + constructor(diagnostics: IDiagnostic[], source: string) { + super(`Error parsing ${source}`, source); + + this._source = source; + this._path = []; + this.errors = diagnostics.filter(StoplightParserError.pickError).map(StoplightParserError.createParserError, this); + } + + protected static createParserError(this: StoplightParserError, diagnostic: IDiagnostic) { + const parserError = new ParserError(diagnostic.message, this.source); + (parserError as WritableJSONParserError).message = diagnostic.message; + return parserError; + } + + protected static pickError(diagnostic: IDiagnostic) { + return diagnostic.severity === 0; + } + + public static hasErrors(diagnostics: IDiagnostic[]) { + return diagnostics.some(StoplightParserError.pickError); + } + + public get source() { + return this._source; + } + + public set source(source) { + this._source = source; + + if (this.errors) { + for (const error of this.errors) { + (error as WritableJSONParserError).source = source; + } + } + } + + public get path() { + return this._path; + } + + public set path(path) { + this._path = path; + + if (this.errors) { + for (const error of this.errors) { + (error as WritableJSONParserError).path = path; + } + } + } +} diff --git a/src/parsers/generic.ts b/src/parsers/generic.ts new file mode 100644 index 0000000..74cd71d --- /dev/null +++ b/src/parsers/generic.ts @@ -0,0 +1,36 @@ +import { ParserOptions } from '@apidevtools/json-schema-ref-parser'; +import { IParserResult } from '@stoplight/types'; +import StoplightParserError from './error'; + +export declare type Parser = ( + value: string, + options: Partial<{ preserveKeyOrder: boolean }>, +) => IParserResult; + +export default (parse: Parser, order: number, canParse: string[]): ParserOptions => ({ + allowEmpty: true, + order, + canParse, + async parse(file) { + let data = file.data; + if (Buffer.isBuffer(data)) { + data = data.toString(); + } + + if (typeof data === 'string') { + if (data.trim().length === 0) { + return; + } else { + const result = parse(data, { preserveKeyOrder: true }); + + if (StoplightParserError.hasErrors(result.diagnostics)) { + throw new StoplightParserError(result.diagnostics, file.url); + } + + return result.data; + } + } else { + return data; + } + }, +}); diff --git a/src/parsers/index.ts b/src/parsers/index.ts new file mode 100644 index 0000000..0e503cb --- /dev/null +++ b/src/parsers/index.ts @@ -0,0 +1,4 @@ +export { default as StoplightParserError } from './error'; +export { default as createGenericParser } from './generic'; +export { default as jsonParser } from './json'; +export { default as yamlParser } from './yaml'; diff --git a/src/parsers/json.ts b/src/parsers/json.ts new file mode 100644 index 0000000..f468dc8 --- /dev/null +++ b/src/parsers/json.ts @@ -0,0 +1,4 @@ +import { parseWithPointers } from '@stoplight/json'; +import createParser from './generic'; + +export default createParser(parseWithPointers, 100, ['.json']); diff --git a/src/parsers/yaml.ts b/src/parsers/yaml.ts new file mode 100644 index 0000000..d2332ba --- /dev/null +++ b/src/parsers/yaml.ts @@ -0,0 +1,4 @@ +import { parseWithPointers } from '@stoplight/yaml'; +import createParser from './generic'; + +export default createParser(parseWithPointers, 200, ['.yaml', '.yml', '.json']); diff --git a/src/resolvers/__tests__/file.spec.ts b/src/resolvers/__tests__/file.spec.ts new file mode 100644 index 0000000..f9e282e --- /dev/null +++ b/src/resolvers/__tests__/file.spec.ts @@ -0,0 +1,37 @@ +import { readFile } from 'fs'; +import { resolveFile } from '../'; +import $RefParser = require('@apidevtools/json-schema-ref-parser'); + +jest.mock('fs'); + +describe('resolveFile()', () => { + afterEach(() => { + jest.resetAllMocks(); + }); + + it('works', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path, _opts, cb) => cb(null, '{"foo":true}')); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz'}, { + resolve: { + file: resolveFile, + } + }); + + return expect(deref).resolves.toStrictEqual({ foo: true }); + }); + + it('handles failures', async () => { + ((readFile as unknown) as jest.Mock).mockImplementation((_path,_opts, cb) => cb(new Error('Using shadow, ha, ha'))); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: './baz'}, { + resolve: { + file: resolveFile, + } + }); + + return expect(deref).rejects.toThrow($RefParser.ResolverError); + }); +}); diff --git a/src/resolvers/__tests__/http.spec.ts b/src/resolvers/__tests__/http.spec.ts new file mode 100644 index 0000000..559baa6 --- /dev/null +++ b/src/resolvers/__tests__/http.spec.ts @@ -0,0 +1,87 @@ +import * as nock from 'nock'; +import { createResolveHttp, resolveHttp } from '../'; +import $RefParser = require('@apidevtools/json-schema-ref-parser'); +import { ResolverError } from '@apidevtools/json-schema-ref-parser'; + +describe('resolveHttp()', () => { + afterAll(() => { + nock.cleanAll(); + }); + + it('works', () => { + nock('https://stoplight.io') + .get('/') + .reply(200, '{"bar":false}'); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: 'https://stoplight.io' }, { + resolve: { + http: resolveHttp, + } + }); + + return expect(deref).resolves.toStrictEqual({ bar: false }); + }); + + it('given a 404 network error, throws an error with different message', () => { + nock('https://stoplight.io') + .get('/') + .reply(404); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: 'https://stoplight.io' }, { + resolve: { + http: resolveHttp, + } + }); + + return Promise.all([ + expect(deref).rejects.toThrow(ResolverError), + expect(deref).rejects.toThrowError('Page not found: https://stoplight.io/'), + ]); + }); + + it('given a network error, throws an error', () => { + nock('https://stoplight.io') + .get('/') + .reply(500); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: 'https://stoplight.io' }, { + resolve: { + http: resolveHttp, + } + }); + + return Promise.all([ + expect(deref).rejects.toThrow(ResolverError), + expect(deref).rejects.toThrowError('500 Internal Server Error'), + ]); + }); +}); + +describe('createResolveHttp()', () => { + afterAll(() => { + nock.cleanAll(); + }); + + it('allows to pass custom RequestInit', () => { + nock('https://stoplight.io') + .get('/') + .basicAuth({ user: 'john', pass: 'doe' }) + .reply(200, '[]'); + + const resolve = createResolveHttp({ + headers: { Authorization: `Basic ${Buffer.from('john:doe').toString('base64')}` }, + }); + + const parser = new $RefParser(); + const deref = parser.dereference({ $ref: 'https://stoplight.io' }, { + resolve: { + http: resolve, + } + }); + + return expect(deref).resolves.toStrictEqual([]); + }); +}); diff --git a/src/resolvers/file.ts b/src/resolvers/file.ts new file mode 100644 index 0000000..7e4e5f7 --- /dev/null +++ b/src/resolvers/file.ts @@ -0,0 +1,25 @@ +import { ResolverError, ResolverOptions } from '@apidevtools/json-schema-ref-parser'; +import { isURL } from '@stoplight/path'; +import { readFile } from 'fs'; + +const resolveFile: ResolverOptions = { + order: 100, + + canRead(file) { + return !isURL(file.url); + }, + + read(file) { + return new Promise((resolve, reject) => { + readFile(file.url, 'utf8', (err, data) => { + if (err) { + reject(new ResolverError(err, file.url)); + } else { + resolve(data); + } + }); + }); + }, +}; + +export { resolveFile as default }; diff --git a/src/resolvers/http.ts b/src/resolvers/http.ts new file mode 100644 index 0000000..3de3bd3 --- /dev/null +++ b/src/resolvers/http.ts @@ -0,0 +1,28 @@ +import { ResolverError, ResolverOptions } from '@apidevtools/json-schema-ref-parser'; +import { isURL } from '@stoplight/path'; +import fetch, { RequestInit } from 'node-fetch'; + +export default (opts: RequestInit = {}): ResolverOptions => ({ + order: 200, + + canRead(file) { + return isURL(file.url); + }, + + async read(file) { + try { + const response = await fetch(file.url, opts); + if (response.ok) { + return await response.text(); + } + + if (response.status === 404) { + throw new Error(`Page not found: ${file.url}`); + } + + throw new Error(`${response.status} ${response.statusText}`); + } catch (ex) { + throw new ResolverError(ex, file.url); + } + }, +}); diff --git a/src/resolvers/index.ts b/src/resolvers/index.ts new file mode 100644 index 0000000..1bc90ea --- /dev/null +++ b/src/resolvers/index.ts @@ -0,0 +1,6 @@ +import createResolveHttp from './http'; + +export { default as resolveFile } from './file'; + +export { createResolveHttp }; +export const resolveHttp = createResolveHttp(); diff --git a/yarn.lock b/yarn.lock index f78ecc2..78f06bd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@apidevtools/json-schema-ref-parser@https://github.com/stoplightio/json-schema-ref-parser#03462047af4e62e889038f5e4ce53c552fbefaee": + version "9.0.1" + resolved "https://github.com/stoplightio/json-schema-ref-parser#03462047af4e62e889038f5e4ce53c552fbefaee" + dependencies: + "@jsdevtools/ono" "^7.1.2" + call-me-maybe "^1.0.1" + js-yaml "^3.13.1" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" @@ -424,6 +432,11 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@jsdevtools/ono@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.2.tgz#373995bb40a6686589a7fcfec06b0e6e304ef6c6" + integrity sha512-qS/a24RA5FEoiJS9wiv6Pwg2c/kiUo3IVUQcfeM9JvsR6pM8Yx+yl/6xWYLckZCT5jpLNhslgjiA8p/XcGyMRQ== + "@marionebl/sander@^0.6.0": version "0.6.1" resolved "https://registry.yarnpkg.com/@marionebl/sander/-/sander-0.6.1.tgz#1958965874f24bc51be48875feb50d642fc41f7b" @@ -774,6 +787,27 @@ lodash "^4.17.4" read-pkg-up "^6.0.0" +"@stoplight/json@^3.7.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@stoplight/json/-/json-3.7.1.tgz#3855478ed3e0baaee6a7627948957ce537e481ad" + integrity sha512-5VUVZxO7Jg+yoyEPa+ymD+fz5Pij96Nv3ei8FpzkzJwZLqY0ycAe8pBTz1mMf9QDUB+7HZZnCrWGCqGtDLYZZA== + dependencies: + "@stoplight/ordered-object-literal" "^1.0.1" + "@stoplight/types" "^11.4.0" + jsonc-parser "~2.2.0" + lodash "^4.17.15" + safe-stable-stringify "^1.1" + +"@stoplight/ordered-object-literal@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@stoplight/ordered-object-literal/-/ordered-object-literal-1.0.1.tgz#01ece81ba5dda199ca3dc5ec7464691efa5d5b76" + integrity sha512-kDcBIKwzAXZTkgzaiPXH2I0JXavBkOb3jFzYNFS5cBuvZS3s/K+knpk2wLVt0n8XrnRQsSffzN6XG9HqUhfq6Q== + +"@stoplight/path@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@stoplight/path/-/path-1.3.1.tgz#1246c983279af20dcfb806d138add9f81cb1efd2" + integrity sha512-I6YEfxspGglxt7MbgNbKThHdqh8CJWnDC1x1JUk2rka2D7mCpMSEu5I8IiAp997Dp4YIXDY6Did6gge8OY8KnA== + "@stoplight/scripts@^7.0.3": version "7.0.3" resolved "https://registry.yarnpkg.com/@stoplight/scripts/-/scripts-7.0.3.tgz#024805f3a97c349836a50821b5ddf68d142be27d" @@ -804,6 +838,29 @@ shelljs "0.8.x" tslib "1.9.3" +"@stoplight/types@^11.1.1", "@stoplight/types@^11.4.0", "@stoplight/types@^11.6.0": + version "11.6.0" + resolved "https://registry.yarnpkg.com/@stoplight/types/-/types-11.6.0.tgz#c4507f564ea4be719f66ae2fd2bb83f4719c2210" + integrity sha512-J2wOl6FlN4IeY99MZTbgLVbIqrE9eVcHIvWmSEFzxfnbHCh4reXcGkvxlQ7I/pTKScd5/F/HJKSYnNXRjCnM2A== + dependencies: + "@types/json-schema" "^7.0.4" + utility-types "^3.10.0" + +"@stoplight/yaml-ast-parser@0.0.45": + version "0.0.45" + resolved "https://registry.yarnpkg.com/@stoplight/yaml-ast-parser/-/yaml-ast-parser-0.0.45.tgz#672c0a1511d581843be5a9c55899ca95a30dcadb" + integrity sha512-0MTEvgp3XMdeMUSTCGiNECuC+YlLbzytDEIOJVDHrrmzVZpIR3gGnHI6mmPI4P7saPxUiHxFF2uuoTuCNlKjrw== + +"@stoplight/yaml@^3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@stoplight/yaml/-/yaml-3.8.1.tgz#2a2accdb8b3b6df5c3f1ba93086ca9deb99be0e4" + integrity sha512-wbhcgo7dTjwjjwFziC/SAcQlwPucYhYq6vjzyOjj8zeOVnnmoa7hzU1i9Kj31473FG/re7xtt6j3LWu2VnYbxg== + dependencies: + "@stoplight/ordered-object-literal" "^1.0.1" + "@stoplight/types" "^11.1.1" + "@stoplight/yaml-ast-parser" "0.0.45" + lodash "^4.17.15" + "@types/babel__core@^7.1.0": version "7.1.3" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30" @@ -888,6 +945,11 @@ dependencies: "@types/jest-diff" "*" +"@types/json-schema@^7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" + integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -927,11 +989,6 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== -"@types/urijs@^1.19.4": - version "1.19.4" - resolved "https://registry.yarnpkg.com/@types/urijs/-/urijs-1.19.4.tgz#29c4a694d4842d7f95e359a26223fc1865f1ab13" - integrity sha512-uHUvuLfy4YkRHL4UH8J8oRsINhdEHd9ymag7KJZVT94CjAmY1njoUzhazJsZjwfy+IpWKQKGVyXCwzhZvg73Fg== - "@types/yargs-parser@*": version "13.1.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" @@ -4463,6 +4520,11 @@ json5@2.x, json5@^2.1.0: dependencies: minimist "^1.2.0" +jsonc-parser@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-2.2.1.tgz#db73cd59d78cce28723199466b2a03d1be1df2bc" + integrity sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w== + jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -6958,6 +7020,11 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safe-stable-stringify@^1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz#c8a220ab525cd94e60ebf47ddc404d610dc5d84a" + integrity sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw== + "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -7918,10 +7985,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da" - integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw== +typescript@^3.8.3: + version "3.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" + integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== uglify-js@^3.1.4: version "3.6.1" @@ -8025,11 +8092,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.19.2: - version "1.19.2" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.2.tgz#f9be09f00c4c5134b7cb3cf475c1dd394526265a" - integrity sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w== - urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -8077,6 +8139,11 @@ util.promisify@^1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +utility-types@^3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b" + integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg== + uuid@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"