Skip to content

Commit 2898c4d

Browse files
authored
feat: release for version 2.4.0 of the spec (#501)
1 parent e31564f commit 2898c4d

19 files changed

+540
-22
lines changed

API.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@
109109
* [.messageTraits()](#module_@asyncapi/parser+Components+messageTraits) ⇒ <code>Object.&lt;string, MessageTrait&gt;</code>
110110
* [.hasMessageTraits()](#module_@asyncapi/parser+Components+hasMessageTraits) ⇒ <code>boolean</code>
111111
* [.messageTrait(name)](#module_@asyncapi/parser+Components+messageTrait) ⇒ <code>MessageTrait</code>
112+
* [.serverVariables()](#module_@asyncapi/parser+Components+serverVariables) ⇒ <code>Object.&lt;string, ServerVariable&gt;</code>
113+
* [.hasServerVariables()](#module_@asyncapi/parser+Components+hasServerVariables) ⇒ <code>boolean</code>
114+
* [.serverVariable(name)](#module_@asyncapi/parser+Components+serverVariable) ⇒ <code>ServerVariable</code>
112115
* [.hasExtensions()](#module_@asyncapi/parser+Components+hasExtensions) ⇒ <code>boolean</code>
113116
* [.extensions()](#module_@asyncapi/parser+Components+extensions) ⇒ <code>Object.&lt;string, any&gt;</code>
114117
* [.extensionKeys()](#module_@asyncapi/parser+Components+extensionKeys) ⇒ <code>Array.&lt;string&gt;</code>
@@ -184,6 +187,7 @@
184187
* [.MessageTraitable](#module_@asyncapi/parser+MessageTraitable) ⇐ <code>Base</code>
185188
* [.headers()](#module_@asyncapi/parser+MessageTraitable+headers) ⇒ <code>Schema</code>
186189
* [.header(name)](#module_@asyncapi/parser+MessageTraitable+header) ⇒ <code>Schema</code>
190+
* [.id()](#module_@asyncapi/parser+MessageTraitable+id) ⇒ <code>string</code>
187191
* [.correlationId()](#module_@asyncapi/parser+MessageTraitable+correlationId) ⇒ <code>CorrelationId</code>
188192
* [.schemaFormat()](#module_@asyncapi/parser+MessageTraitable+schemaFormat) ⇒ <code>string</code>
189193
* [.contentType()](#module_@asyncapi/parser+MessageTraitable+contentType) ⇒ <code>string</code>
@@ -233,6 +237,7 @@
233237
* [.extension(key)](#module_@asyncapi/parser+OAuthFlow+extension) ⇒ <code>any</code>
234238
* [.hasExt(key)](#module_@asyncapi/parser+OAuthFlow+hasExt) ⇒ <code>boolean</code>
235239
* [.ext(key)](#module_@asyncapi/parser+OAuthFlow+ext) ⇒ <code>any</code>
240+
* [.OperationSecurityRequirement](#module_@asyncapi/parser+OperationSecurityRequirement) ⇐ <code>Base</code>
236241
* [.OperationTrait](#module_@asyncapi/parser+OperationTrait) ⇐ <code>OperationTraitable</code>
237242
* [.OperationTraitable](#module_@asyncapi/parser+OperationTraitable) ⇐ <code>Base</code>
238243
* [.id()](#module_@asyncapi/parser+OperationTraitable+id) ⇒ <code>string</code>
@@ -265,6 +270,7 @@
265270
* [.hasTraits()](#module_@asyncapi/parser+Operation+hasTraits) ⇒ <code>boolean</code>
266271
* [.messages()](#module_@asyncapi/parser+Operation+messages) ⇒ <code>Array.&lt;Message&gt;</code>
267272
* [.message()](#module_@asyncapi/parser+Operation+message) ⇒ <code>Message</code>
273+
* [.security()](#module_@asyncapi/parser+Operation+security) ⇒ <code>Array.&lt;OperationSecurityRequirement&gt;</code>
268274
* [.PublishOperation](#module_@asyncapi/parser+PublishOperation) ⇐ <code>Operation</code>
269275
* [.isPublish()](#module_@asyncapi/parser+PublishOperation+isPublish) ⇒ <code>boolean</code>
270276
* [.isSubscribe()](#module_@asyncapi/parser+PublishOperation+isSubscribe) ⇒ <code>boolean</code>
@@ -820,6 +826,9 @@ Implements functions to deal with a Components object.
820826
* [.messageTraits()](#module_@asyncapi/parser+Components+messageTraits) ⇒ <code>Object.&lt;string, MessageTrait&gt;</code>
821827
* [.hasMessageTraits()](#module_@asyncapi/parser+Components+hasMessageTraits) ⇒ <code>boolean</code>
822828
* [.messageTrait(name)](#module_@asyncapi/parser+Components+messageTrait) ⇒ <code>MessageTrait</code>
829+
* [.serverVariables()](#module_@asyncapi/parser+Components+serverVariables) ⇒ <code>Object.&lt;string, ServerVariable&gt;</code>
830+
* [.hasServerVariables()](#module_@asyncapi/parser+Components+hasServerVariables) ⇒ <code>boolean</code>
831+
* [.serverVariable(name)](#module_@asyncapi/parser+Components+serverVariable) ⇒ <code>ServerVariable</code>
823832
* [.hasExtensions()](#module_@asyncapi/parser+Components+hasExtensions) ⇒ <code>boolean</code>
824833
* [.extensions()](#module_@asyncapi/parser+Components+extensions) ⇒ <code>Object.&lt;string, any&gt;</code>
825834
* [.extensionKeys()](#module_@asyncapi/parser+Components+extensionKeys) ⇒ <code>Array.&lt;string&gt;</code>
@@ -982,6 +991,23 @@ Implements functions to deal with a Components object.
982991
| --- | --- | --- |
983992
| name | <code>string</code> | Name of the message trait. |
984993

994+
<a name="module_@asyncapi/parser+Components+serverVariables"></a>
995+
996+
#### components.serverVariables() ⇒ <code>Object.&lt;string, ServerVariable&gt;</code>
997+
**Kind**: instance method of [<code>Components</code>](#module_@asyncapi/parser+Components)
998+
<a name="module_@asyncapi/parser+Components+hasServerVariables"></a>
999+
1000+
#### components.hasServerVariables() ⇒ <code>boolean</code>
1001+
**Kind**: instance method of [<code>Components</code>](#module_@asyncapi/parser+Components)
1002+
<a name="module_@asyncapi/parser+Components+serverVariable"></a>
1003+
1004+
#### components.serverVariable(name) ⇒ <code>ServerVariable</code>
1005+
**Kind**: instance method of [<code>Components</code>](#module_@asyncapi/parser+Components)
1006+
1007+
| Param | Type | Description |
1008+
| --- | --- | --- |
1009+
| name | <code>string</code> | Name of the server variable. |
1010+
9851011
<a name="module_@asyncapi/parser+Components+hasExtensions"></a>
9861012

9871013
#### components.hasExtensions() ⇒ <code>boolean</code>
@@ -1552,6 +1578,7 @@ Implements functions to deal with a the common properties that Message and Messa
15521578
* [.MessageTraitable](#module_@asyncapi/parser+MessageTraitable) ⇐ <code>Base</code>
15531579
* [.headers()](#module_@asyncapi/parser+MessageTraitable+headers) ⇒ <code>Schema</code>
15541580
* [.header(name)](#module_@asyncapi/parser+MessageTraitable+header) ⇒ <code>Schema</code>
1581+
* [.id()](#module_@asyncapi/parser+MessageTraitable+id) ⇒ <code>string</code>
15551582
* [.correlationId()](#module_@asyncapi/parser+MessageTraitable+correlationId) ⇒ <code>CorrelationId</code>
15561583
* [.schemaFormat()](#module_@asyncapi/parser+MessageTraitable+schemaFormat) ⇒ <code>string</code>
15571584
* [.contentType()](#module_@asyncapi/parser+MessageTraitable+contentType) ⇒ <code>string</code>
@@ -1595,6 +1622,10 @@ Implements functions to deal with a the common properties that Message and Messa
15951622
| --- | --- | --- |
15961623
| name | <code>string</code> | Name of the header. |
15971624

1625+
<a name="module_@asyncapi/parser+MessageTraitable+id"></a>
1626+
1627+
#### messageTraitable.id() ⇒ <code>string</code>
1628+
**Kind**: instance method of [<code>MessageTraitable</code>](#module_@asyncapi/parser+MessageTraitable)
15981629
<a name="module_@asyncapi/parser+MessageTraitable+correlationId"></a>
15991630

16001631
#### messageTraitable.correlationId() ⇒ <code>CorrelationId</code>
@@ -1912,6 +1943,13 @@ Implements functions to deal with a OAuthFlow object.
19121943
| --- | --- | --- |
19131944
| key | <code>string</code> | Extension key. |
19141945

1946+
<a name="module_@asyncapi/parser+OperationSecurityRequirement"></a>
1947+
1948+
### @asyncapi/parser.OperationSecurityRequirement ⇐ <code>Base</code>
1949+
Implements functions to deal with a OperationSecurityRequirement object.
1950+
1951+
**Kind**: instance class of [<code>@asyncapi/parser</code>](#module_@asyncapi/parser)
1952+
**Extends**: <code>Base</code>
19151953
<a name="module_@asyncapi/parser+OperationTrait"></a>
19161954

19171955
### @asyncapi/parser.OperationTrait ⇐ <code>OperationTraitable</code>
@@ -2126,6 +2164,7 @@ Implements functions to deal with an Operation object.
21262164
* [.hasTraits()](#module_@asyncapi/parser+Operation+hasTraits) ⇒ <code>boolean</code>
21272165
* [.messages()](#module_@asyncapi/parser+Operation+messages) ⇒ <code>Array.&lt;Message&gt;</code>
21282166
* [.message()](#module_@asyncapi/parser+Operation+message) ⇒ <code>Message</code>
2167+
* [.security()](#module_@asyncapi/parser+Operation+security) ⇒ <code>Array.&lt;OperationSecurityRequirement&gt;</code>
21292168

21302169
<a name="module_@asyncapi/parser+Operation+hasMultipleMessages"></a>
21312170

@@ -2147,6 +2186,10 @@ Implements functions to deal with an Operation object.
21472186

21482187
#### operation.message() ⇒ <code>Message</code>
21492188
**Kind**: instance method of [<code>Operation</code>](#module_@asyncapi/parser+Operation)
2189+
<a name="module_@asyncapi/parser+Operation+security"></a>
2190+
2191+
#### operation.security() ⇒ <code>Array.&lt;OperationSecurityRequirement&gt;</code>
2192+
**Kind**: instance method of [<code>Operation</code>](#module_@asyncapi/parser+Operation)
21502193
<a name="module_@asyncapi/parser+PublishOperation"></a>
21512194

21522195
### @asyncapi/parser.PublishOperation ⇐ <code>Operation</code>

dist/bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/asyncapiSchemaFormatParser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function getMimeTypes() {
4848
'application/schema+json;version=draft-07',
4949
'application/schema+yaml;version=draft-07',
5050
];
51-
['2.0.0', '2.1.0', '2.2.0', '2.3.0'].forEach(version => {
51+
['2.0.0', '2.1.0', '2.2.0', '2.3.0', '2.4.0'].forEach(version => {
5252
mimeTypes.push(
5353
`application/vnd.aai.asyncapi;version=${version}`,
5454
`application/vnd.aai.asyncapi+json;version=${version}`,

lib/customValidators.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,70 @@ function validateOperationId(
174174
return true;
175175
}
176176

177+
/**
178+
* Validates if messageIds are duplicated in the document
179+
*
180+
* @private
181+
* @param {Object} parsedJSON parsed AsyncAPI document
182+
* @param {String} asyncapiYAMLorJSON AsyncAPI document in string
183+
* @param {String} initialFormat information of the document was originally JSON or YAML
184+
* @returns {Boolean} true in case the document is valid, otherwise throws {@link ParserError}
185+
*/
186+
function validateMessageId(
187+
parsedJSON,
188+
asyncapiYAMLorJSON,
189+
initialFormat,
190+
operations
191+
) {
192+
const chnls = parsedJSON.channels;
193+
if (!chnls) return true;
194+
const chnlsMap = new Map(Object.entries(chnls));
195+
//it is a map of paths, the one that is a duplicate and the one that is duplicated
196+
const duplicatedMessages = new Map();
197+
//is is a 2-dimensional array that holds information with messageId value and its path
198+
const allMessages = [];
199+
200+
const addDuplicateToMap = (msg, channelName, opName, oneOf = '') => {
201+
const messageId = msg.messageId;
202+
if (!messageId) return;
203+
204+
const messagePath = `${tilde(channelName)}/${opName}/message${oneOf}/messageId`;
205+
const isMessageIdDuplicated = allMessages.find(v => v[0] === messageId);
206+
if (!isMessageIdDuplicated)
207+
return allMessages.push([messageId, messagePath]);
208+
209+
//isMessageIdDuplicated always holds one record and it is an array of paths, the one that is a duplicate and the one that is duplicated
210+
duplicatedMessages.set(messagePath, isMessageIdDuplicated[1]);
211+
};
212+
213+
chnlsMap.forEach((chnlObj, chnlName) => {
214+
operations.forEach((opName) => {
215+
const op = chnlObj[String(opName)];
216+
if (op && op.message) {
217+
if (op.message.oneOf) op.message.oneOf.forEach((msg, index) => addDuplicateToMap(msg, chnlName, opName , `/oneOf/${index}`));
218+
else addDuplicateToMap(op.message, chnlName, opName);
219+
}
220+
});
221+
});
222+
223+
if (duplicatedMessages.size) {
224+
throw new ParserError({
225+
type: validationError,
226+
title: 'messageId must be unique across all the messages.',
227+
parsedJSON,
228+
validationErrors: groupValidationErrors(
229+
'channels',
230+
'is a duplicate of',
231+
duplicatedMessages,
232+
asyncapiYAMLorJSON,
233+
initialFormat
234+
),
235+
});
236+
}
237+
238+
return true;
239+
}
240+
177241
/**
178242
* Validates if server security is declared properly and the name has a corresponding security schema definition in components with the same name
179243
*
@@ -611,6 +675,7 @@ function getDuplicateTagNames(tags) {
611675
module.exports = {
612676
validateServerVariables,
613677
validateOperationId,
678+
validateMessageId,
614679
validateServerSecurity,
615680
validateChannels,
616681
validateTags,

lib/models/components.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const ChannelParameter = require('./channel-parameter');
1010
const CorrelationId = require('./correlation-id');
1111
const OperationTrait = require('./operation-trait');
1212
const MessageTrait = require('./message-trait');
13+
const ServerVariable = require('./server-variable');
1314

1415
const MixinSpecificationExtensions = require('../mixins/specification-extensions');
1516

@@ -219,6 +220,31 @@ class Components extends Base {
219220
messageTrait(name) {
220221
return getMapValueOfType(this._json.messageTraits, name, MessageTrait);
221222
}
223+
224+
/**
225+
*
226+
* @returns {Object<string, ServerVariable>}
227+
*/
228+
serverVariables() {
229+
return createMapOfType(this._json.serverVariables, ServerVariable);
230+
}
231+
232+
/**
233+
*
234+
* @returns {boolean}
235+
*/
236+
hasServerVariables() {
237+
return !!this._json.serverVariables;
238+
}
239+
240+
/**
241+
*
242+
* @param {string} name - Name of the server variable.
243+
* @returns {ServerVariable}
244+
*/
245+
serverVariable(name) {
246+
return getMapValueOfType(this._json.serverVariables, name, ServerVariable);
247+
}
222248
}
223249

224250
module.exports = mix(Components, MixinSpecificationExtensions);

lib/models/message-traitable.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ class MessageTraitable extends Base {
4040
return getMapValueOfType(this._json.headers.properties, name, Schema);
4141
}
4242

43+
/**
44+
* @returns {string}
45+
*/
46+
id() {
47+
return this._json.messageId;
48+
}
49+
4350
/**
4451
* @returns {CorrelationId}
4552
*/

lib/models/message.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Message extends MessageTraitable {
1414
* @returns {string}
1515
*/
1616
uid() {
17-
return this.name() || this.ext('x-parser-message-name') || Buffer.from(JSON.stringify(this._json)).toString('base64');
17+
return this.id() || this.name() || this.ext('x-parser-message-name') || Buffer.from(JSON.stringify(this._json)).toString('base64');
1818
}
1919

2020
/**
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const Base = require('./base');
2+
3+
/**
4+
* Implements functions to deal with a OperationSecurityRequirement object.
5+
* @class
6+
* @alias module:@asyncapi/parser#OperationSecurityRequirement
7+
* @extends Base
8+
* @returns {OperationSecurityRequirement}
9+
*/
10+
class OperationSecurityRequirement extends Base {
11+
}
12+
13+
module.exports = OperationSecurityRequirement;

lib/models/operation.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const OperationTraitable = require('./operation-traitable');
22
const Message = require('./message');
33
const OperationTrait = require('./operation-trait');
4+
const OperationSecurityRequirement = require('./operation-security-requirement');
45

56
/**
67
* Implements functions to deal with an Operation object.
@@ -54,6 +55,14 @@ class Operation extends OperationTraitable {
5455
if (index > this._json.message.oneOf.length - 1) return null;
5556
return new Message(this._json.message.oneOf[+index]);
5657
}
58+
59+
/**
60+
* @returns {OperationSecurityRequirement[]}
61+
*/
62+
security() {
63+
if (!this._json.security) return null;
64+
return this._json.security.map(sec => new OperationSecurityRequirement(sec));
65+
}
5766
}
5867

5968
module.exports = Operation;

lib/parser.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const asyncapi = require('@asyncapi/specs');
55
const $RefParser = require('@apidevtools/json-schema-ref-parser');
66
const mergePatch = require('tiny-merge-patch').apply;
77
const ParserError = require('./errors/parser-error');
8-
const { validateChannels, validateTags, validateServerVariables, validateOperationId, validateServerSecurity } = require('./customValidators.js');
8+
const { validateChannels, validateTags, validateServerVariables, validateOperationId, validateServerSecurity, validateMessageId } = require('./customValidators.js');
99
const { toJS, findRefs, getLocationOf, improveAjvErrors, getDefaultSchemaFormat } = require('./utils');
1010
const AsyncAPIDocument = require('./models/asyncapi');
1111

@@ -201,6 +201,7 @@ async function customDocumentOperations(parsedJSON, asyncapiYAMLorJSON, initialF
201201
validateTags(parsedJSON, asyncapiYAMLorJSON, initialFormat);
202202
validateChannels(parsedJSON, asyncapiYAMLorJSON, initialFormat);
203203
validateOperationId(parsedJSON, asyncapiYAMLorJSON, initialFormat, OPERATIONS);
204+
validateMessageId(parsedJSON, asyncapiYAMLorJSON, initialFormat, OPERATIONS);
204205

205206
await customComponentsMsgOperations(parsedJSON, asyncapiYAMLorJSON, initialFormat, options);
206207
await customChannelsOperations(parsedJSON, asyncapiYAMLorJSON, initialFormat, options);

package-lock.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@asyncapi/parser",
3-
"version": "1.14.1",
3+
"version": "1.15.0-2022-04-release.4",
44
"description": "JavaScript AsyncAPI parser.",
55
"main": "lib/index.js",
66
"types": "types.d.ts",
@@ -67,7 +67,7 @@
6767
},
6868
"dependencies": {
6969
"@apidevtools/json-schema-ref-parser": "^9.0.6",
70-
"@asyncapi/specs": "^2.13.0",
70+
"@asyncapi/specs": "^2.14.0",
7171
"@fmvilas/pseudo-yaml-ast": "^0.3.1",
7272
"ajv": "^6.10.1",
7373
"js-yaml": "^3.13.1",

0 commit comments

Comments
 (0)