diff --git a/lib/models/asyncapi.js b/lib/models/asyncapi.js index 0a1aa161e..38b126d2e 100644 --- a/lib/models/asyncapi.js +++ b/lib/models/asyncapi.js @@ -140,6 +140,7 @@ class AsyncAPIDocument extends Base { */ allMessages() { const messages = new Map(); + if (this.hasChannels()) { this.channelNames().forEach(channelName => { const channel = this.channel(channelName); @@ -155,11 +156,13 @@ class AsyncAPIDocument extends Base { } }); } + if (this.hasComponents()) { Object.values(this.components().messages()).forEach(m => { messages.set(m.uid(), m); }); } + return messages; } @@ -168,50 +171,22 @@ class AsyncAPIDocument extends Base { */ allSchemas() { const schemas = new Map(); - if (this.hasChannels()) { - this.channelNames().forEach(channelName => { - const channel = this.channel(channelName); - - Object.values(channel.parameters()).forEach(p => { - if (p.schema()) { - schemas.set(p.schema().uid(), p.schema()); - } - }); - - if (channel.hasPublish()) { - channel.publish().messages().forEach(m => { - if (m.headers()) { - schemas.set(m.headers().uid(), m.headers()); - } - - if (m.payload()) { - schemas.set(m.payload().uid(), m.payload()); - } - }); - } - if (channel.hasSubscribe()) { - channel.subscribe().messages().forEach(m => { - if (m.headers()) { - schemas.set(m.headers().uid(), m.headers()); - } - - if (m.payload()) { - schemas.set(m.payload().uid(), m.payload()); - } - }); - } - }); - } + const callback = (schema) => { + if (schema.uid()) { + schemas.set(schema.uid(), schema); + } + }; + schemaDocument(this, callback); if (this.hasComponents()) { Object.values(this.components().schemas()).forEach(s => { - schemas.set(s.uid(), s); + recursiveSchema(s, callback); }); } + return schemas; } } - function assignNameToComponentMessages(doc) { if (doc.hasComponents()) { for (const [key, m] of Object.entries(doc.components().messages())) { @@ -248,6 +223,12 @@ function assignUidToComponentSchemas(doc) { } } } + +/** + * Assign anonymous names to nameless messages. + * + * @param {AsyncAPIDocument} doc + */ function assignNameToAnonymousMessages(doc) { let anonymousMessageCounter = 0; @@ -283,7 +264,8 @@ function assignNameToAnonymousMessages(doc) { function recursiveSchema(schema, callback) { if (schema === null) return; callback(schema); - if (schema.type() !== null) { + + if (schema.type() !== undefined) { switch (schema.type()) { case 'object': const props = schema.properties(); diff --git a/test/models/asyncapi_test.js b/test/models/asyncapi_test.js index ddcd553ce..0e774b8d0 100644 --- a/test/models/asyncapi_test.js +++ b/test/models/asyncapi_test.js @@ -1,6 +1,7 @@ const { expect } = require('chai'); const AsyncAPIDocument = require('../../lib/models/asyncapi'); - +const fs = require('fs'); +const path = require("path"); describe('AsyncAPIDocument', () => { describe('assignUidToParameterSchemas()', () => { it('should assign uids to parameters', () => { @@ -14,21 +15,21 @@ describe('AsyncAPIDocument', () => { it('should support extensions', () => { const doc = { 'x-test': 'testing' }; const d = new AsyncAPIDocument(doc); - expect(d.ext('x-test')).to.be.equal(doc['x-test']); + expect(d.ext('x-test')).to.be.equal(doc['x-test']); expect(d.extension('x-test')).to.be.equal(doc['x-test']); - expect(d.extensions()).to.be.deep.equal({'x-test': 'testing'}); + expect(d.extensions()).to.be.deep.equal({ 'x-test': 'testing' }); }); }); describe('#info()', function () { it('should return an info object', () => { - const doc = { info: { title: 'Test', version: '1.2.3', license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' } }}; + const doc = { info: { title: 'Test', version: '1.2.3', license: { name: 'Apache 2.0', url: 'https://www.apache.org/licenses/LICENSE-2.0' } } }; const d = new AsyncAPIDocument(doc); expect(d.info().constructor.name).to.be.equal('Info'); expect(d.info().json()).to.be.equal(doc.info); }); }); - + describe('#id()', function () { it('should return the id string', () => { const doc = { id: 'urn:test' }; @@ -59,7 +60,7 @@ describe('AsyncAPIDocument', () => { expect(d.servers().test2.json()).to.equal(doc.servers.test2); }); }); - + describe('#server()', function () { it('should return a specific server object', () => { const doc = { servers: { test1: { url: 'test1' }, test2: { url: 'test2' } } }; @@ -67,13 +68,13 @@ describe('AsyncAPIDocument', () => { expect(d.server('test1').constructor.name).to.equal('Server'); expect(d.server('test1').json()).to.equal(doc.servers.test1); }); - + it('should return null if a server name is not provided', () => { const doc = { servers: { test1: { url: 'test1' }, test2: { url: 'test2' } } }; const d = new AsyncAPIDocument(doc); expect(d.server()).to.equal(null); }); - + it('should return null if a server name is not found', () => { const doc = { servers: { test1: { url: 'test1' }, test2: { url: 'test2' } } }; const d = new AsyncAPIDocument(doc); @@ -164,7 +165,7 @@ describe('AsyncAPIDocument', () => { }); }); }); - + describe('#allMessages()', function () { it('should return an array with all the messages used in the document and overwrite the message from channel', () => { const doc = { channels: { test: { publish: { message: { name: 'test', test: false, k: 1 } } } }, components: { messages: { test: { test: true, k: 3 } } } }; @@ -184,9 +185,9 @@ describe('AsyncAPIDocument', () => { }); }); }); - + describe('#allSchemas()', function () { - it('should return an array with all the schemas used in the document', () => { + it('should return a map with all the schemas used in the document', () => { const doc = { channels: { test: { parameters: { testParam1: { schema: { $id: 'testParamSchema', test: true, k: 0 } } }, publish: { message: { headers: { test: true, k: 1 }, payload: { test: true, k: 2 } } } }, test2: { subscribe: { message: { payload: { $id: 'testPayload', test: true, k: 2 } } } } }, components: { schemas: { testSchema: { test: true, k: 3 } } } }; const d = new AsyncAPIDocument(doc); const schemas = d.allSchemas(); @@ -201,7 +202,45 @@ describe('AsyncAPIDocument', () => { "testPayload", "testSchema" ]) - for(const t of schemas.values()){ + for (const t of schemas.values()) { + expect(t.constructor.name).to.be.equal('Schema'); + expect(t.json().test).to.be.equal(true); + } + }); + it('should return a map with all the nested schemas', () => { + const doc = JSON.parse(fs.readFileSync(path.resolve(__dirname, "../nested-schemas.json"), 'utf8')); + const d = new AsyncAPIDocument(doc); + const schemas = d.allSchemas(); + + //Ensure the actual keys are as expected + const schemaKeys = Array.from(schemas.keys()); + console.log(schemaKeys); + expect(schemaKeys).to.deep.equal([ + "testParamSchema", + "testParamNestedSchemaProp", + "testParamNestedNestedSchemaProp2", + "testHeaderSchema", + "testHeaderNestedSchemaProp", + "testHeaderNestedNestedSchemaProp1", + "testHeaderNestedSchemaPropArray", + "testHeaderNestedSchemaPropArrayProp1", + "testPayloadSchema", + "testPayloadNestedSchemaProp", + "testPayloadNestedNestedSchemaProp1", + "testPayloadNestedSchemaPropArray", + "testPayloadNestedSchemaPropArrayProp1", + "testPayload", + "testComponentSchemaSchema", + "testComponentSchemaNestedSchemaPropAllOf", + "testComponentSchemaNestedSchemaPropAllOfSchema1", + "testComponentSchemaNestedSchemaPropAllOfSchema1Prop1", + "testComponentSchemaNestedSchemaPropAllOfSchema2", + "testComponentSchemaNestedSchemaPropAllOfSchema2Prop1", + "testComponentSchemaNestedSchemaPropArray", + "testComponentSchemaNestedSchemaPropArrayProp1", + "testComponentSchemaNestedSchemaPropArrayProp2" + ]) + for (const t of schemas.values()) { expect(t.constructor.name).to.be.equal('Schema'); expect(t.json().test).to.be.equal(true); } diff --git a/test/nested-schemas.json b/test/nested-schemas.json new file mode 100644 index 000000000..f7d3a5831 --- /dev/null +++ b/test/nested-schemas.json @@ -0,0 +1,164 @@ +{ + "channels": { + "test": { + "parameters": { + "testParam1": { + "schema": { + "$id": "testParamSchema", + "type": "object", + "test": true, + "properties": { + "testParamNestedSchemaProp": { + "$id": "testParamNestedSchemaProp", + "type": "object", + "test": true, + "properties": { + "testParamNestedNestedSchemaProp2": { + "$id": "testParamNestedNestedSchemaProp2", + "test": true, + "type": "string" + } + } + } + } + } + } + }, + "publish": { + "message": { + "headers": { + "$id": "testHeaderSchema", + "type": "object", + "test": true, + "properties": { + "testHeaderNestedSchemaProp": { + "$id": "testHeaderNestedSchemaProp", + "type": "object", + "test": true, + "properties": { + "testprop2": { + "$id": "testHeaderNestedNestedSchemaProp1", + "test": true, + "type": "string" + } + } + }, + "testHeaderNestedSchemaPropArray": { + "$id": "testHeaderNestedSchemaPropArray", + "type": "array", + "test": true, + "items": [ + { + "$id": "testHeaderNestedSchemaPropArrayProp1", + "test": true, + "type": "string" + } + ] + } + } + }, + "payload": { + "$id": "testPayloadSchema", + "type": "object", + "test": true, + "properties": { + "testPayloadNestedSchemaProp": { + "$id": "testPayloadNestedSchemaProp", + "type": "object", + "test": true, + "properties": { + "testPayloadNestedNestedSchemaProp1": { + "$id": "testPayloadNestedNestedSchemaProp1", + "test": true, + "type": "string" + } + } + }, + "testPayloadNestedSchemaPropArray": { + "$id": "testPayloadNestedSchemaPropArray", + "type": "array", + "test": true, + "items": [ + { + "$id": "testPayloadNestedSchemaPropArrayProp1", + "test": true, + "type": "string" + } + ] + } + } + } + } + } + }, + "test2": { + "subscribe": { + "message": { + "payload": { + "$id": "testPayload", + "test": true, + "k": 2 + } + } + } + } + }, + "components": { + "schemas": { + "testSchema": { + "$id": "testComponentSchemaSchema", + "type": "object", + "test": true, + "properties": { + "testprop": { + "$id": "testComponentSchemaNestedSchemaPropAllOf", + "test": true, + "allOf": [ + { + "$id": "testComponentSchemaNestedSchemaPropAllOfSchema1", + "type": "object", + "test": true, + "properties": { + "testprop2": { + "$id": "testComponentSchemaNestedSchemaPropAllOfSchema1Prop1", + "test": true, + "type": "string" + } + } + }, + { + "$id": "testComponentSchemaNestedSchemaPropAllOfSchema2", + "type": "object", + "test": true, + "properties": { + "testprop2": { + "$id": "testComponentSchemaNestedSchemaPropAllOfSchema2Prop1", + "test": true, + "type": "string" + } + } + } + ] + }, + "testArray": { + "$id": "testComponentSchemaNestedSchemaPropArray", + "type": "array", + "test": true, + "items": [ + { + "$id": "testComponentSchemaNestedSchemaPropArrayProp1", + "test": true, + "type": "string" + }, + { + "$id": "testComponentSchemaNestedSchemaPropArrayProp2", + "test": true, + "type": "string" + } + ] + } + } + } + } + } +}