From c64cf7c557a94e773cb25835c3b8a063f8a6e3e9 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sat, 16 Jan 2021 15:24:25 -0500 Subject: [PATCH 01/11] feat: initial modularization --- .gitignore | 16 +- .travis.yml | 7 +- README.md | 116 +- lerna.json | 5 + package.json | 78 +- .../.all-contributorsrc | 0 .../express-openapi-validator/.codacy.yml | 0 packages/express-openapi-validator/.gitignore | 16 + .../express-openapi-validator/.npmignore | 0 .../express-openapi-validator/.nycrc | 0 .../.prettierrc.json | 0 .../CHANGE_HISTORY.md | 0 packages/express-openapi-validator/README.md | 1229 ++++++++++++++ .../express-openapi-validator/_config.yml | 0 .../express-openapi-validator/build.sh | 0 .../express-openapi-validator/launch.json | 0 .../package-lock.json | 0 .../express-openapi-validator/package.json | 74 + .../express-openapi-validator/src}/index.ts | 6 +- .../src}/middlewares/index.ts | 0 .../src/middlewares}/modded.express.mung.ts | 18 +- .../src}/middlewares/openapi.metadata.ts | 5 +- .../src}/middlewares/openapi.multipart.ts | 18 +- .../middlewares/openapi.request.validator.ts | 11 +- .../middlewares/openapi.response.validator.ts | 21 +- .../src}/middlewares/openapi.security.ts | 170 +- .../src}/middlewares/parsers/body.parse.ts | 2 +- .../parsers/req.parameter.mutator.ts | 9 +- .../src}/middlewares/parsers/schema.parse.ts | 2 +- .../parsers/schema.preprocessor.ts | 10 +- .../src}/middlewares/parsers/util.ts | 4 +- .../src}/middlewares/util.ts | 2 +- .../src}/openapi.validator.ts | 18 +- .../src}/resolvers.ts | 3 +- .../express-openapi-validator/src/types.ts | 19 + .../test}/356.campaign.spec.ts | 0 .../test}/356.campaign.yaml | 0 .../test}/440.spec.ts | 25 +- .../test}/509.spec.ts | 0 .../test}/511.spec.ts | 0 .../additional.props.query.params.spec.ts | 0 .../test}/additional.props.spec.ts | 0 .../test}/all.of.spec.ts | 0 .../test}/assets/image.png | Bin .../test}/circular.spec.ts | 0 .../test}/coercion.spec.ts | 0 .../test}/common/app.common.ts | 0 .../test}/common/app.mw.ts | 0 .../test}/common/app.ts | 2 +- .../test}/common/run.ts | 0 .../test}/common/test.yaml | 0 .../test}/component.params.spec.ts | 0 .../test}/content.type.spec.ts | 0 .../test}/datetime.validation.spec.ts | 0 .../test}/empty.servers.spec.ts | 0 .../escaped.characters.in.ref.path.spec.ts | 0 .../test}/formats.spec.ts | 0 .../test}/headers.2.spec.ts | 0 .../test}/headers.spec.ts | 0 .../test}/httperror.spec.ts | 2 +- .../test}/ignore.paths.spec.ts | 0 .../test}/missing.spec.ts | 0 .../test}/multipart.disabled.spec.ts | 0 .../test}/multipart.spec.ts | 0 .../test}/nested.routes.spec.ts | 0 .../test}/no.components.spec.ts | 2 +- .../test}/nullable.spec.ts | 0 .../test}/one.of.2.spec.ts | 0 .../test}/one.of.spec.ts | 0 .../test}/oneof.readonly.spec.ts | 0 .../test}/oneof.readonly.yaml | 0 .../test}/openapi.spec.ts | 0 .../test}/operation.handler.spec.ts | 2 +- .../test}/optional-request-body.spec.ts | 0 .../test}/optional-request-body.yaml | 0 .../test}/path.level.parameters.spec.ts | 0 .../test}/path.order.spec.ts | 0 .../test}/path.params.spec.ts | 0 .../test}/paths.sort.spec.ts | 2 +- .../test}/petstore.spec.ts | 2 +- .../test}/query.params.allow.unknown.spec.ts | 0 .../test}/query.params.spec.ts | 0 .../test}/query.serialization.ts | 0 .../test}/read.only.spec.ts | 0 .../test}/request.bodies.ref.spec.ts | 0 ...quest.body.validation.coerce.types.spec.ts | 0 .../resources/additional.properties.yaml | 0 .../additional.props.query.params.yaml | 0 .../test}/resources/all.of.yaml | 0 .../test}/resources/circular.yaml | 0 .../test}/resources/coercion.yaml | 0 .../test}/resources/component.params.yaml | 0 .../test}/resources/datetime.validation.yaml | 0 .../test}/resources/empty.servers.yaml | 0 .../resources/eov-operations.modulepath.yaml | 0 .../test}/resources/eov-operations.yaml | 0 .../resources/escaped.characters.in.path.yaml | 0 .../test}/resources/formats.yaml | 0 .../test}/resources/headers.yaml | 0 .../test}/resources/ignore.paths.yaml | 0 .../test}/resources/multipart.yaml | 0 .../test}/resources/nested.routes.yaml | 0 .../test}/resources/nullable.yaml | 0 .../test}/resources/one.of.2.yaml | 0 .../test}/resources/one.of.yaml | 0 .../test}/resources/openapi.json | 0 .../test}/resources/openapi.yaml | 0 .../resources/path.level.parameters.yaml | 0 .../test}/resources/path.order.yaml | 0 .../test}/resources/path.params.yaml | 0 .../test}/resources/query.params.yaml | 0 .../test}/resources/query.serialization.yaml | 0 .../test}/resources/read.only.yaml | 0 .../test}/resources/request.bodies.ref.yaml | 0 .../resources/response.object.serializer.yaml | 0 .../test}/resources/response.validation.yaml | 0 .../test}/resources/routes/pets.js | 0 .../test}/resources/routes/ping.js | 0 .../test}/resources/security.top.level.yaml | 0 .../test}/resources/security.yaml | 0 .../serialized.objects.defaults.yaml | 0 .../test}/resources/serialized.objects.yaml | 0 .../test}/resources/servers.1.yaml | 0 .../test}/resources/servers.2.yaml | 0 .../test}/resources/services/index.js | 0 .../test}/resources/sub_files/paths/auth.yaml | 0 .../test}/resources/unknown.formats.yaml | 0 .../test}/resources/wildcard.path.params.yaml | 0 .../test}/resources/write.only.yaml | 0 .../test}/resources/xt.newpet.yaml | 0 .../resources/xt.openapi.parameters.yaml | 0 .../test}/response.object.serializer.spec.ts | 0 .../response.validation.coerce.types.spec.ts | 0 .../response.validation.on.error.spec.ts | 0 .../test}/response.validation.options.spec.ts | 0 .../test}/response.validation.spec.ts | 0 .../test}/response.validator.spec.ts | 3 +- .../test}/router.spec.ts | 0 .../test}/security.defaults.spec.ts | 0 .../test}/security.disabled.spec.ts | 0 .../test}/security.handlers.spec.ts | 2 +- .../test}/security.top.level.spec.ts | 0 .../test}/serialized.objects.defaults.spec.ts | 0 .../test}/serialized.objects.spec.ts | 0 .../test}/servers.spec.ts | 0 .../test}/unknown.formats.spec.ts | 0 .../test}/wildcard.path.params.spec.ts | 0 .../test}/write.only.spec.ts | 0 .../express-openapi-validator/tsconfig.json | 0 .../typings}/index.d.ts | 0 packages/framework/.prettierrc.json | 4 + packages/framework/dist/ajv/formats.d.ts | 21 + packages/framework/dist/ajv/formats.js | 35 + packages/framework/dist/ajv/formats.js.map | 1 + packages/framework/dist/ajv/index.d.ts | 4 + packages/framework/dist/ajv/index.js | 93 ++ packages/framework/dist/ajv/index.js.map | 1 + packages/framework/dist/base.path.d.ts | 19 + packages/framework/dist/base.path.js | 113 ++ packages/framework/dist/base.path.js.map | 1 + packages/framework/dist/framework.d.ts | 10 + packages/framework/dist/framework.js | 99 ++ packages/framework/dist/framework.js.map | 1 + packages/framework/dist/index.d.ts | 549 ++++++ packages/framework/dist/index.js | 157 ++ packages/framework/dist/index.js.map | 1 + packages/framework/dist/openapi.context.d.ts | 20 + packages/framework/dist/openapi.context.js | 65 + .../framework/dist/openapi.context.js.map | 1 + .../dist/openapi.schema.validator.d.ts | 12 + .../dist/openapi.schema.validator.js | 31 + .../dist/openapi.schema.validator.js.map | 1 + .../framework/dist/openapi.spec.loader.d.ts | 21 + .../framework/dist/openapi.spec.loader.js | 85 + .../framework/dist/openapi.spec.loader.js.map | 1 + .../framework/dist/openapi.v3.schema.json | 1480 +++++++++++++++++ packages/framework/package-lock.json | 1193 +++++++++++++ packages/framework/package.json | 51 + .../framework/src}/framework/ajv/formats.ts | 0 .../framework/src}/framework/ajv/index.ts | 2 +- .../framework/src}/framework/base.path.ts | 2 +- .../framework/src/framework/framework.ts | 4 +- .../framework/src/framework/index.ts | 32 +- .../src}/framework/openapi.context.ts | 2 +- .../framework/openapi.schema.validator.ts | 2 +- .../src}/framework/openapi.spec.loader.ts | 11 +- .../src}/framework/openapi.v3.schema.json | 0 packages/framework/tsconfig.json | 17 + src/framework/json.ref.schema.ts | 1 - 189 files changed, 5695 insertions(+), 349 deletions(-) create mode 100644 lerna.json rename .all-contributorsrc => packages/express-openapi-validator/.all-contributorsrc (100%) rename .codacy.yml => packages/express-openapi-validator/.codacy.yml (100%) create mode 100644 packages/express-openapi-validator/.gitignore rename .npmignore => packages/express-openapi-validator/.npmignore (100%) rename .nycrc => packages/express-openapi-validator/.nycrc (100%) rename .prettierrc.json => packages/express-openapi-validator/.prettierrc.json (100%) rename CHANGE_HISTORY.md => packages/express-openapi-validator/CHANGE_HISTORY.md (100%) create mode 100644 packages/express-openapi-validator/README.md rename _config.yml => packages/express-openapi-validator/_config.yml (100%) rename build.sh => packages/express-openapi-validator/build.sh (100%) rename launch.json => packages/express-openapi-validator/launch.json (100%) rename package-lock.json => packages/express-openapi-validator/package-lock.json (100%) create mode 100644 packages/express-openapi-validator/package.json rename {src => packages/express-openapi-validator/src}/index.ts (86%) rename {src => packages/express-openapi-validator/src}/middlewares/index.ts (100%) rename {src/framework => packages/express-openapi-validator/src/middlewares}/modded.express.mung.ts (93%) rename {src => packages/express-openapi-validator/src}/middlewares/openapi.metadata.ts (96%) rename {src => packages/express-openapi-validator/src}/middlewares/openapi.multipart.ts (92%) rename {src => packages/express-openapi-validator/src}/middlewares/openapi.request.validator.ts (97%) rename {src => packages/express-openapi-validator/src}/middlewares/openapi.response.validator.ts (95%) rename {src => packages/express-openapi-validator/src}/middlewares/openapi.security.ts (68%) rename {src => packages/express-openapi-validator/src}/middlewares/parsers/body.parse.ts (98%) rename {src => packages/express-openapi-validator/src}/middlewares/parsers/req.parameter.mutator.ts (98%) rename {src => packages/express-openapi-validator/src}/middlewares/parsers/schema.parse.ts (97%) rename {src => packages/express-openapi-validator/src}/middlewares/parsers/schema.preprocessor.ts (98%) rename {src => packages/express-openapi-validator/src}/middlewares/parsers/util.ts (95%) rename {src => packages/express-openapi-validator/src}/middlewares/util.ts (98%) rename {src => packages/express-openapi-validator/src}/openapi.validator.ts (98%) rename {src => packages/express-openapi-validator/src}/resolvers.ts (95%) create mode 100644 packages/express-openapi-validator/src/types.ts rename {test => packages/express-openapi-validator/test}/356.campaign.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/356.campaign.yaml (100%) rename {test => packages/express-openapi-validator/test}/440.spec.ts (80%) rename {test => packages/express-openapi-validator/test}/509.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/511.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/additional.props.query.params.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/additional.props.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/all.of.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/assets/image.png (100%) rename {test => packages/express-openapi-validator/test}/circular.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/coercion.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/common/app.common.ts (100%) rename {test => packages/express-openapi-validator/test}/common/app.mw.ts (100%) rename {test => packages/express-openapi-validator/test}/common/app.ts (96%) rename {test => packages/express-openapi-validator/test}/common/run.ts (100%) rename {test => packages/express-openapi-validator/test}/common/test.yaml (100%) rename {test => packages/express-openapi-validator/test}/component.params.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/content.type.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/datetime.validation.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/empty.servers.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/escaped.characters.in.ref.path.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/formats.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/headers.2.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/headers.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/httperror.spec.ts (98%) rename {test => packages/express-openapi-validator/test}/ignore.paths.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/missing.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/multipart.disabled.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/multipart.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/nested.routes.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/no.components.spec.ts (96%) rename {test => packages/express-openapi-validator/test}/nullable.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/one.of.2.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/one.of.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/oneof.readonly.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/oneof.readonly.yaml (100%) rename {test => packages/express-openapi-validator/test}/openapi.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/operation.handler.spec.ts (98%) rename {test => packages/express-openapi-validator/test}/optional-request-body.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/optional-request-body.yaml (100%) rename {test => packages/express-openapi-validator/test}/path.level.parameters.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/path.order.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/path.params.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/paths.sort.spec.ts (95%) rename {test => packages/express-openapi-validator/test}/petstore.spec.ts (98%) rename {test => packages/express-openapi-validator/test}/query.params.allow.unknown.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/query.params.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/query.serialization.ts (100%) rename {test => packages/express-openapi-validator/test}/read.only.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/request.bodies.ref.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/request.body.validation.coerce.types.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/resources/additional.properties.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/additional.props.query.params.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/all.of.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/circular.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/coercion.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/component.params.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/datetime.validation.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/empty.servers.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/eov-operations.modulepath.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/eov-operations.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/escaped.characters.in.path.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/formats.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/headers.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/ignore.paths.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/multipart.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/nested.routes.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/nullable.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/one.of.2.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/one.of.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/openapi.json (100%) rename {test => packages/express-openapi-validator/test}/resources/openapi.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/path.level.parameters.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/path.order.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/path.params.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/query.params.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/query.serialization.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/read.only.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/request.bodies.ref.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/response.object.serializer.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/response.validation.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/routes/pets.js (100%) rename {test => packages/express-openapi-validator/test}/resources/routes/ping.js (100%) rename {test => packages/express-openapi-validator/test}/resources/security.top.level.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/security.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/serialized.objects.defaults.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/serialized.objects.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/servers.1.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/servers.2.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/services/index.js (100%) rename {test => packages/express-openapi-validator/test}/resources/sub_files/paths/auth.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/unknown.formats.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/wildcard.path.params.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/write.only.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/xt.newpet.yaml (100%) rename {test => packages/express-openapi-validator/test}/resources/xt.openapi.parameters.yaml (100%) rename {test => packages/express-openapi-validator/test}/response.object.serializer.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/response.validation.coerce.types.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/response.validation.on.error.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/response.validation.options.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/response.validation.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/response.validator.spec.ts (97%) rename {test => packages/express-openapi-validator/test}/router.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/security.defaults.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/security.disabled.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/security.handlers.spec.ts (99%) rename {test => packages/express-openapi-validator/test}/security.top.level.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/serialized.objects.defaults.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/serialized.objects.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/servers.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/unknown.formats.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/wildcard.path.params.spec.ts (100%) rename {test => packages/express-openapi-validator/test}/write.only.spec.ts (100%) rename tsconfig.json => packages/express-openapi-validator/tsconfig.json (100%) rename {typings => packages/express-openapi-validator/typings}/index.d.ts (100%) create mode 100644 packages/framework/.prettierrc.json create mode 100644 packages/framework/dist/ajv/formats.d.ts create mode 100644 packages/framework/dist/ajv/formats.js create mode 100644 packages/framework/dist/ajv/formats.js.map create mode 100644 packages/framework/dist/ajv/index.d.ts create mode 100644 packages/framework/dist/ajv/index.js create mode 100644 packages/framework/dist/ajv/index.js.map create mode 100644 packages/framework/dist/base.path.d.ts create mode 100644 packages/framework/dist/base.path.js create mode 100644 packages/framework/dist/base.path.js.map create mode 100644 packages/framework/dist/framework.d.ts create mode 100644 packages/framework/dist/framework.js create mode 100644 packages/framework/dist/framework.js.map create mode 100644 packages/framework/dist/index.d.ts create mode 100644 packages/framework/dist/index.js create mode 100644 packages/framework/dist/index.js.map create mode 100644 packages/framework/dist/openapi.context.d.ts create mode 100644 packages/framework/dist/openapi.context.js create mode 100644 packages/framework/dist/openapi.context.js.map create mode 100644 packages/framework/dist/openapi.schema.validator.d.ts create mode 100644 packages/framework/dist/openapi.schema.validator.js create mode 100644 packages/framework/dist/openapi.schema.validator.js.map create mode 100644 packages/framework/dist/openapi.spec.loader.d.ts create mode 100644 packages/framework/dist/openapi.spec.loader.js create mode 100644 packages/framework/dist/openapi.spec.loader.js.map create mode 100644 packages/framework/dist/openapi.v3.schema.json create mode 100644 packages/framework/package-lock.json create mode 100644 packages/framework/package.json rename {src => packages/framework/src}/framework/ajv/formats.ts (100%) rename {src => packages/framework/src}/framework/ajv/index.ts (98%) rename {src => packages/framework/src}/framework/base.path.ts (98%) rename src/framework/index.ts => packages/framework/src/framework/framework.ts (96%) rename src/framework/types.ts => packages/framework/src/framework/index.ts (96%) rename {src => packages/framework/src}/framework/openapi.context.ts (98%) rename {src => packages/framework/src}/framework/openapi.schema.validator.ts (96%) rename {src => packages/framework/src}/framework/openapi.spec.loader.ts (93%) rename {src => packages/framework/src}/framework/openapi.v3.schema.json (100%) create mode 100644 packages/framework/tsconfig.json delete mode 100644 src/framework/json.ref.schema.ts diff --git a/.gitignore b/.gitignore index 84f4a580..8156aeee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,4 @@ +/_old .vscode .idea -.DS_Store -node_modules -*.orig -dist -/sample -/coverage -.coveralls.yml -.nyc_output -secrets.zip -jest -junk -/a_reference -/sample2 -README.md.sav \ No newline at end of file +node_modules \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 3d8e26f0..0fdd7018 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,10 +9,11 @@ before_install: -in secrets.zip.enc -out secrets.zip -d; fi' - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then unzip secrets.zip; fi' install: -- npm install +- npm install lerna -g +- lerna bootstrap script: -- npm run compile -- npm run test:coverage +- lerna run compile +- lerna run test:coverage - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run coveralls; fi' - 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run codacy; fi' env: diff --git a/README.md b/README.md index 60f8d435..304cfe6a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ npm install express-openapi-validator 1. Require/import the openapi validator ```javascript -const OpenApiValidator = require('express-openapi-validator'); +const OpenApiValidator = require("express-openapi-validator"); ``` 2. Install the middleware @@ -41,10 +41,10 @@ const OpenApiValidator = require('express-openapi-validator'); ```javascript app.use( OpenApiValidator.middleware({ - apiSpec: './openapi.yaml', + apiSpec: "./openapi.yaml", validateRequests: true, // (default) validateResponses: true, // false by default - }), + }) ); ``` @@ -85,14 +85,14 @@ The following demonstrates how to use express-openapi-validator to auto validate See the complete [source code](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/1-standard) and [OpenAPI spec](https://github.com/cdimascio/express-openapi-validator/blob/master/examples/1-standard/api.yaml) for the example below: ```javascript -const express = require('express'); -const path = require('path'); -const bodyParser = require('body-parser'); -const http = require('http'); +const express = require("express"); +const path = require("path"); +const bodyParser = require("body-parser"); +const http = require("http"); const app = express(); // 1. Import the express-openapi-validator library -const OpenApiValidator = require('express-openapi-validator'); +const OpenApiValidator = require("express-openapi-validator"); // 2. Set up body parsers for the request body types you expect // Must be specified prior to endpoints in 5. @@ -101,36 +101,36 @@ app.use(bodyParser.text()); app.use(bodyParser.urlencoded({ extended: false })); // 3. (optionally) Serve the OpenAPI spec -const spec = path.join(__dirname, 'api.yaml'); -app.use('/spec', express.static(spec)); +const spec = path.join(__dirname, "api.yaml"); +app.use("/spec", express.static(spec)); // 4. Install the OpenApiValidator onto your express app app.use( OpenApiValidator.middleware({ - apiSpec: './api.yaml', + apiSpec: "./api.yaml", validateResponses: true, // <-- to validate responses // unknownFormats: ['my-format'] // <-- to provide custom formats - }), + }) ); // 5. Define routes using Express -app.get('/v1/pets', function (req, res, next) { +app.get("/v1/pets", function (req, res, next) { res.json([ - { id: 1, type: 'cat', name: 'max' }, - { id: 2, type: 'cat', name: 'mini' }, + { id: 1, type: "cat", name: "max" }, + { id: 2, type: "cat", name: "mini" }, ]); }); -app.post('/v1/pets', function (req, res, next) { - res.json({ name: 'sparky', type: 'dog' }); +app.post("/v1/pets", function (req, res, next) { + res.json({ name: "sparky", type: "dog" }); }); -app.get('/v1/pets/:id', function (req, res, next) { - res.json({ id: req.params.id, type: 'dog', name: 'sparky' }); +app.get("/v1/pets/:id", function (req, res, next) { + res.json({ id: req.params.id, type: "dog", name: "sparky" }); }); // 5a. Define route(s) to upload file(s) -app.post('/v1/pets/:id/photos', function (req, res, next) { +app.post("/v1/pets/:id/photos", function (req, res, next) { // files are found in req.files // non-file multipart params can be found as such: req.body['my-param'] res.json({ @@ -172,7 +172,7 @@ app.use( OpenApiValidator.middleware({ apiSpec, operationHandlers: path.join(__dirname), - }), + }) ); ``` @@ -199,7 +199,7 @@ app.use( ```javascript module.exports = { // the express handler implementaiton for ping - ping: (req, res) => res.status(200).send('pong'), + ping: (req, res) => res.status(200).send("pong"), }; ``` @@ -210,25 +210,25 @@ Below are some code snippets: **app.js** ```javascript -const express = require('express'); -const path = require('path'); -const bodyParser = require('body-parser'); -const logger = require('morgan'); -const http = require('http'); -const OpenApiValidator = require('express-openapi-validator'); +const express = require("express"); +const path = require("path"); +const bodyParser = require("body-parser"); +const logger = require("morgan"); +const http = require("http"); +const OpenApiValidator = require("express-openapi-validator"); const port = 3000; const app = express(); -const apiSpec = path.join(__dirname, 'api.yaml'); +const apiSpec = path.join(__dirname, "api.yaml"); // 1. Install bodyParsers for the request types your API will support app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.text()); app.use(bodyParser.json()); -app.use(logger('dev')); +app.use(logger("dev")); -app.use('/spec', express.static(apiSpec)); +app.use("/spec", express.static(apiSpec)); // 2. Install the OpenApiValidator on your express app app.use( @@ -237,7 +237,7 @@ app.use( validateResponses: true, // default false // 3. Provide the base path to the operation handlers directory operationHandlers: path.join(__dirname), // default false - }), + }) ); // 4. Woah sweet! With auto-wired operation handlers, I don't have to declare my routes! @@ -275,7 +275,7 @@ module.exports = app; # e.g. operations/base/path/routes/ping.js x-eov-operation-handler: routes/ping responses: - '200': + "200": description: OK # ... ``` @@ -286,7 +286,7 @@ module.exports = app; module.exports = { // ping must match operationId or x-eov-operation-id above // note that x-eov-operation-id overrides operationId - ping: (req, res) => res.status(200).send('pong'), + ping: (req, res) => res.status(200).send("pong"), }; ``` @@ -504,7 +504,7 @@ OpenApiValidator.middleware({ Specifies the path to an OpenAPI 3 specification or a JSON object representing the OpenAPI 3 specificiation ```javascript -apiSpec: './path/to/my-openapi-spec.yaml'; +apiSpec: "./path/to/my-openapi-spec.yaml"; ``` or @@ -603,7 +603,7 @@ Determines whether the validator should validate responses. Also accepts respons ```javascript validateResponses: { - removeAdditional: 'failing'; + removeAdditional: "failing"; } ``` @@ -659,14 +659,14 @@ e.g. ```javascript formats: [ { - name: 'my-three-digit-format', - type: 'number', + name: "my-three-digit-format", + type: "number", // validate returns true the number has 3 digits, false otherwise validate: (v) => /^\d{3}$/.test(v.toString()), }, { - name: 'my-three-letter-format', - type: 'string', + name: "my-three-letter-format", + type: "string", // validate returns true the string has 3 letters, false otherwise validate: (v) => /^[A-Za-z]{3}$/.test(v), }, @@ -698,7 +698,7 @@ Defines how the validator should behave if an unknown or custom format is encoun e.g. ```javascript - unknownFormats: ['phone-number', 'uuid']; + unknownFormats: ["phone-number", "uuid"]; ``` - `"ignore"` - to log warning during schema compilation and always pass validation. This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. @@ -751,7 +751,7 @@ Complete example [here](https://github.com/cdimascio/express-openapi-validator/t # e.g. operations/base/path/routes/ping.js x-eov-operation-handler: routes/ping responses: - '200': + "200": description: OK # ... ``` @@ -764,7 +764,7 @@ Complete example [here](https://github.com/cdimascio/express-openapi-validator/t ```javascript module.exports = { - ping: (req, res) => res.status(200).send('pong'), + ping: (req, res) => res.status(200).send("pong"), }; ``` @@ -797,7 +797,7 @@ Specifies the options to passthrough to multer. express-openapi-validator uses m ```javascript fileUploader: { - dest: 'uploads/'; + dest: "uploads/"; } ``` @@ -814,7 +814,7 @@ e.g. ```javascript $refParser: { - mode: 'bundle'; + mode: "bundle"; } ``` @@ -966,11 +966,11 @@ It may be useful to serve multiple APIs with separate specs via single service. See complete [example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/2-standard-multiple-api-specs) ```javascript -const express = require('express'); -const path = require('path'); -const bodyParser = require('body-parser'); -const http = require('http'); -const OpenApiValidator = require('express-openapi-validator'); +const express = require("express"); +const path = require("path"); +const bodyParser = require("body-parser"); +const http = require("http"); +const OpenApiValidator = require("express-openapi-validator"); app = express(); app.use(bodyParser.urlencoded({ extended: false })); @@ -984,14 +984,14 @@ for (const v of versions) { app.use( OpenApiValidator.middleware({ apiSpec, - }), + }) ); routes(app, v); } http.createServer(app).listen(3000); -console.log('Listening on port 3000'); +console.log("Listening on port 3000"); function routes(app, v) { if (v === 1) routesV1(app); @@ -999,7 +999,7 @@ function routes(app, v) { } function routesV1(app) { - const v = '/v1'; + const v = "/v1"; app.post(`${v}/pets`, (req, res, next) => { res.json({ ...req.body }); }); @@ -1007,8 +1007,8 @@ function routesV1(app) { res.json([ { id: 1, - name: 'happy', - type: 'cat', + name: "happy", + type: "cat", }, ]); }); @@ -1023,13 +1023,13 @@ function routesV1(app) { } function routesV2(app) { - const v = '/v2'; + const v = "/v2"; app.get(`${v}/pets`, (req, res, next) => { res.json([ { pet_id: 1, - pet_name: 'happy', - pet_type: 'kitty', + pet_name: "happy", + pet_type: "kitty", }, ]); }); diff --git a/lerna.json b/lerna.json new file mode 100644 index 00000000..3cc2e9ac --- /dev/null +++ b/lerna.json @@ -0,0 +1,5 @@ +{ + "packages": ["packages/*"], + "version": "1.0.0" + } + \ No newline at end of file diff --git a/package.json b/package.json index b5f7b563..54423a21 100644 --- a/package.json +++ b/package.json @@ -1,73 +1,9 @@ { - "name": "express-openapi-validator", - "version": "4.10.6", - "description": "Automatically validate API requests and responses with OpenAPI 3 and Express.", - "main": "dist/index.js", - "scripts": { - "compile": "rm -rf dist/ && tsc", - "compile:windows": "rmdir dist /s /q & tsc", - "test": "TS_NODE_FILES=true mocha -r source-map-support/register -r ts-node/register --files --recursive -R spec test/**/*.spec.ts", - "test:debug": "TS_NODE_FILES=true mocha -r source-map-support/register -r ts-node/register --inspect-brk --files --recursive test/**/*.spec.ts", - "test:windows": "set TS_NODE_FILES=true & mocha -r source-map-support/register -r ts-node/register --files --recursive test/**/*.spec.ts", - "test:coverage": "TS_NODE_FILES=true nyc mocha -r source-map-support/register -r ts-node/register --recursive test/**/*.spec.ts", - "test:coverage:windows": "set TS_NODE_FILES=true & nyc mocha -r source-map-support/register -r ts-node/register --recursive test/**/*.spec.ts", - "coveralls": "cat coverage/lcov.info | coveralls -v", - "codacy": "cat coverage/lcov.info | codacy-coverage", - "test:reset": "rm -rf node_modules && npm i && npm run compile && npm t", - "commit": "cz" - }, - "repository": { - "url": "https://github.com/cdimascio/express-openapi-validator" - }, - "keywords": [ - "openapi", - "openapi 3", - "expressjs", - "express", - "request validation", - "response validation", - "middleware", - "nodejs" - ], - "author": "Carmine DiMascio ", - "license": "MIT", - "dependencies": { - "ajv": "^6.12.6", - "content-type": "^1.0.4", - "json-schema-ref-parser": "^9.0.6", - "lodash.clonedeep": "^4.5.0", - "lodash.get": "^4.4.2", - "lodash.uniq": "^4.5.0", - "lodash.zipobject": "^4.1.3", - "media-typer": "^1.1.0", - "multer": "^1.4.2", - "ono": "^7.1.3", - "path-to-regexp": "^6.2.0" - }, - "devDependencies": { - "@types/ajv": "^1.0.0", - "@types/cookie-parser": "^1.4.2", - "@types/express": "^4.17.8", - "@types/mocha": "^8.0.3", - "@types/morgan": "^1.9.1", - "@types/multer": "^1.4.4", - "@types/node": "^14.14.2", - "@types/supertest": "^2.0.10", - "body-parser": "^1.19.0", - "chai": "^4.2.0", - "codacy-coverage": "^3.4.0", - "commitizen": "^4.2.2", - "cookie-parser": "^1.4.5", - "coveralls": "^3.1.0", - "express": "^4.17.1", - "mocha": "^8.2.0", - "morgan": "^1.10.0", - "nodemon": "^2.0.6", - "nyc": "^15.1.0", - "prettier": "^2.1.2", - "source-map-support": "0.5.19", - "supertest": "^5.0.0", - "ts-node": "^9.0.0", - "typescript": "^4.0.3" + "name": "root", + "private": true, + "version": "4.10.6", + "devDependencies": { + "lerna": "^3.22.1" + } } -} + \ No newline at end of file diff --git a/.all-contributorsrc b/packages/express-openapi-validator/.all-contributorsrc similarity index 100% rename from .all-contributorsrc rename to packages/express-openapi-validator/.all-contributorsrc diff --git a/.codacy.yml b/packages/express-openapi-validator/.codacy.yml similarity index 100% rename from .codacy.yml rename to packages/express-openapi-validator/.codacy.yml diff --git a/packages/express-openapi-validator/.gitignore b/packages/express-openapi-validator/.gitignore new file mode 100644 index 00000000..84f4a580 --- /dev/null +++ b/packages/express-openapi-validator/.gitignore @@ -0,0 +1,16 @@ +.vscode +.idea +.DS_Store +node_modules +*.orig +dist +/sample +/coverage +.coveralls.yml +.nyc_output +secrets.zip +jest +junk +/a_reference +/sample2 +README.md.sav \ No newline at end of file diff --git a/.npmignore b/packages/express-openapi-validator/.npmignore similarity index 100% rename from .npmignore rename to packages/express-openapi-validator/.npmignore diff --git a/.nycrc b/packages/express-openapi-validator/.nycrc similarity index 100% rename from .nycrc rename to packages/express-openapi-validator/.nycrc diff --git a/.prettierrc.json b/packages/express-openapi-validator/.prettierrc.json similarity index 100% rename from .prettierrc.json rename to packages/express-openapi-validator/.prettierrc.json diff --git a/CHANGE_HISTORY.md b/packages/express-openapi-validator/CHANGE_HISTORY.md similarity index 100% rename from CHANGE_HISTORY.md rename to packages/express-openapi-validator/CHANGE_HISTORY.md diff --git a/packages/express-openapi-validator/README.md b/packages/express-openapi-validator/README.md new file mode 100644 index 00000000..60f8d435 --- /dev/null +++ b/packages/express-openapi-validator/README.md @@ -0,0 +1,1229 @@ +# 🦋 express-openapi-validator + +[![](https://travis-ci.org/cdimascio/express-openapi-validator.svg?branch=master)](#) [![](https://img.shields.io/npm/v/express-openapi-validator.svg)](https://www.npmjs.com/package/express-openapi-validator) [![](https://img.shields.io/npm/dm/express-openapi-validator?color=blue)](https://www.npmjs.com/package/express-openapi-validator) [![All Contributors](https://img.shields.io/badge/all_contributors-42-darkcyan.svg?style=flat)](#contributors) [![Coverage Status](https://coveralls.io/repos/github/cdimascio/express-openapi-validator/badge.svg?branch=master)](https://coveralls.io/github/cdimascio/express-openapi-validator?branch=master) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/1570a06f609345ddb237114bbd6ceed7)](https://www.codacy.com/manual/cdimascio/express-openapi-validator?utm_source=github.com&utm_medium=referral&utm_content=cdimascio/express-openapi-validator&utm_campaign=Badge_Grade) [![](https://img.shields.io/gitter/room/cdimascio-oss/community?color=%23eb205a)](https://gitter.im/cdimascio-oss/community) [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/cdimascio/express-openapi-validator) [![](https://img.shields.io/badge/license-MIT-blue.svg)](#license) + +**An OpenApi validator for ExpressJS** that automatically validates **API** _**requests**_ and _**responses**_ using an **OpenAPI 3** specification. + +

+ +

+ +[🦋express-openapi-validator](https://github.com/cdimascio/express-openapi-validator) is an unopinionated library that integrates with new and existing API applications. express-openapi-validator lets you write code the way you want; it does not impose any coding convention or project layout. Simply, install the validator onto your express app, point it to your OpenAPI 3 specification, then define and implement routes the way you prefer. See an [example](#example-express-api-server). + +**Features:** + +- ✔️ request validation +- ✔️ response validation (json only) +- 👮 security validation / custom security functions +- 👽 3rd party / custom formats +- 🧵 optionally auto-map OpenAPI endpoints to Express handler functions +- ✂️ **\$ref** support; split specs over multiple files +- 🎈 file upload + +[![GitHub stars](https://img.shields.io/github/stars/cdimascio/express-openapi-validator.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/cdimascio/express-openapi-validator/stargazers/) [![Twitter URL](https://img.shields.io/twitter/url/https/github.com/cdimascio/express-openapi-validator.svg?style=social)](https://twitter.com/intent/tweet?text=Check%20out%20express-openapi-validator%20by%20%40CarmineDiMascio%20https%3A%2F%2Fgithub.com%2Fcdimascio%2Fexpress-openapi-validator%20%F0%9F%91%8D) + +## Install + +```shell +npm install express-openapi-validator +``` + +## Usage + +1. Require/import the openapi validator + +```javascript +const OpenApiValidator = require('express-openapi-validator'); +``` + +2. Install the middleware + +```javascript +app.use( + OpenApiValidator.middleware({ + apiSpec: './openapi.yaml', + validateRequests: true, // (default) + validateResponses: true, // false by default + }), +); +``` + +3. Register an error handler + +```javascript +app.use((err, req, res, next) => { + // format error + res.status(err.status || 500).json({ + message: err.message, + errors: err.errors, + }); +}); +``` + +_**Important:** Ensure express is configured with all relevant body parsers. Body parser middleware functions must be specified prior to any validated routes. See an [example](#example-express-api-server)_. + +## Upgrading from 3.x + +In v4.x.x, the validator is installed as standard connect middleware using `app.use(...) and/or router.use(...)` ([example](https://github.com/cdimascio/express-openapi-validator/blob/v4/README.md#Example-Express-API-Server)). This differs from the v3.x.x the installation which required the `install` method(s). The `install` methods no longer exist in v4. + +## Usage (options) + +See [Advanced Usage](#Advanced-Usage) options to: + +- inline api specs as JSON. +- configure request/response validation options +- customize authentication with security validation `handlers`. +- use OpenAPI 3.0.x 3rd party and custom formats. +- tweak the file upload configuration. +- ignore routes +- and more... + +## [Example Express API Server](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/1-standard) + +The following demonstrates how to use express-openapi-validator to auto validate requests and responses. It also includes file upload! + +See the complete [source code](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/1-standard) and [OpenAPI spec](https://github.com/cdimascio/express-openapi-validator/blob/master/examples/1-standard/api.yaml) for the example below: + +```javascript +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const http = require('http'); +const app = express(); + +// 1. Import the express-openapi-validator library +const OpenApiValidator = require('express-openapi-validator'); + +// 2. Set up body parsers for the request body types you expect +// Must be specified prior to endpoints in 5. +app.use(bodyParser.json()); +app.use(bodyParser.text()); +app.use(bodyParser.urlencoded({ extended: false })); + +// 3. (optionally) Serve the OpenAPI spec +const spec = path.join(__dirname, 'api.yaml'); +app.use('/spec', express.static(spec)); + +// 4. Install the OpenApiValidator onto your express app +app.use( + OpenApiValidator.middleware({ + apiSpec: './api.yaml', + validateResponses: true, // <-- to validate responses + // unknownFormats: ['my-format'] // <-- to provide custom formats + }), +); + +// 5. Define routes using Express +app.get('/v1/pets', function (req, res, next) { + res.json([ + { id: 1, type: 'cat', name: 'max' }, + { id: 2, type: 'cat', name: 'mini' }, + ]); +}); + +app.post('/v1/pets', function (req, res, next) { + res.json({ name: 'sparky', type: 'dog' }); +}); + +app.get('/v1/pets/:id', function (req, res, next) { + res.json({ id: req.params.id, type: 'dog', name: 'sparky' }); +}); + +// 5a. Define route(s) to upload file(s) +app.post('/v1/pets/:id/photos', function (req, res, next) { + // files are found in req.files + // non-file multipart params can be found as such: req.body['my-param'] + res.json({ + files_metadata: req.files.map((f) => ({ + originalname: f.originalname, + encoding: f.encoding, + mimetype: f.mimetype, + // Buffer of file conents + buffer: f.buffer, + })), + }); +}); + +// 6. Create an Express error handler +app.use((err, req, res, next) => { + // 7. Customize errors + console.error(err); // dump error to console for debug + res.status(err.status || 500).json({ + message: err.message, + errors: err.errors, + }); +}); + +http.createServer(app).listen(3000); +``` + +## [Example Express API Server: with operationHandlers](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/3-eov-operations) + +Don't want to manually map your OpenAPI endpoints to Express handler functions? express-openapi-validator can do it for you, automatically! + +Use express-openapi-validator's OpenAPI `x-eov-operation-*` vendor extensions. See a full example with [source code](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/3-eov-operations) and an [OpenAPI spec](https://github.com/cdimascio/express-openapi-validator/blob/master/examples/3-eov-operations/api.yaml#L39) + +**Here's the gist** + +- First, specifiy the `operationHandlers` option to set the base directory that contains your operation handler files. + +```javascript +app.use( + OpenApiValidator.middleware({ + apiSpec, + operationHandlers: path.join(__dirname), + }), +); +``` + +- Next, use the `x-eov-operation-id` OpenAPI vendor extension or `operationId` to specify the id of operation handler to invoke. + +```yaml +/ping: + get: + # operationId: ping + x-eov-operation-id: ping +``` + +- Next, use the `x-eov-operation-handler` OpenAPI vendor extension to specify a path (relative to `operationHandlers`) to the module that contains the handler for this operation. + +```yaml +/ping: + get: + x-eov-operation-id: ping + x-eov-operation-handler: routes/ping # no .js or .ts extension +``` + +- Finally, create the express handler module e.g. `routes/ping.js` + +```javascript +module.exports = { + // the express handler implementaiton for ping + ping: (req, res) => res.status(200).send('pong'), +}; +``` + +**Note:** A file may contain _one_ or _many_ handlers. + +Below are some code snippets: + +**app.js** + +```javascript +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const logger = require('morgan'); +const http = require('http'); +const OpenApiValidator = require('express-openapi-validator'); + +const port = 3000; +const app = express(); +const apiSpec = path.join(__dirname, 'api.yaml'); + +// 1. Install bodyParsers for the request types your API will support +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.text()); +app.use(bodyParser.json()); + +app.use(logger('dev')); + +app.use('/spec', express.static(apiSpec)); + +// 2. Install the OpenApiValidator on your express app +app.use( + OpenApiValidator.middleware({ + apiSpec, + validateResponses: true, // default false + // 3. Provide the base path to the operation handlers directory + operationHandlers: path.join(__dirname), // default false + }), +); + +// 4. Woah sweet! With auto-wired operation handlers, I don't have to declare my routes! +// See api.yaml for x-eov-* vendor extensions + +// 5. Create a custom error handler +app.use((err, req, res, next) => { + // format errors + res.status(err.status || 500).json({ + message: err.message, + errors: err.errors, + }); +}); + +http.createServer(app).listen(port); +console.log(`Listening on port ${port}`); + +module.exports = app; +``` + +**api.yaml** + +```yaml +/ping: + get: + description: | + ping then pong! + # OpenAPI's operationId may be used to to specify the operation id + operationId: ping + # x-eov-operation-id may be used to specify the operation id + # Used when operationId is omiited. Overrides operationId when both are specified + x-eov-operation-id: ping + # specifies the path to the operation handler. + # the path is relative to the operationHandlers option + # e.g. operations/base/path/routes/ping.js + x-eov-operation-handler: routes/ping + responses: + '200': + description: OK + # ... +``` + +**ping.js** + +```javascript +module.exports = { + // ping must match operationId or x-eov-operation-id above + // note that x-eov-operation-id overrides operationId + ping: (req, res) => res.status(200).send('pong'), +}; +``` + +## API Validation Response Examples + +#### Validates a query parameter with a value constraint + +```shell +curl -s http://localhost:3000/v1/pets/as |jq +{ + "message": "request.params.id should be integer", + "errors": [ + { + "path": ".params.id", + "message": "should be integer", + "errorCode": "type.openapi.validation" + } + ] +} +``` + +#### Validates a query parameter with a range constraint + +```shell + curl -s 'http://localhost:3000/v1/pets?limit=25' |jq +{ + "message": "request.query should have required property 'type', request.query.limit should be <= 20", + "errors": [ + { + "path": ".query.type", + "message": "should have required property 'type'", + "errorCode": "required.openapi.validation" + }, + { + "path": ".query.limit", + "message": "should be <= 20", + "errorCode": "maximum.openapi.validation" + } + ] +} +``` + +#### Validates securities e.g. API Key + +```shell + curl -s --request POST \ + --url http://localhost:3000/v1/pets \ + --data '{}' |jq +{ + "message": "'X-API-Key' header required", + "errors": [ + { + "path": "/v1/pets", + "message": "'X-API-Key' header required" + } + ] +} +``` + +Providing the header passes OpenAPI validation. + +**Note:** that your Express middleware or endpoint logic can then provide additional checks. + +```shell +curl -XPOST http://localhost:3000/v1/pets \ + --header 'X-Api-Key: XXXXX' \ + --header 'content-type: application/json' \ + -d '{"name": "spot"}' | jq + +{ + "id": 4, + "name": "spot" +} +``` + +#### Validates content-type + +```shell +curl -s --request POST \ + --url http://localhost:3000/v1/pets \ + --header 'content-type: application/xml' \ + --header 'x-api-key: XXXX' \ + --data '{ + "name": "test" +}' |jq + "message": "unsupported media type application/xml", + "errors": [ + { + "path": "/v1/pets", + "message": "unsupported media type application/xml" + } + ] +} +``` + +#### Validates a POST request body + +```shell +curl -s --request POST \ + --url http://localhost:3000/v1/pets \ + --header 'content-type: application/json' \ + --header 'x-api-key: XXXX' \ + --data '{}'|jq +{ + "message": "request.body should have required property 'name'", + "errors": [ + { + "path": ".body.name", + "message": "should have required property 'name'", + "errorCode": "required.openapi.validation" + } + ] +} +``` + +#### File Upload (out of the box) + +```shell +curl -XPOST http://localhost:3000/v1/pets/10/photos -F file=@app.js|jq +{ + "files_metadata": [ + { + "originalname": "app.js", + "encoding": "7bit", + "mimetype": "application/octet-stream" + } + ] +} +``` + +#### Validates responses (optional) + +Errors in response validation return `500`, not of `400` + +`/v1/pets/99` will return a response that does not match the spec + +``` + curl -s 'http://localhost:3000/v1/pets/99' |jq +{ + "message": ".response should have required property 'name', .response should have required property 'id'", + "errors": [ + { + "path": ".response.name", + "message": "should have required property 'name'", + "errorCode": "required.openapi.validation" + }, + { + "path": ".response.id", + "message": "should have required property 'id'", + "errorCode": "required.openapi.validation" + } + ] +} +``` + +### _...and much more. Try it out!_ + +### Response status codes + +express-openapi-validator returns the following error codes depending on the situation. + +#### Request validation (validateRequests=true) + +| status | when | +| -------------------------- | ------------------------------------------------------------------------------------------------- | +| `400` (bad request) | a validation error is encountered | +| `401` (unauthorized) | a security / authentication errors is encountered e.g. missing api-key, Authorization header, etc | +| `404` (not found) | a path is not found i.e. not declared in the API spec | +| `405` (method not allowed) | a path is declared in the API spec, but a no schema is provided for the method | + +#### Response validation (validateResponses=true) + +| status | when | +| ----------------------------- | ----------------------------------------- | +| `500` (internal server error) | any error is encountered by the validator | + +## Advanced Usage + +### OpenApiValidator Middleware Options + +express-openapi validator provides a good deal of flexibility via its options. + +Options are provided via the options object. Options take the following form: + +```javascript +OpenApiValidator.middleware({ + apiSpec: './openapi.yaml', + validateRequests: true, + validateResponses: true, + validateSecurity: { + handlers: { + ApiKeyAuth: (req, scopes, schema) => { + throw { status: 401, message: 'sorry' } + } + } + }, + validateFormats: 'fast', + formats: [{ + name: 'my-custom-format', + type: 'string' | 'number', + validate: (value: any) => boolean, + }], + unknownFormats: ['phone-number', 'uuid'], + operationHandlers: false | 'operations/base/path' | { ... }, + ignorePaths: /.*\/pets$/, + fileUploader: { ... } | true | false, + $refParser: { + mode: 'bundle' + } +}); +``` + +### ▪️ apiSpec (required) + +Specifies the path to an OpenAPI 3 specification or a JSON object representing the OpenAPI 3 specificiation + +```javascript +apiSpec: './path/to/my-openapi-spec.yaml'; +``` + +or + +```javascript + apiSpec: { + openapi: '3.0.1', + info: {...}, + servers: [...], + paths: {...}, + components: { + responses: {...}, + schemas: {...} + } +} +``` + +### ▪️ validateRequests (optional) + +Determines whether the validator should validate requests. + +- `true` (**default**) - validate requests. +- `false` - do not validate requests. +- `{ ... }` - validate requests with options + + **allowUnknownQueryParameters:** + + - `true` - enables unknown/undeclared query parameters to pass validation + - `false` - (**default**) fail validation if an unknown query parameter is present + + For example: + + ```javascript + validateRequests: { + allowUnknownQueryParameters: true; + } + ``` + + `allowUnknownQueryParameters` is set for the entire validator. It can be overwritten per-operation using + a custom property `x-allow-unknown-query-parameters`. + + For example to allow unknown query parameters on ONLY a single endpoint: + + ```yaml + paths: + /allow_unknown: + get: + x-allow-unknown-query-parameters: true + parameters: + - name: value + in: query + schema: + type: string + responses: + 200: + description: success + ``` + + **coerceTypes:** + + Determines whether the validator will coerce the request body. Request query and path params, headers, cookies are coerced by default and this setting does not affect that. + + Options: + + - `true` - coerce scalar data types. + - `false` - (**default**) do not coerce types. (more strict, safer) + - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). + + For example: + + ```javascript + validateRequests: { + coerceTypes: true; + } + ``` + +### ▪️ validateResponses (optional) + +Determines whether the validator should validate responses. Also accepts response validation options. + +- `true` - validate responses in 'strict' mode i.e. responses MUST match the schema. +- `false` (**default**) - do not validate responses +- `{ ... }` - validate responses with options + + **removeAdditional:** + + - `"failing"` - additional properties that fail schema validation are automatically removed from the response. + + **coerceTypes:** + + - `true` - coerce scalar data types. + - `false` - (**default**) do not coerce types. (almost always the desired behavior) + - `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). + + For example: + + ```javascript + validateResponses: { + removeAdditional: 'failing'; + } + ``` + + **onError:** + + A function that will be invoked on response validation error, instead of the default handling. Useful if you want to log an error or emit a metric, but don't want to actually fail the request. Receives the validation error and offending response body. + + For example: + + ``` + validateResponses: { + onError: (error, body) => { + console.log(`Response body fails validation: `, error); + console.debug(body); + } + } + ``` + +### ▪️ validateSecurity (optional) + +Determines whether the validator should validate securities e.g. apikey, basic, oauth2, openid, etc + +- `true` (**default**) - validate security +- `false` - do not validate security +- `{ ... }` - validate security with `handlers`. See [Security handlers](#security-handlers) doc. + + **handlers:** + + For example: + + ```javascript + validateSecurity: { + handlers: { + ApiKeyAuth: function(req, scopes, schema) { + console.log('apikey handler throws custom error', scopes, schema); + throw Error('my message'); + }, + } + } + ``` + +### ▪️ formats (optional) + +Defines a list of custome formats. + +- `[{ ... }]` - array of custom format objects. Each object must have the following properties: + - name: string (required) - the format name + - validate: (v: any) => boolean (required) - the validation function + - type: 'string' | 'number' (optional) - the format's type + +e.g. + +```javascript +formats: [ + { + name: 'my-three-digit-format', + type: 'number', + // validate returns true the number has 3 digits, false otherwise + validate: (v) => /^\d{3}$/.test(v.toString()), + }, + { + name: 'my-three-letter-format', + type: 'string', + // validate returns true the string has 3 letters, false otherwise + validate: (v) => /^[A-Za-z]{3}$/.test(v), + }, +]; +``` + +Then use it in a spec e.g. + +```yaml +my_property: + type: string + format: my-three-letter-format' +``` + +### ▪️ validateFormats (optional) + +Specifies the strictness of validation of string formats. + +- `"fast"` (**default**) - only validate syntax, but not semantics. E.g. `2010-13-30T23:12:35Z` will pass validation eventhough it contains month 13. +- `"full"` - validate both syntax and semantics. Illegal dates will not pass. +- `false` - do not validate formats at all. + +### ▪️ unknownFormats (optional) + +Defines how the validator should behave if an unknown or custom format is encountered. + +- `true` **(default)** - When an unknown format is encountered, the validator will report a 400 error. +- `[string]` **_(recommended for unknown formats)_** - An array of unknown format names that will be ignored by the validator. This option can be used to allow usage of third party schemas with format(s), but still fail if another unknown format is used. + e.g. + + ```javascript + unknownFormats: ['phone-number', 'uuid']; + ``` + +- `"ignore"` - to log warning during schema compilation and always pass validation. This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. + +### ▪️ operationHandlers (optional) + +Defines the base directory for operation handlers. This is used in conjunction with express-openapi-validator's OpenAPI vendor extensions, `x-eov-operation-id`, `x-eov-operation-handler` and OpenAPI's `operationId`. See [example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/3-eov-operations). + +Additionally, if you want to change how modules are resolved e.g. use dot deliminted operation ids e.g. `path.to.module.myFunction`, you may optionally add a custom `resolver`. See [documentation and example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/5-custom-operation-resolver) + +- `string` - the base directory containing operation handlers +- `false` - (default) disable auto wired operation handlers +- `{ ... }` - specifies a base directory and optionally a custom resolver + + **handlers:** + + For example: + + ```javascript + operationHandlers: { + basePath: __dirname, + resolver: function (modulePath, route): express.RequestHandler { + ///... + } + } + ``` + +``` +operationHandlers: 'operations/base/path' +``` + +**Note** that the `x-eov-operation-handler` OpenAPI vendor extension specifies a path relative to `operationHandlers`. Thus if `operationHandlers` is `/handlers` and an `x-eov-operation-handler` has path `routes/ping`, then the handler file `/handlers/routes/ping.js` (or `ts`) is used. + +Complete example [here](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/3-eov-operations) + +**api.yaml** + +```yaml +/ping: + get: + description: | + ping then pong! + # OpenAPI's operationId may be used to to specify the operation id + operationId: ping + # x-eov-operation-id may be used to specify the operation id + # Used when operationId is omiited. Overrides operationId when both are specified + x-eov-operation-id: ping + # specifies the path to the operation handler. + # the path is relative to the operationHandlers option + # e.g. operations/base/path/routes/ping.js + x-eov-operation-handler: routes/ping + responses: + '200': + description: OK + # ... +``` + +**routes/ping.js** + +`x-eov-operation-handler` specifies the path to this handlers file, `ping.js` + +`x-eov-operation-id` (or `operationId`) specifies operation handler's key e.g. `ping` + +```javascript +module.exports = { + ping: (req, res) => res.status(200).send('pong'), +}; +``` + +### ▪️ ignorePaths (optional) + +Defines a regular expression or function that determines whether a path(s) should be ignored. If it's a regular expression, any path that matches the regular expression will be ignored by the validator. If it's a function, it will ignore any paths that returns a truthy value. + +The following ignores any path that ends in `/pets` e.g. `/v1/pets`. +As a regular expression: + +``` +ignorePaths: /.*\/pets$/ +``` + +or as a function: + +``` +ignorePaths: (path) => path.endsWith('/pets') +``` + +### ▪️ fileUploader (optional) + +Specifies the options to passthrough to multer. express-openapi-validator uses multer to handle file uploads. see [multer opts](https://github.com/expressjs/multer) + +- `true` (**default**) - enables multer and provides simple file(s) upload capabilities +- `false` - disables file upload capability. Upload capabilities may be provided by the user +- `{...}` - multer options to be passed-through to multer. see [multer opts](https://github.com/expressjs/multer) for possible options + + e.g. + + ```javascript + fileUploader: { + dest: 'uploads/'; + } + ``` + +### ▪️ \$refParser.mode (optional) + +Determines how JSON schema references are resolved by the internal [json-schema-ref-parser](https://github.com/APIDevTools/json-schema-ref-parser). Generally, the default mode, `bundle` is sufficient, however if you use [escape characters in \$refs](https://swagger.io/docs/specification/using-ref/), `dereference` is necessary. + +- `bundle` **(default)** - Bundles all referenced files/URLs into a single schema that only has internal $ref pointers. This eliminates the risk of circular references, but does not handle escaped characters in $refs. +- `dereference` - Dereferences all $ref pointers in the JSON Schema, replacing each reference with its resolved value. Introduces risk of circular $refs. Handles [escape characters in \$refs](https://swagger.io/docs/specification/using-ref/)) + +See this [issue](https://github.com/APIDevTools/json-schema-ref-parser/issues/101#issuecomment-421755168) for more information. + +e.g. + +```javascript +$refParser: { + mode: 'bundle'; +} +``` + +### ▪️ coerceTypes (optional) - _deprecated_ + +Determines whether the validator should coerce value types to match the those defined in the OpenAPI spec. This option applies **only** to path params, query strings, headers, and cookies. _It is **highly unlikley** that will want to disable this. As such this option is deprecated and will be removed in the next major version_ + +- `true` (**default**) - coerce scalar data types. +- `"array"` - in addition to coercions between scalar types, coerce scalar data to an array with one element and vice versa (as required by the schema). + +## The Base URL + +The validator will only validate requests, securities, and responses that are under +the server's [base URL](https://spec.openapis.org/oas/v3.0.0.html#serverVariableObject). + +This is useful for those times when the API and frontend are being served by the same +application. ([More detail about the base URL](https://swagger.io/docs/specification/api-host-and-base-path/).) + +```yaml +servers: + - url: https://api.example.com/v1 +``` + +The validation applies to all paths defined under this base URL. Routes in your app +that are \_not_se URL—such as pages—will not be validated. + +| URL | Validated? | +| :----------------------------------- | :------------------------- | +| `https://api.example.com/v1/users` | :white_check_mark: | +| `https://api.example.com/index.html` | no; not under the base URL | + +In some cases, it may be necessary to _**skip validation** for paths **under the base url**_. To do this, use the [`ignorePaths`](#ignorepaths) option. + +## Security handlers + +> **Note:** security `handlers` are an optional component. security `handlers` provide a convenience, whereby the request, declared scopes, and the security schema itself are provided as parameters to each security `handlers` callback that you define. The code you write in each callback can then perform authentication and authorization checks. **_Note that the same can be achieved using standard Express middleware_. The difference** is that security `handlers` provide you the OpenAPI schema data described in your specification\_. Ulimately, this means, you don't have to duplicate that information in your code. + +> All in all, security `handlers` are purely optional and are provided as a convenience. + +Security handlers specify a set of custom security handlers to be used to validate security i.e. authentication and authorization. If a security `handlers` object is specified, a handler must be defined for **_all_** securities. If security `handlers are **_not_** specified, a default handler is always used. The default handler will validate against the OpenAPI spec, then call the next middleware. + +If security `handlers` are specified, the validator will validate against the OpenAPI spec, then call the security handler providing it the Express request, the security scopes, and the security schema object. + +- security `handlers` is an object that maps security keys to security handler functions. Each security key must correspond to `securityScheme` name. + The `validateSecurity.handlers` object signature is as follows: + + ```typescript + { + validateSecurity: { + handlers: { + [securityKey]: function( + req: Express.Request, + scopes: string[], + schema: SecuritySchemeObject + ): void, + } + } + } + ``` + + [SecuritySchemeObject](https://github.com/cdimascio/express-openapi-validator/blob/master/src/framework/types.ts#L269) + + **For example:** + + ```javascript + validateSecurity: { + handlers: { + ApiKeyAuth: function(req, scopes, schema) { + console.log('apikey handler throws custom error', scopes, schema); + throw Error('my message'); + }, + } + } + ``` + +The _express-openapi-validator_ performs a basic validation pass prior to delegating to security handlers. If basic validation passes, security handler function(s) are invoked. + +In order to signal an auth failure, the security handler function **must** either: + +1. `throw { status: 403, message: 'forbidden' }` +2. `throw Error('optional message')` +3. `return false` +4. return a promise which resolves to `false` e.g `Promise.resolve(false)` +5. return a promise rejection e.g. + - `Promise.reject({ status: 401, message: 'yikes' });` + - `Promise.reject(Error('optional 'message')` + - `Promise.reject(false)` + +Note: error status `401` is returned, unless option `i.` above is used + +**Some examples:** + +```javascript +validateSecurity: { + handlers: { + ApiKeyAuth: (req, scopes, schema) => { + throw Error('my message'); + }, + OpenID: async (req, scopes, schema) => { + throw { status: 403, message: 'forbidden' } + }, + BasicAuth: (req, scopes, schema) => { + return Promise.resolve(false); + }, + ... + } +} +``` + +In order to grant authz, the handler function **must** either: + +- `return true` +- return a promise which resolves to `true` + +**Some examples** + +```javascript +validateSecurity: { + handlers: { + ApiKeyAuth: (req, scopes, schema) => { + return true; + }, + BearerAuth: async (req, scopes, schema) => { + return true; + }, + ... + } +} +``` + +Each security `handlers`' `securityKey` must match a `components/securitySchemes` property + +```yaml +components: + securitySchemes: + ApiKeyAuth: # <-- Note this name must be used as the name handler function property + type: apiKey + in: header + name: X-API-Key +``` + +See [OpenAPI 3](https://swagger.io/docs/specification/authentication/) authentication for `securityScheme` and `security` documentation +See [examples](https://github.com/cdimascio/express-openapi-validator/blob/security/test/security.spec.ts#L17) from unit tests + +## Example: Multiple Validators and API specs + +It may be useful to serve multiple APIs with separate specs via single service. An example might be an API that serves both `v1` and `v2` from the same service. The sample code below shows how one might accomplish this. + +See complete [example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/2-standard-multiple-api-specs) + +```javascript +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const http = require('http'); +const OpenApiValidator = require('express-openapi-validator'); + +app = express(); +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.text()); +app.use(bodyParser.json()); + +const versions = [1, 2]; + +for (const v of versions) { + const apiSpec = path.join(__dirname, `api.v${v}.yaml`); + app.use( + OpenApiValidator.middleware({ + apiSpec, + }), + ); + + routes(app, v); +} + +http.createServer(app).listen(3000); +console.log('Listening on port 3000'); + +function routes(app, v) { + if (v === 1) routesV1(app); + if (v === 2) routesV2(app); +} + +function routesV1(app) { + const v = '/v1'; + app.post(`${v}/pets`, (req, res, next) => { + res.json({ ...req.body }); + }); + app.get(`${v}/pets`, (req, res, next) => { + res.json([ + { + id: 1, + name: 'happy', + type: 'cat', + }, + ]); + }); + + app.use((err, req, res, next) => { + // format error + res.status(err.status || 500).json({ + message: err.message, + errors: err.errors, + }); + }); +} + +function routesV2(app) { + const v = '/v2'; + app.get(`${v}/pets`, (req, res, next) => { + res.json([ + { + pet_id: 1, + pet_name: 'happy', + pet_type: 'kitty', + }, + ]); + }); + app.post(`${v}/pets`, (req, res, next) => { + res.json({ ...req.body }); + }); + + app.use((err, req, res, next) => { + // format error + res.status(err.status || 500).json({ + message: err.message, + errors: err.errors, + }); + }); +} + +module.exports = app; +``` + +## FAQ + +**Q:** How do I match paths, like those described in RFC-6570? + +**A:** OpenAPI 3.0 does not support RFC-6570. That said, we provide a minimalistic mechanism that conforms syntactically to OpenAPI 3 and accomplishes a common use case. For example, matching file paths and storing the matched path in `req.params` + +Using the following OpenAPI 3.x defintion + +```yaml +/files/{path}*: + get: + parameters: + - name: path + in: path + required: true + schema: + type: string +``` + +With the following Express route defintion + +```javascript + app.get(`/files/:path(*)`, (req, res) => { /* do stuff */ }` +``` + +A path like `/files/some/long/path` will pass validation. The Express `req.params.path` property will hold the value `some/long/path`. + +**Q:** Can I use discriminators with `oneOf` and `anyOf`? + +**A:** +Currently, there is support for top level discriminators. See [top-level discriminator example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/8-top-level-discriminator) + +**Q:** What happened to the `securityHandlers` property? + +**A:** In v3, `securityHandlers` have been replaced by `validateSecurity.handlers`. To use v3 security handlers, move your existing security handlers to the new property. No other change is required. Note that the v2 `securityHandlers` property is supported in v3, but deprecated + +**Q**: What happened to the `multerOpts` property? + +**A**: In v3, `multerOpts` have been replaced by `fileUploader`. In order to use the v3 `fileUploader`, move your multer options to `fileUploader` No other change is required. Note that the v2 `multerOpts` property is supported in v3, but deprecated + +**Q:** I can disallow unknown query parameters with `allowUnknownQueryParameters: false`. How can disallow unknown body parameters? + +**A:** Add `additionalProperties: false` when [describing](https://swagger.io/docs/specification/data-models/keywords/) e.g a `requestBody` to ensure that additional properties are not allowed. For example: + +```yaml +Pet: +additionalProperties: false +required: + - name +properties: + name: + type: string + type: + type: string +``` + +**Q:** I upgraded from from v2 to v3 and validation no longer works. How do I fix it? + +**A**: In version 2.x.x, the `install` method was executed synchronously, in 3.x it's executed asynchronously. To get v2 behavior in v3, use the `installSync` method. See the [synchronous](#synchronous) section for details. + +**Q:** Can I use `express-openapi-validator` with `swagger-ui-express`? + +**A:** Yes. Be sure to `use` the `swagger-ui-express` serve middleware prior to installing `OpenApiValidator`. This will ensure that `swagger-ui-express` is able to fully prepare the spec before before OpenApiValidator attempts to use it. For example: + +```javascript +const swaggerUi = require('swagger-ui-express') +const OpenApiValidator = require('express-openapi-validator') + +... + +app.use('/', swaggerUi.serve, swaggerUi.setup(documentation)) + +app.use(OpenApiValidator.middleware({ + apiSpec, // api spec JSON object + //... other options + } +})) +``` + +**Q:** I have a handler function defined on an `express.Router`. If i call `req.params` each param value has type `string`. If i define same handler function on an `express.Application`, each value in `req.params` is already coerced to the type declare in my spec. Why not coerce theseF values on an `express.Router`? + +**A:** First, it's important to note that this behavior does not impact validation. The validator will validate against the type defined in your spec. + +In order to modify the `req.params`, express requires that a param handler be registered e.g. `app.param(...)` or `router.param(...)`. Since `app` is available to middleware functions, the validator registers an `app.param` handler to coerce and modify the values of `req.params` to their declared types. Unfortunately, express does not provide a means to determine the current router from a middleware function, hence the validator is unable to register the same param handler on an express router. Ultimately, this means if your handler function is defined on `app`, the values of `req.params` will be coerced to their declared types. If your handler function is declare on an `express.Router`, the values of `req.params` values will be of type `string` (You must coerce them e.g. `parseInt(req.params.id)`). + +## Contributors ✨ + +Contributions welcome! Here's how to [contribute](CONTRIBUTING.md). + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Carmine DiMascio

💻 ⚠️ 🚇

Sheldhur Mornor

💻 ⚠️

Andrey Trebler

💻 ⚠️

richdouglasevans

📖

Miran Setinc

💻

Frank Calise

💻

Gonen Dukas

🤔 ⚠️

Sven Eliasson

💻 ⚠️

Spencer Brown

💻 ⚠️

José Neves

💻

mk811

💻 ⚠️

HugoMario

💻 ⚠️

Rowan Cockett

💻

Jacques Yakoub

💻

ckeboss

💻 ⚠️

JacobLey

💻 ⚠️

Dmitriy Voeykov

💻 ⚠️

GARAMKIM

💻 🤔

Mathias Scherer

💻

Mirek

💻

Florian Beutel

💻

jakubskopal

💻 ⚠️ 📖

Jordan Dobrev

⚠️ 💻

Enrico Fabris

💻

Dustin Wheeler

💻 📖 ⚠️

Thomas Carmichael

📖

Jakesterwars

📖

xtrycatchx

💻

Lee Dong Joo

📖

Dmitry Chekanov

💻 ⚠️

Redhart Azul

💻

Joost Diepenmaat

💻 ⚠️

Dom Parfitt

💻 ⚠️

xg1990

💻

ownagedj

💻 ⚠️

David Garner

💻

Balazs Soltesz

💻 ⚠️

Christiaan Nieuwlaat

💻

Ilya

💻 ⚠️

Yuliya Bagriy

💻 ⚠️

Kristjan Siimson

💻 ⚠️

Guillaume

💻 ⚠️

Volodymyr Kolesnykov

💻 ⚠️

Pierre Le Roux

💻 ⚠️ 🤔

Electro Type

🤔
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + +## Community articles, blogs, and tutorials + +_Seeking content creators..._ + +Have you written an article, blog, or tutorial that uses `express-openapi-validator`? + +Please post your links [here](https://github.com/cdimascio/express-openapi-validator/issues/316) + +We plan to publicize a variety of links here. + +## License + +[MIT](LICENSE) + +Buy Me A Coffee diff --git a/_config.yml b/packages/express-openapi-validator/_config.yml similarity index 100% rename from _config.yml rename to packages/express-openapi-validator/_config.yml diff --git a/build.sh b/packages/express-openapi-validator/build.sh similarity index 100% rename from build.sh rename to packages/express-openapi-validator/build.sh diff --git a/launch.json b/packages/express-openapi-validator/launch.json similarity index 100% rename from launch.json rename to packages/express-openapi-validator/launch.json diff --git a/package-lock.json b/packages/express-openapi-validator/package-lock.json similarity index 100% rename from package-lock.json rename to packages/express-openapi-validator/package-lock.json diff --git a/packages/express-openapi-validator/package.json b/packages/express-openapi-validator/package.json new file mode 100644 index 00000000..bdae8dda --- /dev/null +++ b/packages/express-openapi-validator/package.json @@ -0,0 +1,74 @@ +{ + "name": "express-openapi-validator", + "version": "4.10.6", + "description": "Automatically validate API requests and responses with OpenAPI 3 and Express.", + "main": "dist/index.js", + "scripts": { + "compile": "rm -rf dist/ && tsc", + "compile:windows": "rmdir dist /s /q & tsc", + "test": "TS_NODE_FILES=true mocha -r source-map-support/register -r ts-node/register --files --recursive -R spec test/**/*.spec.ts", + "test:debug": "TS_NODE_FILES=true mocha -r source-map-support/register -r ts-node/register --inspect-brk --files --recursive test/**/*.spec.ts", + "test:windows": "set TS_NODE_FILES=true & mocha -r source-map-support/register -r ts-node/register --files --recursive test/**/*.spec.ts", + "test:coverage": "TS_NODE_FILES=true nyc mocha -r source-map-support/register -r ts-node/register --recursive test/**/*.spec.ts", + "test:coverage:windows": "set TS_NODE_FILES=true & nyc mocha -r source-map-support/register -r ts-node/register --recursive test/**/*.spec.ts", + "coveralls": "cat coverage/lcov.info | coveralls -v", + "codacy": "cat coverage/lcov.info | codacy-coverage", + "test:reset": "rm -rf node_modules && npm i && npm run compile && npm t", + "commit": "cz" + }, + "repository": { + "url": "https://github.com/cdimascio/express-openapi-validator" + }, + "keywords": [ + "openapi", + "openapi 3", + "expressjs", + "express", + "request validation", + "response validation", + "middleware", + "nodejs" + ], + "author": "Carmine DiMascio ", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "content-type": "^1.0.4", + "json-schema-ref-parser": "^9.0.6", + "lodash.clonedeep": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.uniq": "^4.5.0", + "lodash.zipobject": "^4.1.3", + "media-typer": "^1.1.0", + "multer": "^1.4.2", + "ono": "^7.1.3", + "path-to-regexp": "^6.2.0", + "framework": "4.10.6" + }, + "devDependencies": { + "@types/ajv": "^1.0.0", + "@types/cookie-parser": "^1.4.2", + "@types/express": "^4.17.8", + "@types/mocha": "^8.0.3", + "@types/morgan": "^1.9.1", + "@types/multer": "^1.4.4", + "@types/node": "^14.14.2", + "@types/supertest": "^2.0.10", + "body-parser": "^1.19.0", + "chai": "^4.2.0", + "codacy-coverage": "^3.4.0", + "commitizen": "^4.2.2", + "cookie-parser": "^1.4.5", + "coveralls": "^3.1.0", + "express": "^4.17.1", + "mocha": "^8.2.0", + "morgan": "^1.10.0", + "nodemon": "^2.0.6", + "nyc": "^15.1.0", + "prettier": "^2.1.2", + "source-map-support": "0.5.19", + "supertest": "^5.0.0", + "ts-node": "^9.0.0", + "typescript": "^4.0.3" + } +} diff --git a/src/index.ts b/packages/express-openapi-validator/src/index.ts similarity index 86% rename from src/index.ts rename to packages/express-openapi-validator/src/index.ts index 9d0ce703..634d9fe9 100644 --- a/src/index.ts +++ b/packages/express-openapi-validator/src/index.ts @@ -1,7 +1,8 @@ import * as res from './resolvers'; import { OpenApiValidator, OpenApiValidatorOpts } from './openapi.validator'; -import { OpenApiSpecLoader } from './framework/openapi.spec.loader'; import { + OpenAPIV3, + OpenApiSpecLoader, InternalServerError, UnsupportedMediaType, RequestEntityTooLarge, @@ -11,9 +12,8 @@ import { NotFound, Unauthorized, Forbidden, -} from './framework/types'; +} from 'framework'; -// export default openapiValidator; export const resolvers = res; export const middleware = openapiValidator; export const error = { diff --git a/src/middlewares/index.ts b/packages/express-openapi-validator/src/middlewares/index.ts similarity index 100% rename from src/middlewares/index.ts rename to packages/express-openapi-validator/src/middlewares/index.ts diff --git a/src/framework/modded.express.mung.ts b/packages/express-openapi-validator/src/middlewares/modded.express.mung.ts similarity index 93% rename from src/framework/modded.express.mung.ts rename to packages/express-openapi-validator/src/middlewares/modded.express.mung.ts index fc6c0a51..6c774880 100644 --- a/src/framework/modded.express.mung.ts +++ b/packages/express-openapi-validator/src/middlewares/modded.express.mung.ts @@ -23,7 +23,7 @@ mung.onError = (err, req, res, next) => { }; mung.json = function json(fn, options) { - return function(req, res, next) { + return function (req, res, next) { let original = res.json; options = options || {}; let mungError = options.mungError; @@ -63,7 +63,7 @@ mung.json = function json(fn, options) { }; mung.jsonAsync = function json(fn, options) { - return function(req, res, next) { + return function (req, res, next) { let original = res.json; options = options || {}; let mungError = options.mungError; @@ -75,7 +75,7 @@ mung.jsonAsync = function json(fn, options) { if (!mungError && res.statusCode >= 400) return original.call(this, json); try { fn(json, req, res) - .then(json => { + .then((json) => { if (res.headersSent) return; // If null, then 204 No Content @@ -89,7 +89,7 @@ mung.jsonAsync = function json(fn, options) { return original.call(this, json); }) - .catch(e => mung.onError(e, req, res, next)); + .catch((e) => mung.onError(e, req, res, next)); } catch (e) { mung.onError(e, req, res, next); } @@ -103,7 +103,7 @@ mung.jsonAsync = function json(fn, options) { }; mung.headers = function headers(fn) { - return function(req, res, next) { + return function (req, res, next) { let original = res.end; function headers_hook() { res.end = original; @@ -129,9 +129,9 @@ mung.headers = function headers(fn) { }; mung.headersAsync = function headersAsync(fn) { - return function(req, res, next) { + return function (req, res, next) { let original = res.end; - let onError = e => { + let onError = (e) => { res.end = original; return mung.onError(e, req, res, next); }; @@ -146,7 +146,7 @@ mung.headersAsync = function headersAsync(fn) { if (res.headersSent) return; original.apply(this, args); }) - .catch(e => onError(e)); + .catch((e) => onError(e)); } catch (e) { onError(e); } @@ -158,7 +158,7 @@ mung.headersAsync = function headersAsync(fn) { }; mung.write = function write(fn, options: any = {}) { - return function(req, res, next) { + return function (req, res, next) { const original = res.write; const mungError = options.mungError; diff --git a/src/middlewares/openapi.metadata.ts b/packages/express-openapi-validator/src/middlewares/openapi.metadata.ts similarity index 96% rename from src/middlewares/openapi.metadata.ts rename to packages/express-openapi-validator/src/middlewares/openapi.metadata.ts index 67817cd2..3d234dab 100644 --- a/src/middlewares/openapi.metadata.ts +++ b/packages/express-openapi-validator/src/middlewares/openapi.metadata.ts @@ -1,13 +1,12 @@ import * as _zipObject from 'lodash.zipobject'; import { pathToRegexp } from 'path-to-regexp'; import { Response, NextFunction } from 'express'; -import { OpenApiContext } from '../framework/openapi.context'; +import { OpenApiContext, OpenAPIV3 } from 'framework'; import { OpenApiRequest, OpenApiRequestHandler, OpenApiRequestMetadata, - OpenAPIV3, -} from '../framework/types'; +} from '../types'; export function applyOpenApiMetadata( openApiContext: OpenApiContext, diff --git a/src/middlewares/openapi.multipart.ts b/packages/express-openapi-validator/src/middlewares/openapi.multipart.ts similarity index 92% rename from src/middlewares/openapi.multipart.ts rename to packages/express-openapi-validator/src/middlewares/openapi.multipart.ts index 52a071bf..5130b278 100644 --- a/src/middlewares/openapi.multipart.ts +++ b/packages/express-openapi-validator/src/middlewares/openapi.multipart.ts @@ -1,15 +1,13 @@ -import { OpenApiContext } from '../framework/openapi.context'; -import { createRequestAjv } from '../framework/ajv'; import { + Ajv, OpenAPIV3, - OpenApiRequest, - OpenApiRequestHandler, ValidationError, BadRequest, InternalServerError, HttpError, MultipartOpts, -} from '../framework/types'; +} from 'framework'; +import { OpenApiRequest, OpenApiRequestHandler } from '../types'; import { MulterError } from 'multer'; const multer = require('multer'); @@ -19,11 +17,11 @@ export function multipart( options: MultipartOpts, ): OpenApiRequestHandler { const mult = multer(options.multerOpts); - const Ajv = createRequestAjv(apiDoc, { ...options.ajvOpts }); + const ajv = Ajv.createRequestAjv(apiDoc, { ...options.ajvOpts }); return (req, res, next) => { // TODO check that format: binary (for upload) else do not use multer.any() // use multer.none() if no binary parameters exist - if (shouldHandle(Ajv, req)) { + if (shouldHandle(ajv, req)) { mult.any()(req, res, (err) => { if (err) { next(error(req, err)); @@ -71,7 +69,7 @@ export function multipart( }; } -function shouldHandle(Ajv, req: OpenApiRequest): boolean { +function shouldHandle(ajv, req: OpenApiRequest): boolean { const reqContentType = req.headers['content-type']; if (isMultipart(req) && reqContentType?.includes('multipart/form-data')) { return true; @@ -79,7 +77,7 @@ function shouldHandle(Ajv, req: OpenApiRequest): boolean { const bodyRef = (req?.openapi)?.schema?.$ref; const requestBody = bodyRef - ? Ajv.getSchema(bodyRef) + ? ajv.getSchema(bodyRef) : (req?.openapi)?.schema?.requestBody; const bodyContent = requestBody?.content; if (!bodyContent) return false; @@ -90,7 +88,7 @@ function shouldHandle(Ajv, req: OpenApiRequest): boolean { if (!contentType.includes(reqContentType)) continue; const mediaTypeSchema = mediaType?.schema; const schema = mediaTypeSchema?.$ref - ? Ajv.getSchema(mediaTypeSchema.$ref) + ? ajv.getSchema(mediaTypeSchema.$ref) : mediaTypeSchema; const format = schema?.format; if (format === 'binary') { diff --git a/src/middlewares/openapi.request.validator.ts b/packages/express-openapi-validator/src/middlewares/openapi.request.validator.ts similarity index 97% rename from src/middlewares/openapi.request.validator.ts rename to packages/express-openapi-validator/src/middlewares/openapi.request.validator.ts index 6d4f4433..6436e9f5 100644 --- a/src/middlewares/openapi.request.validator.ts +++ b/packages/express-openapi-validator/src/middlewares/openapi.request.validator.ts @@ -1,5 +1,4 @@ import { Ajv, ValidateFunction } from 'ajv'; -import { createRequestAjv } from '../framework/ajv'; import { ContentType, ajvErrorsToValidatorError, @@ -7,18 +6,18 @@ import { } from './util'; import { NextFunction, RequestHandler, Response } from 'express'; import { + Ajv as fAjv, OpenAPIV3, - OpenApiRequest, RequestValidatorOptions, ValidateRequestOpts, - OpenApiRequestMetadata, NotFound, MethodNotAllowed, BadRequest, ParametersSchema, BodySchema, ValidationSchema, -} from '../framework/types'; +} from 'framework'; +import { OpenApiRequest, OpenApiRequestMetadata } from '../types'; import { BodySchemaParser } from './parsers/body.parse'; import { ParametersSchemaParser } from './parsers/schema.parse'; import { RequestParameterMutator } from './parsers/req.parameter.mutator'; @@ -45,8 +44,8 @@ export class RequestValidator { this.apiDoc = apiDoc; this.requestOpts.allowUnknownQueryParameters = options.allowUnknownQueryParameters; - this.ajv = createRequestAjv(apiDoc, { ...options, coerceTypes: true }); - this.ajvBody = createRequestAjv(apiDoc, options); + this.ajv = fAjv.createRequestAjv(apiDoc, { ...options, coerceTypes: true }); + this.ajvBody = fAjv.createRequestAjv(apiDoc, options); } public validate( diff --git a/src/middlewares/openapi.response.validator.ts b/packages/express-openapi-validator/src/middlewares/openapi.response.validator.ts similarity index 95% rename from src/middlewares/openapi.response.validator.ts rename to packages/express-openapi-validator/src/middlewares/openapi.response.validator.ts index 798a2ba3..7a92f6a4 100644 --- a/src/middlewares/openapi.response.validator.ts +++ b/packages/express-openapi-validator/src/middlewares/openapi.response.validator.ts @@ -1,7 +1,7 @@ import { RequestHandler } from 'express'; import * as ajv from 'ajv'; -import mung from '../framework/modded.express.mung'; -import { createResponseAjv } from '../framework/ajv'; +import mung from './modded.express.mung'; +import { Ajv } from 'framework'; import { augmentAjvErrors, ContentType, @@ -10,11 +10,10 @@ import { } from './util'; import { OpenAPIV3, - OpenApiRequest, - OpenApiRequestMetadata, InternalServerError, ValidateResponseOpts, -} from '../framework/types'; +} from 'framework'; +import { OpenApiRequest, OpenApiRequestMetadata } from '../types'; import * as mediaTypeParser from 'media-typer'; import * as contentTypeParser from 'content-type'; @@ -31,15 +30,15 @@ export class ResponseValidator { private validatorsCache: { [key: string]: { [key: string]: ajv.ValidateFunction }; } = {}; - private eovOptions: ValidateResponseOpts + private eovOptions: ValidateResponseOpts; constructor( - openApiSpec: OpenAPIV3.Document, - options: ajv.Options = {}, - eovOptions: ValidateResponseOpts = {} + openApiSpec: OpenAPIV3.Document, + options: ajv.Options = {}, + eovOptions: ValidateResponseOpts = {}, ) { this.spec = openApiSpec; - this.ajvBody = createResponseAjv(openApiSpec, options); + this.ajvBody = Ajv.createResponseAjv(openApiSpec, options); this.eovOptions = eovOptions; // This is a pseudo-middleware function. It doesn't get registered with @@ -80,7 +79,7 @@ export class ResponseValidator { } catch (err) { // If a custom error handler was provided, we call that if (err instanceof InternalServerError && this.eovOptions.onError) { - this.eovOptions.onError(err, body) + this.eovOptions.onError(err, body); } else { // No custom error handler, or something unexpected happen. throw err; diff --git a/src/middlewares/openapi.security.ts b/packages/express-openapi-validator/src/middlewares/openapi.security.ts similarity index 68% rename from src/middlewares/openapi.security.ts rename to packages/express-openapi-validator/src/middlewares/openapi.security.ts index 5a90a609..30c7a7e7 100644 --- a/src/middlewares/openapi.security.ts +++ b/packages/express-openapi-validator/src/middlewares/openapi.security.ts @@ -1,14 +1,16 @@ import { OpenAPIV3, - OpenApiRequest, SecurityHandlers, - OpenApiRequestMetadata, - OpenApiRequestHandler, NotFound, MethodNotAllowed, InternalServerError, HttpError, -} from '../framework/types'; +} from 'framework'; +import { + OpenApiRequest, + OpenApiRequestMetadata, + OpenApiRequestHandler, +} from '../types'; const defaultSecurityHandler = ( req: Express.Request, @@ -82,54 +84,54 @@ export function security( securitySchemes, securityHandlers, securities, - ).executeHandlers(req); - + ).executeHandlers(req); + // TODO handle AND'd and OR'd security // This assumes OR only! i.e. at least one security passed authentication - let firstError: SecurityHandlerResult = null; + let firstError: SecurityHandlerResult = null; let success = false; - + function checkErrorWithOr(res) { - return res.forEach(r => { - if (r.success) { - success = true; - } else if (!firstError) { - firstError = r; - } - }) + return res.forEach((r) => { + if (r.success) { + success = true; + } else if (!firstError) { + firstError = r; + } + }); } function checkErrorsWithAnd(res) { - let allSuccess = false; - - res.forEach(r => { - if (!r.success) { - allSuccess = false; - if (!firstError) { - firstError = r; - } - } else if (!firstError) { - allSuccess = true; - } - }) - - if (allSuccess) { - success = true; + let allSuccess = false; + + res.forEach((r) => { + if (!r.success) { + allSuccess = false; + if (!firstError) { + firstError = r; + } + } else if (!firstError) { + allSuccess = true; } + }); + + if (allSuccess) { + success = true; + } } - results.forEach(result => { - if (Array.isArray(result) && result.length > 1) { - checkErrorsWithAnd(result); - } else { - checkErrorWithOr(result); - } + results.forEach((result) => { + if (Array.isArray(result) && result.length > 1) { + checkErrorsWithAnd(result); + } else { + checkErrorWithOr(result); + } }); if (success) { - next(); + next(); } else { - throw firstError; + throw firstError; } } catch (e) { const message = e?.error?.message || 'unauthorized'; @@ -177,50 +179,56 @@ class SecuritySchemes { // anonumous security return [{ success: true }]; } - return Promise.all(Object.keys(s).map(async (securityKey) => { - var _a, _b, _c; - try { - const scheme = this.securitySchemes[securityKey]; - const handler = (_b = (_a = this.securityHandlers) === null || _a === void 0 ? void 0 : _a[securityKey]) !== null && _b !== void 0 ? _b : fallbackHandler; - const scopesTmp = s[securityKey]; - const scopes = Array.isArray(scopesTmp) ? scopesTmp : []; - if (!scheme) { - const message = `components.securitySchemes.${securityKey} does not exist`; - throw new InternalServerError({ message }); - } - if (!scheme.hasOwnProperty('type')) { - const message = `components.securitySchemes.${securityKey} must have property 'type'`; - throw new InternalServerError({ message }); - } - if (!handler) { - const message = `a security handler for '${securityKey}' does not exist`; - throw new InternalServerError({ message }); - } - new AuthValidator(req, scheme, scopes).validate(); - // expected handler results are: - // - throw exception, - // - return true, - // - return Promise, - // - return false, - // - return Promise - // everything else should be treated as false - const securityScheme = scheme; - const success = await handler(req, scopes, securityScheme); - if (success === true) { - return { success }; - } - else { - throw Error(); + return Promise.all( + Object.keys(s).map(async (securityKey) => { + var _a, _b, _c; + try { + const scheme = this.securitySchemes[securityKey]; + const handler = + (_b = + (_a = this.securityHandlers) === null || _a === void 0 + ? void 0 + : _a[securityKey]) !== null && _b !== void 0 + ? _b + : fallbackHandler; + const scopesTmp = s[securityKey]; + const scopes = Array.isArray(scopesTmp) ? scopesTmp : []; + if (!scheme) { + const message = `components.securitySchemes.${securityKey} does not exist`; + throw new InternalServerError({ message }); + } + if (!scheme.hasOwnProperty('type')) { + const message = `components.securitySchemes.${securityKey} must have property 'type'`; + throw new InternalServerError({ message }); + } + if (!handler) { + const message = `a security handler for '${securityKey}' does not exist`; + throw new InternalServerError({ message }); + } + new AuthValidator(req, scheme, scopes).validate(); + // expected handler results are: + // - throw exception, + // - return true, + // - return Promise, + // - return false, + // - return Promise + // everything else should be treated as false + const securityScheme = scheme; + const success = await handler(req, scopes, securityScheme); + if (success === true) { + return { success }; + } else { + throw Error(); + } + } catch (e) { + return { + success: false, + status: (_c = e.status) !== null && _c !== void 0 ? _c : 401, + error: e, + }; } - } - catch (e) { - return { - success: false, - status: (_c = e.status) !== null && _c !== void 0 ? _c : 401, - error: e, - }; - } - })); + }), + ); }); return Promise.all(promises); } diff --git a/src/middlewares/parsers/body.parse.ts b/packages/express-openapi-validator/src/middlewares/parsers/body.parse.ts similarity index 98% rename from src/middlewares/parsers/body.parse.ts rename to packages/express-openapi-validator/src/middlewares/parsers/body.parse.ts index fdbddf17..458aae47 100644 --- a/src/middlewares/parsers/body.parse.ts +++ b/packages/express-openapi-validator/src/middlewares/parsers/body.parse.ts @@ -4,7 +4,7 @@ import { OpenAPIV3, BodySchema, UnsupportedMediaType, -} from '../../framework/types'; +} from 'framework'; export class BodySchemaParser { constructor() { diff --git a/src/middlewares/parsers/req.parameter.mutator.ts b/packages/express-openapi-validator/src/middlewares/parsers/req.parameter.mutator.ts similarity index 98% rename from src/middlewares/parsers/req.parameter.mutator.ts rename to packages/express-openapi-validator/src/middlewares/parsers/req.parameter.mutator.ts index 16dccbce..4bdebb14 100644 --- a/src/middlewares/parsers/req.parameter.mutator.ts +++ b/packages/express-openapi-validator/src/middlewares/parsers/req.parameter.mutator.ts @@ -1,12 +1,7 @@ import { Request } from 'express'; import { Ajv } from 'ajv'; -import { - OpenAPIV3, - OpenApiRequest, - OpenApiRequestMetadata, - ValidationSchema, - BadRequest, -} from '../../framework/types'; +import { OpenAPIV3, ValidationSchema, BadRequest } from 'framework'; +import { OpenApiRequest, OpenApiRequestMetadata } from '../../types'; import * as url from 'url'; import { dereferenceParameter, normalizeParameter } from './util'; import * as mediaTypeParser from 'media-typer'; diff --git a/src/middlewares/parsers/schema.parse.ts b/packages/express-openapi-validator/src/middlewares/parsers/schema.parse.ts similarity index 97% rename from src/middlewares/parsers/schema.parse.ts rename to packages/express-openapi-validator/src/middlewares/parsers/schema.parse.ts index 29562e27..14aa2803 100644 --- a/src/middlewares/parsers/schema.parse.ts +++ b/packages/express-openapi-validator/src/middlewares/parsers/schema.parse.ts @@ -1,4 +1,4 @@ -import { OpenAPIV3, ParametersSchema, BadRequest } from '../../framework/types'; +import { OpenAPIV3, ParametersSchema, BadRequest } from 'framework'; import { dereferenceParameter, normalizeParameter } from './util'; import { Ajv } from 'ajv'; diff --git a/src/middlewares/parsers/schema.preprocessor.ts b/packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts similarity index 98% rename from src/middlewares/parsers/schema.preprocessor.ts rename to packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts index 196ccd9e..95dc9da1 100644 --- a/src/middlewares/parsers/schema.preprocessor.ts +++ b/packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts @@ -2,12 +2,13 @@ import { Ajv } from 'ajv'; import ajv = require('ajv'); import * as cloneDeep from 'lodash.clonedeep'; import * as _get from 'lodash.get'; -import { createRequestAjv } from '../../framework/ajv'; + import { + Ajv as fAjv, OpenAPIV3, Serializer, ValidateResponseOpts, -} from '../../framework/types'; +} from 'framework'; interface TraversalStates { req: TraversalState; @@ -93,7 +94,7 @@ export class SchemaPreprocessor { ajvOptions: ajv.Options, validateResponsesOpts: ValidateResponseOpts, ) { - this.ajv = createRequestAjv(apiDoc, ajvOptions); + this.ajv = fAjv.createRequestAjv(apiDoc, ajvOptions); this.apiDoc = apiDoc; this.responseOpts = validateResponsesOpts; } @@ -259,7 +260,8 @@ export class SchemaPreprocessor { const options = opts[kind]; options.path = node.path; - if (nschema) { // This null check should no longer be necessary + if (nschema) { + // This null check should no longer be necessary this.handleSerDes(pschema, nschema, options); this.handleReadonly(pschema, nschema, options); this.processDiscriminator(pschema, nschema, options); diff --git a/src/middlewares/parsers/util.ts b/packages/express-openapi-validator/src/middlewares/parsers/util.ts similarity index 95% rename from src/middlewares/parsers/util.ts rename to packages/express-openapi-validator/src/middlewares/parsers/util.ts index f7031d93..c27e9515 100644 --- a/src/middlewares/parsers/util.ts +++ b/packages/express-openapi-validator/src/middlewares/parsers/util.ts @@ -1,7 +1,5 @@ import { Ajv } from 'ajv'; -import { OpenAPIV3 } from '../../framework/types'; -import ajv = require('ajv'); -import { OpenAPIFramework } from '../../framework'; +import { OpenAPIV3 } from 'framework'; export function dereferenceParameter( apiDocs: OpenAPIV3.Document, diff --git a/src/middlewares/util.ts b/packages/express-openapi-validator/src/middlewares/util.ts similarity index 98% rename from src/middlewares/util.ts rename to packages/express-openapi-validator/src/middlewares/util.ts index 1d747bc5..1eda95d9 100644 --- a/src/middlewares/util.ts +++ b/packages/express-openapi-validator/src/middlewares/util.ts @@ -1,6 +1,6 @@ import * as Ajv from 'ajv'; import { Request } from 'express'; -import { ValidationError } from '../framework/types'; +import { ValidationError } from 'framework'; export class ContentType { public readonly contentType: string = null; diff --git a/src/openapi.validator.ts b/packages/express-openapi-validator/src/openapi.validator.ts similarity index 98% rename from src/openapi.validator.ts rename to packages/express-openapi-validator/src/openapi.validator.ts index 2f7080af..41897ac9 100644 --- a/src/openapi.validator.ts +++ b/packages/express-openapi-validator/src/openapi.validator.ts @@ -4,22 +4,24 @@ import * as express from 'express'; import * as _uniq from 'lodash.uniq'; import * as middlewares from './middlewares'; import { Application, Response, NextFunction, Router } from 'express'; -import { OpenApiContext } from './framework/openapi.context'; -import { Spec } from './framework/openapi.spec.loader'; import { OpenApiValidatorOpts, + OpenApiContext, + OperationHandlerOptions, + Spec, ValidateRequestOpts, ValidateResponseOpts, - OpenApiRequest, - OpenApiRequestHandler, - OpenApiRequestMetadata, ValidateSecurityOpts, OpenAPIV3, RequestValidatorOptions, Options, -} from './framework/types'; +} from 'framework'; +import { + OpenApiRequest, + OpenApiRequestHandler, + OpenApiRequestMetadata, +} from './types'; import { defaultResolver } from './resolvers'; -import { OperationHandlerOptions } from './framework/types'; import { SchemaPreprocessor } from './middlewares/parsers/schema.preprocessor'; export { @@ -33,7 +35,7 @@ export { NotFound, Unauthorized, Forbidden, -} from './framework/types'; +} from 'framework'; export class OpenApiValidator { readonly options: OpenApiValidatorOpts; diff --git a/src/resolvers.ts b/packages/express-openapi-validator/src/resolvers.ts similarity index 95% rename from src/resolvers.ts rename to packages/express-openapi-validator/src/resolvers.ts index 7d7445f5..0a7b9919 100644 --- a/src/resolvers.ts +++ b/packages/express-openapi-validator/src/resolvers.ts @@ -1,7 +1,6 @@ import * as path from 'path'; import { RequestHandler } from 'express'; -import { RouteMetadata } from './framework/openapi.spec.loader'; -import { OpenAPIV3 } from './framework/types'; +import { OpenAPIV3, RouteMetadata } from 'framework'; const cache = {}; export function defaultResolver( diff --git a/packages/express-openapi-validator/src/types.ts b/packages/express-openapi-validator/src/types.ts new file mode 100644 index 00000000..6931fcc1 --- /dev/null +++ b/packages/express-openapi-validator/src/types.ts @@ -0,0 +1,19 @@ +import { Request, Response, NextFunction } from 'express'; +import { OpenAPIV3 } from 'framework'; + +export interface OpenApiRequest extends Request { + openapi?: OpenApiRequestMetadata | {}; +} + +export interface OpenApiRequestMetadata { + expressRoute: string; + openApiRoute: string; + pathParams: { [index: string]: string }; + schema: OpenAPIV3.OperationObject; +} + +export type OpenApiRequestHandler = ( + req: OpenApiRequest, + res: Response, + next: NextFunction, +) => any; diff --git a/test/356.campaign.spec.ts b/packages/express-openapi-validator/test/356.campaign.spec.ts similarity index 100% rename from test/356.campaign.spec.ts rename to packages/express-openapi-validator/test/356.campaign.spec.ts diff --git a/test/356.campaign.yaml b/packages/express-openapi-validator/test/356.campaign.yaml similarity index 100% rename from test/356.campaign.yaml rename to packages/express-openapi-validator/test/356.campaign.yaml diff --git a/test/440.spec.ts b/packages/express-openapi-validator/test/440.spec.ts similarity index 80% rename from test/440.spec.ts rename to packages/express-openapi-validator/test/440.spec.ts index e105f07e..fdb71658 100644 --- a/test/440.spec.ts +++ b/packages/express-openapi-validator/test/440.spec.ts @@ -2,7 +2,7 @@ import * as express from 'express'; import * as request from 'supertest'; import { createApp } from './common/app'; import * as packageJson from '../package.json'; -import { OpenAPIV3 } from '../src/framework/types'; +import { OpenAPIV3 } from 'framework'; describe(packageJson.name, () => { let app = null; @@ -45,16 +45,19 @@ describe(packageJson.name, () => { }, }, }; - app = await createApp({ - apiSpec, - validateRequests: true, - validateResponses: true, - }, 3005, (app) => - app.use( - express - .Router() - .post(`/test/abc123`, (req, res) => res.status(200).json(req.body)), - ), + app = await createApp( + { + apiSpec, + validateRequests: true, + validateResponses: true, + }, + 3005, + (app) => + app.use( + express + .Router() + .post(`/test/abc123`, (req, res) => res.status(200).json(req.body)), + ), ); }); diff --git a/test/509.spec.ts b/packages/express-openapi-validator/test/509.spec.ts similarity index 100% rename from test/509.spec.ts rename to packages/express-openapi-validator/test/509.spec.ts diff --git a/test/511.spec.ts b/packages/express-openapi-validator/test/511.spec.ts similarity index 100% rename from test/511.spec.ts rename to packages/express-openapi-validator/test/511.spec.ts diff --git a/test/additional.props.query.params.spec.ts b/packages/express-openapi-validator/test/additional.props.query.params.spec.ts similarity index 100% rename from test/additional.props.query.params.spec.ts rename to packages/express-openapi-validator/test/additional.props.query.params.spec.ts diff --git a/test/additional.props.spec.ts b/packages/express-openapi-validator/test/additional.props.spec.ts similarity index 100% rename from test/additional.props.spec.ts rename to packages/express-openapi-validator/test/additional.props.spec.ts diff --git a/test/all.of.spec.ts b/packages/express-openapi-validator/test/all.of.spec.ts similarity index 100% rename from test/all.of.spec.ts rename to packages/express-openapi-validator/test/all.of.spec.ts diff --git a/test/assets/image.png b/packages/express-openapi-validator/test/assets/image.png similarity index 100% rename from test/assets/image.png rename to packages/express-openapi-validator/test/assets/image.png diff --git a/test/circular.spec.ts b/packages/express-openapi-validator/test/circular.spec.ts similarity index 100% rename from test/circular.spec.ts rename to packages/express-openapi-validator/test/circular.spec.ts diff --git a/test/coercion.spec.ts b/packages/express-openapi-validator/test/coercion.spec.ts similarity index 100% rename from test/coercion.spec.ts rename to packages/express-openapi-validator/test/coercion.spec.ts diff --git a/test/common/app.common.ts b/packages/express-openapi-validator/test/common/app.common.ts similarity index 100% rename from test/common/app.common.ts rename to packages/express-openapi-validator/test/common/app.common.ts diff --git a/test/common/app.mw.ts b/packages/express-openapi-validator/test/common/app.mw.ts similarity index 100% rename from test/common/app.mw.ts rename to packages/express-openapi-validator/test/common/app.mw.ts diff --git a/test/common/app.ts b/packages/express-openapi-validator/test/common/app.ts similarity index 96% rename from test/common/app.ts rename to packages/express-openapi-validator/test/common/app.ts index cbefea40..f8e34f65 100644 --- a/test/common/app.ts +++ b/packages/express-openapi-validator/test/common/app.ts @@ -6,7 +6,7 @@ import * as logger from 'morgan'; import * as OpenApiValidator from '../../src'; import { startServer, routes } from './app.common'; -import { OpenApiValidatorOpts } from '../../src/framework/types'; +import { OpenApiValidatorOpts } from 'framework'; export async function createApp( opts?: OpenApiValidatorOpts, diff --git a/test/common/run.ts b/packages/express-openapi-validator/test/common/run.ts similarity index 100% rename from test/common/run.ts rename to packages/express-openapi-validator/test/common/run.ts diff --git a/test/common/test.yaml b/packages/express-openapi-validator/test/common/test.yaml similarity index 100% rename from test/common/test.yaml rename to packages/express-openapi-validator/test/common/test.yaml diff --git a/test/component.params.spec.ts b/packages/express-openapi-validator/test/component.params.spec.ts similarity index 100% rename from test/component.params.spec.ts rename to packages/express-openapi-validator/test/component.params.spec.ts diff --git a/test/content.type.spec.ts b/packages/express-openapi-validator/test/content.type.spec.ts similarity index 100% rename from test/content.type.spec.ts rename to packages/express-openapi-validator/test/content.type.spec.ts diff --git a/test/datetime.validation.spec.ts b/packages/express-openapi-validator/test/datetime.validation.spec.ts similarity index 100% rename from test/datetime.validation.spec.ts rename to packages/express-openapi-validator/test/datetime.validation.spec.ts diff --git a/test/empty.servers.spec.ts b/packages/express-openapi-validator/test/empty.servers.spec.ts similarity index 100% rename from test/empty.servers.spec.ts rename to packages/express-openapi-validator/test/empty.servers.spec.ts diff --git a/test/escaped.characters.in.ref.path.spec.ts b/packages/express-openapi-validator/test/escaped.characters.in.ref.path.spec.ts similarity index 100% rename from test/escaped.characters.in.ref.path.spec.ts rename to packages/express-openapi-validator/test/escaped.characters.in.ref.path.spec.ts diff --git a/test/formats.spec.ts b/packages/express-openapi-validator/test/formats.spec.ts similarity index 100% rename from test/formats.spec.ts rename to packages/express-openapi-validator/test/formats.spec.ts diff --git a/test/headers.2.spec.ts b/packages/express-openapi-validator/test/headers.2.spec.ts similarity index 100% rename from test/headers.2.spec.ts rename to packages/express-openapi-validator/test/headers.2.spec.ts diff --git a/test/headers.spec.ts b/packages/express-openapi-validator/test/headers.spec.ts similarity index 100% rename from test/headers.spec.ts rename to packages/express-openapi-validator/test/headers.spec.ts diff --git a/test/httperror.spec.ts b/packages/express-openapi-validator/test/httperror.spec.ts similarity index 98% rename from test/httperror.spec.ts rename to packages/express-openapi-validator/test/httperror.spec.ts index 6b87d652..46106697 100644 --- a/test/httperror.spec.ts +++ b/packages/express-openapi-validator/test/httperror.spec.ts @@ -1,7 +1,7 @@ import { expect } from 'chai'; import * as packageJson from '../package.json'; import { error } from '../src'; -import { HttpError } from '../src/framework/types'; +import { HttpError } from 'framework'; describe(packageJson.name, () => { it('should be an instance of BadRequest', (done) => { diff --git a/test/ignore.paths.spec.ts b/packages/express-openapi-validator/test/ignore.paths.spec.ts similarity index 100% rename from test/ignore.paths.spec.ts rename to packages/express-openapi-validator/test/ignore.paths.spec.ts diff --git a/test/missing.spec.ts b/packages/express-openapi-validator/test/missing.spec.ts similarity index 100% rename from test/missing.spec.ts rename to packages/express-openapi-validator/test/missing.spec.ts diff --git a/test/multipart.disabled.spec.ts b/packages/express-openapi-validator/test/multipart.disabled.spec.ts similarity index 100% rename from test/multipart.disabled.spec.ts rename to packages/express-openapi-validator/test/multipart.disabled.spec.ts diff --git a/test/multipart.spec.ts b/packages/express-openapi-validator/test/multipart.spec.ts similarity index 100% rename from test/multipart.spec.ts rename to packages/express-openapi-validator/test/multipart.spec.ts diff --git a/test/nested.routes.spec.ts b/packages/express-openapi-validator/test/nested.routes.spec.ts similarity index 100% rename from test/nested.routes.spec.ts rename to packages/express-openapi-validator/test/nested.routes.spec.ts diff --git a/test/no.components.spec.ts b/packages/express-openapi-validator/test/no.components.spec.ts similarity index 96% rename from test/no.components.spec.ts rename to packages/express-openapi-validator/test/no.components.spec.ts index 0373bd3f..f1a7b296 100644 --- a/test/no.components.spec.ts +++ b/packages/express-openapi-validator/test/no.components.spec.ts @@ -2,7 +2,7 @@ import * as express from 'express'; import { expect } from 'chai'; import * as request from 'supertest'; import { createApp } from './common/app'; -import { OpenAPIV3 } from '../src/framework/types'; +import { OpenAPIV3 } from 'framework'; describe('no components', () => { let app = null; diff --git a/test/nullable.spec.ts b/packages/express-openapi-validator/test/nullable.spec.ts similarity index 100% rename from test/nullable.spec.ts rename to packages/express-openapi-validator/test/nullable.spec.ts diff --git a/test/one.of.2.spec.ts b/packages/express-openapi-validator/test/one.of.2.spec.ts similarity index 100% rename from test/one.of.2.spec.ts rename to packages/express-openapi-validator/test/one.of.2.spec.ts diff --git a/test/one.of.spec.ts b/packages/express-openapi-validator/test/one.of.spec.ts similarity index 100% rename from test/one.of.spec.ts rename to packages/express-openapi-validator/test/one.of.spec.ts diff --git a/test/oneof.readonly.spec.ts b/packages/express-openapi-validator/test/oneof.readonly.spec.ts similarity index 100% rename from test/oneof.readonly.spec.ts rename to packages/express-openapi-validator/test/oneof.readonly.spec.ts diff --git a/test/oneof.readonly.yaml b/packages/express-openapi-validator/test/oneof.readonly.yaml similarity index 100% rename from test/oneof.readonly.yaml rename to packages/express-openapi-validator/test/oneof.readonly.yaml diff --git a/test/openapi.spec.ts b/packages/express-openapi-validator/test/openapi.spec.ts similarity index 100% rename from test/openapi.spec.ts rename to packages/express-openapi-validator/test/openapi.spec.ts diff --git a/test/operation.handler.spec.ts b/packages/express-openapi-validator/test/operation.handler.spec.ts similarity index 98% rename from test/operation.handler.spec.ts rename to packages/express-openapi-validator/test/operation.handler.spec.ts index b7e60fe9..8a7e5e78 100644 --- a/test/operation.handler.spec.ts +++ b/packages/express-openapi-validator/test/operation.handler.spec.ts @@ -5,7 +5,7 @@ import * as request from 'supertest'; import * as OpenApiValidator from '../src'; import * as resolvers from '../src/resolvers'; import { createApp } from './common/app'; -import { OpenApiValidatorOpts } from '../src/framework/types'; +import { OpenApiValidatorOpts } from 'framework'; describe('operation handler', () => { let defaultNumberOfRoutes = null; diff --git a/test/optional-request-body.spec.ts b/packages/express-openapi-validator/test/optional-request-body.spec.ts similarity index 100% rename from test/optional-request-body.spec.ts rename to packages/express-openapi-validator/test/optional-request-body.spec.ts diff --git a/test/optional-request-body.yaml b/packages/express-openapi-validator/test/optional-request-body.yaml similarity index 100% rename from test/optional-request-body.yaml rename to packages/express-openapi-validator/test/optional-request-body.yaml diff --git a/test/path.level.parameters.spec.ts b/packages/express-openapi-validator/test/path.level.parameters.spec.ts similarity index 100% rename from test/path.level.parameters.spec.ts rename to packages/express-openapi-validator/test/path.level.parameters.spec.ts diff --git a/test/path.order.spec.ts b/packages/express-openapi-validator/test/path.order.spec.ts similarity index 100% rename from test/path.order.spec.ts rename to packages/express-openapi-validator/test/path.order.spec.ts diff --git a/test/path.params.spec.ts b/packages/express-openapi-validator/test/path.params.spec.ts similarity index 100% rename from test/path.params.spec.ts rename to packages/express-openapi-validator/test/path.params.spec.ts diff --git a/test/paths.sort.spec.ts b/packages/express-openapi-validator/test/paths.sort.spec.ts similarity index 95% rename from test/paths.sort.spec.ts rename to packages/express-openapi-validator/test/paths.sort.spec.ts index 6d2fc4fa..6429d559 100644 --- a/test/paths.sort.spec.ts +++ b/packages/express-openapi-validator/test/paths.sort.spec.ts @@ -1,6 +1,6 @@ import { sortRoutes, -} from '../src/framework/openapi.spec.loader'; +} from 'framework/dist/openapi.spec.loader'; import { expect } from 'chai'; describe('url sorter', () => { diff --git a/test/petstore.spec.ts b/packages/express-openapi-validator/test/petstore.spec.ts similarity index 98% rename from test/petstore.spec.ts rename to packages/express-openapi-validator/test/petstore.spec.ts index 1edf43e7..67b62e62 100644 --- a/test/petstore.spec.ts +++ b/packages/express-openapi-validator/test/petstore.spec.ts @@ -1,5 +1,5 @@ import * as request from 'supertest'; -import { OpenAPIV3 } from '../src/framework/types'; +import { OpenAPIV3 } from 'framework'; import { createApp } from './common/app'; describe('petstore', () => { diff --git a/test/query.params.allow.unknown.spec.ts b/packages/express-openapi-validator/test/query.params.allow.unknown.spec.ts similarity index 100% rename from test/query.params.allow.unknown.spec.ts rename to packages/express-openapi-validator/test/query.params.allow.unknown.spec.ts diff --git a/test/query.params.spec.ts b/packages/express-openapi-validator/test/query.params.spec.ts similarity index 100% rename from test/query.params.spec.ts rename to packages/express-openapi-validator/test/query.params.spec.ts diff --git a/test/query.serialization.ts b/packages/express-openapi-validator/test/query.serialization.ts similarity index 100% rename from test/query.serialization.ts rename to packages/express-openapi-validator/test/query.serialization.ts diff --git a/test/read.only.spec.ts b/packages/express-openapi-validator/test/read.only.spec.ts similarity index 100% rename from test/read.only.spec.ts rename to packages/express-openapi-validator/test/read.only.spec.ts diff --git a/test/request.bodies.ref.spec.ts b/packages/express-openapi-validator/test/request.bodies.ref.spec.ts similarity index 100% rename from test/request.bodies.ref.spec.ts rename to packages/express-openapi-validator/test/request.bodies.ref.spec.ts diff --git a/test/request.body.validation.coerce.types.spec.ts b/packages/express-openapi-validator/test/request.body.validation.coerce.types.spec.ts similarity index 100% rename from test/request.body.validation.coerce.types.spec.ts rename to packages/express-openapi-validator/test/request.body.validation.coerce.types.spec.ts diff --git a/test/resources/additional.properties.yaml b/packages/express-openapi-validator/test/resources/additional.properties.yaml similarity index 100% rename from test/resources/additional.properties.yaml rename to packages/express-openapi-validator/test/resources/additional.properties.yaml diff --git a/test/resources/additional.props.query.params.yaml b/packages/express-openapi-validator/test/resources/additional.props.query.params.yaml similarity index 100% rename from test/resources/additional.props.query.params.yaml rename to packages/express-openapi-validator/test/resources/additional.props.query.params.yaml diff --git a/test/resources/all.of.yaml b/packages/express-openapi-validator/test/resources/all.of.yaml similarity index 100% rename from test/resources/all.of.yaml rename to packages/express-openapi-validator/test/resources/all.of.yaml diff --git a/test/resources/circular.yaml b/packages/express-openapi-validator/test/resources/circular.yaml similarity index 100% rename from test/resources/circular.yaml rename to packages/express-openapi-validator/test/resources/circular.yaml diff --git a/test/resources/coercion.yaml b/packages/express-openapi-validator/test/resources/coercion.yaml similarity index 100% rename from test/resources/coercion.yaml rename to packages/express-openapi-validator/test/resources/coercion.yaml diff --git a/test/resources/component.params.yaml b/packages/express-openapi-validator/test/resources/component.params.yaml similarity index 100% rename from test/resources/component.params.yaml rename to packages/express-openapi-validator/test/resources/component.params.yaml diff --git a/test/resources/datetime.validation.yaml b/packages/express-openapi-validator/test/resources/datetime.validation.yaml similarity index 100% rename from test/resources/datetime.validation.yaml rename to packages/express-openapi-validator/test/resources/datetime.validation.yaml diff --git a/test/resources/empty.servers.yaml b/packages/express-openapi-validator/test/resources/empty.servers.yaml similarity index 100% rename from test/resources/empty.servers.yaml rename to packages/express-openapi-validator/test/resources/empty.servers.yaml diff --git a/test/resources/eov-operations.modulepath.yaml b/packages/express-openapi-validator/test/resources/eov-operations.modulepath.yaml similarity index 100% rename from test/resources/eov-operations.modulepath.yaml rename to packages/express-openapi-validator/test/resources/eov-operations.modulepath.yaml diff --git a/test/resources/eov-operations.yaml b/packages/express-openapi-validator/test/resources/eov-operations.yaml similarity index 100% rename from test/resources/eov-operations.yaml rename to packages/express-openapi-validator/test/resources/eov-operations.yaml diff --git a/test/resources/escaped.characters.in.path.yaml b/packages/express-openapi-validator/test/resources/escaped.characters.in.path.yaml similarity index 100% rename from test/resources/escaped.characters.in.path.yaml rename to packages/express-openapi-validator/test/resources/escaped.characters.in.path.yaml diff --git a/test/resources/formats.yaml b/packages/express-openapi-validator/test/resources/formats.yaml similarity index 100% rename from test/resources/formats.yaml rename to packages/express-openapi-validator/test/resources/formats.yaml diff --git a/test/resources/headers.yaml b/packages/express-openapi-validator/test/resources/headers.yaml similarity index 100% rename from test/resources/headers.yaml rename to packages/express-openapi-validator/test/resources/headers.yaml diff --git a/test/resources/ignore.paths.yaml b/packages/express-openapi-validator/test/resources/ignore.paths.yaml similarity index 100% rename from test/resources/ignore.paths.yaml rename to packages/express-openapi-validator/test/resources/ignore.paths.yaml diff --git a/test/resources/multipart.yaml b/packages/express-openapi-validator/test/resources/multipart.yaml similarity index 100% rename from test/resources/multipart.yaml rename to packages/express-openapi-validator/test/resources/multipart.yaml diff --git a/test/resources/nested.routes.yaml b/packages/express-openapi-validator/test/resources/nested.routes.yaml similarity index 100% rename from test/resources/nested.routes.yaml rename to packages/express-openapi-validator/test/resources/nested.routes.yaml diff --git a/test/resources/nullable.yaml b/packages/express-openapi-validator/test/resources/nullable.yaml similarity index 100% rename from test/resources/nullable.yaml rename to packages/express-openapi-validator/test/resources/nullable.yaml diff --git a/test/resources/one.of.2.yaml b/packages/express-openapi-validator/test/resources/one.of.2.yaml similarity index 100% rename from test/resources/one.of.2.yaml rename to packages/express-openapi-validator/test/resources/one.of.2.yaml diff --git a/test/resources/one.of.yaml b/packages/express-openapi-validator/test/resources/one.of.yaml similarity index 100% rename from test/resources/one.of.yaml rename to packages/express-openapi-validator/test/resources/one.of.yaml diff --git a/test/resources/openapi.json b/packages/express-openapi-validator/test/resources/openapi.json similarity index 100% rename from test/resources/openapi.json rename to packages/express-openapi-validator/test/resources/openapi.json diff --git a/test/resources/openapi.yaml b/packages/express-openapi-validator/test/resources/openapi.yaml similarity index 100% rename from test/resources/openapi.yaml rename to packages/express-openapi-validator/test/resources/openapi.yaml diff --git a/test/resources/path.level.parameters.yaml b/packages/express-openapi-validator/test/resources/path.level.parameters.yaml similarity index 100% rename from test/resources/path.level.parameters.yaml rename to packages/express-openapi-validator/test/resources/path.level.parameters.yaml diff --git a/test/resources/path.order.yaml b/packages/express-openapi-validator/test/resources/path.order.yaml similarity index 100% rename from test/resources/path.order.yaml rename to packages/express-openapi-validator/test/resources/path.order.yaml diff --git a/test/resources/path.params.yaml b/packages/express-openapi-validator/test/resources/path.params.yaml similarity index 100% rename from test/resources/path.params.yaml rename to packages/express-openapi-validator/test/resources/path.params.yaml diff --git a/test/resources/query.params.yaml b/packages/express-openapi-validator/test/resources/query.params.yaml similarity index 100% rename from test/resources/query.params.yaml rename to packages/express-openapi-validator/test/resources/query.params.yaml diff --git a/test/resources/query.serialization.yaml b/packages/express-openapi-validator/test/resources/query.serialization.yaml similarity index 100% rename from test/resources/query.serialization.yaml rename to packages/express-openapi-validator/test/resources/query.serialization.yaml diff --git a/test/resources/read.only.yaml b/packages/express-openapi-validator/test/resources/read.only.yaml similarity index 100% rename from test/resources/read.only.yaml rename to packages/express-openapi-validator/test/resources/read.only.yaml diff --git a/test/resources/request.bodies.ref.yaml b/packages/express-openapi-validator/test/resources/request.bodies.ref.yaml similarity index 100% rename from test/resources/request.bodies.ref.yaml rename to packages/express-openapi-validator/test/resources/request.bodies.ref.yaml diff --git a/test/resources/response.object.serializer.yaml b/packages/express-openapi-validator/test/resources/response.object.serializer.yaml similarity index 100% rename from test/resources/response.object.serializer.yaml rename to packages/express-openapi-validator/test/resources/response.object.serializer.yaml diff --git a/test/resources/response.validation.yaml b/packages/express-openapi-validator/test/resources/response.validation.yaml similarity index 100% rename from test/resources/response.validation.yaml rename to packages/express-openapi-validator/test/resources/response.validation.yaml diff --git a/test/resources/routes/pets.js b/packages/express-openapi-validator/test/resources/routes/pets.js similarity index 100% rename from test/resources/routes/pets.js rename to packages/express-openapi-validator/test/resources/routes/pets.js diff --git a/test/resources/routes/ping.js b/packages/express-openapi-validator/test/resources/routes/ping.js similarity index 100% rename from test/resources/routes/ping.js rename to packages/express-openapi-validator/test/resources/routes/ping.js diff --git a/test/resources/security.top.level.yaml b/packages/express-openapi-validator/test/resources/security.top.level.yaml similarity index 100% rename from test/resources/security.top.level.yaml rename to packages/express-openapi-validator/test/resources/security.top.level.yaml diff --git a/test/resources/security.yaml b/packages/express-openapi-validator/test/resources/security.yaml similarity index 100% rename from test/resources/security.yaml rename to packages/express-openapi-validator/test/resources/security.yaml diff --git a/test/resources/serialized.objects.defaults.yaml b/packages/express-openapi-validator/test/resources/serialized.objects.defaults.yaml similarity index 100% rename from test/resources/serialized.objects.defaults.yaml rename to packages/express-openapi-validator/test/resources/serialized.objects.defaults.yaml diff --git a/test/resources/serialized.objects.yaml b/packages/express-openapi-validator/test/resources/serialized.objects.yaml similarity index 100% rename from test/resources/serialized.objects.yaml rename to packages/express-openapi-validator/test/resources/serialized.objects.yaml diff --git a/test/resources/servers.1.yaml b/packages/express-openapi-validator/test/resources/servers.1.yaml similarity index 100% rename from test/resources/servers.1.yaml rename to packages/express-openapi-validator/test/resources/servers.1.yaml diff --git a/test/resources/servers.2.yaml b/packages/express-openapi-validator/test/resources/servers.2.yaml similarity index 100% rename from test/resources/servers.2.yaml rename to packages/express-openapi-validator/test/resources/servers.2.yaml diff --git a/test/resources/services/index.js b/packages/express-openapi-validator/test/resources/services/index.js similarity index 100% rename from test/resources/services/index.js rename to packages/express-openapi-validator/test/resources/services/index.js diff --git a/test/resources/sub_files/paths/auth.yaml b/packages/express-openapi-validator/test/resources/sub_files/paths/auth.yaml similarity index 100% rename from test/resources/sub_files/paths/auth.yaml rename to packages/express-openapi-validator/test/resources/sub_files/paths/auth.yaml diff --git a/test/resources/unknown.formats.yaml b/packages/express-openapi-validator/test/resources/unknown.formats.yaml similarity index 100% rename from test/resources/unknown.formats.yaml rename to packages/express-openapi-validator/test/resources/unknown.formats.yaml diff --git a/test/resources/wildcard.path.params.yaml b/packages/express-openapi-validator/test/resources/wildcard.path.params.yaml similarity index 100% rename from test/resources/wildcard.path.params.yaml rename to packages/express-openapi-validator/test/resources/wildcard.path.params.yaml diff --git a/test/resources/write.only.yaml b/packages/express-openapi-validator/test/resources/write.only.yaml similarity index 100% rename from test/resources/write.only.yaml rename to packages/express-openapi-validator/test/resources/write.only.yaml diff --git a/test/resources/xt.newpet.yaml b/packages/express-openapi-validator/test/resources/xt.newpet.yaml similarity index 100% rename from test/resources/xt.newpet.yaml rename to packages/express-openapi-validator/test/resources/xt.newpet.yaml diff --git a/test/resources/xt.openapi.parameters.yaml b/packages/express-openapi-validator/test/resources/xt.openapi.parameters.yaml similarity index 100% rename from test/resources/xt.openapi.parameters.yaml rename to packages/express-openapi-validator/test/resources/xt.openapi.parameters.yaml diff --git a/test/response.object.serializer.spec.ts b/packages/express-openapi-validator/test/response.object.serializer.spec.ts similarity index 100% rename from test/response.object.serializer.spec.ts rename to packages/express-openapi-validator/test/response.object.serializer.spec.ts diff --git a/test/response.validation.coerce.types.spec.ts b/packages/express-openapi-validator/test/response.validation.coerce.types.spec.ts similarity index 100% rename from test/response.validation.coerce.types.spec.ts rename to packages/express-openapi-validator/test/response.validation.coerce.types.spec.ts diff --git a/test/response.validation.on.error.spec.ts b/packages/express-openapi-validator/test/response.validation.on.error.spec.ts similarity index 100% rename from test/response.validation.on.error.spec.ts rename to packages/express-openapi-validator/test/response.validation.on.error.spec.ts diff --git a/test/response.validation.options.spec.ts b/packages/express-openapi-validator/test/response.validation.options.spec.ts similarity index 100% rename from test/response.validation.options.spec.ts rename to packages/express-openapi-validator/test/response.validation.options.spec.ts diff --git a/test/response.validation.spec.ts b/packages/express-openapi-validator/test/response.validation.spec.ts similarity index 100% rename from test/response.validation.spec.ts rename to packages/express-openapi-validator/test/response.validation.spec.ts diff --git a/test/response.validator.spec.ts b/packages/express-openapi-validator/test/response.validator.spec.ts similarity index 97% rename from test/response.validator.spec.ts rename to packages/express-openapi-validator/test/response.validator.spec.ts index b640fecb..226873f5 100644 --- a/test/response.validator.spec.ts +++ b/packages/express-openapi-validator/test/response.validator.spec.ts @@ -5,7 +5,8 @@ import * as jsyaml from 'js-yaml'; import { expect } from 'chai'; import { ResponseValidator } from '../src/middlewares/openapi.response.validator'; import * as packageJson from '../package.json'; -import { OpenAPIV3, OpenApiRequest } from '../src/framework/types'; +import { OpenAPIV3 } from 'framework'; +import { OpenApiRequest } from '../src/types' const apiSpecPath = path.join('test', 'resources', 'response.validation.yaml'); const apiSpec = jsyaml.safeLoad(fs.readFileSync(apiSpecPath, 'utf8')); diff --git a/test/router.spec.ts b/packages/express-openapi-validator/test/router.spec.ts similarity index 100% rename from test/router.spec.ts rename to packages/express-openapi-validator/test/router.spec.ts diff --git a/test/security.defaults.spec.ts b/packages/express-openapi-validator/test/security.defaults.spec.ts similarity index 100% rename from test/security.defaults.spec.ts rename to packages/express-openapi-validator/test/security.defaults.spec.ts diff --git a/test/security.disabled.spec.ts b/packages/express-openapi-validator/test/security.disabled.spec.ts similarity index 100% rename from test/security.disabled.spec.ts rename to packages/express-openapi-validator/test/security.disabled.spec.ts diff --git a/test/security.handlers.spec.ts b/packages/express-openapi-validator/test/security.handlers.spec.ts similarity index 99% rename from test/security.handlers.spec.ts rename to packages/express-openapi-validator/test/security.handlers.spec.ts index 209f16d1..58b8f1bb 100644 --- a/test/security.handlers.spec.ts +++ b/packages/express-openapi-validator/test/security.handlers.spec.ts @@ -7,7 +7,7 @@ import { OpenApiValidatorOpts, ValidateSecurityOpts, OpenAPIV3, -} from '../src/framework/types'; +} from 'framework'; // NOTE/TODO: These tests modify eovConf.validateSecurity.handlers // Thus test execution order matters :-( diff --git a/test/security.top.level.spec.ts b/packages/express-openapi-validator/test/security.top.level.spec.ts similarity index 100% rename from test/security.top.level.spec.ts rename to packages/express-openapi-validator/test/security.top.level.spec.ts diff --git a/test/serialized.objects.defaults.spec.ts b/packages/express-openapi-validator/test/serialized.objects.defaults.spec.ts similarity index 100% rename from test/serialized.objects.defaults.spec.ts rename to packages/express-openapi-validator/test/serialized.objects.defaults.spec.ts diff --git a/test/serialized.objects.spec.ts b/packages/express-openapi-validator/test/serialized.objects.spec.ts similarity index 100% rename from test/serialized.objects.spec.ts rename to packages/express-openapi-validator/test/serialized.objects.spec.ts diff --git a/test/servers.spec.ts b/packages/express-openapi-validator/test/servers.spec.ts similarity index 100% rename from test/servers.spec.ts rename to packages/express-openapi-validator/test/servers.spec.ts diff --git a/test/unknown.formats.spec.ts b/packages/express-openapi-validator/test/unknown.formats.spec.ts similarity index 100% rename from test/unknown.formats.spec.ts rename to packages/express-openapi-validator/test/unknown.formats.spec.ts diff --git a/test/wildcard.path.params.spec.ts b/packages/express-openapi-validator/test/wildcard.path.params.spec.ts similarity index 100% rename from test/wildcard.path.params.spec.ts rename to packages/express-openapi-validator/test/wildcard.path.params.spec.ts diff --git a/test/write.only.spec.ts b/packages/express-openapi-validator/test/write.only.spec.ts similarity index 100% rename from test/write.only.spec.ts rename to packages/express-openapi-validator/test/write.only.spec.ts diff --git a/tsconfig.json b/packages/express-openapi-validator/tsconfig.json similarity index 100% rename from tsconfig.json rename to packages/express-openapi-validator/tsconfig.json diff --git a/typings/index.d.ts b/packages/express-openapi-validator/typings/index.d.ts similarity index 100% rename from typings/index.d.ts rename to packages/express-openapi-validator/typings/index.d.ts diff --git a/packages/framework/.prettierrc.json b/packages/framework/.prettierrc.json new file mode 100644 index 00000000..a20502b7 --- /dev/null +++ b/packages/framework/.prettierrc.json @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/packages/framework/dist/ajv/formats.d.ts b/packages/framework/dist/ajv/formats.d.ts new file mode 100644 index 00000000..bbe9434b --- /dev/null +++ b/packages/framework/dist/ajv/formats.d.ts @@ -0,0 +1,21 @@ +export declare const formats: { + int32: { + validate: (i: any) => boolean; + type: string; + }; + int64: { + validate: (i: any) => boolean; + type: string; + }; + float: { + validate: (i: any) => boolean; + type: string; + }; + double: { + validate: (i: any) => boolean; + type: string; + }; + byte: (b: any) => boolean; + binary: () => boolean; + password: () => boolean; +}; diff --git a/packages/framework/dist/ajv/formats.js b/packages/framework/dist/ajv/formats.js new file mode 100644 index 00000000..da50515b --- /dev/null +++ b/packages/framework/dist/ajv/formats.js @@ -0,0 +1,35 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.formats = void 0; +const maxInt32 = 2 ** 31 - 1; +const minInt32 = (-2) ** 31; +const maxInt64 = 2 ** 63 - 1; +const minInt64 = (-2) ** 63; +const maxFloat = (2 - 2 ** -23) * 2 ** 127; +const minPosFloat = 2 ** -126; +const minFloat = -1 * maxFloat; +const maxNegFloat = -1 * minPosFloat; +const alwaysTrue = () => true; +const base64regExp = /^[A-Za-z0-9+/]*(=|==)?$/; +exports.formats = { + int32: { + validate: i => Number.isInteger(i) && i <= maxInt32 && i >= minInt32, + type: 'number', + }, + int64: { + validate: i => Number.isInteger(i) && i <= maxInt64 && i >= minInt64, + type: 'number', + }, + float: { + validate: i => typeof i === 'number' && (i === 0 || (i <= maxFloat && i >= minPosFloat) || (i >= minFloat && i <= maxNegFloat)), + type: 'number', + }, + double: { + validate: i => typeof i === 'number', + type: 'number', + }, + byte: b => b.length % 4 === 0 && base64regExp.test(b), + binary: alwaysTrue, + password: alwaysTrue, +}; +//# sourceMappingURL=formats.js.map \ No newline at end of file diff --git a/packages/framework/dist/ajv/formats.js.map b/packages/framework/dist/ajv/formats.js.map new file mode 100644 index 00000000..4dbfb27b --- /dev/null +++ b/packages/framework/dist/ajv/formats.js.map @@ -0,0 +1 @@ +{"version":3,"file":"formats.js","sourceRoot":"","sources":["../../src/framework/ajv/formats.ts"],"names":[],"mappings":";;;AAAA,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AAC3C,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AAC/B,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;AAErC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AAC9B,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAElC,QAAA,OAAO,GAAG;IACrB,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;QAC/H,IAAI,EAAE,QAAQ;KACf;IACD,MAAM,EAAE;QACN,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ;QACpC,IAAI,EAAE,QAAQ;KACf;IACD,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,UAAU;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/framework/dist/ajv/index.d.ts b/packages/framework/dist/ajv/index.d.ts new file mode 100644 index 00000000..c98bc614 --- /dev/null +++ b/packages/framework/dist/ajv/index.d.ts @@ -0,0 +1,4 @@ +import * as Ajv from 'ajv'; +import { OpenAPIV3, Options } from '..'; +export declare function createRequestAjv(openApiSpec: OpenAPIV3.Document, options?: Options): Ajv.Ajv; +export declare function createResponseAjv(openApiSpec: OpenAPIV3.Document, options?: Options): Ajv.Ajv; diff --git a/packages/framework/dist/ajv/index.js b/packages/framework/dist/ajv/index.js new file mode 100644 index 00000000..8e4ad536 --- /dev/null +++ b/packages/framework/dist/ajv/index.js @@ -0,0 +1,93 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createResponseAjv = exports.createRequestAjv = void 0; +const Ajv = require("ajv"); +const draftSchema = require("ajv/lib/refs/json-schema-draft-04.json"); +const formats_1 = require("./formats"); +function createRequestAjv(openApiSpec, options = {}) { + return createAjv(openApiSpec, options); +} +exports.createRequestAjv = createRequestAjv; +function createResponseAjv(openApiSpec, options = {}) { + return createAjv(openApiSpec, options, false); +} +exports.createResponseAjv = createResponseAjv; +function createAjv(openApiSpec, options = {}, request = true) { + var _a; + const ajv = new Ajv(Object.assign(Object.assign({}, options), { schemaId: 'auto', allErrors: true, meta: draftSchema, formats: Object.assign(Object.assign({}, formats_1.formats), options.formats), unknownFormats: options.unknownFormats })); + ajv.removeKeyword('propertyNames'); + ajv.removeKeyword('contains'); + ajv.removeKeyword('const'); + if (request) { + ajv.removeKeyword('readOnly'); + ajv.addKeyword('readOnly', { + modifying: true, + compile: (sch) => { + if (sch) { + return function validate(data, path, obj, propName) { + const isValid = !(sch === true && data != null); + delete obj[propName]; + validate.errors = [ + { + keyword: 'readOnly', + schemaPath: data, + dataPath: path, + message: `is read-only`, + params: { readOnly: propName }, + }, + ]; + return isValid; + }; + } + return () => true; + }, + }); + } + else { + // response + ajv.addKeyword('x-eov-serializer', { + modifying: true, + compile: (sch) => { + if (sch) { + const isDate = ['date', 'date-time'].includes(sch.format); + return function validate(data, path, obj, propName) { + if (typeof data === 'string' && isDate) + return true; + obj[propName] = sch.serialize(data); + return true; + }; + } + return () => true; + }, + }); + ajv.removeKeyword('writeOnly'); + ajv.addKeyword('writeOnly', { + modifying: true, + compile: (sch) => { + if (sch) { + return function validate(data, path, obj, propName) { + const isValid = !(sch === true && data != null); + validate.errors = [ + { + keyword: 'writeOnly', + dataPath: path, + schemaPath: path, + message: `is write-only`, + params: { writeOnly: propName }, + }, + ]; + return isValid; + }; + } + return () => true; + }, + }); + } + if ((_a = openApiSpec.components) === null || _a === void 0 ? void 0 : _a.schemas) { + Object.entries(openApiSpec.components.schemas).forEach(([id, schema]) => { + ajv.addSchema(openApiSpec.components.schemas[id], `#/components/schemas/${id}`); + }); + } + return ajv; +} +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/framework/dist/ajv/index.js.map b/packages/framework/dist/ajv/index.js.map new file mode 100644 index 00000000..a1a35d84 --- /dev/null +++ b/packages/framework/dist/ajv/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/framework/ajv/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/base.path.d.ts b/packages/framework/dist/base.path.d.ts new file mode 100644 index 00000000..79e1bf0b --- /dev/null +++ b/packages/framework/dist/base.path.d.ts @@ -0,0 +1,19 @@ +import { OpenAPIV3 } from '.'; +interface ServerUrlVariables { + [key: string]: ServerUrlValues; +} +interface ServerUrlValues { + enum: string[]; + default?: string; +} +export declare class BasePath { + readonly variables: ServerUrlVariables; + readonly expressPath: string; + private allPaths; + constructor(server: OpenAPIV3.ServerObject); + static fromServers(servers: OpenAPIV3.ServerObject[]): BasePath[]; + hasVariables(): boolean; + all(): string[]; + private findUrlPath; +} +export {}; diff --git a/packages/framework/dist/base.path.js b/packages/framework/dist/base.path.js new file mode 100644 index 00000000..a4f1e5ca --- /dev/null +++ b/packages/framework/dist/base.path.js @@ -0,0 +1,113 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BasePath = void 0; +const path_to_regexp_1 = require("path-to-regexp"); +class BasePath { + constructor(server) { + var _a; + this.variables = {}; + this.expressPath = ''; + this.allPaths = null; + // break the url into parts + // baseUrl param added to make the parsing of relative paths go well + let urlPath = this.findUrlPath(server.url); + if (/:/.test(urlPath)) { + // escape colons as (any at this point) do not signify express route params. + // this is an openapi base path, thus route params are wrapped in braces {}, + // not prefixed by colon : (like express route params) + urlPath = urlPath.replace(':', '\\:'); + } + if (/{\w+}/.test(urlPath)) { + // has variable that we need to check out + urlPath = urlPath.replace(/{(\w+)}/g, (substring, p1) => `:${p1}(.*)`); + } + this.expressPath = urlPath; + for (const variable in server.variables) { + if (server.variables.hasOwnProperty(variable)) { + const v = server.variables[variable]; + const enums = (_a = v.enum) !== null && _a !== void 0 ? _a : []; + if (enums.length === 0 && v.default) + enums.push(v.default); + this.variables[variable] = { + enum: enums, + default: v.default, + }; + } + } + } + static fromServers(servers) { + if (!servers) { + return [new BasePath({ url: '' })]; + } + return servers.map(server => new BasePath(server)); + } + hasVariables() { + return Object.keys(this.variables).length > 0; + } + all() { + if (!this.hasVariables()) + return [this.expressPath]; + if (this.allPaths) + return this.allPaths; + // TODO performance optimization + // ignore variables that are not part of path params + const allParams = Object.entries(this.variables).reduce((acc, v) => { + const [key, value] = v; + const params = value.enum.map(e => ({ + [key]: e, + })); + acc.push(params); + return acc; + }, []); + const allParamCombos = cartesian(...allParams); + const toPath = path_to_regexp_1.compile(this.expressPath); + const paths = new Set(); + for (const combo of allParamCombos) { + paths.add(toPath(combo)); + } + this.allPaths = Array.from(paths); + return this.allPaths; + } + findUrlPath(u) { + const findColonSlashSlash = p => { + const r = /:\/\//.exec(p); + if (r) + return r.index; + return -1; + }; + const findFirstSlash = p => { + const r = /\//.exec(p); + if (r) + return r.index; + return -1; + }; + const fcssIdx = findColonSlashSlash(u); + const startSearchIdx = fcssIdx !== -1 ? fcssIdx + 3 : 0; + const startPathIdx = findFirstSlash(u.substring(startSearchIdx)); + if (startPathIdx === -1) + return '/'; + const pathIdx = startPathIdx + startSearchIdx; + const path = u.substring(pathIdx); + // ensure a trailing slash is always present + return path[path.length - 1] === '/' ? path : path + '/'; + } +} +exports.BasePath = BasePath; +function cartesian(...arg) { + const r = [], max = arg.length - 1; + function helper(obj, i) { + const values = arg[i]; + for (var j = 0, l = values.length; j < l; j++) { + const a = Object.assign({}, obj); + const key = Object.keys(values[j])[0]; + a[key] = values[j][key]; + if (i == max) + r.push(a); + else + helper(a, i + 1); + } + } + helper({}, 0); + return r; +} +//# sourceMappingURL=base.path.js.map \ No newline at end of file diff --git a/packages/framework/dist/base.path.js.map b/packages/framework/dist/base.path.js.map new file mode 100644 index 00000000..72d3196b --- /dev/null +++ b/packages/framework/dist/base.path.js.map @@ -0,0 +1 @@ +{"version":3,"file":"base.path.js","sourceRoot":"","sources":["../src/framework/base.path.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/framework.d.ts b/packages/framework/dist/framework.d.ts new file mode 100644 index 00000000..ef4532dd --- /dev/null +++ b/packages/framework/dist/framework.d.ts @@ -0,0 +1,10 @@ +import { OpenAPIFrameworkArgs, OpenAPIFrameworkInit, OpenAPIFrameworkVisitor } from '.'; +export declare class OpenAPIFramework { + private readonly args; + private readonly loggingPrefix; + constructor(args: OpenAPIFrameworkArgs); + initialize(visitor: OpenAPIFrameworkVisitor): Promise; + private loadSpec; + private sortApiDocTags; + private getBasePathsFromServers; +} diff --git a/packages/framework/dist/framework.js b/packages/framework/dist/framework.js new file mode 100644 index 00000000..06c00234 --- /dev/null +++ b/packages/framework/dist/framework.js @@ -0,0 +1,99 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OpenAPIFramework = void 0; +const fs = require("fs"); +const path = require("path"); +const $RefParser = require("json-schema-ref-parser"); +const openapi_schema_validator_1 = require("./openapi.schema.validator"); +const base_path_1 = require("./base.path"); +class OpenAPIFramework { + constructor(args) { + this.loggingPrefix = 'openapi.validator: '; + this.args = args; + } + // TODO the visitor should be implemented in the corresponding framework specific package + // e.g. express-openapi-validator + async initialize(visitor) { + const args = this.args; + const apiDoc = await this.loadSpec(args.apiDoc, args.$refParser); + const basePathObs = this.getBasePathsFromServers(apiDoc.servers); + const basePaths = Array.from(basePathObs.reduce((acc, bp) => { + bp.all().forEach((path) => acc.add(path)); + return acc; + }, new Set())); + const validateApiDoc = 'validateApiDoc' in args ? !!args.validateApiDoc : true; + const validator = new openapi_schema_validator_1.OpenAPISchemaValidator({ + version: apiDoc.openapi, + }); + if (validateApiDoc) { + const apiDocValidation = validator.validate(apiDoc); + if (apiDocValidation.errors.length) { + console.error(`${this.loggingPrefix}Validating schema`); + console.error(`${this.loggingPrefix}validation errors`, JSON.stringify(apiDocValidation.errors, null, ' ')); + throw new Error(`${this.loggingPrefix}args.apiDoc was invalid. See the output.`); + } + } + const getApiDoc = () => { + return apiDoc; + }; + this.sortApiDocTags(apiDoc); + if (visitor.visitApi) { + // const basePaths = basePathObs; + visitor.visitApi({ + basePaths, + getApiDoc, + }); + } + return { + apiDoc, + basePaths, + }; + } + loadSpec(filePath, $refParser = { mode: 'bundle' }) { + // Because of this issue ( https://github.com/APIDevTools/json-schema-ref-parser/issues/101#issuecomment-421755168 ) + // We need this workaround ( use '$RefParser.dereference' instead of '$RefParser.bundle' ) if asked by user + if (typeof filePath === 'string') { + const origCwd = process.cwd(); + const specDir = path.resolve(origCwd, path.dirname(filePath)); + const absolutePath = path.resolve(origCwd, filePath); + if (fs.existsSync(absolutePath)) { + // Get document, or throw exception on error + try { + process.chdir(specDir); + return $refParser.mode === 'dereference' + ? $RefParser.dereference(absolutePath) + : $RefParser.bundle(absolutePath); + } + finally { + process.chdir(origCwd); + } + } + else { + throw new Error(`${this.loggingPrefix}spec could not be read at ${filePath}`); + } + } + return $refParser.mode === 'dereference' + ? $RefParser.dereference(filePath) + : $RefParser.bundle(filePath); + } + sortApiDocTags(apiDoc) { + if (apiDoc && Array.isArray(apiDoc.tags)) { + apiDoc.tags.sort((a, b) => { + return a.name < b.name ? -1 : 1; + }); + } + } + getBasePathsFromServers(servers) { + if (!servers || servers.length === 0) { + return [new base_path_1.BasePath({ url: '' })]; + } + const basePathsMap = {}; + for (const server of servers) { + const basePath = new base_path_1.BasePath(server); + basePathsMap[basePath.expressPath] = basePath; + } + return Object.keys(basePathsMap).map((key) => basePathsMap[key]); + } +} +exports.OpenAPIFramework = OpenAPIFramework; +//# sourceMappingURL=framework.js.map \ No newline at end of file diff --git a/packages/framework/dist/framework.js.map b/packages/framework/dist/framework.js.map new file mode 100644 index 00000000..ddc11501 --- /dev/null +++ b/packages/framework/dist/framework.js.map @@ -0,0 +1 @@ +{"version":3,"file":"framework.js","sourceRoot":"","sources":["../src/framework/framework.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/index.d.ts b/packages/framework/dist/index.d.ts new file mode 100644 index 00000000..d3eaa991 --- /dev/null +++ b/packages/framework/dist/index.d.ts @@ -0,0 +1,549 @@ +import * as ajv from 'ajv'; +import * as multer from 'multer'; +import { createRequestAjv, createResponseAjv } from './ajv'; +export { OpenAPIFramework } from './framework'; +export { OpenApiSpecLoader, Spec, RouteMetadata } from './openapi.spec.loader'; +export { OpenApiContext } from './openapi.context'; +export declare const Ajv: { + createRequestAjv: typeof createRequestAjv; + createResponseAjv: typeof createResponseAjv; +}; +export declare type BodySchema = OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject | {}; +export interface ParametersSchema { + query: object; + headers: object; + params: object; + cookies: object; +} +export interface ValidationSchema extends ParametersSchema { + body: BodySchema; +} +export interface OpenAPIFrameworkInit { + apiDoc: OpenAPIV3.Document; + basePaths: string[]; +} +export declare type SecurityHandlers = { + [key: string]: (req: Request, scopes: string[], schema: OpenAPIV3.SecuritySchemeObject) => boolean | Promise; +}; +export interface MultipartOpts { + multerOpts: boolean | multer.Options; + ajvOpts: Options; +} +export interface Options extends ajv.Options { + schemaObjectMapper?: object; +} +export interface RequestValidatorOptions extends Options, ValidateRequestOpts { +} +export declare type ValidateRequestOpts = { + allowUnknownQueryParameters?: boolean; + coerceTypes?: boolean | 'array'; +}; +export declare type ValidateResponseOpts = { + removeAdditional?: 'failing' | boolean; + coerceTypes?: boolean | 'array'; + onError?: (err: InternalServerError, json: any) => void; +}; +export declare type ValidateSecurityOpts = { + handlers?: SecurityHandlers; +}; +export declare type OperationHandlerOptions = { + basePath: string; + resolver: Function; +}; +export declare type Format = { + name: string; + type?: 'number' | 'string'; + validate: (v: any) => boolean; +}; +export declare type Serializer = { + format: string; + serialize: (o: unknown) => string; +}; +export interface OpenApiValidatorOpts { + apiSpec: OpenAPIV3.Document | string; + validateResponses?: boolean | ValidateResponseOpts; + validateRequests?: boolean | ValidateRequestOpts; + validateSecurity?: boolean | ValidateSecurityOpts; + ignorePaths?: RegExp | Function; + securityHandlers?: SecurityHandlers; + coerceTypes?: boolean | 'array'; + unknownFormats?: true | string[] | 'ignore'; + formats?: Format[]; + fileUploader?: boolean | multer.Options; + multerOpts?: multer.Options; + $refParser?: { + mode: 'bundle' | 'dereference'; + }; + operationHandlers?: false | string | OperationHandlerOptions; + validateFormats?: false | 'fast' | 'full'; +} +export declare namespace OpenAPIV3 { + export interface Document { + openapi: string; + info: InfoObject; + servers?: ServerObject[]; + paths: PathsObject; + components?: ComponentsObject; + security?: SecurityRequirementObject[]; + tags?: TagObject[]; + externalDocs?: ExternalDocumentationObject; + } + export interface InfoObject { + title: string; + description?: string; + termsOfService?: string; + contact?: ContactObject; + license?: LicenseObject; + version: string; + } + export interface ContactObject { + name?: string; + url?: string; + email?: string; + } + export interface LicenseObject { + name: string; + url?: string; + } + export interface ServerObject { + url: string; + description?: string; + variables?: { + [variable: string]: ServerVariableObject; + }; + } + export interface ServerVariableObject { + enum?: string[]; + default: string; + description?: string; + } + export interface PathsObject { + [pattern: string]: PathItemObject; + } + export interface PathItemObject { + $ref?: string; + summary?: string; + description?: string; + get?: OperationObject; + put?: OperationObject; + post?: OperationObject; + delete?: OperationObject; + options?: OperationObject; + head?: OperationObject; + patch?: OperationObject; + trace?: OperationObject; + servers?: ServerObject[]; + parameters?: Array; + } + export interface OperationObject { + tags?: string[]; + summary?: string; + description?: string; + externalDocs?: ExternalDocumentationObject; + operationId?: string; + parameters?: Array; + requestBody?: ReferenceObject | RequestBodyObject; + responses?: ResponsesObject; + callbacks?: { + [callback: string]: ReferenceObject | CallbackObject; + }; + deprecated?: boolean; + security?: SecurityRequirementObject[]; + servers?: ServerObject[]; + } + export interface ExternalDocumentationObject { + description?: string; + url: string; + } + export interface ParameterObject extends ParameterBaseObject { + name: string; + in: string; + } + export interface HeaderObject extends ParameterBaseObject { + } + interface ParameterBaseObject { + description?: string; + required?: boolean; + deprecated?: boolean; + allowEmptyValue?: boolean; + style?: string; + explode?: boolean; + allowReserved?: boolean; + schema?: ReferenceObject | SchemaObject; + example?: any; + examples?: { + [media: string]: ReferenceObject | ExampleObject; + }; + content?: { + [media: string]: MediaTypeObject; + }; + } + export type NonArraySchemaObjectType = 'null' | 'boolean' | 'object' | 'number' | 'string' | 'integer'; + export type ArraySchemaObjectType = 'array'; + export type SchemaObject = ArraySchemaObject | NonArraySchemaObject; + export interface ArraySchemaObject extends BaseSchemaObject { + type: ArraySchemaObjectType; + items: ReferenceObject | SchemaObject; + } + export interface NonArraySchemaObject extends BaseSchemaObject { + type: NonArraySchemaObjectType; + } + interface BaseSchemaObject { + title?: string; + description?: string; + format?: string; + default?: any; + multipleOf?: number; + maximum?: number; + exclusiveMaximum?: boolean; + minimum?: number; + exclusiveMinimum?: boolean; + maxLength?: number; + minLength?: number; + pattern?: string; + additionalProperties?: boolean | ReferenceObject | SchemaObject; + maxItems?: number; + minItems?: number; + uniqueItems?: boolean; + maxProperties?: number; + minProperties?: number; + required?: string[]; + enum?: any[]; + properties?: { + [name: string]: ReferenceObject | SchemaObject; + }; + allOf?: Array; + oneOf?: Array; + anyOf?: Array; + not?: ReferenceObject | SchemaObject; + nullable?: boolean; + discriminator?: DiscriminatorObject; + readOnly?: boolean; + writeOnly?: boolean; + xml?: XMLObject; + externalDocs?: ExternalDocumentationObject; + example?: any; + deprecated?: boolean; + componentId?: string; + } + export interface DiscriminatorObject { + propertyName: string; + mapping?: { + [value: string]: string; + }; + } + export interface XMLObject { + name?: string; + namespace?: string; + prefix?: string; + attribute?: boolean; + wrapped?: boolean; + } + export interface ReferenceObject { + $ref: string; + } + export interface ExampleObject { + summary?: string; + description?: string; + value?: any; + externalValue?: string; + } + export interface MediaTypeObject { + schema?: ReferenceObject | SchemaObject; + example?: any; + examples?: { + [media: string]: ReferenceObject | ExampleObject; + }; + encoding?: { + [media: string]: EncodingObject; + }; + } + export interface EncodingObject { + contentType?: string; + headers?: { + [header: string]: ReferenceObject | HeaderObject; + }; + style?: string; + explode?: boolean; + allowReserved?: boolean; + } + export interface RequestBodyObject { + description?: string; + content: { + [media: string]: MediaTypeObject; + }; + required?: boolean; + } + export interface ResponsesObject { + [code: string]: ReferenceObject | ResponseObject; + } + export interface ResponseObject { + description: string; + headers?: { + [header: string]: ReferenceObject | HeaderObject; + }; + content?: { + [media: string]: MediaTypeObject; + }; + links?: { + [link: string]: ReferenceObject | LinkObject; + }; + } + export interface LinkObject { + operationRef?: string; + operationId?: string; + parameters?: { + [parameter: string]: any; + }; + requestBody?: any; + description?: string; + server?: ServerObject; + } + export interface CallbackObject { + [url: string]: PathItemObject; + } + export interface SecurityRequirementObject { + [name: string]: string[]; + } + export interface ComponentsObject { + schemas?: { + [key: string]: ReferenceObject | SchemaObject; + }; + responses?: { + [key: string]: ReferenceObject | ResponseObject; + }; + parameters?: { + [key: string]: ReferenceObject | ParameterObject; + }; + examples?: { + [key: string]: ReferenceObject | ExampleObject; + }; + requestBodies?: { + [key: string]: ReferenceObject | RequestBodyObject; + }; + headers?: { + [key: string]: ReferenceObject | HeaderObject; + }; + securitySchemes?: { + [key: string]: ReferenceObject | SecuritySchemeObject; + }; + links?: { + [key: string]: ReferenceObject | LinkObject; + }; + callbacks?: { + [key: string]: ReferenceObject | CallbackObject; + }; + } + export type SecuritySchemeObject = HttpSecurityScheme | ApiKeySecurityScheme | OAuth2SecurityScheme | OpenIdSecurityScheme; + export interface HttpSecurityScheme { + type: 'http'; + description?: string; + scheme: string; + bearerFormat?: string; + } + export interface ApiKeySecurityScheme { + type: 'apiKey'; + description?: string; + name: string; + in: string; + } + export interface OAuth2SecurityScheme { + type: 'oauth2'; + flows: { + implicit?: { + authorizationUrl: string; + refreshUrl?: string; + scopes: { + [scope: string]: string; + }; + }; + password?: { + tokenUrl: string; + refreshUrl?: string; + scopes: { + [scope: string]: string; + }; + }; + clientCredentials?: { + tokenUrl: string; + refreshUrl?: string; + scopes: { + [scope: string]: string; + }; + }; + authorizationCode?: { + authorizationUrl: string; + tokenUrl: string; + refreshUrl?: string; + scopes: { + [scope: string]: string; + }; + }; + }; + } + export interface OpenIdSecurityScheme { + type: 'openIdConnect'; + description?: string; + openIdConnectUrl: string; + } + export interface TagObject { + name: string; + description?: string; + externalDocs?: ExternalDocumentationObject; + } + export {}; +} +export interface OpenAPIFrameworkPathObject { + path?: string; + module?: any; +} +export interface OpenAPIFrameworkArgs { + apiDoc: OpenAPIV3.Document | string; + validateApiDoc?: boolean; + $refParser?: { + mode: 'bundle' | 'dereference'; + }; +} +export interface OpenAPIFrameworkAPIContext { + basePaths: string[]; + getApiDoc(): OpenAPIV3.Document; +} +export interface OpenAPIFrameworkVisitor { + visitApi?(context: OpenAPIFrameworkAPIContext): void; +} +export interface IJsonSchema { + id?: string; + $schema?: string; + title?: string; + description?: string; + multipleOf?: number; + maximum?: number; + exclusiveMaximum?: boolean; + minimum?: number; + exclusiveMinimum?: boolean; + maxLength?: number; + minLength?: number; + pattern?: string; + additionalItems?: boolean | IJsonSchema; + items?: IJsonSchema | IJsonSchema[]; + maxItems?: number; + minItems?: number; + uniqueItems?: boolean; + maxProperties?: number; + minProperties?: number; + required?: string[]; + additionalProperties?: boolean | IJsonSchema; + definitions?: { + [name: string]: IJsonSchema; + }; + properties?: { + [name: string]: IJsonSchema; + }; + patternProperties?: { + [name: string]: IJsonSchema; + }; + dependencies?: { + [name: string]: IJsonSchema | string[]; + }; + enum?: any[]; + type?: string | string[]; + allOf?: IJsonSchema[]; + anyOf?: IJsonSchema[]; + oneOf?: IJsonSchema[]; + not?: IJsonSchema; +} +export interface ValidationError { + message?: string; + status: number; + errors: ValidationErrorItem[]; +} +export interface ValidationErrorItem { + path: string; + message: string; + error_code?: string; +} +export declare class HttpError extends Error implements ValidationError { + status: number; + message: string; + errors: ValidationErrorItem[]; + path?: string; + name: string; + constructor(err: { + status: number; + path: string; + name: string; + message?: string; + errors?: ValidationErrorItem[]; + }); + static create(err: { + status: number; + path: string; + message?: string; + errors?: ValidationErrorItem[]; + }): InternalServerError | UnsupportedMediaType | RequestEntityTooLarge | BadRequest | MethodNotAllowed | NotAcceptable | NotFound | Unauthorized | Forbidden; +} +export declare class NotFound extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class NotAcceptable extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class MethodNotAllowed extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class BadRequest extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + errors?: ValidationErrorItem[]; + }); +} +export declare class RequestEntityTooLarge extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class InternalServerError extends HttpError { + constructor(err: { + path?: string; + message?: string; + overrideStatus?: number; + errors?: ValidationErrorItem[]; + }); +} +export declare class UnsupportedMediaType extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class Unauthorized extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} +export declare class Forbidden extends HttpError { + constructor(err: { + path: string; + message?: string; + overrideStatus?: number; + }); +} diff --git a/packages/framework/dist/index.js b/packages/framework/dist/index.js new file mode 100644 index 00000000..843fe325 --- /dev/null +++ b/packages/framework/dist/index.js @@ -0,0 +1,157 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Forbidden = exports.Unauthorized = exports.UnsupportedMediaType = exports.InternalServerError = exports.RequestEntityTooLarge = exports.BadRequest = exports.MethodNotAllowed = exports.NotAcceptable = exports.NotFound = exports.HttpError = exports.Ajv = exports.OpenApiContext = exports.OpenApiSpecLoader = exports.OpenAPIFramework = void 0; +const ajv_1 = require("./ajv"); +var framework_1 = require("./framework"); +Object.defineProperty(exports, "OpenAPIFramework", { enumerable: true, get: function () { return framework_1.OpenAPIFramework; } }); +var openapi_spec_loader_1 = require("./openapi.spec.loader"); +Object.defineProperty(exports, "OpenApiSpecLoader", { enumerable: true, get: function () { return openapi_spec_loader_1.OpenApiSpecLoader; } }); +var openapi_context_1 = require("./openapi.context"); +Object.defineProperty(exports, "OpenApiContext", { enumerable: true, get: function () { return openapi_context_1.OpenApiContext; } }); +exports.Ajv = { + createRequestAjv: ajv_1.createRequestAjv, + createResponseAjv: ajv_1.createResponseAjv, +}; +class HttpError extends Error { + constructor(err) { + super(err.name); + this.name = err.name; + this.status = err.status; + this.path = err.path; + this.message = err.message; + this.errors = + err.errors == undefined + ? [ + { + path: err.path, + message: err.message, + }, + ] + : err.errors; + } + static create(err) { + switch (err.status) { + case 400: + return new BadRequest(err); + case 401: + return new Unauthorized(err); + case 403: + return new Forbidden(err); + case 404: + return new NotFound(err); + case 405: + return new MethodNotAllowed(err); + case 406: + return new NotAcceptable(err); + case 413: + return new RequestEntityTooLarge(err); + case 415: + return new UnsupportedMediaType(err); + default: + return new InternalServerError(err); + } + } +} +exports.HttpError = HttpError; +class NotFound extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 404, + path: err.path, + message: err.message, + name: 'Not Found', + }); + } +} +exports.NotFound = NotFound; +class NotAcceptable extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 406, + path: err.path, + name: 'Not Acceptable', + message: err.message, + }); + } +} +exports.NotAcceptable = NotAcceptable; +class MethodNotAllowed extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 405, + path: err.path, + name: 'Method Not Allowed', + message: err.message, + }); + } +} +exports.MethodNotAllowed = MethodNotAllowed; +class BadRequest extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 400, + path: err.path, + name: 'Bad Request', + message: err.message, + errors: err.errors, + }); + } +} +exports.BadRequest = BadRequest; +class RequestEntityTooLarge extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 413, + path: err.path, + name: 'Request Entity Too Large', + message: err.message, + }); + } +} +exports.RequestEntityTooLarge = RequestEntityTooLarge; +class InternalServerError extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 500, + path: err.path, + name: 'Internal Server Error', + message: err.message, + errors: err.errors, + }); + } +} +exports.InternalServerError = InternalServerError; +class UnsupportedMediaType extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 415, + path: err.path, + name: 'Unsupported Media Type', + message: err.message, + }); + } +} +exports.UnsupportedMediaType = UnsupportedMediaType; +class Unauthorized extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 401, + path: err.path, + name: 'Unauthorized', + message: err.message, + }); + } +} +exports.Unauthorized = Unauthorized; +class Forbidden extends HttpError { + constructor(err) { + super({ + status: err.overrideStatus || 403, + path: err.path, + name: 'Forbidden', + message: err.message, + }); + } +} +exports.Forbidden = Forbidden; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/packages/framework/dist/index.js.map b/packages/framework/dist/index.js.map new file mode 100644 index 00000000..914cad3c --- /dev/null +++ b/packages/framework/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/framework/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.context.d.ts b/packages/framework/dist/openapi.context.d.ts new file mode 100644 index 00000000..5fc632c6 --- /dev/null +++ b/packages/framework/dist/openapi.context.d.ts @@ -0,0 +1,20 @@ +import { OpenAPIV3 } from '.'; +import { Spec, RouteMetadata } from './openapi.spec.loader'; +export interface RoutePair { + expressRoute: string; + openApiRoute: string; +} +export declare class OpenApiContext { + readonly apiDoc: OpenAPIV3.Document; + readonly expressRouteMap: {}; + readonly openApiRouteMap: {}; + readonly routes: RouteMetadata[]; + private readonly basePaths; + private readonly ignorePaths; + constructor(spec: Spec, ignorePaths: RegExp | Function); + isManagedRoute(path: string): boolean; + shouldIgnoreRoute(path: string): any; + routePair(route: string): RoutePair; + private methods; + private buildRouteMaps; +} diff --git a/packages/framework/dist/openapi.context.js b/packages/framework/dist/openapi.context.js new file mode 100644 index 00000000..4fba9cdf --- /dev/null +++ b/packages/framework/dist/openapi.context.js @@ -0,0 +1,65 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OpenApiContext = void 0; +class OpenApiContext { + constructor(spec, ignorePaths) { + this.expressRouteMap = {}; + this.openApiRouteMap = {}; + this.routes = []; + this.apiDoc = spec.apiDoc; + this.basePaths = spec.basePaths; + this.routes = spec.routes; + this.ignorePaths = ignorePaths; + this.buildRouteMaps(spec.routes); + } + isManagedRoute(path) { + for (const bp of this.basePaths) { + if (path.startsWith(bp) && !this.shouldIgnoreRoute(path)) { + return true; + } + } + return false; + } + shouldIgnoreRoute(path) { + var _a; + return typeof this.ignorePaths === 'function' ? this.ignorePaths(path) : (_a = this.ignorePaths) === null || _a === void 0 ? void 0 : _a.test(path); + } + routePair(route) { + const methods = this.methods(route); + if (methods) { + return { + expressRoute: methods._expressRoute, + openApiRoute: methods._openApiRoute, + }; + } + return null; + } + methods(route) { + const expressRouteMethods = this.expressRouteMap[route]; + if (expressRouteMethods) + return expressRouteMethods; + const openApiRouteMethods = this.openApiRouteMap[route]; + return openApiRouteMethods; + } + // side-effecting builds express/openapi route maps + buildRouteMaps(routes) { + for (const route of routes) { + const { basePath, expressRoute, openApiRoute, method } = route; + const routeMethods = this.expressRouteMap[expressRoute]; + const pathKey = openApiRoute.substring(basePath.length); + const schema = this.apiDoc.paths[pathKey][method.toLowerCase()]; + if (routeMethods) { + routeMethods[route.method] = schema; + } + else { + const { basePath, openApiRoute, expressRoute } = route; + const routeMethod = { [route.method]: schema }; + const routeDetails = Object.assign({ basePath, _openApiRoute: openApiRoute, _expressRoute: expressRoute }, routeMethod); + this.expressRouteMap[route.expressRoute] = routeDetails; + this.openApiRouteMap[route.openApiRoute] = routeDetails; + } + } + } +} +exports.OpenApiContext = OpenApiContext; +//# sourceMappingURL=openapi.context.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.context.js.map b/packages/framework/dist/openapi.context.js.map new file mode 100644 index 00000000..d70bf7dc --- /dev/null +++ b/packages/framework/dist/openapi.context.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openapi.context.js","sourceRoot":"","sources":["../src/framework/openapi.context.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.schema.validator.d.ts b/packages/framework/dist/openapi.schema.validator.d.ts new file mode 100644 index 00000000..951f0900 --- /dev/null +++ b/packages/framework/dist/openapi.schema.validator.d.ts @@ -0,0 +1,12 @@ +import * as Ajv from 'ajv'; +import { OpenAPIV3 } from './index.js'; +export declare class OpenAPISchemaValidator { + private validator; + constructor({ version }: { + version: string; + extensions?: object; + }); + validate(openapiDoc: OpenAPIV3.Document): { + errors: Array | null; + }; +} diff --git a/packages/framework/dist/openapi.schema.validator.js b/packages/framework/dist/openapi.schema.validator.js new file mode 100644 index 00000000..34760585 --- /dev/null +++ b/packages/framework/dist/openapi.schema.validator.js @@ -0,0 +1,31 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OpenAPISchemaValidator = void 0; +const Ajv = require("ajv"); +const draftSchema = require("ajv/lib/refs/json-schema-draft-04.json"); +// https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json +const openapi3Schema = require("./openapi.v3.schema.json"); +class OpenAPISchemaValidator { + constructor({ version }) { + const v = new Ajv({ schemaId: 'auto', allErrors: true }); + v.addMetaSchema(draftSchema); + const ver = version && parseInt(String(version), 10); + if (!ver) + throw Error('version missing from OpenAPI specification'); + if (ver != 3) + throw Error('OpenAPI v3 specification version is required'); + v.addSchema(openapi3Schema); + this.validator = v.compile(openapi3Schema); + } + validate(openapiDoc) { + const valid = this.validator(openapiDoc); + if (!valid) { + return { errors: this.validator.errors }; + } + else { + return { errors: [] }; + } + } +} +exports.OpenAPISchemaValidator = OpenAPISchemaValidator; +//# sourceMappingURL=openapi.schema.validator.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.schema.validator.js.map b/packages/framework/dist/openapi.schema.validator.js.map new file mode 100644 index 00000000..07082ffe --- /dev/null +++ b/packages/framework/dist/openapi.schema.validator.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openapi.schema.validator.js","sourceRoot":"","sources":["../src/framework/openapi.schema.validator.ts"],"names":[],"mappings":";;;AAAA,2BAA2B;AAC3B,sEAAsE;AACtE,oFAAoF;AACpF,2DAA2D;AAG3D,MAAa,sBAAsB;IAEjC,YAAY,EAAE,OAAO,EAA4C;QAC/D,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAE7B,MAAM,GAAG,GAAG,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG;YAAE,MAAM,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACpE,IAAI,GAAG,IAAI,CAAC;YAAE,MAAM,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAE1E,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;IAEM,QAAQ,CACb,UAA8B;QAE9B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,EAAE;YACV,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;SAC1C;aAAM;YACL,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;SACvB;IACH,CAAC;CACF;AAxBD,wDAwBC"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.spec.loader.d.ts b/packages/framework/dist/openapi.spec.loader.d.ts new file mode 100644 index 00000000..8ae671e9 --- /dev/null +++ b/packages/framework/dist/openapi.spec.loader.d.ts @@ -0,0 +1,21 @@ +import { OpenAPIV3, OpenAPIFrameworkArgs } from '.'; +export interface Spec { + apiDoc: OpenAPIV3.Document; + basePaths: string[]; + routes: RouteMetadata[]; +} +export interface RouteMetadata { + basePath: string; + expressRoute: string; + openApiRoute: string; + method: string; + pathParams: string[]; +} +export declare const sortRoutes: (r1: any, r2: any) => 1 | -1; +export declare class OpenApiSpecLoader { + private readonly framework; + constructor(opts: OpenAPIFrameworkArgs); + load(): Promise; + private discoverRoutes; + private toExpressParams; +} diff --git a/packages/framework/dist/openapi.spec.loader.js b/packages/framework/dist/openapi.spec.loader.js new file mode 100644 index 00000000..4338f24a --- /dev/null +++ b/packages/framework/dist/openapi.spec.loader.js @@ -0,0 +1,85 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.OpenApiSpecLoader = exports.sortRoutes = void 0; +const framework_1 = require("./framework"); +// Sort routes by most specific to least specific i.e. static routes before dynamic +// e.g. /users/my_route before /users/{id} +// Exported for tests +// TODO this should be part of the express package +const sortRoutes = (r1, r2) => { + const e1 = r1.expressRoute.replace(/\/:/g, '/~'); + const e2 = r2.expressRoute.replace(/\/:/g, '/~'); + return e1 > e2 ? 1 : -1; +}; +exports.sortRoutes = sortRoutes; +class OpenApiSpecLoader { + constructor(opts) { + this.framework = new framework_1.OpenAPIFramework(opts); + } + async load() { + return this.discoverRoutes(); + } + async discoverRoutes() { + const routes = []; + const toExpressParams = this.toExpressParams; + // const basePaths = this.framework.basePaths; + // let apiDoc: OpenAPIV3.Document = null; + // let basePaths: string[] = null; + const { apiDoc, basePaths } = await this.framework.initialize({ + visitApi(ctx) { + var _a; + const apiDoc = ctx.getApiDoc(); + const basePaths = ctx.basePaths; + for (const bpa of basePaths) { + const bp = bpa.replace(/\/$/, ''); + for (const [path, methods] of Object.entries(apiDoc.paths)) { + for (const [method, schema] of Object.entries(methods)) { + if (method.startsWith('x-') || + ['parameters', 'summary', 'description'].includes(method)) { + continue; + } + const pathParams = new Set(); + for (const param of (_a = schema.parameters) !== null && _a !== void 0 ? _a : []) { + if (param.in === 'path') { + pathParams.add(param.name); + } + } + const openApiRoute = `${bp}${path}`; + const expressRoute = `${openApiRoute}` + .split(':') + .map(toExpressParams) + .join('\\:'); + routes.push({ + basePath: bp, + expressRoute, + openApiRoute, + method: method.toUpperCase(), + pathParams: Array.from(pathParams), + }); + } + } + } + }, + }); + routes.sort(exports.sortRoutes); + return { + apiDoc, + basePaths, + routes, + }; + } + toExpressParams(part) { + // substitute wildcard path with express equivalent + // {/path} => /path(*) <--- RFC 6570 format (not supported by openapi) + // const pass1 = part.replace(/\{(\/)([^\*]+)(\*)}/g, '$1:$2$3'); + // instead create our own syntax that is compatible with express' pathToRegex + // /{path}* => /:path*) + // /{path}(*) => /:path*) + const pass1 = part.replace(/\/{([^\*]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2'); + // substitute params with express equivalent + // /path/{id} => /path/:id + return pass1.replace(/\{([^}]+)}/g, ':$1'); + } +} +exports.OpenApiSpecLoader = OpenApiSpecLoader; +//# sourceMappingURL=openapi.spec.loader.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.spec.loader.js.map b/packages/framework/dist/openapi.spec.loader.js.map new file mode 100644 index 00000000..e7abbbac --- /dev/null +++ b/packages/framework/dist/openapi.spec.loader.js.map @@ -0,0 +1 @@ +{"version":3,"file":"openapi.spec.loader.js","sourceRoot":"","sources":["../src/framework/openapi.spec.loader.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.v3.schema.json b/packages/framework/dist/openapi.v3.schema.json new file mode 100644 index 00000000..9bcb3bf7 --- /dev/null +++ b/packages/framework/dist/openapi.v3.schema.json @@ -0,0 +1,1480 @@ +{ + "id": "https://spec.openapis.org/oas/3.0/schema/2019-04-02", + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "Validation schema for OpenAPI Specification 3.0.X.", + "type": "object", + "required": ["openapi", "info", "paths"], + "properties": { + "openapi": { + "type": "string", + "pattern": "^3\\.0\\.\\d(-.+)?$" + }, + "info": { + "$ref": "#/definitions/Info" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/Tag" + }, + "uniqueItems": true + }, + "paths": { + "$ref": "#/definitions/Paths" + }, + "components": { + "$ref": "#/definitions/Components" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "definitions": { + "Reference": { + "type": "object", + "required": ["$ref"], + "patternProperties": { + "^\\$ref$": { + "type": "string", + "format": "uri-reference" + } + } + }, + "Info": { + "type": "object", + "required": ["title", "version"], + "properties": { + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "termsOfService": { + "type": "string", + "format": "uri-reference" + }, + "contact": { + "$ref": "#/definitions/Contact" + }, + "license": { + "$ref": "#/definitions/License" + }, + "version": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Contact": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + }, + "email": { + "type": "string", + "format": "email" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "License": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Server": { + "type": "object", + "required": ["url"], + "properties": { + "url": { + "type": "string" + }, + "description": { + "type": "string" + }, + "variables": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/ServerVariable" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ServerVariable": { + "type": "object", + "required": ["default"], + "properties": { + "enum": { + "type": "array", + "items": { + "type": "string" + } + }, + "default": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Components": { + "type": "object", + "properties": { + "schemas": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "responses": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Response" + } + ] + } + } + }, + "parameters": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Parameter" + } + ] + } + } + }, + "examples": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Example" + } + ] + } + } + }, + "requestBodies": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/RequestBody" + } + ] + } + } + }, + "headers": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Header" + } + ] + } + } + }, + "securitySchemes": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/SecurityScheme" + } + ] + } + } + }, + "links": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Link" + } + ] + } + } + }, + "callbacks": { + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9\\.\\-_]+$": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/Callback" + } + ] + } + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Schema": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "multipleOf": { + "type": "number", + "minimum": 0, + "exclusiveMinimum": true + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "boolean", + "default": false + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "boolean", + "default": false + }, + "maxLength": { + "type": "integer", + "minimum": 0 + }, + "minLength": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "pattern": { + "type": "string", + "format": "regex" + }, + "maxItems": { + "type": "integer", + "minimum": 0 + }, + "minItems": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "maxProperties": { + "type": "integer", + "minimum": 0 + }, + "minProperties": { + "type": "integer", + "minimum": 0, + "default": 0 + }, + "required": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "enum": { + "type": "array", + "items": {}, + "minItems": 1, + "uniqueItems": false + }, + "type": { + "type": "string", + "enum": ["array", "boolean", "integer", "number", "object", "string"] + }, + "not": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "allOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "oneOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "anyOf": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "properties": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + }, + { + "type": "boolean" + } + ], + "default": true + }, + "description": { + "type": "string" + }, + "format": { + "type": "string" + }, + "default": {}, + "nullable": { + "type": "boolean", + "default": false + }, + "discriminator": { + "$ref": "#/definitions/Discriminator" + }, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "example": {}, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "xml": { + "$ref": "#/definitions/XML" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Discriminator": { + "type": "object", + "required": ["propertyName"], + "properties": { + "propertyName": { + "type": "string" + }, + "mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "XML": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string", + "format": "uri" + }, + "prefix": { + "type": "string" + }, + "attribute": { + "type": "boolean", + "default": false + }, + "wrapped": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Response": { + "type": "object", + "required": ["description"], + "properties": { + "description": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Header" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + } + }, + "links": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Link" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "MediaType": { + "type": "object", + "properties": { + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "example": {}, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "encoding": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Encoding" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + } + ] + }, + "Example": { + "type": "object", + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "value": {}, + "externalValue": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Header": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "allowEmptyValue": { + "type": "boolean", + "default": false + }, + "style": { + "type": "string", + "enum": ["simple"], + "default": "simple" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + }, + "minProperties": 1, + "maxProperties": 1 + }, + "example": {}, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + }, + { + "$ref": "#/definitions/SchemaXORContent" + } + ] + }, + "Paths": { + "type": "object", + "patternProperties": { + "^\\/": { + "$ref": "#/definitions/PathItem" + }, + "^x-": {} + }, + "additionalProperties": false + }, + "PathItem": { + "type": "object", + "properties": { + "$ref": { + "type": "string" + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + }, + "parameters": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Parameter" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "uniqueItems": true + } + }, + "patternProperties": { + "^(get|put|post|delete|options|head|patch|trace)$": { + "$ref": "#/definitions/Operation" + }, + "^x-": {} + }, + "additionalProperties": false + }, + "Operation": { + "type": "object", + "required": ["responses"], + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + }, + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + }, + "operationId": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Parameter" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "uniqueItems": true + }, + "requestBody": { + "oneOf": [ + { + "$ref": "#/definitions/RequestBody" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "responses": { + "$ref": "#/definitions/Responses" + }, + "callbacks": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Callback" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "security": { + "type": "array", + "items": { + "$ref": "#/definitions/SecurityRequirement" + } + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/Server" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Responses": { + "type": "object", + "properties": { + "default": { + "oneOf": [ + { + "$ref": "#/definitions/Response" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + }, + "patternProperties": { + "^[1-5](?:\\d{2}|XX)$": { + "oneOf": [ + { + "$ref": "#/definitions/Response" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "^x-": {} + }, + "minProperties": 1, + "additionalProperties": false + }, + "SecurityRequirement": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "Tag": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "externalDocs": { + "$ref": "#/definitions/ExternalDocumentation" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ExternalDocumentation": { + "type": "object", + "required": ["url"], + "properties": { + "description": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri-reference" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ExampleXORExamples": { + "description": "Example and examples are mutually exclusive", + "not": { + "required": ["example", "examples"] + } + }, + "SchemaXORContent": { + "description": "Schema and content are mutually exclusive, at least one is required", + "not": { + "required": ["schema", "content"] + }, + "oneOf": [ + { + "required": ["schema"] + }, + { + "required": ["content"], + "description": "Some properties are not allowed if content is present", + "allOf": [ + { + "not": { + "required": ["style"] + } + }, + { + "not": { + "required": ["explode"] + } + }, + { + "not": { + "required": ["allowReserved"] + } + }, + { + "not": { + "required": ["example"] + } + }, + { + "not": { + "required": ["examples"] + } + } + ] + } + ] + }, + "Parameter": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "in": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean", + "default": false + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "allowEmptyValue": { + "type": "boolean", + "default": false + }, + "style": { + "type": "string" + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + }, + "schema": { + "oneOf": [ + { + "$ref": "#/definitions/Schema" + }, + { + "$ref": "#/definitions/Reference" + } + ] + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + }, + "minProperties": 1, + "maxProperties": 1 + }, + "example": {}, + "examples": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Example" + }, + { + "$ref": "#/definitions/Reference" + } + ] + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "required": ["name", "in"], + "allOf": [ + { + "$ref": "#/definitions/ExampleXORExamples" + }, + { + "$ref": "#/definitions/SchemaXORContent" + }, + { + "$ref": "#/definitions/ParameterLocation" + } + ] + }, + "ParameterLocation": { + "description": "Parameter location", + "oneOf": [ + { + "description": "Parameter in path", + "required": ["required"], + "properties": { + "in": { + "enum": ["path"] + }, + "style": { + "enum": ["matrix", "label", "simple"], + "default": "simple" + }, + "required": { + "enum": [true] + } + } + }, + { + "description": "Parameter in query", + "properties": { + "in": { + "enum": ["query"] + }, + "style": { + "enum": ["form", "spaceDelimited", "pipeDelimited", "deepObject"], + "default": "form" + } + } + }, + { + "description": "Parameter in header", + "properties": { + "in": { + "enum": ["header"] + }, + "style": { + "enum": ["simple"], + "default": "simple" + } + } + }, + { + "description": "Parameter in cookie", + "properties": { + "in": { + "enum": ["cookie"] + }, + "style": { + "enum": ["form"], + "default": "form" + } + } + } + ] + }, + "RequestBody": { + "type": "object", + "required": ["content"], + "properties": { + "description": { + "type": "string" + }, + "content": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/MediaType" + } + }, + "required": { + "type": "boolean", + "default": false + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "SecurityScheme": { + "oneOf": [ + { + "$ref": "#/definitions/APIKeySecurityScheme" + }, + { + "$ref": "#/definitions/HTTPSecurityScheme" + }, + { + "$ref": "#/definitions/OAuth2SecurityScheme" + }, + { + "$ref": "#/definitions/OpenIdConnectSecurityScheme" + } + ] + }, + "APIKeySecurityScheme": { + "type": "object", + "required": ["type", "name", "in"], + "properties": { + "type": { + "type": "string", + "enum": ["apiKey"] + }, + "name": { + "type": "string" + }, + "in": { + "type": "string", + "enum": ["header", "query", "cookie"] + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "HTTPSecurityScheme": { + "type": "object", + "required": ["scheme", "type"], + "properties": { + "scheme": { + "type": "string" + }, + "bearerFormat": { + "type": "string" + }, + "description": { + "type": "string" + }, + "type": { + "type": "string", + "enum": ["http"] + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "oneOf": [ + { + "description": "Bearer", + "properties": { + "scheme": { + "enum": ["bearer"] + } + } + }, + { + "description": "Non Bearer", + "not": { + "required": ["bearerFormat"] + }, + "properties": { + "scheme": { + "not": { + "enum": ["bearer"] + } + } + } + } + ] + }, + "OAuth2SecurityScheme": { + "type": "object", + "required": ["type", "flows"], + "properties": { + "type": { + "type": "string", + "enum": ["oauth2"] + }, + "flows": { + "$ref": "#/definitions/OAuthFlows" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "OpenIdConnectSecurityScheme": { + "type": "object", + "required": ["type", "openIdConnectUrl"], + "properties": { + "type": { + "type": "string", + "enum": ["openIdConnect"] + }, + "openIdConnectUrl": { + "type": "string", + "format": "uri-reference" + }, + "description": { + "type": "string" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "OAuthFlows": { + "type": "object", + "properties": { + "implicit": { + "$ref": "#/definitions/ImplicitOAuthFlow" + }, + "password": { + "$ref": "#/definitions/PasswordOAuthFlow" + }, + "clientCredentials": { + "$ref": "#/definitions/ClientCredentialsFlow" + }, + "authorizationCode": { + "$ref": "#/definitions/AuthorizationCodeOAuthFlow" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ImplicitOAuthFlow": { + "type": "object", + "required": ["authorizationUrl", "scopes"], + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "PasswordOAuthFlow": { + "type": "object", + "required": ["tokenUrl"], + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "ClientCredentialsFlow": { + "type": "object", + "required": ["tokenUrl"], + "properties": { + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "AuthorizationCodeOAuthFlow": { + "type": "object", + "required": ["authorizationUrl", "tokenUrl"], + "properties": { + "authorizationUrl": { + "type": "string", + "format": "uri-reference" + }, + "tokenUrl": { + "type": "string", + "format": "uri-reference" + }, + "refreshUrl": { + "type": "string", + "format": "uri-reference" + }, + "scopes": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false + }, + "Link": { + "type": "object", + "properties": { + "operationId": { + "type": "string" + }, + "operationRef": { + "type": "string", + "format": "uri-reference" + }, + "parameters": { + "type": "object", + "additionalProperties": {} + }, + "requestBody": {}, + "description": { + "type": "string" + }, + "server": { + "$ref": "#/definitions/Server" + } + }, + "patternProperties": { + "^x-": {} + }, + "additionalProperties": false, + "not": { + "description": "Operation Id and Operation Ref are mutually exclusive", + "required": ["operationId", "operationRef"] + } + }, + "Callback": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/PathItem" + }, + "patternProperties": { + "^x-": {} + } + }, + "Encoding": { + "type": "object", + "properties": { + "contentType": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Header" + } + }, + "style": { + "type": "string", + "enum": ["form", "spaceDelimited", "pipeDelimited", "deepObject"] + }, + "explode": { + "type": "boolean" + }, + "allowReserved": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + } +} diff --git a/packages/framework/package-lock.json b/packages/framework/package-lock.json new file mode 100644 index 00000000..9fdc0522 --- /dev/null +++ b/packages/framework/package-lock.json @@ -0,0 +1,1193 @@ +{ + "name": "framework", + "version": "4.10.6", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz", + "integrity": "sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.13.1" + } + }, + "@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" + }, + "@types/ajv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/ajv/-/ajv-1.0.0.tgz", + "integrity": "sha1-T7JEB0Ly9sMOf7B5e4OfxvaWaCo=", + "dev": true, + "requires": { + "ajv": "*" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==", + "dev": true + }, + "@types/express": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", + "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.18", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.18.tgz", + "integrity": "sha512-m4JTwx5RUBNZvky/JJ8swEJPKFd8si08pPF2PfizYjGZOKr/svUWPcoUmLow6MmPzhasphB7gSTINY67xn3JNA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==", + "dev": true + }, + "@types/mocha": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.0.tgz", + "integrity": "sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ==", + "dev": true + }, + "@types/morgan": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.2.tgz", + "integrity": "sha512-edtGMEdit146JwwIeyQeHHg9yID4WSolQPxpEorHmN3KuytuCHyn2ELNr5Uxy8SerniFbbkmgKMrGM933am5BQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/multer": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.5.tgz", + "integrity": "sha512-9b/0a8JyrR0r2nQhL73JR86obWL7cogfX12augvlrvcpciCo/hkvEsgu80Z4S2g2DHGVXHr8pUIi1VhqFJ8Ufw==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/node": { + "version": "14.14.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz", + "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==", + "dev": true + }, + "@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.8.tgz", + "integrity": "sha512-MoJhSQreaVoL+/hurAZzIm8wafFR6ajiTM1m4A0kv6AGeVBl4r4pOV8bGFrjjq1sGxDTnCoF8i22o0/aE5XCyA==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/superagent": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.10.tgz", + "integrity": "sha512-xAgkb2CMWUMCyVc/3+7iQfOEBE75NvuZeezvmixbUw3nmENf2tCnQkW5yQLTYqvXUQ+R6EXxdqKKbal2zM5V/g==", + "dev": true, + "requires": { + "@types/cookiejar": "*", + "@types/node": "*" + } + }, + "@types/supertest": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.10.tgz", + "integrity": "sha512-Xt8TbEyZTnD5Xulw95GLMOkmjGICrOQyJ2jqgkSjAUR3mm7pAIzSR0NFBaMcwlzVvlpCjNwbATcWWwjNiZiFrQ==", + "dev": true, + "requires": { + "@types/superagent": "*" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "codacy-coverage": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/codacy-coverage/-/codacy-coverage-3.4.0.tgz", + "integrity": "sha512-A0ats3/gZtOw76muu++HZ6QrInztWjjLefkLJmmBpjPfyn6nNwNLoApmGmj3F3dfgl2+o6u5GwPnUBkKdfKXTQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.x", + "commander": "^2.x", + "jacoco-parse": "^2.x", + "joi": "^13.x", + "lcov-parse": "^1.x", + "lodash": "^4.17.4", + "log-driver": "^1.x", + "request": "^2.88.0", + "request-promise": "^4.x" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hoek": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", + "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isemail": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", + "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", + "dev": true, + "requires": { + "punycode": "2.x.x" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jacoco-parse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jacoco-parse/-/jacoco-parse-2.0.1.tgz", + "integrity": "sha512-YGhIb2iXuQ4/zNh2zgHd6Z6dqlYwLYH1wfsxtTNQ+jnHH9PhhuMwqOFihXymSI41trxok48LdKkSeDIWs28tYg==", + "dev": true, + "requires": { + "mocha": "^5.2.0", + "xml2js": "^0.4.9" + } + }, + "joi": { + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", + "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", + "dev": true, + "requires": { + "hoek": "5.x.x", + "isemail": "3.x.x", + "topo": "3.x.x" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-ref-parser": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz", + "integrity": "sha512-z0JGv7rRD3CnJbZY/qCpscyArdtLJhr/wRBmFUdoZ8xMjsFyNdILSprG2degqRLjBjyhZHAEBpGOxniO9rKTxA==", + "requires": { + "@apidevtools/json-schema-ref-parser": "9.0.6" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "lcov-parse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", + "dev": true + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" + }, + "lodash.zipobject": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz", + "integrity": "sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg=" + }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", + "dev": true + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mime-db": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==" + }, + "mime-types": { + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", + "requires": { + "mime-db": "1.45.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + }, + "dependencies": { + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multer": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-9jnfVriq7uJM4o5ganUY54ntUm+5EK21EGaQ5NWnkWg3zz5ywbbonlBguRcnmF1/HDiIe3zxNxXcO1YPBmPcQQ==", + "requires": { + "@jsdevtools/ono": "7.1.3" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-to-regexp": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz", + "integrity": "sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "request-promise": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.6.tgz", + "integrity": "sha512-HCHI3DJJUakkOr8fNoCc73E5nU5bqITjOYFMDrKHYOXWXrgD/SBaC7LjwuPymUprRyuF06UK7hd/lMHkmUXglQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "topo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", + "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", + "dev": true, + "requires": { + "hoek": "6.x.x" + }, + "dependencies": { + "hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "dev": true + } + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/packages/framework/package.json b/packages/framework/package.json new file mode 100644 index 00000000..c660941a --- /dev/null +++ b/packages/framework/package.json @@ -0,0 +1,51 @@ +{ + "name": "framework", + "private": true, + "version": "4.10.6", + "description": "Automatically validate API requests and responses with OpenAPI 3 and Express.", + "main": "dist/index.js", + "scripts": { + "compile": "rm -rf dist/ && tsc" + }, + "repository": { + "url": "https://github.com/cdimascio/express-openapi-validator" + }, + "keywords": [ + "openapi", + "openapi 3", + "expressjs", + "express", + "request validation", + "response validation", + "middleware", + "nodejs" + ], + "author": "Carmine DiMascio ", + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "json-schema-ref-parser": "^9.0.6", + "lodash.clonedeep": "^4.5.0", + "lodash.get": "^4.4.2", + "lodash.uniq": "^4.5.0", + "lodash.zipobject": "^4.1.3", + "multer": "^1.4.2", + "ono": "^7.1.3", + "path-to-regexp": "^6.2.0" + }, + "devDependencies": { + "@types/ajv": "^1.0.0", + "@types/cookie-parser": "^1.4.2", + "@types/express": "^4.17.8", + "@types/mocha": "^8.0.3", + "@types/morgan": "^1.9.1", + "@types/multer": "^1.4.4", + "@types/node": "^14.14.2", + "@types/supertest": "^2.0.10", + "codacy-coverage": "^3.4.0", + "prettier": "^2.1.2", + "source-map-support": "0.5.19", + "ts-node": "^9.0.0", + "typescript": "^4.0.3" + } +} diff --git a/src/framework/ajv/formats.ts b/packages/framework/src/framework/ajv/formats.ts similarity index 100% rename from src/framework/ajv/formats.ts rename to packages/framework/src/framework/ajv/formats.ts diff --git a/src/framework/ajv/index.ts b/packages/framework/src/framework/ajv/index.ts similarity index 98% rename from src/framework/ajv/index.ts rename to packages/framework/src/framework/ajv/index.ts index 9db8583b..ddd23618 100644 --- a/src/framework/ajv/index.ts +++ b/packages/framework/src/framework/ajv/index.ts @@ -1,7 +1,7 @@ import * as Ajv from 'ajv'; import * as draftSchema from 'ajv/lib/refs/json-schema-draft-04.json'; import { formats } from './formats'; -import { OpenAPIV3, Options } from '../types'; +import { OpenAPIV3, Options } from '..'; import ajv = require('ajv'); export function createRequestAjv( diff --git a/src/framework/base.path.ts b/packages/framework/src/framework/base.path.ts similarity index 98% rename from src/framework/base.path.ts rename to packages/framework/src/framework/base.path.ts index f67dbdd2..8f2cfbbc 100644 --- a/src/framework/base.path.ts +++ b/packages/framework/src/framework/base.path.ts @@ -1,5 +1,5 @@ import { compile } from 'path-to-regexp'; -import { OpenAPIV3 } from './types'; +import { OpenAPIV3 } from '.'; interface ServerUrlVariables { [key: string]: ServerUrlValues; diff --git a/src/framework/index.ts b/packages/framework/src/framework/framework.ts similarity index 96% rename from src/framework/index.ts rename to packages/framework/src/framework/framework.ts index 5c807201..e12dc7cb 100644 --- a/src/framework/index.ts +++ b/packages/framework/src/framework/framework.ts @@ -8,7 +8,7 @@ import { OpenAPIFrameworkInit, OpenAPIFrameworkVisitor, OpenAPIV3, -} from './types'; +} from '.'; export class OpenAPIFramework { private readonly args: OpenAPIFrameworkArgs; @@ -18,6 +18,8 @@ export class OpenAPIFramework { this.args = args; } + // TODO the visitor should be implemented in the corresponding framework specific package + // e.g. express-openapi-validator public async initialize( visitor: OpenAPIFrameworkVisitor, ): Promise { diff --git a/src/framework/types.ts b/packages/framework/src/framework/index.ts similarity index 96% rename from src/framework/types.ts rename to packages/framework/src/framework/index.ts index 994b70ca..846ab719 100644 --- a/src/framework/types.ts +++ b/packages/framework/src/framework/index.ts @@ -1,7 +1,14 @@ import * as ajv from 'ajv'; import * as multer from 'multer'; -import { Request, Response, NextFunction } from 'express'; -export { OpenAPIFrameworkArgs }; +import { createRequestAjv, createResponseAjv } from './ajv'; + +export { OpenAPIFramework } from './framework'; +export { OpenApiSpecLoader, Spec, RouteMetadata } from './openapi.spec.loader'; +export { OpenApiContext } from './openapi.context'; +export const Ajv = { + createRequestAjv, + createResponseAjv, +}; export type BodySchema = | OpenAPIV3.ReferenceObject @@ -70,7 +77,7 @@ export type Format = { }; export type Serializer = { - format: string, + format: string; serialize: (o: unknown) => string; }; @@ -410,7 +417,7 @@ export interface OpenAPIFrameworkPathObject { module?: any; } -interface OpenAPIFrameworkArgs { +export interface OpenAPIFrameworkArgs { apiDoc: OpenAPIV3.Document | string; validateApiDoc?: boolean; $refParser?: { @@ -428,23 +435,6 @@ export interface OpenAPIFrameworkVisitor { visitApi?(context: OpenAPIFrameworkAPIContext): void; } -export interface OpenApiRequestMetadata { - expressRoute: string; - openApiRoute: string; - pathParams: { [index: string]: string }; - schema: OpenAPIV3.OperationObject; -} - -export interface OpenApiRequest extends Request { - openapi?: OpenApiRequestMetadata | {}; -} - -export type OpenApiRequestHandler = ( - req: OpenApiRequest, - res: Response, - next: NextFunction, -) => any; - export interface IJsonSchema { id?: string; $schema?: string; diff --git a/src/framework/openapi.context.ts b/packages/framework/src/framework/openapi.context.ts similarity index 98% rename from src/framework/openapi.context.ts rename to packages/framework/src/framework/openapi.context.ts index 62106cce..1d79aded 100644 --- a/src/framework/openapi.context.ts +++ b/packages/framework/src/framework/openapi.context.ts @@ -1,4 +1,4 @@ -import { OpenAPIV3 } from './types'; +import { OpenAPIV3 } from '.'; import { Spec, RouteMetadata } from './openapi.spec.loader'; export interface RoutePair { diff --git a/src/framework/openapi.schema.validator.ts b/packages/framework/src/framework/openapi.schema.validator.ts similarity index 96% rename from src/framework/openapi.schema.validator.ts rename to packages/framework/src/framework/openapi.schema.validator.ts index c0f5351f..7ba442b6 100644 --- a/src/framework/openapi.schema.validator.ts +++ b/packages/framework/src/framework/openapi.schema.validator.ts @@ -2,7 +2,7 @@ import * as Ajv from 'ajv'; import * as draftSchema from 'ajv/lib/refs/json-schema-draft-04.json'; // https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json import * as openapi3Schema from './openapi.v3.schema.json'; -import { OpenAPIV3 } from './types.js'; +import { OpenAPIV3 } from './index.js'; export class OpenAPISchemaValidator { private validator: Ajv.ValidateFunction; diff --git a/src/framework/openapi.spec.loader.ts b/packages/framework/src/framework/openapi.spec.loader.ts similarity index 93% rename from src/framework/openapi.spec.loader.ts rename to packages/framework/src/framework/openapi.spec.loader.ts index 6460fe4c..dbe67ac1 100644 --- a/src/framework/openapi.spec.loader.ts +++ b/packages/framework/src/framework/openapi.spec.loader.ts @@ -1,9 +1,5 @@ -import { OpenAPIFramework } from './index'; -import { - OpenAPIFrameworkAPIContext, - OpenAPIV3, - OpenAPIFrameworkArgs, -} from './types'; +import { OpenAPIFramework } from './framework'; +import { OpenAPIFrameworkAPIContext, OpenAPIV3, OpenAPIFrameworkArgs } from '.'; export interface Spec { apiDoc: OpenAPIV3.Document; @@ -27,6 +23,7 @@ interface DiscoveredRoutes { // Sort routes by most specific to least specific i.e. static routes before dynamic // e.g. /users/my_route before /users/{id} // Exported for tests +// TODO this should be part of the express package export const sortRoutes = (r1, r2) => { const e1 = r1.expressRoute.replace(/\/:/g, '/~'); const e2 = r2.expressRoute.replace(/\/:/g, '/~'); @@ -104,7 +101,7 @@ export class OpenApiSpecLoader { // instead create our own syntax that is compatible with express' pathToRegex // /{path}* => /:path*) - // /{path}(*) => /:path*) + // /{path}(*) => /:path*) const pass1 = part.replace(/\/{([^\*]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2'); // substitute params with express equivalent // /path/{id} => /path/:id diff --git a/src/framework/openapi.v3.schema.json b/packages/framework/src/framework/openapi.v3.schema.json similarity index 100% rename from src/framework/openapi.v3.schema.json rename to packages/framework/src/framework/openapi.v3.schema.json diff --git a/packages/framework/tsconfig.json b/packages/framework/tsconfig.json new file mode 100644 index 00000000..135ce33e --- /dev/null +++ b/packages/framework/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "es2017", + "lib": ["es2019", "es2019.array"], + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist", + "sourceMap": true, + "resolveJsonModule": true, + "typeRoots": ["./node_modules/@types", "./typings"] + }, + "exclude": ["node_modules"], + "include": [ + "src/**/*.ts", + ] +} diff --git a/src/framework/json.ref.schema.ts b/src/framework/json.ref.schema.ts deleted file mode 100644 index 8b137891..00000000 --- a/src/framework/json.ref.schema.ts +++ /dev/null @@ -1 +0,0 @@ - From c65c89e8ad89ffc7b22eee770a7fcb922ffcbaa9 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sat, 16 Jan 2021 15:29:01 -0500 Subject: [PATCH 02/11] fix: formatting --- .../.prettierrc.json => .prettierrc.json | 0 README.md | 116 +++++++++--------- package-lock.json | 20 +++ package.json | 15 +-- packages/framework/src/framework/base.path.ts | 12 +- 5 files changed, 92 insertions(+), 71 deletions(-) rename packages/express-openapi-validator/.prettierrc.json => .prettierrc.json (100%) create mode 100644 package-lock.json diff --git a/packages/express-openapi-validator/.prettierrc.json b/.prettierrc.json similarity index 100% rename from packages/express-openapi-validator/.prettierrc.json rename to .prettierrc.json diff --git a/README.md b/README.md index 304cfe6a..60f8d435 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ npm install express-openapi-validator 1. Require/import the openapi validator ```javascript -const OpenApiValidator = require("express-openapi-validator"); +const OpenApiValidator = require('express-openapi-validator'); ``` 2. Install the middleware @@ -41,10 +41,10 @@ const OpenApiValidator = require("express-openapi-validator"); ```javascript app.use( OpenApiValidator.middleware({ - apiSpec: "./openapi.yaml", + apiSpec: './openapi.yaml', validateRequests: true, // (default) validateResponses: true, // false by default - }) + }), ); ``` @@ -85,14 +85,14 @@ The following demonstrates how to use express-openapi-validator to auto validate See the complete [source code](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/1-standard) and [OpenAPI spec](https://github.com/cdimascio/express-openapi-validator/blob/master/examples/1-standard/api.yaml) for the example below: ```javascript -const express = require("express"); -const path = require("path"); -const bodyParser = require("body-parser"); -const http = require("http"); +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const http = require('http'); const app = express(); // 1. Import the express-openapi-validator library -const OpenApiValidator = require("express-openapi-validator"); +const OpenApiValidator = require('express-openapi-validator'); // 2. Set up body parsers for the request body types you expect // Must be specified prior to endpoints in 5. @@ -101,36 +101,36 @@ app.use(bodyParser.text()); app.use(bodyParser.urlencoded({ extended: false })); // 3. (optionally) Serve the OpenAPI spec -const spec = path.join(__dirname, "api.yaml"); -app.use("/spec", express.static(spec)); +const spec = path.join(__dirname, 'api.yaml'); +app.use('/spec', express.static(spec)); // 4. Install the OpenApiValidator onto your express app app.use( OpenApiValidator.middleware({ - apiSpec: "./api.yaml", + apiSpec: './api.yaml', validateResponses: true, // <-- to validate responses // unknownFormats: ['my-format'] // <-- to provide custom formats - }) + }), ); // 5. Define routes using Express -app.get("/v1/pets", function (req, res, next) { +app.get('/v1/pets', function (req, res, next) { res.json([ - { id: 1, type: "cat", name: "max" }, - { id: 2, type: "cat", name: "mini" }, + { id: 1, type: 'cat', name: 'max' }, + { id: 2, type: 'cat', name: 'mini' }, ]); }); -app.post("/v1/pets", function (req, res, next) { - res.json({ name: "sparky", type: "dog" }); +app.post('/v1/pets', function (req, res, next) { + res.json({ name: 'sparky', type: 'dog' }); }); -app.get("/v1/pets/:id", function (req, res, next) { - res.json({ id: req.params.id, type: "dog", name: "sparky" }); +app.get('/v1/pets/:id', function (req, res, next) { + res.json({ id: req.params.id, type: 'dog', name: 'sparky' }); }); // 5a. Define route(s) to upload file(s) -app.post("/v1/pets/:id/photos", function (req, res, next) { +app.post('/v1/pets/:id/photos', function (req, res, next) { // files are found in req.files // non-file multipart params can be found as such: req.body['my-param'] res.json({ @@ -172,7 +172,7 @@ app.use( OpenApiValidator.middleware({ apiSpec, operationHandlers: path.join(__dirname), - }) + }), ); ``` @@ -199,7 +199,7 @@ app.use( ```javascript module.exports = { // the express handler implementaiton for ping - ping: (req, res) => res.status(200).send("pong"), + ping: (req, res) => res.status(200).send('pong'), }; ``` @@ -210,25 +210,25 @@ Below are some code snippets: **app.js** ```javascript -const express = require("express"); -const path = require("path"); -const bodyParser = require("body-parser"); -const logger = require("morgan"); -const http = require("http"); -const OpenApiValidator = require("express-openapi-validator"); +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const logger = require('morgan'); +const http = require('http'); +const OpenApiValidator = require('express-openapi-validator'); const port = 3000; const app = express(); -const apiSpec = path.join(__dirname, "api.yaml"); +const apiSpec = path.join(__dirname, 'api.yaml'); // 1. Install bodyParsers for the request types your API will support app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.text()); app.use(bodyParser.json()); -app.use(logger("dev")); +app.use(logger('dev')); -app.use("/spec", express.static(apiSpec)); +app.use('/spec', express.static(apiSpec)); // 2. Install the OpenApiValidator on your express app app.use( @@ -237,7 +237,7 @@ app.use( validateResponses: true, // default false // 3. Provide the base path to the operation handlers directory operationHandlers: path.join(__dirname), // default false - }) + }), ); // 4. Woah sweet! With auto-wired operation handlers, I don't have to declare my routes! @@ -275,7 +275,7 @@ module.exports = app; # e.g. operations/base/path/routes/ping.js x-eov-operation-handler: routes/ping responses: - "200": + '200': description: OK # ... ``` @@ -286,7 +286,7 @@ module.exports = app; module.exports = { // ping must match operationId or x-eov-operation-id above // note that x-eov-operation-id overrides operationId - ping: (req, res) => res.status(200).send("pong"), + ping: (req, res) => res.status(200).send('pong'), }; ``` @@ -504,7 +504,7 @@ OpenApiValidator.middleware({ Specifies the path to an OpenAPI 3 specification or a JSON object representing the OpenAPI 3 specificiation ```javascript -apiSpec: "./path/to/my-openapi-spec.yaml"; +apiSpec: './path/to/my-openapi-spec.yaml'; ``` or @@ -603,7 +603,7 @@ Determines whether the validator should validate responses. Also accepts respons ```javascript validateResponses: { - removeAdditional: "failing"; + removeAdditional: 'failing'; } ``` @@ -659,14 +659,14 @@ e.g. ```javascript formats: [ { - name: "my-three-digit-format", - type: "number", + name: 'my-three-digit-format', + type: 'number', // validate returns true the number has 3 digits, false otherwise validate: (v) => /^\d{3}$/.test(v.toString()), }, { - name: "my-three-letter-format", - type: "string", + name: 'my-three-letter-format', + type: 'string', // validate returns true the string has 3 letters, false otherwise validate: (v) => /^[A-Za-z]{3}$/.test(v), }, @@ -698,7 +698,7 @@ Defines how the validator should behave if an unknown or custom format is encoun e.g. ```javascript - unknownFormats: ["phone-number", "uuid"]; + unknownFormats: ['phone-number', 'uuid']; ``` - `"ignore"` - to log warning during schema compilation and always pass validation. This option is not recommended, as it allows to mistype format name and it won't be validated without any error message. @@ -751,7 +751,7 @@ Complete example [here](https://github.com/cdimascio/express-openapi-validator/t # e.g. operations/base/path/routes/ping.js x-eov-operation-handler: routes/ping responses: - "200": + '200': description: OK # ... ``` @@ -764,7 +764,7 @@ Complete example [here](https://github.com/cdimascio/express-openapi-validator/t ```javascript module.exports = { - ping: (req, res) => res.status(200).send("pong"), + ping: (req, res) => res.status(200).send('pong'), }; ``` @@ -797,7 +797,7 @@ Specifies the options to passthrough to multer. express-openapi-validator uses m ```javascript fileUploader: { - dest: "uploads/"; + dest: 'uploads/'; } ``` @@ -814,7 +814,7 @@ e.g. ```javascript $refParser: { - mode: "bundle"; + mode: 'bundle'; } ``` @@ -966,11 +966,11 @@ It may be useful to serve multiple APIs with separate specs via single service. See complete [example](https://github.com/cdimascio/express-openapi-validator/tree/master/examples/2-standard-multiple-api-specs) ```javascript -const express = require("express"); -const path = require("path"); -const bodyParser = require("body-parser"); -const http = require("http"); -const OpenApiValidator = require("express-openapi-validator"); +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const http = require('http'); +const OpenApiValidator = require('express-openapi-validator'); app = express(); app.use(bodyParser.urlencoded({ extended: false })); @@ -984,14 +984,14 @@ for (const v of versions) { app.use( OpenApiValidator.middleware({ apiSpec, - }) + }), ); routes(app, v); } http.createServer(app).listen(3000); -console.log("Listening on port 3000"); +console.log('Listening on port 3000'); function routes(app, v) { if (v === 1) routesV1(app); @@ -999,7 +999,7 @@ function routes(app, v) { } function routesV1(app) { - const v = "/v1"; + const v = '/v1'; app.post(`${v}/pets`, (req, res, next) => { res.json({ ...req.body }); }); @@ -1007,8 +1007,8 @@ function routesV1(app) { res.json([ { id: 1, - name: "happy", - type: "cat", + name: 'happy', + type: 'cat', }, ]); }); @@ -1023,13 +1023,13 @@ function routesV1(app) { } function routesV2(app) { - const v = "/v2"; + const v = '/v2'; app.get(`${v}/pets`, (req, res, next) => { res.json([ { pet_id: 1, - pet_name: "happy", - pet_type: "kitty", + pet_name: 'happy', + pet_type: 'kitty', }, ]); }); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..e60a9b53 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,20 @@ +{ + "name": "root", + "version": "4.10.6", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, + "typescript": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 54423a21..655abbac 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,10 @@ { - "name": "root", - "private": true, - "version": "4.10.6", - "devDependencies": { - "lerna": "^3.22.1" - } + "name": "root", + "private": true, + "version": "4.10.6", + "devDependencies": { + "lerna": "^3.22.1", + "prettier": "^2.2.1", + "typescript": "^4.1.3" } - \ No newline at end of file +} diff --git a/packages/framework/src/framework/base.path.ts b/packages/framework/src/framework/base.path.ts index 8f2cfbbc..fd9c3aeb 100644 --- a/packages/framework/src/framework/base.path.ts +++ b/packages/framework/src/framework/base.path.ts @@ -20,9 +20,9 @@ export class BasePath { let urlPath = this.findUrlPath(server.url); if (/:/.test(urlPath)) { // escape colons as (any at this point) do not signify express route params. - // this is an openapi base path, thus route params are wrapped in braces {}, + // this is an openapi base path, thus route params are wrapped in braces {}, // not prefixed by colon : (like express route params) - urlPath = urlPath.replace(':','\\:') + urlPath = urlPath.replace(':', '\\:'); } if (/{\w+}/.test(urlPath)) { // has variable that we need to check out @@ -47,7 +47,7 @@ export class BasePath { if (!servers) { return [new BasePath({ url: '' })]; } - return servers.map(server => new BasePath(server)); + return servers.map((server) => new BasePath(server)); } public hasVariables(): boolean { @@ -61,7 +61,7 @@ export class BasePath { // ignore variables that are not part of path params const allParams = Object.entries(this.variables).reduce((acc, v) => { const [key, value] = v; - const params = value.enum.map(e => ({ + const params = value.enum.map((e) => ({ [key]: e, })); acc.push(params); @@ -79,12 +79,12 @@ export class BasePath { } private findUrlPath(u: string): string { - const findColonSlashSlash = p => { + const findColonSlashSlash = (p) => { const r = /:\/\//.exec(p); if (r) return r.index; return -1; }; - const findFirstSlash = p => { + const findFirstSlash = (p) => { const r = /\//.exec(p); if (r) return r.index; return -1; From 624f34e94b96be0b6fbfcab1805d40850e4c362e Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sat, 16 Jan 2021 20:59:52 -0500 Subject: [PATCH 03/11] modular updates --- .gitignore | 3 +- .../package-lock.json | 6 +- .../express-openapi-validator/package.json | 2 +- .../src/openapi.validator.ts | 2 +- .../test/common/app.mw.ts | 2 +- .../test/missing.spec.ts | 1 - .../express-openapi-validator/test/mocha.opts | 3 + .../test/paths.sort.spec.ts | 2 +- .../express-openapi-validator/tsconfig.json | 9 +- packages/framework/dist/ajv/formats.js.map | 2 +- packages/framework/dist/ajv/index.js.map | 2 +- packages/framework/dist/base.path.d.ts | 19 - packages/framework/dist/base.path.js | 113 -- packages/framework/dist/base.path.js.map | 1 - packages/framework/dist/framework.d.ts | 10 - packages/framework/dist/framework.js | 99 -- packages/framework/dist/framework.js.map | 1 - packages/framework/dist/index.d.ts | 6 +- packages/framework/dist/index.js | 6 +- packages/framework/dist/index.js.map | 2 +- packages/framework/dist/openapi.context.d.ts | 20 - packages/framework/dist/openapi.context.js | 65 - .../framework/dist/openapi.context.js.map | 1 - .../dist/openapi.schema.validator.d.ts | 12 - .../dist/openapi.schema.validator.js | 31 - .../dist/openapi.schema.validator.js.map | 1 - .../framework/dist/openapi.spec.loader.d.ts | 21 - .../framework/dist/openapi.spec.loader.js | 85 - .../framework/dist/openapi.spec.loader.js.map | 1 - .../framework/dist/openapi.v3.schema.json | 1480 ----------------- .../src/{framework => }/ajv/formats.ts | 0 .../src/{framework => }/ajv/index.ts | 0 packages/framework/src/framework/base.path.ts | 2 +- packages/framework/src/framework/framework.ts | 2 +- .../src/framework/openapi.context.ts | 2 +- .../src/framework/openapi.schema.validator.ts | 2 +- .../src/framework/openapi.spec.loader.ts | 2 +- .../src/framework}/schema.preprocessor.ts | 13 +- .../framework/src/{framework => }/index.ts | 6 +- packages/framework/tsconfig.json | 11 +- tsconfig.json | 15 + 41 files changed, 51 insertions(+), 2012 deletions(-) create mode 100644 packages/express-openapi-validator/test/mocha.opts delete mode 100644 packages/framework/dist/base.path.d.ts delete mode 100644 packages/framework/dist/base.path.js delete mode 100644 packages/framework/dist/base.path.js.map delete mode 100644 packages/framework/dist/framework.d.ts delete mode 100644 packages/framework/dist/framework.js delete mode 100644 packages/framework/dist/framework.js.map delete mode 100644 packages/framework/dist/openapi.context.d.ts delete mode 100644 packages/framework/dist/openapi.context.js delete mode 100644 packages/framework/dist/openapi.context.js.map delete mode 100644 packages/framework/dist/openapi.schema.validator.d.ts delete mode 100644 packages/framework/dist/openapi.schema.validator.js delete mode 100644 packages/framework/dist/openapi.schema.validator.js.map delete mode 100644 packages/framework/dist/openapi.spec.loader.d.ts delete mode 100644 packages/framework/dist/openapi.spec.loader.js delete mode 100644 packages/framework/dist/openapi.spec.loader.js.map delete mode 100644 packages/framework/dist/openapi.v3.schema.json rename packages/framework/src/{framework => }/ajv/formats.ts (100%) rename packages/framework/src/{framework => }/ajv/index.ts (100%) rename packages/{express-openapi-validator/src/middlewares/parsers => framework/src/framework}/schema.preprocessor.ts (98%) rename packages/framework/src/{framework => }/index.ts (98%) create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index 8156aeee..bcd1b786 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /_old .vscode .idea -node_modules \ No newline at end of file +node_modules +dist \ No newline at end of file diff --git a/packages/express-openapi-validator/package-lock.json b/packages/express-openapi-validator/package-lock.json index 52aad1c5..403953db 100644 --- a/packages/express-openapi-validator/package-lock.json +++ b/packages/express-openapi-validator/package-lock.json @@ -460,9 +460,9 @@ "dev": true }, "@types/mocha": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.0.3.tgz", - "integrity": "sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-8.2.0.tgz", + "integrity": "sha512-/Sge3BymXo4lKc31C8OINJgXLaw+7vL1/L1pGiBNpGrBiT8FQiaFpSYV0uhTaG4y78vcMBTMFsWaHDvuD+xGzQ==", "dev": true }, "@types/morgan": { diff --git a/packages/express-openapi-validator/package.json b/packages/express-openapi-validator/package.json index bdae8dda..028c0234 100644 --- a/packages/express-openapi-validator/package.json +++ b/packages/express-openapi-validator/package.json @@ -49,7 +49,7 @@ "@types/ajv": "^1.0.0", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.8", - "@types/mocha": "^8.0.3", + "@types/mocha": "^8.2.0", "@types/morgan": "^1.9.1", "@types/multer": "^1.4.4", "@types/node": "^14.14.2", diff --git a/packages/express-openapi-validator/src/openapi.validator.ts b/packages/express-openapi-validator/src/openapi.validator.ts index 41897ac9..7df97f8e 100644 --- a/packages/express-openapi-validator/src/openapi.validator.ts +++ b/packages/express-openapi-validator/src/openapi.validator.ts @@ -22,7 +22,7 @@ import { OpenApiRequestMetadata, } from './types'; import { defaultResolver } from './resolvers'; -import { SchemaPreprocessor } from './middlewares/parsers/schema.preprocessor'; +import { SchemaPreprocessor } from 'framework/src/framework/schema.preprocessor'; export { OpenApiValidatorOpts, diff --git a/packages/express-openapi-validator/test/common/app.mw.ts b/packages/express-openapi-validator/test/common/app.mw.ts index a9a6bd47..366a4b23 100644 --- a/packages/express-openapi-validator/test/common/app.mw.ts +++ b/packages/express-openapi-validator/test/common/app.mw.ts @@ -6,7 +6,7 @@ import * as logger from 'morgan'; import * as OpenApiValidator from '../../src'; import { startServer, routes } from './app.common'; -import { OpenApiValidatorOpts } from '../../src/framework/types'; +import { OpenApiValidatorOpts } from 'framework'; export async function createApp( opts?: OpenApiValidatorOpts, diff --git a/packages/express-openapi-validator/test/missing.spec.ts b/packages/express-openapi-validator/test/missing.spec.ts index ccb57a23..731130d2 100644 --- a/packages/express-openapi-validator/test/missing.spec.ts +++ b/packages/express-openapi-validator/test/missing.spec.ts @@ -1,6 +1,5 @@ import * as path from 'path'; import * as express from 'express'; -import { expect } from 'chai'; import * as request from 'supertest'; import { createApp } from './common/app'; import * as packageJson from '../package.json'; diff --git a/packages/express-openapi-validator/test/mocha.opts b/packages/express-openapi-validator/test/mocha.opts new file mode 100644 index 00000000..d9ce4b97 --- /dev/null +++ b/packages/express-openapi-validator/test/mocha.opts @@ -0,0 +1,3 @@ +--require ts-node/register +--full-trace +--timeout 2000 diff --git a/packages/express-openapi-validator/test/paths.sort.spec.ts b/packages/express-openapi-validator/test/paths.sort.spec.ts index 6429d559..5052c058 100644 --- a/packages/express-openapi-validator/test/paths.sort.spec.ts +++ b/packages/express-openapi-validator/test/paths.sort.spec.ts @@ -1,6 +1,6 @@ import { sortRoutes, -} from 'framework/dist/openapi.spec.loader'; +} from 'framework/dist/framework/openapi.spec.loader'; import { expect } from 'chai'; describe('url sorter', () => { diff --git a/packages/express-openapi-validator/tsconfig.json b/packages/express-openapi-validator/tsconfig.json index 44ce2375..63d53911 100644 --- a/packages/express-openapi-validator/tsconfig.json +++ b/packages/express-openapi-validator/tsconfig.json @@ -1,16 +1,9 @@ { + "extends": "../../tsconfig.json", "compilerOptions": { - "declaration": true, - "target": "es2017", - "lib": ["es2019", "es2019.array"], - "module": "commonjs", - "moduleResolution": "node", "outDir": "dist", - "sourceMap": true, - "resolveJsonModule": true, "typeRoots": ["./node_modules/@types", "./typings"] }, - "exclude": ["node_modules"], "include": [ "typings/**/*.d.ts", "src/**/*.ts", diff --git a/packages/framework/dist/ajv/formats.js.map b/packages/framework/dist/ajv/formats.js.map index 4dbfb27b..187ae792 100644 --- a/packages/framework/dist/ajv/formats.js.map +++ b/packages/framework/dist/ajv/formats.js.map @@ -1 +1 @@ -{"version":3,"file":"formats.js","sourceRoot":"","sources":["../../src/framework/ajv/formats.ts"],"names":[],"mappings":";;;AAAA,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AAC3C,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AAC/B,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;AAErC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AAC9B,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAElC,QAAA,OAAO,GAAG;IACrB,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;QAC/H,IAAI,EAAE,QAAQ;KACf;IACD,MAAM,EAAE;QACN,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ;QACpC,IAAI,EAAE,QAAQ;KACf;IACD,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,UAAU;CACrB,CAAC"} \ No newline at end of file +{"version":3,"file":"formats.js","sourceRoot":"","sources":["../../src/ajv/formats.ts"],"names":[],"mappings":";;;AAAA,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAC7B,MAAM,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC;AAC3C,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;AAC9B,MAAM,QAAQ,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;AAC/B,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC;AAErC,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AAC9B,MAAM,YAAY,GAAG,yBAAyB,CAAC;AAElC,QAAA,OAAO,GAAG;IACrB,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ;QACpE,IAAI,EAAE,QAAQ;KACf;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,WAAW,CAAC,CAAC;QAC/H,IAAI,EAAE,QAAQ;KACf;IACD,MAAM,EAAE;QACN,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ;QACpC,IAAI,EAAE,QAAQ;KACf;IACD,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,MAAM,EAAE,UAAU;IAClB,QAAQ,EAAE,UAAU;CACrB,CAAC"} \ No newline at end of file diff --git a/packages/framework/dist/ajv/index.js.map b/packages/framework/dist/ajv/index.js.map index a1a35d84..7a79facc 100644 --- a/packages/framework/dist/ajv/index.js.map +++ b/packages/framework/dist/ajv/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/framework/ajv/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ajv/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/base.path.d.ts b/packages/framework/dist/base.path.d.ts deleted file mode 100644 index 79e1bf0b..00000000 --- a/packages/framework/dist/base.path.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { OpenAPIV3 } from '.'; -interface ServerUrlVariables { - [key: string]: ServerUrlValues; -} -interface ServerUrlValues { - enum: string[]; - default?: string; -} -export declare class BasePath { - readonly variables: ServerUrlVariables; - readonly expressPath: string; - private allPaths; - constructor(server: OpenAPIV3.ServerObject); - static fromServers(servers: OpenAPIV3.ServerObject[]): BasePath[]; - hasVariables(): boolean; - all(): string[]; - private findUrlPath; -} -export {}; diff --git a/packages/framework/dist/base.path.js b/packages/framework/dist/base.path.js deleted file mode 100644 index a4f1e5ca..00000000 --- a/packages/framework/dist/base.path.js +++ /dev/null @@ -1,113 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.BasePath = void 0; -const path_to_regexp_1 = require("path-to-regexp"); -class BasePath { - constructor(server) { - var _a; - this.variables = {}; - this.expressPath = ''; - this.allPaths = null; - // break the url into parts - // baseUrl param added to make the parsing of relative paths go well - let urlPath = this.findUrlPath(server.url); - if (/:/.test(urlPath)) { - // escape colons as (any at this point) do not signify express route params. - // this is an openapi base path, thus route params are wrapped in braces {}, - // not prefixed by colon : (like express route params) - urlPath = urlPath.replace(':', '\\:'); - } - if (/{\w+}/.test(urlPath)) { - // has variable that we need to check out - urlPath = urlPath.replace(/{(\w+)}/g, (substring, p1) => `:${p1}(.*)`); - } - this.expressPath = urlPath; - for (const variable in server.variables) { - if (server.variables.hasOwnProperty(variable)) { - const v = server.variables[variable]; - const enums = (_a = v.enum) !== null && _a !== void 0 ? _a : []; - if (enums.length === 0 && v.default) - enums.push(v.default); - this.variables[variable] = { - enum: enums, - default: v.default, - }; - } - } - } - static fromServers(servers) { - if (!servers) { - return [new BasePath({ url: '' })]; - } - return servers.map(server => new BasePath(server)); - } - hasVariables() { - return Object.keys(this.variables).length > 0; - } - all() { - if (!this.hasVariables()) - return [this.expressPath]; - if (this.allPaths) - return this.allPaths; - // TODO performance optimization - // ignore variables that are not part of path params - const allParams = Object.entries(this.variables).reduce((acc, v) => { - const [key, value] = v; - const params = value.enum.map(e => ({ - [key]: e, - })); - acc.push(params); - return acc; - }, []); - const allParamCombos = cartesian(...allParams); - const toPath = path_to_regexp_1.compile(this.expressPath); - const paths = new Set(); - for (const combo of allParamCombos) { - paths.add(toPath(combo)); - } - this.allPaths = Array.from(paths); - return this.allPaths; - } - findUrlPath(u) { - const findColonSlashSlash = p => { - const r = /:\/\//.exec(p); - if (r) - return r.index; - return -1; - }; - const findFirstSlash = p => { - const r = /\//.exec(p); - if (r) - return r.index; - return -1; - }; - const fcssIdx = findColonSlashSlash(u); - const startSearchIdx = fcssIdx !== -1 ? fcssIdx + 3 : 0; - const startPathIdx = findFirstSlash(u.substring(startSearchIdx)); - if (startPathIdx === -1) - return '/'; - const pathIdx = startPathIdx + startSearchIdx; - const path = u.substring(pathIdx); - // ensure a trailing slash is always present - return path[path.length - 1] === '/' ? path : path + '/'; - } -} -exports.BasePath = BasePath; -function cartesian(...arg) { - const r = [], max = arg.length - 1; - function helper(obj, i) { - const values = arg[i]; - for (var j = 0, l = values.length; j < l; j++) { - const a = Object.assign({}, obj); - const key = Object.keys(values[j])[0]; - a[key] = values[j][key]; - if (i == max) - r.push(a); - else - helper(a, i + 1); - } - } - helper({}, 0); - return r; -} -//# sourceMappingURL=base.path.js.map \ No newline at end of file diff --git a/packages/framework/dist/base.path.js.map b/packages/framework/dist/base.path.js.map deleted file mode 100644 index 72d3196b..00000000 --- a/packages/framework/dist/base.path.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"base.path.js","sourceRoot":"","sources":["../src/framework/base.path.ts"],"names":[],"mappings":";;;AAAA,mDAAyC;AAWzC,MAAa,QAAQ;IAKnB,YAAY,MAA8B;;QAJ1B,cAAS,GAAuB,EAAE,CAAC;QACnC,gBAAW,GAAW,EAAE,CAAC;QACjC,aAAQ,GAAa,IAAI,CAAC;QAGhC,2BAA2B;QAC3B,oEAAoE;QACpE,IAAI,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACrB,4EAA4E;YAC5E,6EAA6E;YAC7E,sDAAsD;YACtD,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAC,KAAK,CAAC,CAAA;SACrC;QACD,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACzB,yCAAyC;YACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;SACxE;QACD,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC;QAC3B,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE;YACvC,IAAI,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE;gBAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM,KAAK,SAAG,CAAC,CAAC,IAAI,mCAAI,EAAE,CAAC;gBAC3B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO;oBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;gBAE3D,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG;oBACzB,IAAI,EAAE,KAAK;oBACX,OAAO,EAAE,CAAC,CAAC,OAAO;iBACnB,CAAC;aACH;SACF;IACH,CAAC;IAEM,MAAM,CAAC,WAAW,CAAC,OAAiC;QACzD,IAAI,CAAC,OAAO,EAAE;YACZ,OAAO,CAAC,IAAI,QAAQ,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;SACpC;QACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC;IAEM,YAAY;QACjB,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAChD,CAAC;IAEM,GAAG;QACR,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE;YAAE,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC;QACxC,gCAAgC;QAChC,oDAAoD;QACpD,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;YACjE,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;YACvB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAClC,CAAC,GAAG,CAAC,EAAE,CAAC;aACT,CAAC,CAAC,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjB,OAAO,GAAG,CAAC;QACb,CAAC,EAAE,EAAE,CAAC,CAAC;QAEP,MAAM,cAAc,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,wBAAO,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE;YAClC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;SAC1B;QACD,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClC,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAEO,WAAW,CAAC,CAAS;QAC3B,MAAM,mBAAmB,GAAG,CAAC,CAAC,EAAE;YAC9B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC;gBAAE,OAAO,CAAC,CAAC,KAAK,CAAC;YACtB,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,cAAc,GAAG,CAAC,CAAC,EAAE;YACzB,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACvB,IAAI,CAAC;gBAAE,OAAO,CAAC,CAAC,KAAK,CAAC;YACtB,OAAO,CAAC,CAAC,CAAC;QACZ,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACvC,MAAM,cAAc,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,YAAY,GAAG,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;QACjE,IAAI,YAAY,KAAK,CAAC,CAAC;YAAE,OAAO,GAAG,CAAC;QAEpC,MAAM,OAAO,GAAG,YAAY,GAAG,cAAc,CAAC;QAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAClC,4CAA4C;QAC5C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC;IAC3D,CAAC;CACF;AA3FD,4BA2FC;AAED,SAAS,SAAS,CAAC,GAAG,GAAG;IACvB,MAAM,CAAC,GAAG,EAAE,EACV,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACvB,SAAS,MAAM,CAAC,GAAG,EAAE,CAAS;QAC5B,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;YAC7C,MAAM,CAAC,qBAAQ,GAAG,CAAE,CAAC;YACrB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtC,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACxB,IAAI,CAAC,IAAI,GAAG;gBAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;gBACnB,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;SACvB;IACH,CAAC;IACD,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACd,OAAO,CAAC,CAAC;AACX,CAAC"} \ No newline at end of file diff --git a/packages/framework/dist/framework.d.ts b/packages/framework/dist/framework.d.ts deleted file mode 100644 index ef4532dd..00000000 --- a/packages/framework/dist/framework.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { OpenAPIFrameworkArgs, OpenAPIFrameworkInit, OpenAPIFrameworkVisitor } from '.'; -export declare class OpenAPIFramework { - private readonly args; - private readonly loggingPrefix; - constructor(args: OpenAPIFrameworkArgs); - initialize(visitor: OpenAPIFrameworkVisitor): Promise; - private loadSpec; - private sortApiDocTags; - private getBasePathsFromServers; -} diff --git a/packages/framework/dist/framework.js b/packages/framework/dist/framework.js deleted file mode 100644 index 06c00234..00000000 --- a/packages/framework/dist/framework.js +++ /dev/null @@ -1,99 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.OpenAPIFramework = void 0; -const fs = require("fs"); -const path = require("path"); -const $RefParser = require("json-schema-ref-parser"); -const openapi_schema_validator_1 = require("./openapi.schema.validator"); -const base_path_1 = require("./base.path"); -class OpenAPIFramework { - constructor(args) { - this.loggingPrefix = 'openapi.validator: '; - this.args = args; - } - // TODO the visitor should be implemented in the corresponding framework specific package - // e.g. express-openapi-validator - async initialize(visitor) { - const args = this.args; - const apiDoc = await this.loadSpec(args.apiDoc, args.$refParser); - const basePathObs = this.getBasePathsFromServers(apiDoc.servers); - const basePaths = Array.from(basePathObs.reduce((acc, bp) => { - bp.all().forEach((path) => acc.add(path)); - return acc; - }, new Set())); - const validateApiDoc = 'validateApiDoc' in args ? !!args.validateApiDoc : true; - const validator = new openapi_schema_validator_1.OpenAPISchemaValidator({ - version: apiDoc.openapi, - }); - if (validateApiDoc) { - const apiDocValidation = validator.validate(apiDoc); - if (apiDocValidation.errors.length) { - console.error(`${this.loggingPrefix}Validating schema`); - console.error(`${this.loggingPrefix}validation errors`, JSON.stringify(apiDocValidation.errors, null, ' ')); - throw new Error(`${this.loggingPrefix}args.apiDoc was invalid. See the output.`); - } - } - const getApiDoc = () => { - return apiDoc; - }; - this.sortApiDocTags(apiDoc); - if (visitor.visitApi) { - // const basePaths = basePathObs; - visitor.visitApi({ - basePaths, - getApiDoc, - }); - } - return { - apiDoc, - basePaths, - }; - } - loadSpec(filePath, $refParser = { mode: 'bundle' }) { - // Because of this issue ( https://github.com/APIDevTools/json-schema-ref-parser/issues/101#issuecomment-421755168 ) - // We need this workaround ( use '$RefParser.dereference' instead of '$RefParser.bundle' ) if asked by user - if (typeof filePath === 'string') { - const origCwd = process.cwd(); - const specDir = path.resolve(origCwd, path.dirname(filePath)); - const absolutePath = path.resolve(origCwd, filePath); - if (fs.existsSync(absolutePath)) { - // Get document, or throw exception on error - try { - process.chdir(specDir); - return $refParser.mode === 'dereference' - ? $RefParser.dereference(absolutePath) - : $RefParser.bundle(absolutePath); - } - finally { - process.chdir(origCwd); - } - } - else { - throw new Error(`${this.loggingPrefix}spec could not be read at ${filePath}`); - } - } - return $refParser.mode === 'dereference' - ? $RefParser.dereference(filePath) - : $RefParser.bundle(filePath); - } - sortApiDocTags(apiDoc) { - if (apiDoc && Array.isArray(apiDoc.tags)) { - apiDoc.tags.sort((a, b) => { - return a.name < b.name ? -1 : 1; - }); - } - } - getBasePathsFromServers(servers) { - if (!servers || servers.length === 0) { - return [new base_path_1.BasePath({ url: '' })]; - } - const basePathsMap = {}; - for (const server of servers) { - const basePath = new base_path_1.BasePath(server); - basePathsMap[basePath.expressPath] = basePath; - } - return Object.keys(basePathsMap).map((key) => basePathsMap[key]); - } -} -exports.OpenAPIFramework = OpenAPIFramework; -//# sourceMappingURL=framework.js.map \ No newline at end of file diff --git a/packages/framework/dist/framework.js.map b/packages/framework/dist/framework.js.map deleted file mode 100644 index ddc11501..00000000 --- a/packages/framework/dist/framework.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"framework.js","sourceRoot":"","sources":["../src/framework/framework.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/index.d.ts b/packages/framework/dist/index.d.ts index d3eaa991..2950aeef 100644 --- a/packages/framework/dist/index.d.ts +++ b/packages/framework/dist/index.d.ts @@ -1,9 +1,9 @@ import * as ajv from 'ajv'; import * as multer from 'multer'; import { createRequestAjv, createResponseAjv } from './ajv'; -export { OpenAPIFramework } from './framework'; -export { OpenApiSpecLoader, Spec, RouteMetadata } from './openapi.spec.loader'; -export { OpenApiContext } from './openapi.context'; +export { OpenAPIFramework } from './framework/framework'; +export { OpenApiSpecLoader, Spec, RouteMetadata } from './framework/openapi.spec.loader'; +export { OpenApiContext } from './framework/openapi.context'; export declare const Ajv: { createRequestAjv: typeof createRequestAjv; createResponseAjv: typeof createResponseAjv; diff --git a/packages/framework/dist/index.js b/packages/framework/dist/index.js index 843fe325..e616bcc6 100644 --- a/packages/framework/dist/index.js +++ b/packages/framework/dist/index.js @@ -2,11 +2,11 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.Forbidden = exports.Unauthorized = exports.UnsupportedMediaType = exports.InternalServerError = exports.RequestEntityTooLarge = exports.BadRequest = exports.MethodNotAllowed = exports.NotAcceptable = exports.NotFound = exports.HttpError = exports.Ajv = exports.OpenApiContext = exports.OpenApiSpecLoader = exports.OpenAPIFramework = void 0; const ajv_1 = require("./ajv"); -var framework_1 = require("./framework"); +var framework_1 = require("./framework/framework"); Object.defineProperty(exports, "OpenAPIFramework", { enumerable: true, get: function () { return framework_1.OpenAPIFramework; } }); -var openapi_spec_loader_1 = require("./openapi.spec.loader"); +var openapi_spec_loader_1 = require("./framework/openapi.spec.loader"); Object.defineProperty(exports, "OpenApiSpecLoader", { enumerable: true, get: function () { return openapi_spec_loader_1.OpenApiSpecLoader; } }); -var openapi_context_1 = require("./openapi.context"); +var openapi_context_1 = require("./framework/openapi.context"); Object.defineProperty(exports, "OpenApiContext", { enumerable: true, get: function () { return openapi_context_1.OpenApiContext; } }); exports.Ajv = { createRequestAjv: ajv_1.createRequestAjv, diff --git a/packages/framework/dist/index.js.map b/packages/framework/dist/index.js.map index 914cad3c..a6affcdc 100644 --- a/packages/framework/dist/index.js.map +++ b/packages/framework/dist/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/framework/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.context.d.ts b/packages/framework/dist/openapi.context.d.ts deleted file mode 100644 index 5fc632c6..00000000 --- a/packages/framework/dist/openapi.context.d.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { OpenAPIV3 } from '.'; -import { Spec, RouteMetadata } from './openapi.spec.loader'; -export interface RoutePair { - expressRoute: string; - openApiRoute: string; -} -export declare class OpenApiContext { - readonly apiDoc: OpenAPIV3.Document; - readonly expressRouteMap: {}; - readonly openApiRouteMap: {}; - readonly routes: RouteMetadata[]; - private readonly basePaths; - private readonly ignorePaths; - constructor(spec: Spec, ignorePaths: RegExp | Function); - isManagedRoute(path: string): boolean; - shouldIgnoreRoute(path: string): any; - routePair(route: string): RoutePair; - private methods; - private buildRouteMaps; -} diff --git a/packages/framework/dist/openapi.context.js b/packages/framework/dist/openapi.context.js deleted file mode 100644 index 4fba9cdf..00000000 --- a/packages/framework/dist/openapi.context.js +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.OpenApiContext = void 0; -class OpenApiContext { - constructor(spec, ignorePaths) { - this.expressRouteMap = {}; - this.openApiRouteMap = {}; - this.routes = []; - this.apiDoc = spec.apiDoc; - this.basePaths = spec.basePaths; - this.routes = spec.routes; - this.ignorePaths = ignorePaths; - this.buildRouteMaps(spec.routes); - } - isManagedRoute(path) { - for (const bp of this.basePaths) { - if (path.startsWith(bp) && !this.shouldIgnoreRoute(path)) { - return true; - } - } - return false; - } - shouldIgnoreRoute(path) { - var _a; - return typeof this.ignorePaths === 'function' ? this.ignorePaths(path) : (_a = this.ignorePaths) === null || _a === void 0 ? void 0 : _a.test(path); - } - routePair(route) { - const methods = this.methods(route); - if (methods) { - return { - expressRoute: methods._expressRoute, - openApiRoute: methods._openApiRoute, - }; - } - return null; - } - methods(route) { - const expressRouteMethods = this.expressRouteMap[route]; - if (expressRouteMethods) - return expressRouteMethods; - const openApiRouteMethods = this.openApiRouteMap[route]; - return openApiRouteMethods; - } - // side-effecting builds express/openapi route maps - buildRouteMaps(routes) { - for (const route of routes) { - const { basePath, expressRoute, openApiRoute, method } = route; - const routeMethods = this.expressRouteMap[expressRoute]; - const pathKey = openApiRoute.substring(basePath.length); - const schema = this.apiDoc.paths[pathKey][method.toLowerCase()]; - if (routeMethods) { - routeMethods[route.method] = schema; - } - else { - const { basePath, openApiRoute, expressRoute } = route; - const routeMethod = { [route.method]: schema }; - const routeDetails = Object.assign({ basePath, _openApiRoute: openApiRoute, _expressRoute: expressRoute }, routeMethod); - this.expressRouteMap[route.expressRoute] = routeDetails; - this.openApiRouteMap[route.openApiRoute] = routeDetails; - } - } - } -} -exports.OpenApiContext = OpenApiContext; -//# sourceMappingURL=openapi.context.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.context.js.map b/packages/framework/dist/openapi.context.js.map deleted file mode 100644 index d70bf7dc..00000000 --- a/packages/framework/dist/openapi.context.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openapi.context.js","sourceRoot":"","sources":["../src/framework/openapi.context.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.schema.validator.d.ts b/packages/framework/dist/openapi.schema.validator.d.ts deleted file mode 100644 index 951f0900..00000000 --- a/packages/framework/dist/openapi.schema.validator.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as Ajv from 'ajv'; -import { OpenAPIV3 } from './index.js'; -export declare class OpenAPISchemaValidator { - private validator; - constructor({ version }: { - version: string; - extensions?: object; - }); - validate(openapiDoc: OpenAPIV3.Document): { - errors: Array | null; - }; -} diff --git a/packages/framework/dist/openapi.schema.validator.js b/packages/framework/dist/openapi.schema.validator.js deleted file mode 100644 index 34760585..00000000 --- a/packages/framework/dist/openapi.schema.validator.js +++ /dev/null @@ -1,31 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.OpenAPISchemaValidator = void 0; -const Ajv = require("ajv"); -const draftSchema = require("ajv/lib/refs/json-schema-draft-04.json"); -// https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json -const openapi3Schema = require("./openapi.v3.schema.json"); -class OpenAPISchemaValidator { - constructor({ version }) { - const v = new Ajv({ schemaId: 'auto', allErrors: true }); - v.addMetaSchema(draftSchema); - const ver = version && parseInt(String(version), 10); - if (!ver) - throw Error('version missing from OpenAPI specification'); - if (ver != 3) - throw Error('OpenAPI v3 specification version is required'); - v.addSchema(openapi3Schema); - this.validator = v.compile(openapi3Schema); - } - validate(openapiDoc) { - const valid = this.validator(openapiDoc); - if (!valid) { - return { errors: this.validator.errors }; - } - else { - return { errors: [] }; - } - } -} -exports.OpenAPISchemaValidator = OpenAPISchemaValidator; -//# sourceMappingURL=openapi.schema.validator.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.schema.validator.js.map b/packages/framework/dist/openapi.schema.validator.js.map deleted file mode 100644 index 07082ffe..00000000 --- a/packages/framework/dist/openapi.schema.validator.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openapi.schema.validator.js","sourceRoot":"","sources":["../src/framework/openapi.schema.validator.ts"],"names":[],"mappings":";;;AAAA,2BAA2B;AAC3B,sEAAsE;AACtE,oFAAoF;AACpF,2DAA2D;AAG3D,MAAa,sBAAsB;IAEjC,YAAY,EAAE,OAAO,EAA4C;QAC/D,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;QAE7B,MAAM,GAAG,GAAG,OAAO,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACrD,IAAI,CAAC,GAAG;YAAE,MAAM,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACpE,IAAI,GAAG,IAAI,CAAC;YAAE,MAAM,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAE1E,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QAC5B,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC;IAEM,QAAQ,CACb,UAA8B;QAE9B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,KAAK,EAAE;YACV,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;SAC1C;aAAM;YACL,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;SACvB;IACH,CAAC;CACF;AAxBD,wDAwBC"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.spec.loader.d.ts b/packages/framework/dist/openapi.spec.loader.d.ts deleted file mode 100644 index 8ae671e9..00000000 --- a/packages/framework/dist/openapi.spec.loader.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { OpenAPIV3, OpenAPIFrameworkArgs } from '.'; -export interface Spec { - apiDoc: OpenAPIV3.Document; - basePaths: string[]; - routes: RouteMetadata[]; -} -export interface RouteMetadata { - basePath: string; - expressRoute: string; - openApiRoute: string; - method: string; - pathParams: string[]; -} -export declare const sortRoutes: (r1: any, r2: any) => 1 | -1; -export declare class OpenApiSpecLoader { - private readonly framework; - constructor(opts: OpenAPIFrameworkArgs); - load(): Promise; - private discoverRoutes; - private toExpressParams; -} diff --git a/packages/framework/dist/openapi.spec.loader.js b/packages/framework/dist/openapi.spec.loader.js deleted file mode 100644 index 4338f24a..00000000 --- a/packages/framework/dist/openapi.spec.loader.js +++ /dev/null @@ -1,85 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.OpenApiSpecLoader = exports.sortRoutes = void 0; -const framework_1 = require("./framework"); -// Sort routes by most specific to least specific i.e. static routes before dynamic -// e.g. /users/my_route before /users/{id} -// Exported for tests -// TODO this should be part of the express package -const sortRoutes = (r1, r2) => { - const e1 = r1.expressRoute.replace(/\/:/g, '/~'); - const e2 = r2.expressRoute.replace(/\/:/g, '/~'); - return e1 > e2 ? 1 : -1; -}; -exports.sortRoutes = sortRoutes; -class OpenApiSpecLoader { - constructor(opts) { - this.framework = new framework_1.OpenAPIFramework(opts); - } - async load() { - return this.discoverRoutes(); - } - async discoverRoutes() { - const routes = []; - const toExpressParams = this.toExpressParams; - // const basePaths = this.framework.basePaths; - // let apiDoc: OpenAPIV3.Document = null; - // let basePaths: string[] = null; - const { apiDoc, basePaths } = await this.framework.initialize({ - visitApi(ctx) { - var _a; - const apiDoc = ctx.getApiDoc(); - const basePaths = ctx.basePaths; - for (const bpa of basePaths) { - const bp = bpa.replace(/\/$/, ''); - for (const [path, methods] of Object.entries(apiDoc.paths)) { - for (const [method, schema] of Object.entries(methods)) { - if (method.startsWith('x-') || - ['parameters', 'summary', 'description'].includes(method)) { - continue; - } - const pathParams = new Set(); - for (const param of (_a = schema.parameters) !== null && _a !== void 0 ? _a : []) { - if (param.in === 'path') { - pathParams.add(param.name); - } - } - const openApiRoute = `${bp}${path}`; - const expressRoute = `${openApiRoute}` - .split(':') - .map(toExpressParams) - .join('\\:'); - routes.push({ - basePath: bp, - expressRoute, - openApiRoute, - method: method.toUpperCase(), - pathParams: Array.from(pathParams), - }); - } - } - } - }, - }); - routes.sort(exports.sortRoutes); - return { - apiDoc, - basePaths, - routes, - }; - } - toExpressParams(part) { - // substitute wildcard path with express equivalent - // {/path} => /path(*) <--- RFC 6570 format (not supported by openapi) - // const pass1 = part.replace(/\{(\/)([^\*]+)(\*)}/g, '$1:$2$3'); - // instead create our own syntax that is compatible with express' pathToRegex - // /{path}* => /:path*) - // /{path}(*) => /:path*) - const pass1 = part.replace(/\/{([^\*]+)}\({0,1}(\*)\){0,1}/g, '/:$1$2'); - // substitute params with express equivalent - // /path/{id} => /path/:id - return pass1.replace(/\{([^}]+)}/g, ':$1'); - } -} -exports.OpenApiSpecLoader = OpenApiSpecLoader; -//# sourceMappingURL=openapi.spec.loader.js.map \ No newline at end of file diff --git a/packages/framework/dist/openapi.spec.loader.js.map b/packages/framework/dist/openapi.spec.loader.js.map deleted file mode 100644 index e7abbbac..00000000 --- a/packages/framework/dist/openapi.spec.loader.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"openapi.spec.loader.js","sourceRoot":"","sources":["../src/framework/openapi.spec.loader.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/framework/dist/openapi.v3.schema.json b/packages/framework/dist/openapi.v3.schema.json deleted file mode 100644 index 9bcb3bf7..00000000 --- a/packages/framework/dist/openapi.v3.schema.json +++ /dev/null @@ -1,1480 +0,0 @@ -{ - "id": "https://spec.openapis.org/oas/3.0/schema/2019-04-02", - "$schema": "http://json-schema.org/draft-04/schema#", - "description": "Validation schema for OpenAPI Specification 3.0.X.", - "type": "object", - "required": ["openapi", "info", "paths"], - "properties": { - "openapi": { - "type": "string", - "pattern": "^3\\.0\\.\\d(-.+)?$" - }, - "info": { - "$ref": "#/definitions/Info" - }, - "externalDocs": { - "$ref": "#/definitions/ExternalDocumentation" - }, - "servers": { - "type": "array", - "items": { - "$ref": "#/definitions/Server" - } - }, - "security": { - "type": "array", - "items": { - "$ref": "#/definitions/SecurityRequirement" - } - }, - "tags": { - "type": "array", - "items": { - "$ref": "#/definitions/Tag" - }, - "uniqueItems": true - }, - "paths": { - "$ref": "#/definitions/Paths" - }, - "components": { - "$ref": "#/definitions/Components" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "definitions": { - "Reference": { - "type": "object", - "required": ["$ref"], - "patternProperties": { - "^\\$ref$": { - "type": "string", - "format": "uri-reference" - } - } - }, - "Info": { - "type": "object", - "required": ["title", "version"], - "properties": { - "title": { - "type": "string" - }, - "description": { - "type": "string" - }, - "termsOfService": { - "type": "string", - "format": "uri-reference" - }, - "contact": { - "$ref": "#/definitions/Contact" - }, - "license": { - "$ref": "#/definitions/License" - }, - "version": { - "type": "string" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Contact": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "url": { - "type": "string", - "format": "uri-reference" - }, - "email": { - "type": "string", - "format": "email" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "License": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string" - }, - "url": { - "type": "string", - "format": "uri-reference" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Server": { - "type": "object", - "required": ["url"], - "properties": { - "url": { - "type": "string" - }, - "description": { - "type": "string" - }, - "variables": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/ServerVariable" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "ServerVariable": { - "type": "object", - "required": ["default"], - "properties": { - "enum": { - "type": "array", - "items": { - "type": "string" - } - }, - "default": { - "type": "string" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Components": { - "type": "object", - "properties": { - "schemas": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - } - }, - "responses": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Response" - } - ] - } - } - }, - "parameters": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Parameter" - } - ] - } - } - }, - "examples": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Example" - } - ] - } - } - }, - "requestBodies": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/RequestBody" - } - ] - } - } - }, - "headers": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Header" - } - ] - } - } - }, - "securitySchemes": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/SecurityScheme" - } - ] - } - } - }, - "links": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Link" - } - ] - } - } - }, - "callbacks": { - "type": "object", - "patternProperties": { - "^[a-zA-Z0-9\\.\\-_]+$": { - "oneOf": [ - { - "$ref": "#/definitions/Reference" - }, - { - "$ref": "#/definitions/Callback" - } - ] - } - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Schema": { - "type": "object", - "properties": { - "title": { - "type": "string" - }, - "multipleOf": { - "type": "number", - "minimum": 0, - "exclusiveMinimum": true - }, - "maximum": { - "type": "number" - }, - "exclusiveMaximum": { - "type": "boolean", - "default": false - }, - "minimum": { - "type": "number" - }, - "exclusiveMinimum": { - "type": "boolean", - "default": false - }, - "maxLength": { - "type": "integer", - "minimum": 0 - }, - "minLength": { - "type": "integer", - "minimum": 0, - "default": 0 - }, - "pattern": { - "type": "string", - "format": "regex" - }, - "maxItems": { - "type": "integer", - "minimum": 0 - }, - "minItems": { - "type": "integer", - "minimum": 0, - "default": 0 - }, - "uniqueItems": { - "type": "boolean", - "default": false - }, - "maxProperties": { - "type": "integer", - "minimum": 0 - }, - "minProperties": { - "type": "integer", - "minimum": 0, - "default": 0 - }, - "required": { - "type": "array", - "items": { - "type": "string" - }, - "minItems": 1, - "uniqueItems": true - }, - "enum": { - "type": "array", - "items": {}, - "minItems": 1, - "uniqueItems": false - }, - "type": { - "type": "string", - "enum": ["array", "boolean", "integer", "number", "object", "string"] - }, - "not": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "allOf": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "oneOf": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "anyOf": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "properties": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - }, - { - "type": "boolean" - } - ], - "default": true - }, - "description": { - "type": "string" - }, - "format": { - "type": "string" - }, - "default": {}, - "nullable": { - "type": "boolean", - "default": false - }, - "discriminator": { - "$ref": "#/definitions/Discriminator" - }, - "readOnly": { - "type": "boolean", - "default": false - }, - "writeOnly": { - "type": "boolean", - "default": false - }, - "example": {}, - "externalDocs": { - "$ref": "#/definitions/ExternalDocumentation" - }, - "deprecated": { - "type": "boolean", - "default": false - }, - "xml": { - "$ref": "#/definitions/XML" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Discriminator": { - "type": "object", - "required": ["propertyName"], - "properties": { - "propertyName": { - "type": "string" - }, - "mapping": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - }, - "XML": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "namespace": { - "type": "string", - "format": "uri" - }, - "prefix": { - "type": "string" - }, - "attribute": { - "type": "boolean", - "default": false - }, - "wrapped": { - "type": "boolean", - "default": false - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Response": { - "type": "object", - "required": ["description"], - "properties": { - "description": { - "type": "string" - }, - "headers": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Header" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "content": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/MediaType" - } - }, - "links": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Link" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "MediaType": { - "type": "object", - "properties": { - "schema": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "example": {}, - "examples": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Example" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "encoding": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Encoding" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "allOf": [ - { - "$ref": "#/definitions/ExampleXORExamples" - } - ] - }, - "Example": { - "type": "object", - "properties": { - "summary": { - "type": "string" - }, - "description": { - "type": "string" - }, - "value": {}, - "externalValue": { - "type": "string", - "format": "uri-reference" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Header": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "required": { - "type": "boolean", - "default": false - }, - "deprecated": { - "type": "boolean", - "default": false - }, - "allowEmptyValue": { - "type": "boolean", - "default": false - }, - "style": { - "type": "string", - "enum": ["simple"], - "default": "simple" - }, - "explode": { - "type": "boolean" - }, - "allowReserved": { - "type": "boolean", - "default": false - }, - "schema": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "content": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/MediaType" - }, - "minProperties": 1, - "maxProperties": 1 - }, - "example": {}, - "examples": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Example" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "allOf": [ - { - "$ref": "#/definitions/ExampleXORExamples" - }, - { - "$ref": "#/definitions/SchemaXORContent" - } - ] - }, - "Paths": { - "type": "object", - "patternProperties": { - "^\\/": { - "$ref": "#/definitions/PathItem" - }, - "^x-": {} - }, - "additionalProperties": false - }, - "PathItem": { - "type": "object", - "properties": { - "$ref": { - "type": "string" - }, - "summary": { - "type": "string" - }, - "description": { - "type": "string" - }, - "servers": { - "type": "array", - "items": { - "$ref": "#/definitions/Server" - } - }, - "parameters": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Parameter" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "uniqueItems": true - } - }, - "patternProperties": { - "^(get|put|post|delete|options|head|patch|trace)$": { - "$ref": "#/definitions/Operation" - }, - "^x-": {} - }, - "additionalProperties": false - }, - "Operation": { - "type": "object", - "required": ["responses"], - "properties": { - "tags": { - "type": "array", - "items": { - "type": "string" - } - }, - "summary": { - "type": "string" - }, - "description": { - "type": "string" - }, - "externalDocs": { - "$ref": "#/definitions/ExternalDocumentation" - }, - "operationId": { - "type": "string" - }, - "parameters": { - "type": "array", - "items": { - "oneOf": [ - { - "$ref": "#/definitions/Parameter" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "uniqueItems": true - }, - "requestBody": { - "oneOf": [ - { - "$ref": "#/definitions/RequestBody" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "responses": { - "$ref": "#/definitions/Responses" - }, - "callbacks": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Callback" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "deprecated": { - "type": "boolean", - "default": false - }, - "security": { - "type": "array", - "items": { - "$ref": "#/definitions/SecurityRequirement" - } - }, - "servers": { - "type": "array", - "items": { - "$ref": "#/definitions/Server" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Responses": { - "type": "object", - "properties": { - "default": { - "oneOf": [ - { - "$ref": "#/definitions/Response" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - }, - "patternProperties": { - "^[1-5](?:\\d{2}|XX)$": { - "oneOf": [ - { - "$ref": "#/definitions/Response" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "^x-": {} - }, - "minProperties": 1, - "additionalProperties": false - }, - "SecurityRequirement": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "Tag": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "externalDocs": { - "$ref": "#/definitions/ExternalDocumentation" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "ExternalDocumentation": { - "type": "object", - "required": ["url"], - "properties": { - "description": { - "type": "string" - }, - "url": { - "type": "string", - "format": "uri-reference" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "ExampleXORExamples": { - "description": "Example and examples are mutually exclusive", - "not": { - "required": ["example", "examples"] - } - }, - "SchemaXORContent": { - "description": "Schema and content are mutually exclusive, at least one is required", - "not": { - "required": ["schema", "content"] - }, - "oneOf": [ - { - "required": ["schema"] - }, - { - "required": ["content"], - "description": "Some properties are not allowed if content is present", - "allOf": [ - { - "not": { - "required": ["style"] - } - }, - { - "not": { - "required": ["explode"] - } - }, - { - "not": { - "required": ["allowReserved"] - } - }, - { - "not": { - "required": ["example"] - } - }, - { - "not": { - "required": ["examples"] - } - } - ] - } - ] - }, - "Parameter": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "in": { - "type": "string" - }, - "description": { - "type": "string" - }, - "required": { - "type": "boolean", - "default": false - }, - "deprecated": { - "type": "boolean", - "default": false - }, - "allowEmptyValue": { - "type": "boolean", - "default": false - }, - "style": { - "type": "string" - }, - "explode": { - "type": "boolean" - }, - "allowReserved": { - "type": "boolean", - "default": false - }, - "schema": { - "oneOf": [ - { - "$ref": "#/definitions/Schema" - }, - { - "$ref": "#/definitions/Reference" - } - ] - }, - "content": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/MediaType" - }, - "minProperties": 1, - "maxProperties": 1 - }, - "example": {}, - "examples": { - "type": "object", - "additionalProperties": { - "oneOf": [ - { - "$ref": "#/definitions/Example" - }, - { - "$ref": "#/definitions/Reference" - } - ] - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "required": ["name", "in"], - "allOf": [ - { - "$ref": "#/definitions/ExampleXORExamples" - }, - { - "$ref": "#/definitions/SchemaXORContent" - }, - { - "$ref": "#/definitions/ParameterLocation" - } - ] - }, - "ParameterLocation": { - "description": "Parameter location", - "oneOf": [ - { - "description": "Parameter in path", - "required": ["required"], - "properties": { - "in": { - "enum": ["path"] - }, - "style": { - "enum": ["matrix", "label", "simple"], - "default": "simple" - }, - "required": { - "enum": [true] - } - } - }, - { - "description": "Parameter in query", - "properties": { - "in": { - "enum": ["query"] - }, - "style": { - "enum": ["form", "spaceDelimited", "pipeDelimited", "deepObject"], - "default": "form" - } - } - }, - { - "description": "Parameter in header", - "properties": { - "in": { - "enum": ["header"] - }, - "style": { - "enum": ["simple"], - "default": "simple" - } - } - }, - { - "description": "Parameter in cookie", - "properties": { - "in": { - "enum": ["cookie"] - }, - "style": { - "enum": ["form"], - "default": "form" - } - } - } - ] - }, - "RequestBody": { - "type": "object", - "required": ["content"], - "properties": { - "description": { - "type": "string" - }, - "content": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/MediaType" - } - }, - "required": { - "type": "boolean", - "default": false - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "SecurityScheme": { - "oneOf": [ - { - "$ref": "#/definitions/APIKeySecurityScheme" - }, - { - "$ref": "#/definitions/HTTPSecurityScheme" - }, - { - "$ref": "#/definitions/OAuth2SecurityScheme" - }, - { - "$ref": "#/definitions/OpenIdConnectSecurityScheme" - } - ] - }, - "APIKeySecurityScheme": { - "type": "object", - "required": ["type", "name", "in"], - "properties": { - "type": { - "type": "string", - "enum": ["apiKey"] - }, - "name": { - "type": "string" - }, - "in": { - "type": "string", - "enum": ["header", "query", "cookie"] - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "HTTPSecurityScheme": { - "type": "object", - "required": ["scheme", "type"], - "properties": { - "scheme": { - "type": "string" - }, - "bearerFormat": { - "type": "string" - }, - "description": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["http"] - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "oneOf": [ - { - "description": "Bearer", - "properties": { - "scheme": { - "enum": ["bearer"] - } - } - }, - { - "description": "Non Bearer", - "not": { - "required": ["bearerFormat"] - }, - "properties": { - "scheme": { - "not": { - "enum": ["bearer"] - } - } - } - } - ] - }, - "OAuth2SecurityScheme": { - "type": "object", - "required": ["type", "flows"], - "properties": { - "type": { - "type": "string", - "enum": ["oauth2"] - }, - "flows": { - "$ref": "#/definitions/OAuthFlows" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "OpenIdConnectSecurityScheme": { - "type": "object", - "required": ["type", "openIdConnectUrl"], - "properties": { - "type": { - "type": "string", - "enum": ["openIdConnect"] - }, - "openIdConnectUrl": { - "type": "string", - "format": "uri-reference" - }, - "description": { - "type": "string" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "OAuthFlows": { - "type": "object", - "properties": { - "implicit": { - "$ref": "#/definitions/ImplicitOAuthFlow" - }, - "password": { - "$ref": "#/definitions/PasswordOAuthFlow" - }, - "clientCredentials": { - "$ref": "#/definitions/ClientCredentialsFlow" - }, - "authorizationCode": { - "$ref": "#/definitions/AuthorizationCodeOAuthFlow" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "ImplicitOAuthFlow": { - "type": "object", - "required": ["authorizationUrl", "scopes"], - "properties": { - "authorizationUrl": { - "type": "string", - "format": "uri-reference" - }, - "refreshUrl": { - "type": "string", - "format": "uri-reference" - }, - "scopes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "PasswordOAuthFlow": { - "type": "object", - "required": ["tokenUrl"], - "properties": { - "tokenUrl": { - "type": "string", - "format": "uri-reference" - }, - "refreshUrl": { - "type": "string", - "format": "uri-reference" - }, - "scopes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "ClientCredentialsFlow": { - "type": "object", - "required": ["tokenUrl"], - "properties": { - "tokenUrl": { - "type": "string", - "format": "uri-reference" - }, - "refreshUrl": { - "type": "string", - "format": "uri-reference" - }, - "scopes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "AuthorizationCodeOAuthFlow": { - "type": "object", - "required": ["authorizationUrl", "tokenUrl"], - "properties": { - "authorizationUrl": { - "type": "string", - "format": "uri-reference" - }, - "tokenUrl": { - "type": "string", - "format": "uri-reference" - }, - "refreshUrl": { - "type": "string", - "format": "uri-reference" - }, - "scopes": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false - }, - "Link": { - "type": "object", - "properties": { - "operationId": { - "type": "string" - }, - "operationRef": { - "type": "string", - "format": "uri-reference" - }, - "parameters": { - "type": "object", - "additionalProperties": {} - }, - "requestBody": {}, - "description": { - "type": "string" - }, - "server": { - "$ref": "#/definitions/Server" - } - }, - "patternProperties": { - "^x-": {} - }, - "additionalProperties": false, - "not": { - "description": "Operation Id and Operation Ref are mutually exclusive", - "required": ["operationId", "operationRef"] - } - }, - "Callback": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/PathItem" - }, - "patternProperties": { - "^x-": {} - } - }, - "Encoding": { - "type": "object", - "properties": { - "contentType": { - "type": "string" - }, - "headers": { - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Header" - } - }, - "style": { - "type": "string", - "enum": ["form", "spaceDelimited", "pipeDelimited", "deepObject"] - }, - "explode": { - "type": "boolean" - }, - "allowReserved": { - "type": "boolean", - "default": false - } - }, - "additionalProperties": false - } - } -} diff --git a/packages/framework/src/framework/ajv/formats.ts b/packages/framework/src/ajv/formats.ts similarity index 100% rename from packages/framework/src/framework/ajv/formats.ts rename to packages/framework/src/ajv/formats.ts diff --git a/packages/framework/src/framework/ajv/index.ts b/packages/framework/src/ajv/index.ts similarity index 100% rename from packages/framework/src/framework/ajv/index.ts rename to packages/framework/src/ajv/index.ts diff --git a/packages/framework/src/framework/base.path.ts b/packages/framework/src/framework/base.path.ts index fd9c3aeb..a3f3dc3a 100644 --- a/packages/framework/src/framework/base.path.ts +++ b/packages/framework/src/framework/base.path.ts @@ -1,5 +1,5 @@ import { compile } from 'path-to-regexp'; -import { OpenAPIV3 } from '.'; +import { OpenAPIV3 } from '..'; interface ServerUrlVariables { [key: string]: ServerUrlValues; diff --git a/packages/framework/src/framework/framework.ts b/packages/framework/src/framework/framework.ts index e12dc7cb..364299c4 100644 --- a/packages/framework/src/framework/framework.ts +++ b/packages/framework/src/framework/framework.ts @@ -8,7 +8,7 @@ import { OpenAPIFrameworkInit, OpenAPIFrameworkVisitor, OpenAPIV3, -} from '.'; +} from '..'; export class OpenAPIFramework { private readonly args: OpenAPIFrameworkArgs; diff --git a/packages/framework/src/framework/openapi.context.ts b/packages/framework/src/framework/openapi.context.ts index 1d79aded..02f32df2 100644 --- a/packages/framework/src/framework/openapi.context.ts +++ b/packages/framework/src/framework/openapi.context.ts @@ -1,4 +1,4 @@ -import { OpenAPIV3 } from '.'; +import { OpenAPIV3 } from '..'; import { Spec, RouteMetadata } from './openapi.spec.loader'; export interface RoutePair { diff --git a/packages/framework/src/framework/openapi.schema.validator.ts b/packages/framework/src/framework/openapi.schema.validator.ts index 7ba442b6..fbd46664 100644 --- a/packages/framework/src/framework/openapi.schema.validator.ts +++ b/packages/framework/src/framework/openapi.schema.validator.ts @@ -2,7 +2,7 @@ import * as Ajv from 'ajv'; import * as draftSchema from 'ajv/lib/refs/json-schema-draft-04.json'; // https://github.com/OAI/OpenAPI-Specification/blob/master/schemas/v3.0/schema.json import * as openapi3Schema from './openapi.v3.schema.json'; -import { OpenAPIV3 } from './index.js'; +import { OpenAPIV3 } from '../index.js'; export class OpenAPISchemaValidator { private validator: Ajv.ValidateFunction; diff --git a/packages/framework/src/framework/openapi.spec.loader.ts b/packages/framework/src/framework/openapi.spec.loader.ts index dbe67ac1..313a9be1 100644 --- a/packages/framework/src/framework/openapi.spec.loader.ts +++ b/packages/framework/src/framework/openapi.spec.loader.ts @@ -1,5 +1,5 @@ import { OpenAPIFramework } from './framework'; -import { OpenAPIFrameworkAPIContext, OpenAPIV3, OpenAPIFrameworkArgs } from '.'; +import { OpenAPIFrameworkAPIContext, OpenAPIV3, OpenAPIFrameworkArgs } from '..'; export interface Spec { apiDoc: OpenAPIV3.Document; diff --git a/packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts b/packages/framework/src/framework/schema.preprocessor.ts similarity index 98% rename from packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts rename to packages/framework/src/framework/schema.preprocessor.ts index 95dc9da1..1e706bc1 100644 --- a/packages/express-openapi-validator/src/middlewares/parsers/schema.preprocessor.ts +++ b/packages/framework/src/framework/schema.preprocessor.ts @@ -1,14 +1,9 @@ import { Ajv } from 'ajv'; -import ajv = require('ajv'); +import { createRequestAjv } from '../ajv'; import * as cloneDeep from 'lodash.clonedeep'; import * as _get from 'lodash.get'; - -import { - Ajv as fAjv, - OpenAPIV3, - Serializer, - ValidateResponseOpts, -} from 'framework'; +import { OpenAPIV3, Serializer, ValidateResponseOpts } from '..'; +import ajv = require('ajv'); interface TraversalStates { req: TraversalState; @@ -94,7 +89,7 @@ export class SchemaPreprocessor { ajvOptions: ajv.Options, validateResponsesOpts: ValidateResponseOpts, ) { - this.ajv = fAjv.createRequestAjv(apiDoc, ajvOptions); + this.ajv = createRequestAjv(apiDoc, ajvOptions); this.apiDoc = apiDoc; this.responseOpts = validateResponsesOpts; } diff --git a/packages/framework/src/framework/index.ts b/packages/framework/src/index.ts similarity index 98% rename from packages/framework/src/framework/index.ts rename to packages/framework/src/index.ts index 846ab719..25991135 100644 --- a/packages/framework/src/framework/index.ts +++ b/packages/framework/src/index.ts @@ -2,9 +2,9 @@ import * as ajv from 'ajv'; import * as multer from 'multer'; import { createRequestAjv, createResponseAjv } from './ajv'; -export { OpenAPIFramework } from './framework'; -export { OpenApiSpecLoader, Spec, RouteMetadata } from './openapi.spec.loader'; -export { OpenApiContext } from './openapi.context'; +export { OpenAPIFramework } from './framework/framework'; +export { OpenApiSpecLoader, Spec, RouteMetadata } from './framework/openapi.spec.loader'; +export { OpenApiContext } from './framework/openapi.context'; export const Ajv = { createRequestAjv, createResponseAjv, diff --git a/packages/framework/tsconfig.json b/packages/framework/tsconfig.json index 135ce33e..5c59217e 100644 --- a/packages/framework/tsconfig.json +++ b/packages/framework/tsconfig.json @@ -1,16 +1,9 @@ { + "extends": "../../tsconfig.json", "compilerOptions": { - "declaration": true, - "target": "es2017", - "lib": ["es2019", "es2019.array"], - "module": "commonjs", - "moduleResolution": "node", "outDir": "dist", - "sourceMap": true, - "resolveJsonModule": true, - "typeRoots": ["./node_modules/@types", "./typings"] + "typeRoots": ["./node_modules/@types"] }, - "exclude": ["node_modules"], "include": [ "src/**/*.ts", ] diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..bc727a71 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "declaration": true, + "target": "es2017", + "lib": ["es2019", "es2019.array"], + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist", + "sourceMap": true, + "resolveJsonModule": true, + "typeRoots": ["./node_modules/@types", "./typings"] + }, + "exclude": ["node_modules"] + } + \ No newline at end of file From f7d642c25e8e0673d2627cb0155fb42020527755 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sat, 16 Jan 2021 21:17:15 -0500 Subject: [PATCH 04/11] help vscode recognize mocha --- packages/express-openapi-validator/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/express-openapi-validator/tsconfig.json b/packages/express-openapi-validator/tsconfig.json index 63d53911..9fd4ec55 100644 --- a/packages/express-openapi-validator/tsconfig.json +++ b/packages/express-openapi-validator/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", - "typeRoots": ["./node_modules/@types", "./typings"] + "typeRoots": ["./node_modules/@types", "./typings", "./packages/node_modules/@types"] }, "include": [ "typings/**/*.d.ts", From 4e146ad18da1b64c1895f8c251d6626c9cc7f74c Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sat, 16 Jan 2021 22:24:17 -0500 Subject: [PATCH 05/11] npm to lerna --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0fdd7018..0610440e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,8 +14,8 @@ install: script: - lerna run compile - lerna run test:coverage -- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run coveralls; fi' -- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then npm run codacy; fi' +- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then lerna run coveralls; fi' +- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then lerna run codacy; fi' env: global: - secure: x+Nxbq8RrOVJyQ7JWNRpXdBmp61rXPKulYPxUwGeIe/ZJwX1QHsy2HAAB2m7aRvAMBAqr2urBaIKgPBmBklyY0elRTD/chUdT5cJiPhMIxBghqkQ1NYqx/WzcCBUrZbRzoQcpAES7sJnUs0PMujKv3wMsujoFJ9b9Z+trHMqD0IztBlg45azAh4A6ApVcDB8j4L+g42kps6d4r5jUt2d4uW537PKXpsnWJMaaj2Pw7pxU2H5kBaeNGnvlK+w9k3porToop7OUG+HBTN2BjofdF1PSHm8fizzFL6/h2x39cLYMxFvHb7oVUKBiWQe8PBXD5+k/X0RgPJMZO9AggMHln5MIihTowGvuSLK/3d95ta/qXTmzG0Csv4J8xWD+koCJm0xpSzsrBSUOPt5ZKN71o0VmLmc7U4Z0aEplZyVcMdTbwA1XeoeXD4UU1fD7BlzYl4oOTB8HlucJILwAZFg0upPB33lQchAUIgoUCDxze3OoG3V1Odcw4u64bXlPrdqgCg8AQZgnrYP+EzKczjGd7pBQZRVxKyq+44JV8JOUAXEka3qQRPvmw5wcAaXgsqU7uv1C6FcQb+j/ZKQ6GlWu8qDzouRR+OqbKeLk2lOvtU08Y32tn6u14+vVNbmsG3iXxGf2+esGcETFP/0EYluPGpo257h/9qC1yMN8ZExey0= From dc151baaa725b4760a73dced6b6c9a073c4f2cc1 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 09:46:40 -0500 Subject: [PATCH 06/11] doc: update contributing --- CONTRIBUTING.md | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1d042550..56006e20 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,10 @@ Contributors are welcome! See something that needs fixing? Got an idea for a new feature? Contribute a [Pull Request](#Create-a-Pull-Request)! +## Background + +This project is set up as a mono-repo. We use `lerna` to manage dependencies. Thus, after the initial `npm install` (to get lerna), you will use `lerna bootstrap` in place of `npm install`. This will ensure all local package / dependies are compiled/transpiled. + ## Easy path to contribution Click the Gitpod badge to setup a ready to code dev env in the cloud. @@ -23,19 +27,41 @@ Click the Gitpod badge to setup a ready to code dev env in the cloud. 2. Install the dependencies ```shell - # From the project directory, run - npm i + # install lerna and common deps + npm install + + # run lerna bootstrap to install module dependencies + # note: use lerna bootstrap, rather than npm install + lerna bootstrap + ``` + +3. Navigate to the package dir you'd like to modify + + **Packages:** + - [framework](/packages/framework) - core schema load and preprocess logic + - [express-openapi-validator](/packages/express-openapi-validator) - the express middleware + + ```shell + # for example, navigate the express validator package + cd packages/express-openapi-validator ``` -Be [Create a Pull Request](#create-a-pull-request) once you've written you code. +4. Be [Create a Pull Request](#create-a-pull-request) once you've written you code. ## Run the tests 3. Run the tests - ```shell - npm test - ``` + Run tests for all packages + ```shell + lerna run test + ``` + + Run tests in the current package: + ```shell + npm run test + ``` + ## Develop From c60cc8e0606fbeb8d0e9061fdb9ce76b4685bbed Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 09:48:00 -0500 Subject: [PATCH 07/11] feat: update gitpod --- .gitpod.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitpod.yml b/.gitpod.yml index 2b06da22..359a18fb 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,2 +1,3 @@ tasks: - init: npm install + command: lerna bootstrap && lerna run compile From 37d86a0e1a56fcc90ebc35587749a48c694b40e9 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 10:12:21 -0500 Subject: [PATCH 08/11] install lerna globally --- .gitpod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitpod.yml b/.gitpod.yml index 359a18fb..98045c68 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,3 +1,3 @@ tasks: - - init: npm install + - init: npm install && npm install lerna -g command: lerna bootstrap && lerna run compile From 60a28cb7b08679055a17963fb0801345bac76e15 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 15:49:45 -0500 Subject: [PATCH 09/11] chore: tsconfig --- packages/express-openapi-validator/.npmignore | 1 + .../test/servers.spec.ts | 4 +-- .../express-openapi-validator/tsconfig.json | 11 +++----- packages/framework/package-lock.json | 2 +- packages/framework/tsconfig.json | 6 ++--- tsconfig.json | 25 ++++++++++--------- 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/packages/express-openapi-validator/.npmignore b/packages/express-openapi-validator/.npmignore index de727f0b..6e1fdf59 100644 --- a/packages/express-openapi-validator/.npmignore +++ b/packages/express-openapi-validator/.npmignore @@ -3,6 +3,7 @@ /assets /examples /example +/dist/test /docs node_modules /src diff --git a/packages/express-openapi-validator/test/servers.spec.ts b/packages/express-openapi-validator/test/servers.spec.ts index ed229c29..a668eaa1 100644 --- a/packages/express-openapi-validator/test/servers.spec.ts +++ b/packages/express-openapi-validator/test/servers.spec.ts @@ -1,9 +1,9 @@ +import 'mocha' import * as path from 'path'; import * as request from 'supertest'; import { createApp } from './common/app'; -import * as packageJson from '../package.json'; -describe(packageJson.name, () => { +describe('servers property', () => { let app = null; before(async () => { diff --git a/packages/express-openapi-validator/tsconfig.json b/packages/express-openapi-validator/tsconfig.json index c7a4e81a..eecc4b37 100644 --- a/packages/express-openapi-validator/tsconfig.json +++ b/packages/express-openapi-validator/tsconfig.json @@ -2,13 +2,10 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "dist", - "typeRoots": [ - "./node_modules/@types", - "./typings" - ], + "typeRoots": ["node_modules/@types", "typings"] }, "include": [ - "typings/**/*.d.ts", "src/**/*.ts" - ] -} + ], + "exclude": ["node_modules"] +} \ No newline at end of file diff --git a/packages/framework/package-lock.json b/packages/framework/package-lock.json index 9fdc0522..fdf509b7 100644 --- a/packages/framework/package-lock.json +++ b/packages/framework/package-lock.json @@ -1,6 +1,6 @@ { "name": "framework", - "version": "4.10.6", + "version": "4.10.8", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/packages/framework/tsconfig.json b/packages/framework/tsconfig.json index 001dba0f..53213ff1 100644 --- a/packages/framework/tsconfig.json +++ b/packages/framework/tsconfig.json @@ -1,10 +1,10 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "outDir": "dist", - "typeRoots": ["./node_modules/@types"] + "outDir": "dist" }, "include": [ "src/**/*.ts" - ] + ], + "exclude": ["node_modules"] } diff --git a/tsconfig.json b/tsconfig.json index 7854a2ea..876504c1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,14 +1,15 @@ { - "compilerOptions": { - "declaration": true, - "target": "es2017", - "lib": ["es2019", "es2019.array"], - "module": "commonjs", - "moduleResolution": "node", - "outDir": "dist", - "sourceMap": true, - "resolveJsonModule": true - }, - "exclude": ["node_modules"] + "compilerOptions": { + "declaration": true, + "target": "es2017", + "lib": ["es2019", "es2019.array"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": false, + "sourceMap": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "typeRoots": ["node_modules/@types"], } - \ No newline at end of file +} \ No newline at end of file From 216ebcd78fb825bb68ace7267c3df43d6a927a83 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 15:56:21 -0500 Subject: [PATCH 10/11] ts config and type fixes --- .../express-openapi-validator/package-lock.json | 12 ++++++++++++ packages/express-openapi-validator/package.json | 2 ++ .../test/servers.spec.ts | 2 +- packages/express-openapi-validator/tsconfig.json | 11 ++++++++++- packages/framework/tsconfig.json | 14 ++++++++++++-- tsconfig.json | 15 --------------- 6 files changed, 37 insertions(+), 19 deletions(-) delete mode 100644 tsconfig.json diff --git a/packages/express-openapi-validator/package-lock.json b/packages/express-openapi-validator/package-lock.json index 403953db..1aad590d 100644 --- a/packages/express-openapi-validator/package-lock.json +++ b/packages/express-openapi-validator/package-lock.json @@ -415,6 +415,12 @@ "@types/node": "*" } }, + "@types/content-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/content-type/-/content-type-1.1.3.tgz", + "integrity": "sha512-pv8VcFrZ3fN93L4rTNIbbUzdkzjEyVMp5mPVjsFfOYTDOZMZiZ8P1dhu+kEv3faYyKzZgLlSvnyQNFg+p/v5ug==", + "dev": true + }, "@types/cookie-parser": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", @@ -453,6 +459,12 @@ "@types/range-parser": "*" } }, + "@types/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-JTkIazWsZYHon19I15kuPeJP/Cg6aLFBSXxF8Pj4uqxDkKo3+jqHy6u55ebTJaMvxbutjsIHqLx+osisSQIHbA==", + "dev": true + }, "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", diff --git a/packages/express-openapi-validator/package.json b/packages/express-openapi-validator/package.json index 2b9c95c4..b35f9b3b 100644 --- a/packages/express-openapi-validator/package.json +++ b/packages/express-openapi-validator/package.json @@ -47,8 +47,10 @@ }, "devDependencies": { "@types/ajv": "^1.0.0", + "@types/content-type": "^1.1.3", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.8", + "@types/media-typer": "^1.1.0", "@types/mocha": "^8.2.0", "@types/morgan": "^1.9.1", "@types/multer": "^1.4.4", diff --git a/packages/express-openapi-validator/test/servers.spec.ts b/packages/express-openapi-validator/test/servers.spec.ts index a668eaa1..825c435c 100644 --- a/packages/express-openapi-validator/test/servers.spec.ts +++ b/packages/express-openapi-validator/test/servers.spec.ts @@ -37,7 +37,7 @@ describe('servers property', () => { request(app).get('/api/v3/petstore/ping').send({}).expect(200)); }); -describe(packageJson.name, () => { +describe('servers property test', () => { let app = null; before(async () => { diff --git a/packages/express-openapi-validator/tsconfig.json b/packages/express-openapi-validator/tsconfig.json index eecc4b37..bff449c2 100644 --- a/packages/express-openapi-validator/tsconfig.json +++ b/packages/express-openapi-validator/tsconfig.json @@ -1,6 +1,15 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { + "declaration": true, + "target": "es2017", + "lib": ["es2019", "es2019.array"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": false, + "sourceMap": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, "outDir": "dist", "typeRoots": ["node_modules/@types", "typings"] }, diff --git a/packages/framework/tsconfig.json b/packages/framework/tsconfig.json index 53213ff1..82f19d8f 100644 --- a/packages/framework/tsconfig.json +++ b/packages/framework/tsconfig.json @@ -1,7 +1,17 @@ { - "extends": "../../tsconfig.json", "compilerOptions": { - "outDir": "dist" + "declaration": true, + "target": "es2017", + "lib": ["es2019", "es2019.array"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": false, + "sourceMap": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "dist", + "typeRoots": ["node_modules/@types"] }, "include": [ "src/**/*.ts" diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index 876504c1..00000000 --- a/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "target": "es2017", - "lib": ["es2019", "es2019.array"], - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": false, - "sourceMap": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "typeRoots": ["node_modules/@types"], - } -} \ No newline at end of file From edb05866b97da1517e74fc02d5269ac4ce338f65 Mon Sep 17 00:00:00 2001 From: Carmine DiMascio Date: Sun, 17 Jan 2021 16:28:31 -0500 Subject: [PATCH 11/11] fix: vscode errors --- lerna.json | 2 +- packages/express-openapi-validator/package-lock.json | 6 ++++++ packages/express-openapi-validator/package.json | 1 + packages/express-openapi-validator/src/index.ts | 1 - .../express-openapi-validator/test/356.campaign.spec.ts | 3 +-- packages/express-openapi-validator/test/440.spec.ts | 3 +-- 6 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lerna.json b/lerna.json index 3cc2e9ac..3ee4d808 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { "packages": ["packages/*"], - "version": "1.0.0" + "version": "4.10.8" } \ No newline at end of file diff --git a/packages/express-openapi-validator/package-lock.json b/packages/express-openapi-validator/package-lock.json index 1aad590d..c4f11d81 100644 --- a/packages/express-openapi-validator/package-lock.json +++ b/packages/express-openapi-validator/package-lock.json @@ -400,6 +400,12 @@ "@types/node": "*" } }, + "@types/chai": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.14.tgz", + "integrity": "sha512-G+ITQPXkwTrslfG5L/BksmbLUA0M1iybEsmCWPqzSxsRRhJZimBKJkoMi8fr/CPygPTj4zO5pJH7I2/cm9M7SQ==", + "dev": true + }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", diff --git a/packages/express-openapi-validator/package.json b/packages/express-openapi-validator/package.json index b35f9b3b..6242e037 100644 --- a/packages/express-openapi-validator/package.json +++ b/packages/express-openapi-validator/package.json @@ -47,6 +47,7 @@ }, "devDependencies": { "@types/ajv": "^1.0.0", + "@types/chai": "^4.2.14", "@types/content-type": "^1.1.3", "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.8", diff --git a/packages/express-openapi-validator/src/index.ts b/packages/express-openapi-validator/src/index.ts index 634d9fe9..c78af6ce 100644 --- a/packages/express-openapi-validator/src/index.ts +++ b/packages/express-openapi-validator/src/index.ts @@ -1,7 +1,6 @@ import * as res from './resolvers'; import { OpenApiValidator, OpenApiValidatorOpts } from './openapi.validator'; import { - OpenAPIV3, OpenApiSpecLoader, InternalServerError, UnsupportedMediaType, diff --git a/packages/express-openapi-validator/test/356.campaign.spec.ts b/packages/express-openapi-validator/test/356.campaign.spec.ts index 57004cd5..a9934a3e 100644 --- a/packages/express-openapi-validator/test/356.campaign.spec.ts +++ b/packages/express-openapi-validator/test/356.campaign.spec.ts @@ -2,10 +2,9 @@ import * as path from 'path'; import * as express from 'express'; import * as request from 'supertest'; import { createApp } from './common/app'; -import * as packageJson from '../package.json'; import { expect } from 'chai'; -describe(packageJson.name, () => { +describe('issue #356', () => { let app = null; before(async () => { diff --git a/packages/express-openapi-validator/test/440.spec.ts b/packages/express-openapi-validator/test/440.spec.ts index fdb71658..a17dc2f0 100644 --- a/packages/express-openapi-validator/test/440.spec.ts +++ b/packages/express-openapi-validator/test/440.spec.ts @@ -1,10 +1,9 @@ import * as express from 'express'; import * as request from 'supertest'; import { createApp } from './common/app'; -import * as packageJson from '../package.json'; import { OpenAPIV3 } from 'framework'; -describe(packageJson.name, () => { +describe('issue #440', () => { let app = null; before(async () => {