├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── index.ts ├── lib ├── Errors.ts ├── ResponseValidator.ts └── Types.ts ├── package-lock.json ├── package.json └── tsconfig.json /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | .DS_Store 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Oleksandr Khotemskyi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # response-openapi-validator 2 | 3 | This library allows to match your existing response against your swagger/openapi docs. 4 | 5 | - Does lookup in your docs, and finds schema defined for provided response 6 | - Uses AJV to validate response body against found schema 7 | - Provides nice and clean errors 8 | - Framework/Stack agnostic (works with everything) 9 | - OpenApi v3 support is not yet verified 10 | 11 | 12 | ```typescript 13 | import { ResponseValidator } from "response-openapi-validator"; 14 | 15 | const validator = new ResponseValidator({ 16 | // Also can be URL 17 | openApiSpecPath: "./.temp/open_api_docs.json", 18 | }); 19 | 20 | const response = await got("http://someserver.com/api/something"); 21 | 22 | await validator.assertResponse({ 23 | method: response.request?.options?.method, 24 | requestUrl: response?.request?.requestUrl, 25 | statusCode: response?.statusCode, 26 | body: response.body, 27 | }); 28 | ``` 29 | 30 | ### Option: ajvOptions 31 | 32 | AJV is used to match found JSON schema against body. 33 | You can define AJV options by passing param: 34 | 35 | ```typescript 36 | const validator = new ResponseValidator({ 37 | // Also can be URL 38 | openApiSpecPath: "./.temp/open_api_docs.json", 39 | // You can see all AJV options here 40 | // https://github.com/ajv-validator/ajv#options 41 | ajvOptions: { 42 | // I recommend to keep allErrors, verbose, and jsonPointers options enabled 43 | allErrors: true, 44 | verbose: true, 45 | jsonPointers: true, 46 | 47 | // Define additional JSON schema formats, if needed 48 | formats: { 49 | double: "[+-]?\\d*\\.?\\d+", 50 | int32: /^(-?\d{1,9}|-?1\d{9}|-?20\d{8}|-?21[0-3]\d{7}|-?214[0-6]\d{6}|-?2147[0-3]\d{5}|-?21474[0-7]\d{4}|-?214748[012]\d{4}|-?2147483[0-5]\d{3}|-?21474836[0-3]\d{2}|214748364[0-7]|-214748364[0-8])$/, 51 | int64: /^\d+$/, 52 | }, 53 | }, 54 | }); 55 | ``` 56 | 57 | ### Option: apiPathPrefix 58 | 59 | Sometimes API has prefix part, which is not defined in docs. 60 | 61 | Real path: 62 | 63 | ``` 64 | /core/user/create 65 | ``` 66 | 67 | Path defined in docs: 68 | 69 | ``` 70 | /user/create 71 | ``` 72 | 73 | You can specify such prefix in options: 74 | 75 | ```typescript 76 | const validator = new OpenApiValidator({ 77 | apiPathPrefix: '/core' 78 | openApiSpecPath: "./.temp/open_api_docs.json", 79 | }); 80 | 81 | await validator.assertResponse({ 82 | method: response.request?.options?.method, 83 | requestUrl: response?.request?.requestUrl, 84 | statusCode: response?.statusCode, 85 | body: response.body, 86 | }); 87 | ``` 88 | -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | export { ResponseValidator } from './lib/ResponseValidator' -------------------------------------------------------------------------------- /lib/Errors.ts: -------------------------------------------------------------------------------- 1 | import type * as Ajv from 'ajv'; 2 | import { ResponseToValidate } from "./Types" 3 | 4 | export class OpenApiValidationError extends Error { 5 | isOpenApiValidationError: boolean = true 6 | } 7 | 8 | export class ResponseDoesNotMatchJSONSchemaError extends OpenApiValidationError { 9 | constructor(public validationResult: { response: ResponseToValidate, schema: any, validationErrors: Ajv.ErrorObject[] }) { 10 | super(` 11 | Response does not match defined Open API JSON schema. 12 | 13 | Response: 14 | ${validationResult.response.method} | ${validationResult.response.requestUrl} | ${validationResult.response.statusCode} 15 | 16 | Body: 17 | ${JSON.stringify(validationResult.response.body, null, 2)} 18 | 19 | Validation errors: 20 | ${JSON.stringify(validationResult.validationErrors, null, 2)} 21 | `) 22 | this.name = 'ResponseDoesNotMatchJSONSchemaError' 23 | } 24 | } 25 | 26 | export class JSONSchemaMissingError extends OpenApiValidationError { 27 | constructor(response: ResponseToValidate) { 28 | super(` 29 | OpenApi spec does not contain body schema found for response: 30 | ${response.method} | ${response.requestUrl} | ${response.statusCode} 31 | Validation cannot be done 32 | `) 33 | this.name = 'JSONSchemaMissingError' 34 | } 35 | } 36 | 37 | export class MultipleJSONSchemasDefinedError extends OpenApiValidationError { 38 | constructor(response: ResponseToValidate) { 39 | super(` 40 | OpenApi has multiple schemas defined for response: 41 | ${response.method} | ${response.requestUrl} | ${response.statusCode} 42 | Validation cannot be done 43 | `) 44 | this.name = 'MultipleJSONSchemasDefinedError' 45 | } 46 | } 47 | 48 | export class JSONSchemaCannotBeCompiledError extends OpenApiValidationError { 49 | constructor(response: ResponseToValidate, jsonSchemaCompilationError: Error) { 50 | super(` 51 | JSON schema for response: 52 | ${response.method} | ${response.requestUrl} | ${response.statusCode} 53 | is found, but cannot be used since AJV cannot compile schema. This is OpenApi spec issue. 54 | 55 | Got AJV error ${jsonSchemaCompilationError.name} with message: 56 | ${jsonSchemaCompilationError.message} 57 | 58 | Validation cannot be done 59 | `) 60 | this.name = 'JSONSchemaCannotBeCompiledError' 61 | } 62 | } 63 | 64 | export class UrlIsNotDescribedInOpenApiError extends OpenApiValidationError { 65 | constructor(url: string) { 66 | super(` 67 | OpenApi specification does not contain specification for ${url} 68 | `) 69 | this.name = 'UrlIsNotDescribedInOpenApiError' 70 | } 71 | } -------------------------------------------------------------------------------- /lib/ResponseValidator.ts: -------------------------------------------------------------------------------- 1 | import * as OpenAPIParser from '@readme/openapi-parser'; 2 | import URItemplate from 'uri-templates'; 3 | import Ajv from "ajv/dist/core"; 4 | import addFormats from 'ajv-formats' 5 | import type { OpenAPI, OpenAPIV2, OpenAPIV3 } from "openapi-types"; 6 | 7 | import { 8 | UrlIsNotDescribedInOpenApiError, JSONSchemaMissingError, MultipleJSONSchemasDefinedError, 9 | JSONSchemaCannotBeCompiledError, ResponseDoesNotMatchJSONSchemaError 10 | } from "./Errors"; 11 | import { ResponseToValidate, ResponseValidatorOptions } from "./Types"; 12 | 13 | 14 | 15 | const defaultOptions: ResponseValidatorOptions = { 16 | apiPathPrefix: '', 17 | openApiSpecPath: '', // TODO: throw error when path not provided 18 | ajvOptions: { 19 | allErrors: true, 20 | verbose: true, 21 | strict: 'log' 22 | } 23 | } 24 | 25 | export class ResponseValidator { 26 | private readonly options: ResponseValidatorOptions; 27 | private cachedApi: OpenAPI.Document | null = null; 28 | 29 | constructor(options: ResponseValidatorOptions) { 30 | this.options = { 31 | ...defaultOptions, 32 | ...options 33 | } 34 | } 35 | 36 | protected async loadApiDocs(): Promise { 37 | if (this.cachedApi === null) { 38 | this.cachedApi = await (OpenAPIParser as any).dereference(this.options.openApiSpecPath); 39 | } 40 | return this.cachedApi; 41 | } 42 | 43 | protected async findMatchingPathInDocs(url: string): Promise> { 44 | const api = await this.loadApiDocs(); 45 | const urlPath = new URL(url).pathname; 46 | 47 | for (const template of Object.keys(api.paths)) { 48 | if (`${this.options.apiPathPrefix}${template}` === urlPath) { 49 | return { [template]: api.paths[template] as OpenAPIV3.PathItemObject }; 50 | } 51 | } 52 | 53 | const matchingPaths = Object.keys(api.paths).filter(template => { 54 | try { 55 | const templatePath = `${this.options.apiPathPrefix}${template}`; 56 | if (templatePath.split('/').length !== urlPath.split('/').length) { 57 | return false; 58 | } 59 | return (URItemplate(templatePath) as any).test(urlPath); 60 | } catch (err) { 61 | return false; 62 | } 63 | }).filter(Boolean); 64 | 65 | if (matchingPaths.length === 0) { 66 | throw new UrlIsNotDescribedInOpenApiError(url); 67 | } 68 | 69 | return Object.fromEntries( 70 | matchingPaths.map(pth => [pth, api.paths[pth] as OpenAPIV3.PathItemObject]) 71 | ) as Partial; 72 | } 73 | 74 | public async assertResponse(response: ResponseToValidate): Promise { 75 | if (!response) { 76 | throw new Error('response argument is not defined. This is testing framework issue, not real bug') 77 | } 78 | const findSchemaInPath = function (path) { 79 | if (path.schema !== undefined) { 80 | return path.schema 81 | } 82 | let result, property 83 | for (property in path) { 84 | if (path.hasOwnProperty(property) &&typeof path[property] === 'object') { 85 | result = findSchemaInPath(path[property]) 86 | if (result) { 87 | return result 88 | } 89 | } 90 | } 91 | return result 92 | } 93 | const matchingPaths = await this.findMatchingPathInDocs(response.requestUrl); 94 | const schemas = Object.values(matchingPaths) 95 | .flatMap(pathObj => { 96 | const method = response.method.toLowerCase() as keyof OpenAPIV3.PathItemObject; 97 | const methodObj = pathObj[method] as OpenAPIV3.OperationObject | undefined; 98 | const responseObj = methodObj?.responses?.[response.statusCode]; 99 | return responseObj ? [findSchemaInPath(responseObj)] : []; 100 | }) 101 | .filter((schema): schema is NonNullable> => 102 | schema !== undefined && schema !== null 103 | ); 104 | 105 | if (schemas.length === 0) { 106 | throw new JSONSchemaMissingError(response) 107 | } 108 | if (schemas.length > 1) { 109 | throw new MultipleJSONSchemasDefinedError(response) 110 | } 111 | const schema = schemas[0]; 112 | 113 | const ajv = new Ajv({ 114 | ...this.options.ajvOptions, 115 | strict: false 116 | }); 117 | (addFormats as any)(ajv); 118 | for (const key in this.options.ajvOptions.formats) { 119 | ajv.addFormat(key, this.options.ajvOptions.formats[key]) 120 | } 121 | let validate 122 | try { 123 | validate = ajv.compile(schema); 124 | } catch (jsonSchemaCompilationError) { 125 | throw new JSONSchemaCannotBeCompiledError(response, jsonSchemaCompilationError); 126 | } 127 | 128 | const valid = await validate(response.body); 129 | if (!valid) { 130 | throw new ResponseDoesNotMatchJSONSchemaError({ 131 | response: { 132 | method: response.method, 133 | requestUrl: response.requestUrl, 134 | statusCode: response.statusCode, 135 | body: response.body, 136 | }, 137 | schema: schema, 138 | validationErrors: validate.errors 139 | }) 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /lib/Types.ts: -------------------------------------------------------------------------------- 1 | import type * as Ajv from 'ajv'; 2 | 3 | export interface ResponseValidatorOptions { 4 | apiPathPrefix?: string, 5 | openApiSpecPath: string 6 | ajvOptions?: Ajv.Options 7 | } 8 | 9 | export interface ResponseToValidate { 10 | requestUrl: string, 11 | statusCode: number, 12 | method: string, 13 | body: any 14 | } -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "response-openapi-validator", 3 | "version": "2.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "response-openapi-validator", 9 | "version": "2.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@readme/openapi-parser": "^2.6.0", 13 | "ajv": "8.17.1", 14 | "ajv-formats": "3.0.1", 15 | "uri-templates": "0.2.0" 16 | }, 17 | "devDependencies": { 18 | "@types/node": "20.14.11", 19 | "typescript": "5.5.3" 20 | } 21 | }, 22 | "node_modules/@apidevtools/swagger-methods": { 23 | "version": "3.0.2", 24 | "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz", 25 | "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==" 26 | }, 27 | "node_modules/@babel/code-frame": { 28 | "version": "7.24.7", 29 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", 30 | "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", 31 | "dependencies": { 32 | "@babel/highlight": "^7.24.7", 33 | "picocolors": "^1.0.0" 34 | }, 35 | "engines": { 36 | "node": ">=6.9.0" 37 | } 38 | }, 39 | "node_modules/@babel/helper-validator-identifier": { 40 | "version": "7.24.7", 41 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", 42 | "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", 43 | "engines": { 44 | "node": ">=6.9.0" 45 | } 46 | }, 47 | "node_modules/@babel/highlight": { 48 | "version": "7.24.7", 49 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", 50 | "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", 51 | "dependencies": { 52 | "@babel/helper-validator-identifier": "^7.24.7", 53 | "chalk": "^2.4.2", 54 | "js-tokens": "^4.0.0", 55 | "picocolors": "^1.0.0" 56 | }, 57 | "engines": { 58 | "node": ">=6.9.0" 59 | } 60 | }, 61 | "node_modules/@babel/highlight/node_modules/ansi-styles": { 62 | "version": "3.2.1", 63 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 64 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 65 | "dependencies": { 66 | "color-convert": "^1.9.0" 67 | }, 68 | "engines": { 69 | "node": ">=4" 70 | } 71 | }, 72 | "node_modules/@babel/highlight/node_modules/chalk": { 73 | "version": "2.4.2", 74 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 75 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 76 | "dependencies": { 77 | "ansi-styles": "^3.2.1", 78 | "escape-string-regexp": "^1.0.5", 79 | "supports-color": "^5.3.0" 80 | }, 81 | "engines": { 82 | "node": ">=4" 83 | } 84 | }, 85 | "node_modules/@babel/highlight/node_modules/color-convert": { 86 | "version": "1.9.3", 87 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 88 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 89 | "dependencies": { 90 | "color-name": "1.1.3" 91 | } 92 | }, 93 | "node_modules/@babel/highlight/node_modules/color-name": { 94 | "version": "1.1.3", 95 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 96 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 97 | }, 98 | "node_modules/@babel/highlight/node_modules/has-flag": { 99 | "version": "3.0.0", 100 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 101 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 102 | "engines": { 103 | "node": ">=4" 104 | } 105 | }, 106 | "node_modules/@babel/highlight/node_modules/supports-color": { 107 | "version": "5.5.0", 108 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 109 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 110 | "dependencies": { 111 | "has-flag": "^3.0.0" 112 | }, 113 | "engines": { 114 | "node": ">=4" 115 | } 116 | }, 117 | "node_modules/@babel/runtime": { 118 | "version": "7.24.8", 119 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", 120 | "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", 121 | "dependencies": { 122 | "regenerator-runtime": "^0.14.0" 123 | }, 124 | "engines": { 125 | "node": ">=6.9.0" 126 | } 127 | }, 128 | "node_modules/@humanwhocodes/momoa": { 129 | "version": "2.0.4", 130 | "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz", 131 | "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==", 132 | "engines": { 133 | "node": ">=10.10.0" 134 | } 135 | }, 136 | "node_modules/@jsdevtools/ono": { 137 | "version": "7.1.3", 138 | "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", 139 | "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==" 140 | }, 141 | "node_modules/@readme/better-ajv-errors": { 142 | "version": "1.6.0", 143 | "resolved": "https://registry.npmjs.org/@readme/better-ajv-errors/-/better-ajv-errors-1.6.0.tgz", 144 | "integrity": "sha512-9gO9rld84Jgu13kcbKRU+WHseNhaVt76wYMeRDGsUGYxwJtI3RmEJ9LY9dZCYQGI8eUZLuxb5qDja0nqklpFjQ==", 145 | "dependencies": { 146 | "@babel/code-frame": "^7.16.0", 147 | "@babel/runtime": "^7.21.0", 148 | "@humanwhocodes/momoa": "^2.0.3", 149 | "chalk": "^4.1.2", 150 | "json-to-ast": "^2.0.3", 151 | "jsonpointer": "^5.0.0", 152 | "leven": "^3.1.0" 153 | }, 154 | "engines": { 155 | "node": ">=14" 156 | }, 157 | "peerDependencies": { 158 | "ajv": "4.11.8 - 8" 159 | } 160 | }, 161 | "node_modules/@readme/json-schema-ref-parser": { 162 | "version": "1.2.0", 163 | "resolved": "https://registry.npmjs.org/@readme/json-schema-ref-parser/-/json-schema-ref-parser-1.2.0.tgz", 164 | "integrity": "sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==", 165 | "dependencies": { 166 | "@jsdevtools/ono": "^7.1.3", 167 | "@types/json-schema": "^7.0.6", 168 | "call-me-maybe": "^1.0.1", 169 | "js-yaml": "^4.1.0" 170 | } 171 | }, 172 | "node_modules/@readme/json-schema-ref-parser/node_modules/argparse": { 173 | "version": "2.0.1", 174 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 175 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" 176 | }, 177 | "node_modules/@readme/json-schema-ref-parser/node_modules/js-yaml": { 178 | "version": "4.1.0", 179 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 180 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 181 | "dependencies": { 182 | "argparse": "^2.0.1" 183 | }, 184 | "bin": { 185 | "js-yaml": "bin/js-yaml.js" 186 | } 187 | }, 188 | "node_modules/@readme/openapi-parser": { 189 | "version": "2.6.0", 190 | "resolved": "https://registry.npmjs.org/@readme/openapi-parser/-/openapi-parser-2.6.0.tgz", 191 | "integrity": "sha512-pyFJXezWj9WI1O+gdp95CoxfY+i+Uq3kKk4zXIFuRAZi9YnHpHOpjumWWr67wkmRTw19Hskh9spyY0Iyikf3fA==", 192 | "dependencies": { 193 | "@apidevtools/swagger-methods": "^3.0.2", 194 | "@jsdevtools/ono": "^7.1.3", 195 | "@readme/better-ajv-errors": "^1.6.0", 196 | "@readme/json-schema-ref-parser": "^1.2.0", 197 | "@readme/openapi-schemas": "^3.1.0", 198 | "ajv": "^8.12.0", 199 | "ajv-draft-04": "^1.0.0", 200 | "call-me-maybe": "^1.0.1" 201 | }, 202 | "engines": { 203 | "node": ">=18" 204 | }, 205 | "peerDependencies": { 206 | "openapi-types": ">=7" 207 | } 208 | }, 209 | "node_modules/@readme/openapi-schemas": { 210 | "version": "3.1.0", 211 | "resolved": "https://registry.npmjs.org/@readme/openapi-schemas/-/openapi-schemas-3.1.0.tgz", 212 | "integrity": "sha512-9FC/6ho8uFa8fV50+FPy/ngWN53jaUu4GRXlAjcxIRrzhltJnpKkBG2Tp0IDraFJeWrOpk84RJ9EMEEYzaI1Bw==", 213 | "engines": { 214 | "node": ">=18" 215 | } 216 | }, 217 | "node_modules/@types/json-schema": { 218 | "version": "7.0.15", 219 | "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 220 | "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" 221 | }, 222 | "node_modules/@types/node": { 223 | "version": "20.14.11", 224 | "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", 225 | "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", 226 | "dev": true, 227 | "dependencies": { 228 | "undici-types": "~5.26.4" 229 | } 230 | }, 231 | "node_modules/ajv": { 232 | "version": "8.17.1", 233 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", 234 | "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", 235 | "dependencies": { 236 | "fast-deep-equal": "^3.1.3", 237 | "fast-uri": "^3.0.1", 238 | "json-schema-traverse": "^1.0.0", 239 | "require-from-string": "^2.0.2" 240 | }, 241 | "funding": { 242 | "type": "github", 243 | "url": "https://github.com/sponsors/epoberezkin" 244 | } 245 | }, 246 | "node_modules/ajv-draft-04": { 247 | "version": "1.0.0", 248 | "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", 249 | "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", 250 | "peerDependencies": { 251 | "ajv": "^8.5.0" 252 | }, 253 | "peerDependenciesMeta": { 254 | "ajv": { 255 | "optional": true 256 | } 257 | } 258 | }, 259 | "node_modules/ajv-formats": { 260 | "version": "3.0.1", 261 | "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", 262 | "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", 263 | "dependencies": { 264 | "ajv": "^8.0.0" 265 | }, 266 | "peerDependencies": { 267 | "ajv": "^8.0.0" 268 | }, 269 | "peerDependenciesMeta": { 270 | "ajv": { 271 | "optional": true 272 | } 273 | } 274 | }, 275 | "node_modules/ansi-styles": { 276 | "version": "4.3.0", 277 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 278 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 279 | "dependencies": { 280 | "color-convert": "^2.0.1" 281 | }, 282 | "engines": { 283 | "node": ">=8" 284 | }, 285 | "funding": { 286 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 287 | } 288 | }, 289 | "node_modules/call-me-maybe": { 290 | "version": "1.0.2", 291 | "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz", 292 | "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==" 293 | }, 294 | "node_modules/chalk": { 295 | "version": "4.1.2", 296 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 297 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 298 | "dependencies": { 299 | "ansi-styles": "^4.1.0", 300 | "supports-color": "^7.1.0" 301 | }, 302 | "engines": { 303 | "node": ">=10" 304 | }, 305 | "funding": { 306 | "url": "https://github.com/chalk/chalk?sponsor=1" 307 | } 308 | }, 309 | "node_modules/code-error-fragment": { 310 | "version": "0.0.230", 311 | "resolved": "https://registry.npmjs.org/code-error-fragment/-/code-error-fragment-0.0.230.tgz", 312 | "integrity": "sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==", 313 | "engines": { 314 | "node": ">= 4" 315 | } 316 | }, 317 | "node_modules/color-convert": { 318 | "version": "2.0.1", 319 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 320 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 321 | "dependencies": { 322 | "color-name": "~1.1.4" 323 | }, 324 | "engines": { 325 | "node": ">=7.0.0" 326 | } 327 | }, 328 | "node_modules/color-name": { 329 | "version": "1.1.4", 330 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 331 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 332 | }, 333 | "node_modules/escape-string-regexp": { 334 | "version": "1.0.5", 335 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 336 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 337 | "engines": { 338 | "node": ">=0.8.0" 339 | } 340 | }, 341 | "node_modules/fast-deep-equal": { 342 | "version": "3.1.3", 343 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 344 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 345 | }, 346 | "node_modules/fast-uri": { 347 | "version": "3.0.1", 348 | "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", 349 | "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==" 350 | }, 351 | "node_modules/grapheme-splitter": { 352 | "version": "1.0.4", 353 | "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", 354 | "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" 355 | }, 356 | "node_modules/has-flag": { 357 | "version": "4.0.0", 358 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 359 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 360 | "engines": { 361 | "node": ">=8" 362 | } 363 | }, 364 | "node_modules/js-tokens": { 365 | "version": "4.0.0", 366 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 367 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 368 | }, 369 | "node_modules/json-schema-traverse": { 370 | "version": "1.0.0", 371 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 372 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" 373 | }, 374 | "node_modules/json-to-ast": { 375 | "version": "2.1.0", 376 | "resolved": "https://registry.npmjs.org/json-to-ast/-/json-to-ast-2.1.0.tgz", 377 | "integrity": "sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==", 378 | "dependencies": { 379 | "code-error-fragment": "0.0.230", 380 | "grapheme-splitter": "^1.0.4" 381 | }, 382 | "engines": { 383 | "node": ">= 4" 384 | } 385 | }, 386 | "node_modules/jsonpointer": { 387 | "version": "5.0.1", 388 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", 389 | "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", 390 | "engines": { 391 | "node": ">=0.10.0" 392 | } 393 | }, 394 | "node_modules/leven": { 395 | "version": "3.1.0", 396 | "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", 397 | "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", 398 | "engines": { 399 | "node": ">=6" 400 | } 401 | }, 402 | "node_modules/openapi-types": { 403 | "version": "12.1.3", 404 | "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", 405 | "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==", 406 | "peer": true 407 | }, 408 | "node_modules/picocolors": { 409 | "version": "1.0.1", 410 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", 411 | "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" 412 | }, 413 | "node_modules/regenerator-runtime": { 414 | "version": "0.14.1", 415 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", 416 | "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" 417 | }, 418 | "node_modules/require-from-string": { 419 | "version": "2.0.2", 420 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", 421 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", 422 | "engines": { 423 | "node": ">=0.10.0" 424 | } 425 | }, 426 | "node_modules/supports-color": { 427 | "version": "7.2.0", 428 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 429 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 430 | "dependencies": { 431 | "has-flag": "^4.0.0" 432 | }, 433 | "engines": { 434 | "node": ">=8" 435 | } 436 | }, 437 | "node_modules/typescript": { 438 | "version": "5.5.3", 439 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", 440 | "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", 441 | "dev": true, 442 | "bin": { 443 | "tsc": "bin/tsc", 444 | "tsserver": "bin/tsserver" 445 | }, 446 | "engines": { 447 | "node": ">=14.17" 448 | } 449 | }, 450 | "node_modules/undici-types": { 451 | "version": "5.26.5", 452 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", 453 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", 454 | "dev": true 455 | }, 456 | "node_modules/uri-templates": { 457 | "version": "0.2.0", 458 | "resolved": "https://registry.npmjs.org/uri-templates/-/uri-templates-0.2.0.tgz", 459 | "integrity": "sha512-EWkjYEN0L6KOfEoOH6Wj4ghQqU7eBZMJqRHQnxQAq+dSEzRPClkWjf8557HkWQXF6BrAUoLSAyy9i3RVTliaNg==" 460 | } 461 | } 462 | } 463 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "response-openapi-validator", 3 | "version": "2.0.2", 4 | "description": "Asserts your responses using Swagger/OpenApi docs. Useful for API testing.", 5 | "main": "dist/index.js", 6 | "types": "dist/index.d.ts", 7 | "scripts": { 8 | "build": "tsc" 9 | }, 10 | "author": "Oleksandr Khotemskyi ", 11 | "license": "MIT", 12 | "files": [ 13 | "dist" 14 | ], 15 | "dependencies": { 16 | "@readme/openapi-parser": "^2.6.0", 17 | "ajv": "8.17.1", 18 | "ajv-formats": "3.0.1", 19 | "uri-templates": "0.2.0" 20 | }, 21 | "devDependencies": { 22 | "@types/node": "20.14.11", 23 | "typescript": "5.5.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./dist", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": false, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | 44 | /* Module Resolution Options */ 45 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 46 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 47 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 48 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 49 | // "typeRoots": [], /* List of folders to include type definitions from. */ 50 | // "types": [], /* Type declaration files to be included in compilation. */ 51 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 52 | // "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 53 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 54 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 55 | 56 | /* Source Map Options */ 57 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 58 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 59 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 60 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 61 | 62 | /* Experimental Options */ 63 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 64 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 65 | 66 | /* Advanced Options */ 67 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 68 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 69 | } 70 | } 71 | --------------------------------------------------------------------------------