diff --git a/src/impl/v2/index.js b/src/impl/v2/index.js index 1fe1e13..92c4ad4 100644 --- a/src/impl/v2/index.js +++ b/src/impl/v2/index.js @@ -8,7 +8,7 @@ const cloneDeep = require('lodash.clonedeep'), // CONSTANTS -const PATH__EXAMPLES = '$..examples[?(@property.match(/[\/+]json/))]', +const PATH__EXAMPLES = '$..examples[?(@property && typeof @property === "string" && @property.match(/[\/+]json/))]', PROP__SCHEMA = 'schema', PROP__EXAMPLES = 'examples'; diff --git a/src/impl/v3/index.js b/src/impl/v3/index.js index 8111dc9..93a3730 100644 --- a/src/impl/v3/index.js +++ b/src/impl/v3/index.js @@ -9,8 +9,9 @@ const cloneDeep = require('lodash.clonedeep'), // CONSTANTS -const RESPONSES = '$..responses..content[?(@property.match(/[\/+]json/))]'; -const REQUEST = '$..requestBody.content[?(@property.match(/[\/+]json/))]'; +// eslint-disable-next-line max-len +const RESPONSES = '$..responses..content[?(@property && typeof @property === "string" && @property.match(/[\/+]json/))]'; +const REQUEST = '$..requestBody.content[?(@property && typeof @property === "string" && @property.match(/[\/+]json/))]'; const SINGLE_EXAMPLE = '.example'; const MANY_EXAMPLES = '.examples.*.value'; diff --git a/test/data/v2/response-valid-content-array.yaml b/test/data/v2/response-valid-content-array.yaml new file mode 100644 index 0000000..297488b --- /dev/null +++ b/test/data/v2/response-valid-content-array.yaml @@ -0,0 +1,32 @@ +swagger: '2.0' +info: + title: API + version: 1.0.0 +paths: + /metrics: + get: + summary: Get info + operationId: get_info + description: | + This API hook returns server metrics. + produces: + - application/json + responses: + 200: + description: OK + schema: + type: object + properties: + examples: + type: array + description: Array of valid entries + items: + type: object + properties: + type: + type: integer + description: RR type of entry + examples: + application/json: + examples: + - type: 0 diff --git a/test/data/v3/response-valid-content-array.yaml b/test/data/v3/response-valid-content-array.yaml new file mode 100644 index 0000000..a3802df --- /dev/null +++ b/test/data/v3/response-valid-content-array.yaml @@ -0,0 +1,32 @@ +openapi: 3.0.2 +components: + paths: + metrics: + get: + summary: Get info + operationId: "get_info" + description: | + This API hook returns server metrics. + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + content: + type: array + description: Array of valid entries + items: + type: object + properties: + type: + type: integer + description: RR type of entry + examples: + metrics: + summary: Server metrics + value: + content: + - type: 0 diff --git a/test/specs/impl/v2/index.js b/test/specs/impl/v2/index.js index 7772971..3e18085 100644 --- a/test/specs/impl/v2/index.js +++ b/test/specs/impl/v2/index.js @@ -4,6 +4,7 @@ const path = require('path'), { validateExample, 'default': validateExamples, validateExamplesByMap } = require('../../../../src/index'), { ApplicationError, ErrorType } = require('../../../../src/application-error'); const { prepare } = require('../../../../src/impl/v2'); +const { validateFile } = require('../../../../src'); const PATH__SCHEMA_EXTERNAL_EXAMPLE = '$.paths./.get.responses.200.schema', PATH__SCHEMA_EXTERNAL_EXAMPLE_INVALID = '$.hmm.what.am.i.gonna.get.for.lunch', @@ -27,7 +28,9 @@ const PATH__SCHEMA_EXTERNAL_EXAMPLE = '$.paths./.get.responses.200.schema', FILE_PATH__NOT_EXISTS = 'there is no spoon', FILE_PATH__EXTERNAL_EXAMPLE_INVALID_TYPE = path.join('test', 'data', 'v2', 'external-examples-invalid-type.json'), FILE_PATH__EXTERNAL_EXAMPLE_INVALID_MISSING_LINK = path.join('test', 'data', 'v2', - 'external-examples-invalid-missing-link.json'); + 'external-examples-invalid-missing-link.json'), + FILE_PATH__VALID__RESPONSE__EXAMPLES_CONTENT_ARRAY + = path.join(__dirname, '../../../data/v2/response-valid-content-array.yaml'); describe('Main-module, for v2 should', () => { describe('recognize', () => { @@ -421,6 +424,19 @@ describe('Main-module, for v2 should', () => { preparedOpenapi.should.deep.equal(loadTestData('v2/valid-with-all-properties-required')); }); }); + describe('handle elements named "content" which are Arrays', function() { + it('should validate successfully', async function() { + const { valid, statistics } = structuredClone( + await validateFile(FILE_PATH__VALID__RESPONSE__EXAMPLES_CONTENT_ARRAY) + ); + valid.should.equal(true); + statistics.should.deep.equal({ + schemasWithExamples: 1, + examplesWithoutSchema: 0, + examplesTotal: 1 + }); + }); + }); }); function removeMapFilePath(errors) { diff --git a/test/specs/impl/v3/index.js b/test/specs/impl/v3/index.js index 2343d04..105242f 100644 --- a/test/specs/impl/v3/index.js +++ b/test/specs/impl/v3/index.js @@ -80,7 +80,9 @@ const JSON_PATH__CONTEXT_MUTUALLY_EXCLUSIVE = '/paths/~1pets/get/responses/200/c = path.join(__dirname, '../../../data/v3/simple-api-with-examples-exclusive-minimum-invalid.json'), FILE_PATH__EXAMPLE_NAMES_TO_BE_ESCAPED = path.join(__dirname, '../../../data/v3/simple-api-with-example-names-to-be-escaped.json'), - FILE_PATH__UNKNOWN_FORMATS = path.join(__dirname, '../../../data/v3/unknown-formats.json'); + FILE_PATH__UNKNOWN_FORMATS = path.join(__dirname, '../../../data/v3/unknown-formats.json'), + FILE_PATH__VALID__RESPONSE__EXAMPLES_CONTENT_ARRAY + = path.join(__dirname, '../../../data/v3/response-valid-content-array.yaml'); describe('Main-module, for v3 should', function() { describe('recognize', function() { @@ -514,6 +516,19 @@ unknown format "country-code-2" ignored in schema at path "#/properties/country" })).valid.should.equal(true); }); }); + describe('handle elements named "content" which are Arrays', function() { + it('should validate successfully', async function() { + const { valid, statistics } = structuredClone( + await validateFile(FILE_PATH__VALID__RESPONSE__EXAMPLES_CONTENT_ARRAY) + ); + valid.should.equal(true); + statistics.should.deep.equal({ + schemasWithExamples: 1, + examplesWithoutSchema: 0, + examplesTotal: 1 + }); + }); + }); }); function _expandFilePathOfErrors(errors, propertyName) {