1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-05-03 01:18:43 +02:00

fix: fix broken OpenAPI spec (#1846)

* Wip: fix openapi spec

* Feat: add openapi enforcer for enforcing the generated schema

* Chore: Allow the example keyword in params

* Feat: add validator tests and fix some errors

* Use @apidevtools/swagger-parser for schema validation

* Wip: refactor tests for updated schema name

* Feat: update request params creation method

* Feat: add query params to state

* Refactor: move mapping test into separate function

* Refactor: rename request-parameters -> query-parameters

* Refactor: expose only finished query parameters

* Wip: fixup param types

* Refactor: remove unused types

* Chore: rename and cleanup

* Chore: cleanup

* Fix: Update snapshot

* Fix: use ?? Instead of paramToBool to get defaults

* Wip: generate query param object type from openapi params list

* Wip: use generated types for export query params

* Revert "Fix: use ?? Instead of paramToBool to get defaults"

This reverts commit 842567500b.

Because we accept bools, strings, and numbers, this is the only way to
do it.

* Chore: update and pin json-schema-to-ts

* Fix: use `&` to merge types

* Update snapshot

* Chore: rename export-parameters-schema -> export-query-parameters

When it ends in `schema`, the tests expect it to be included in the
openapi index file.
This commit is contained in:
Thomas Heartman 2022-07-28 09:19:58 +02:00 committed by GitHub
parent f6192b50b0
commit 6afc0a6954
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 407 additions and 139 deletions

View File

@ -100,7 +100,7 @@
"helmet": "^5.0.0", "helmet": "^5.0.0",
"joi": "^17.3.0", "joi": "^17.3.0",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"json-schema-to-ts": "^2.5.3", "json-schema-to-ts": "2.5.4",
"knex": "^2.0.0", "knex": "^2.0.0",
"log4js": "^6.0.0", "log4js": "^6.0.0",
"make-fetch-happen": "^10.1.2", "make-fetch-happen": "^10.1.2",
@ -120,12 +120,14 @@
"semver": "^7.3.5", "semver": "^7.3.5",
"serve-favicon": "^2.5.0", "serve-favicon": "^2.5.0",
"stoppable": "^1.1.0", "stoppable": "^1.1.0",
"ts-toolbelt": "^9.6.0",
"type-is": "^1.6.18", "type-is": "^1.6.18",
"unleash-client": "^3.15.0", "unleash-client": "^3.15.0",
"unleash-frontend": "4.14.0-beta.6", "unleash-frontend": "4.14.0-beta.6",
"uuid": "^8.3.2" "uuid": "^8.3.2"
}, },
"devDependencies": { "devDependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"@babel/core": "7.18.9", "@babel/core": "7.18.9",
"@types/bcryptjs": "2.4.2", "@types/bcryptjs": "2.4.2",
"@types/express": "4.17.13", "@types/express": "4.17.13",

View File

@ -30,7 +30,6 @@ import { environmentSchema } from './spec/environment-schema';
import { environmentsSchema } from './spec/environments-schema'; import { environmentsSchema } from './spec/environments-schema';
import { eventSchema } from './spec/event-schema'; import { eventSchema } from './spec/event-schema';
import { eventsSchema } from './spec/events-schema'; import { eventsSchema } from './spec/events-schema';
import { exportParametersSchema } from './spec/export-parameters-schema';
import { featureEnvironmentMetricsSchema } from './spec/feature-environment-metrics-schema'; import { featureEnvironmentMetricsSchema } from './spec/feature-environment-metrics-schema';
import { featureEnvironmentSchema } from './spec/feature-environment-schema'; import { featureEnvironmentSchema } from './spec/feature-environment-schema';
import { featureEventsSchema } from './spec/feature-events-schema'; import { featureEventsSchema } from './spec/feature-events-schema';
@ -139,7 +138,6 @@ export const schemas = {
environmentsSchema, environmentsSchema,
eventSchema, eventSchema,
eventsSchema, eventsSchema,
exportParametersSchema,
featureEnvironmentMetricsSchema, featureEnvironmentMetricsSchema,
featureEnvironmentSchema, featureEnvironmentSchema,
featureEventsSchema, featureEventsSchema,

View File

@ -3,7 +3,6 @@ import { FromSchema } from 'json-schema-to-ts';
export const clientFeaturesQuerySchema = { export const clientFeaturesQuerySchema = {
$id: '#/components/schemas/clientFeaturesQuerySchema', $id: '#/components/schemas/clientFeaturesQuerySchema',
type: 'object', type: 'object',
required: [],
additionalProperties: false, additionalProperties: false,
properties: { properties: {
tag: { tag: {

View File

@ -1,32 +0,0 @@
import { FromSchema } from 'json-schema-to-ts';
export const exportParametersSchema = {
$id: '#/components/schemas/exportParametersSchema',
type: 'object',
properties: {
format: {
type: 'string',
},
download: {
type: 'boolean',
},
strategies: {
type: 'boolean',
},
featureToggles: {
type: 'boolean',
},
projects: {
type: 'boolean',
},
tags: {
type: 'boolean',
},
environments: {
type: 'boolean',
},
},
components: {},
} as const;
export type ExportParametersSchema = FromSchema<typeof exportParametersSchema>;

View File

@ -0,0 +1,143 @@
import { FromQueryParams } from '../util/from-query-params';
export const exportQueryParameters = [
{
name: 'format',
schema: {
type: 'string',
enum: ['json', 'yaml'],
default: 'json',
},
description: 'Desired export format. Must be either `json` or `yaml`.',
in: 'query',
},
{
name: 'download',
schema: {
default: false,
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
},
description: 'Whether exported data should be downloaded as a file.',
in: 'query',
},
{
name: 'strategies',
schema: {
default: true,
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
},
description:
'Whether strategies should be included in the exported data.',
in: 'query',
},
{
name: 'featureToggles',
schema: {
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
default: true,
},
description:
'Whether feature toggles should be included in the exported data.',
in: 'query',
},
{
name: 'projects',
schema: {
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
default: true,
},
description:
'Whether projects should be included in the exported data.',
in: 'query',
},
{
name: 'tags',
schema: {
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
default: true,
},
description:
'Whether tag types, tags, and feature_tags should be included in the exported data.',
in: 'query',
},
{
name: 'environments',
schema: {
anyOf: [
{
type: 'boolean',
},
{
type: 'string',
minLength: 1,
},
{
type: 'number',
},
],
default: true,
},
description:
'Whether environments should be included in the exported data.',
in: 'query',
},
] as const;
export type ExportQueryParameters = FromQueryParams<
typeof exportQueryParameters
>;

View File

@ -4,7 +4,6 @@ export const feedbackSchema = {
$id: '#/components/schemas/feedbackSchema', $id: '#/components/schemas/feedbackSchema',
type: 'object', type: 'object',
additionalProperties: false, additionalProperties: false,
required: [],
properties: { properties: {
userId: { userId: {
type: 'number', type: 'number',

View File

@ -10,9 +10,9 @@ export const playgroundFeatureSchema = {
additionalProperties: false, additionalProperties: false,
required: ['name', 'projectId', 'isEnabled', 'variant', 'variants'], required: ['name', 'projectId', 'isEnabled', 'variant', 'variants'],
properties: { properties: {
name: { type: 'string', examples: ['my-feature'] }, name: { type: 'string', example: 'my-feature' },
projectId: { type: 'string', examples: ['my-project'] }, projectId: { type: 'string', example: 'my-project' },
isEnabled: { type: 'boolean', examples: [true] }, isEnabled: { type: 'boolean', example: true },
variant: { variant: {
type: 'object', type: 'object',
additionalProperties: false, additionalProperties: false,
@ -34,7 +34,7 @@ export const playgroundFeatureSchema = {
}, },
}, },
nullable: true, nullable: true,
examples: ['green'], example: { name: 'green', enabled: true },
}, },
variants: { type: 'array', items: { $ref: variantSchema.$id } }, variants: { type: 'array', items: { $ref: variantSchema.$id } },
}, },

View File

@ -8,13 +8,13 @@ export const playgroundRequestSchema = {
type: 'object', type: 'object',
required: ['environment', 'context'], required: ['environment', 'context'],
properties: { properties: {
environment: { type: 'string', examples: ['development'] }, environment: { type: 'string', example: 'development' },
projects: { projects: {
oneOf: [ oneOf: [
{ {
type: 'array', type: 'array',
items: { type: 'string' }, items: { type: 'string' },
examples: ['my-project', 'my-other-project'], example: ['my-project'],
description: 'A list of projects to check for toggles in.', description: 'A list of projects to check for toggles in.',
}, },
{ {

View File

@ -6,40 +6,38 @@ export const sdkContextSchema = {
type: 'object', type: 'object',
additionalProperties: { additionalProperties: {
type: 'string', type: 'string',
examples: ['top-level custom context value'], example: 'top-level custom context value',
}, },
required: ['appName'], required: ['appName'],
properties: { properties: {
appName: { appName: {
type: 'string', type: 'string',
minLength: 1, minLength: 1,
examples: ['My cool application.'], example: 'My cool application.',
}, },
currentTime: { currentTime: {
type: 'string', type: 'string',
format: 'date-time', format: 'date-time',
examples: ['2022-07-05T12:56:41+02:00'], example: '2022-07-05T12:56:41+02:00',
}, },
environment: { type: 'string', deprecated: true }, environment: { type: 'string', deprecated: true },
properties: { properties: {
type: 'object', type: 'object',
additionalProperties: { type: 'string' }, additionalProperties: { type: 'string' },
examples: [ example: {
{
customContextField: 'this is one!', customContextField: 'this is one!',
otherCustomField: 3, otherCustomField: '3',
}, },
],
}, },
remoteAddress: { remoteAddress: {
type: 'string', type: 'string',
examples: ['192.168.1.1'], example: '192.168.1.1',
}, },
sessionId: { sessionId: {
type: 'string', type: 'string',
examples: ['b65e7b23-fec0-4814-a129-0e9861ef18fc'], example: 'b65e7b23-fec0-4814-a129-0e9861ef18fc',
}, },
userId: { type: 'string', examples: ['username@provider.com'] }, userId: { type: 'string', example: 'username@provider.com' },
}, },
components: {}, components: {},
} as const; } as const;

View File

@ -0,0 +1,32 @@
// module to create typescript types from query param lists. Based on
// input in this GitHub issue:
// https://github.com/ThomasAribart/json-schema-to-ts/issues/82
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { O, L, A } from 'ts-toolbelt';
type OpenApiParam = {
readonly name: string;
readonly schema: JSONSchema;
// Parameter types:
// https://swagger.io/docs/specification/describing-parameters/#types
readonly in: 'query' | 'path' | 'header' | 'cookie';
};
type RecurseOnParams<
P extends readonly OpenApiParam[],
R extends O.Object = {},
> = {
continue: RecurseOnParams<
L.Tail<P>,
L.Head<P>['in'] extends 'query'
? R & {
[key in L.Head<P>['name']]: FromSchema<L.Head<P>['schema']>;
}
: R
>;
stop: A.Compute<R>;
}[P extends readonly [OpenApiParam, ...OpenApiParam[]] ? 'continue' : 'stop'];
export type FromQueryParams<P extends readonly OpenApiParam[]> =
RecurseOnParams<P>;

View File

@ -16,6 +16,10 @@ const ajv = new Ajv({
addFormats(ajv, ['date-time']); addFormats(ajv, ['date-time']);
// example was superseded by examples in openapi 3.1, but we're still on 3.0, so
// let's add it back in!
ajv.addKeyword('example');
export const validateSchema = ( export const validateSchema = (
schema: SchemaId, schema: SchemaId,
data: unknown, data: unknown,

View File

@ -14,8 +14,12 @@ import { IAuthRequest } from '../unleash-types';
import { OpenApiService } from '../../services/openapi-service'; import { OpenApiService } from '../../services/openapi-service';
import { createRequestSchema } from '../../openapi/util/create-request-schema'; import { createRequestSchema } from '../../openapi/util/create-request-schema';
import { createResponseSchema } from '../../openapi/util/create-response-schema'; import { createResponseSchema } from '../../openapi/util/create-response-schema';
import { ExportParametersSchema } from '../../openapi/spec/export-parameters-schema'; import {
exportQueryParameters,
ExportQueryParameters,
} from '../../openapi/spec/export-query-parameters';
import { emptyResponse } from '../../openapi/util/standard-responses'; import { emptyResponse } from '../../openapi/util/standard-responses';
import { OpenAPIV3 } from 'openapi-types';
const upload = multer({ limits: { fileSize: 5242880 } }); const upload = multer({ limits: { fileSize: 5242880 } });
const paramToBool = (param, def) => { const paramToBool = (param, def) => {
@ -75,11 +79,8 @@ class StateController extends Controller {
responses: { responses: {
200: createResponseSchema('stateSchema'), 200: createResponseSchema('stateSchema'),
}, },
parameters: [ parameters:
{ exportQueryParameters as unknown as OpenAPIV3.ParameterObject[],
$ref: '#/components/schema/exportParametersSchema',
},
],
}), }),
], ],
}); });
@ -114,7 +115,7 @@ class StateController extends Controller {
} }
async export( async export(
req: Request<unknown, unknown, unknown, ExportParametersSchema>, req: Request<unknown, unknown, unknown, ExportQueryParameters>,
res: Response, res: Response,
): Promise<void> { ): Promise<void> {
const { format } = req.query; const { format } = req.query;

View File

@ -553,7 +553,6 @@ Object {
"type": "array", "type": "array",
}, },
}, },
"required": Array [],
"type": "object", "type": "object",
}, },
"clientFeaturesSchema": Object { "clientFeaturesSchema": Object {
@ -1018,32 +1017,6 @@ Object {
], ],
"type": "object", "type": "object",
}, },
"exportParametersSchema": Object {
"properties": Object {
"download": Object {
"type": "boolean",
},
"environments": Object {
"type": "boolean",
},
"featureToggles": Object {
"type": "boolean",
},
"format": Object {
"type": "string",
},
"projects": Object {
"type": "boolean",
},
"strategies": Object {
"type": "boolean",
},
"tags": Object {
"type": "boolean",
},
},
"type": "object",
},
"featureEnvironmentMetricsSchema": Object { "featureEnvironmentMetricsSchema": Object {
"additionalProperties": false, "additionalProperties": false,
"properties": Object { "properties": Object {
@ -1465,7 +1438,6 @@ Object {
"type": "number", "type": "number",
}, },
}, },
"required": Array [],
"type": "object", "type": "object",
}, },
"groupSchema": Object { "groupSchema": Object {
@ -1834,28 +1806,23 @@ Object {
"description": "A simplified feature toggle model intended for the Unleash playground.", "description": "A simplified feature toggle model intended for the Unleash playground.",
"properties": Object { "properties": Object {
"isEnabled": Object { "isEnabled": Object {
"examples": Array [ "example": true,
true,
],
"type": "boolean", "type": "boolean",
}, },
"name": Object { "name": Object {
"examples": Array [ "example": "my-feature",
"my-feature",
],
"type": "string", "type": "string",
}, },
"projectId": Object { "projectId": Object {
"examples": Array [ "example": "my-project",
"my-project",
],
"type": "string", "type": "string",
}, },
"variant": Object { "variant": Object {
"additionalProperties": false, "additionalProperties": false,
"examples": Array [ "example": Object {
"green", "enabled": true,
], "name": "green",
},
"nullable": true, "nullable": true,
"properties": Object { "properties": Object {
"enabled": Object { "enabled": Object {
@ -1915,18 +1882,15 @@ Object {
"$ref": "#/components/schemas/sdkContextSchema", "$ref": "#/components/schemas/sdkContextSchema",
}, },
"environment": Object { "environment": Object {
"examples": Array [ "example": "development",
"development",
],
"type": "string", "type": "string",
}, },
"projects": Object { "projects": Object {
"oneOf": Array [ "oneOf": Array [
Object { Object {
"description": "A list of projects to check for toggles in.", "description": "A list of projects to check for toggles in.",
"examples": Array [ "example": Array [
"my-project", "my-project",
"my-other-project",
], ],
"items": Object { "items": Object {
"type": "string", "type": "string",
@ -2074,24 +2038,18 @@ Object {
}, },
"sdkContextSchema": Object { "sdkContextSchema": Object {
"additionalProperties": Object { "additionalProperties": Object {
"examples": Array [ "example": "top-level custom context value",
"top-level custom context value",
],
"type": "string", "type": "string",
}, },
"description": "The Unleash context as modeled in client SDKs", "description": "The Unleash context as modeled in client SDKs",
"properties": Object { "properties": Object {
"appName": Object { "appName": Object {
"examples": Array [ "example": "My cool application.",
"My cool application.",
],
"minLength": 1, "minLength": 1,
"type": "string", "type": "string",
}, },
"currentTime": Object { "currentTime": Object {
"examples": Array [ "example": "2022-07-05T12:56:41+02:00",
"2022-07-05T12:56:41+02:00",
],
"format": "date-time", "format": "date-time",
"type": "string", "type": "string",
}, },
@ -2103,30 +2061,22 @@ Object {
"additionalProperties": Object { "additionalProperties": Object {
"type": "string", "type": "string",
}, },
"examples": Array [ "example": Object {
Object {
"customContextField": "this is one!", "customContextField": "this is one!",
"otherCustomField": 3, "otherCustomField": "3",
}, },
],
"type": "object", "type": "object",
}, },
"remoteAddress": Object { "remoteAddress": Object {
"examples": Array [ "example": "192.168.1.1",
"192.168.1.1",
],
"type": "string", "type": "string",
}, },
"sessionId": Object { "sessionId": Object {
"examples": Array [ "example": "b65e7b23-fec0-4814-a129-0e9861ef18fc",
"b65e7b23-fec0-4814-a129-0e9861ef18fc",
],
"type": "string", "type": "string",
}, },
"userId": Object { "userId": Object {
"examples": Array [ "example": "username@provider.com",
"username@provider.com",
],
"type": "string", "type": "string",
}, },
}, },
@ -5168,7 +5118,137 @@ If the provided project does not exist, the list of events will be empty.",
"operationId": "export", "operationId": "export",
"parameters": Array [ "parameters": Array [
Object { Object {
"$ref": "#/components/schema/exportParametersSchema", "description": "Desired export format. Must be either \`json\` or \`yaml\`.",
"in": "query",
"name": "format",
"schema": Object {
"default": "json",
"enum": Array [
"json",
"yaml",
],
"type": "string",
},
},
Object {
"description": "Whether exported data should be downloaded as a file.",
"in": "query",
"name": "download",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": false,
},
},
Object {
"description": "Whether strategies should be included in the exported data.",
"in": "query",
"name": "strategies",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": true,
},
},
Object {
"description": "Whether feature toggles should be included in the exported data.",
"in": "query",
"name": "featureToggles",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": true,
},
},
Object {
"description": "Whether projects should be included in the exported data.",
"in": "query",
"name": "projects",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": true,
},
},
Object {
"description": "Whether tag types, tags, and feature_tags should be included in the exported data.",
"in": "query",
"name": "tags",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": true,
},
},
Object {
"description": "Whether environments should be included in the exported data.",
"in": "query",
"name": "environments",
"schema": Object {
"anyOf": Array [
Object {
"type": "boolean",
},
Object {
"minLength": 1,
"type": "string",
},
Object {
"type": "number",
},
],
"default": true,
},
}, },
], ],
"responses": Object { "responses": Object {

View File

@ -1,6 +1,7 @@
import { setupApp } from '../../helpers/test-helper'; import { setupApp } from '../../helpers/test-helper';
import dbInit from '../../helpers/database-init'; import dbInit from '../../helpers/database-init';
import getLogger from '../../../fixtures/no-logger'; import getLogger from '../../../fixtures/no-logger';
import SwaggerParser from '@apidevtools/swagger-parser';
let app; let app;
let db; let db;
@ -36,3 +37,19 @@ test('should serve the OpenAPI spec', async () => {
expect(res.body).toMatchSnapshot(); expect(res.body).toMatchSnapshot();
}); });
}); });
test('the generated OpenAPI spec is valid', async () => {
const { body } = await app.request
.get('/docs/openapi.json')
.expect('Content-Type', /json/)
.expect(200);
// this throws if the swagger parser can't parse it correctly
// also parses examples, but _does_ do some string coercion in examples
try {
await SwaggerParser.validate(body);
} catch (err) {
console.error(err);
return false;
}
});

View File

@ -9,6 +9,15 @@
dependencies: dependencies:
"@jridgewell/trace-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.0"
"@apidevtools/json-schema-ref-parser@9.0.6":
version "9.0.6"
resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c"
integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==
dependencies:
"@jsdevtools/ono" "^7.1.3"
call-me-maybe "^1.0.1"
js-yaml "^3.13.1"
"@apidevtools/json-schema-ref-parser@^9.0.6": "@apidevtools/json-schema-ref-parser@^9.0.6":
version "9.0.9" version "9.0.9"
resolved "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz" resolved "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz"
@ -19,7 +28,7 @@
call-me-maybe "^1.0.1" call-me-maybe "^1.0.1"
js-yaml "^4.1.0" js-yaml "^4.1.0"
"@apidevtools/openapi-schemas@^2.0.4": "@apidevtools/openapi-schemas@^2.0.4", "@apidevtools/openapi-schemas@^2.1.0":
version "2.1.0" version "2.1.0"
resolved "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz" resolved "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz"
integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==
@ -41,6 +50,19 @@
call-me-maybe "^1.0.1" call-me-maybe "^1.0.1"
z-schema "^5.0.1" z-schema "^5.0.1"
"@apidevtools/swagger-parser@^10.1.0":
version "10.1.0"
resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6"
integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==
dependencies:
"@apidevtools/json-schema-ref-parser" "9.0.6"
"@apidevtools/openapi-schemas" "^2.1.0"
"@apidevtools/swagger-methods" "^3.0.2"
"@jsdevtools/ono" "^7.1.3"
ajv "^8.6.3"
ajv-draft-04 "^1.0.0"
call-me-maybe "^1.0.1"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13":
version "7.12.13" version "7.12.13"
resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz"
@ -1417,6 +1439,11 @@ aggregate-error@^3.0.0:
clean-stack "^2.0.0" clean-stack "^2.0.0"
indent-string "^4.0.0" indent-string "^4.0.0"
ajv-draft-04@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8"
integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==
ajv-formats@^2.1.1: ajv-formats@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
@ -1434,7 +1461,7 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4:
json-schema-traverse "^0.4.1" json-schema-traverse "^0.4.1"
uri-js "^4.2.2" uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.11.0: ajv@^8.0.0, ajv@^8.11.0, ajv@^8.6.3:
version "8.11.0" version "8.11.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
@ -4928,10 +4955,10 @@ json-parse-even-better-errors@^2.3.0:
resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
json-schema-to-ts@^2.5.3: json-schema-to-ts@2.5.4:
version "2.5.3" version "2.5.4"
resolved "https://registry.yarnpkg.com/json-schema-to-ts/-/json-schema-to-ts-2.5.3.tgz#10a1ad27a3cc6117ae9c652cc583a9e0ed10f0c8" resolved "https://registry.yarnpkg.com/json-schema-to-ts/-/json-schema-to-ts-2.5.4.tgz#64008cf5e203284289922bd622bff82043a1a4ed"
integrity sha512-2vABI+1IZNkChaPfLu7PG192ZY9gvRY00RbuN3VGlNNZkvYRpIECdBZPBVMe41r3wX0sl9emjRyhHT3gTm7HIg== integrity sha512-wlaYrGg+aYq0aEjSDY3cAFNzJVD2GvdrVIlvMdrbOLwkaMarXBiX+k0qm5Myb2aI3xjvdqsZoGs63JPS/M8+dg==
dependencies: dependencies:
"@types/json-schema" "^7.0.9" "@types/json-schema" "^7.0.9"
ts-algebra "^1.1.1" ts-algebra "^1.1.1"
@ -7658,7 +7685,7 @@ ts-node@10.9.1:
ts-toolbelt@^9.6.0: ts-toolbelt@^9.6.0:
version "9.6.0" version "9.6.0"
resolved "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz" resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-9.6.0.tgz#50a25426cfed500d4a09bd1b3afb6f28879edfd5"
integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w== integrity sha512-nsZd8ZeNUzukXPlJmTBwUAuABDe/9qtVDelJeT/qW0ow3ZS3BsQJtNkan1802aM9Uf68/Y8ljw86Hu0h5IUW3w==
tsc-watch@5.0.3: tsc-watch@5.0.3: