Skip to content

Commit d3ee61c

Browse files
authored
feat: add support for messageId (#510)
1 parent 328f511 commit d3ee61c

11 files changed

+372
-35
lines changed

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/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/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
/**

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: 13 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
},
6868
"dependencies": {
6969
"@apidevtools/json-schema-ref-parser": "^9.0.6",
70-
"@asyncapi/specs": "^v2.14.0-2022-04-release.2",
70+
"@asyncapi/specs": "^v2.14.0-2022-04-release.3",
7171
"@fmvilas/pseudo-yaml-ast": "^0.3.1",
7272
"ajv": "^6.10.1",
7373
"js-yaml": "^3.13.1",

0 commit comments

Comments
 (0)