Skip to content

Commit

Permalink
feat: release 2.2.0 spec version (#376)
Browse files Browse the repository at this point in the history
Co-authored-by: Maciej Urbańczyk <[email protected]>
Co-authored-by: Gerald Loeffler <[email protected]>
  • Loading branch information
3 people authored Sep 28, 2021
1 parent 5df796f commit 41e135b
Show file tree
Hide file tree
Showing 16 changed files with 320 additions and 33 deletions.
23 changes: 23 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
* [.parameters()](#module_@asyncapi/parser+Channel+parameters) ⇒ <code>Object.&lt;string, ChannelParameter&gt;</code>
* [.parameter(name)](#module_@asyncapi/parser+Channel+parameter) ⇒ <code>ChannelParameter</code>
* [.hasParameters()](#module_@asyncapi/parser+Channel+hasParameters) ⇒ <code>boolean</code>
* [.hasServers()](#module_@asyncapi/parser+Channel+hasServers) ⇒ <code>boolean</code>
* [.servers()](#module_@asyncapi/parser+Channel+servers) ⇒ <code>Array.&lt;String&gt;</code>
* [.server(index)](#module_@asyncapi/parser+Channel+server) ⇒ <code>String</code>
* [.publish()](#module_@asyncapi/parser+Channel+publish) ⇒ <code>PublishOperation</code>
* [.subscribe()](#module_@asyncapi/parser+Channel+subscribe) ⇒ <code>SubscribeOperation</code>
* [.hasPublish()](#module_@asyncapi/parser+Channel+hasPublish) ⇒ <code>boolean</code>
Expand Down Expand Up @@ -578,6 +581,9 @@ Implements functions to deal with a Channel object.
* [.parameters()](#module_@asyncapi/parser+Channel+parameters) ⇒ <code>Object.&lt;string, ChannelParameter&gt;</code>
* [.parameter(name)](#module_@asyncapi/parser+Channel+parameter) ⇒ <code>ChannelParameter</code>
* [.hasParameters()](#module_@asyncapi/parser+Channel+hasParameters) ⇒ <code>boolean</code>
* [.hasServers()](#module_@asyncapi/parser+Channel+hasServers) ⇒ <code>boolean</code>
* [.servers()](#module_@asyncapi/parser+Channel+servers) ⇒ <code>Array.&lt;String&gt;</code>
* [.server(index)](#module_@asyncapi/parser+Channel+server) ⇒ <code>String</code>
* [.publish()](#module_@asyncapi/parser+Channel+publish) ⇒ <code>PublishOperation</code>
* [.subscribe()](#module_@asyncapi/parser+Channel+subscribe) ⇒ <code>SubscribeOperation</code>
* [.hasPublish()](#module_@asyncapi/parser+Channel+hasPublish) ⇒ <code>boolean</code>
Expand Down Expand Up @@ -615,6 +621,23 @@ Implements functions to deal with a Channel object.

#### channel.hasParameters() ⇒ <code>boolean</code>
**Kind**: instance method of [<code>Channel</code>](#module_@asyncapi/parser+Channel)
<a name="module_@asyncapi/parser+Channel+hasServers"></a>

#### channel.hasServers() ⇒ <code>boolean</code>
**Kind**: instance method of [<code>Channel</code>](#module_@asyncapi/parser+Channel)
<a name="module_@asyncapi/parser+Channel+servers"></a>

#### channel.servers() ⇒ <code>Array.&lt;String&gt;</code>
**Kind**: instance method of [<code>Channel</code>](#module_@asyncapi/parser+Channel)
<a name="module_@asyncapi/parser+Channel+server"></a>

#### channel.server(index) ⇒ <code>String</code>
**Kind**: instance method of [<code>Channel</code>](#module_@asyncapi/parser+Channel)

| Param | Type | Description |
| --- | --- | --- |
| index | <code>number</code> | Index of the server. |

<a name="module_@asyncapi/parser+Channel+publish"></a>

#### channel.publish() ⇒ <code>PublishOperation</code>
Expand Down
2 changes: 1 addition & 1 deletion dist/bundle.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions lib/asyncapiSchemaFormatParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ function getMimeTypes() {
return [
'application/vnd.aai.asyncapi;version=2.0.0',
'application/vnd.aai.asyncapi;version=2.1.0',
'application/vnd.aai.asyncapi;version=2.2.0',
'application/vnd.aai.asyncapi+json;version=2.0.0',
'application/vnd.aai.asyncapi+json;version=2.1.0',
'application/vnd.aai.asyncapi+json;version=2.2.0',
'application/vnd.aai.asyncapi+yaml;version=2.0.0',
'application/vnd.aai.asyncapi+yaml;version=2.1.0',
'application/vnd.aai.asyncapi+yaml;version=2.2.0',
'application/schema;version=draft-07',
'application/schema+json;version=draft-07',
'application/schema+yaml;version=draft-07',
Expand Down
24 changes: 19 additions & 5 deletions lib/customValidators.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const {
groupValidationErrors,
tilde,
parseUrlQueryParameters,
setNotProvidedParams
setNotProvidedParams,
getUnknownServers
} = require('./utils');
const validationError = 'validation-errors';

Expand Down Expand Up @@ -298,7 +299,8 @@ function isSrvrSecProperArray(schemaType, specialSecTypes, secObj, secName) {
}

/**
* Validates if parameters specified in the channel have corresponding parameters object defined and if name does not contain url parameters
* Validates if parameters specified in the channel have corresponding parameters object defined and if name does not contain url parameters.
* Also validates that all servers listed for this channel are declared in the top-level servers object.
*
* @private
* @param {Object} parsedJSON parsed AsyncAPI document
Expand All @@ -313,11 +315,13 @@ function validateChannels(parsedJSON, asyncapiYAMLorJSON, initialFormat) {
const chnlsMap = new Map(Object.entries(chnls));
const notProvidedParams = new Map(); //return object for missing parameters
const invalidChannelName = new Map(); //return object for invalid channel names with query parameters
const unknownServers = new Map(); //return object for server names not declared in top-level servers object

chnlsMap.forEach((val, key) => {
const variables = parseUrlVariables(key);
const notProvidedChannelParams = notProvidedParams.get(tilde(key));
const queryParameters = parseUrlQueryParameters(key);
const unknownServerNames = getUnknownServers(parsedJSON, val);

//channel variable validation: fill return obeject with missing parameters
if (variables) {
Expand All @@ -334,6 +338,11 @@ function validateChannels(parsedJSON, asyncapiYAMLorJSON, initialFormat) {
if (queryParameters) {
invalidChannelName.set(tilde(key), queryParameters);
}

//server validatoin: fill return object with unknown server names
if (unknownServerNames.length > 0) {
unknownServers.set(tilde(key), unknownServerNames);
}
});

//combine validation errors of both checks and output them as one array
Expand All @@ -351,12 +360,17 @@ function validateChannels(parsedJSON, asyncapiYAMLorJSON, initialFormat) {
asyncapiYAMLorJSON,
initialFormat
);
const allValidationErrors = parameterValidationErrors.concat(
nameValidationErrors
const serverValidationErrors = groupValidationErrors(
'channels',
'channel contains servers that are not on the servers list in the root of the document',
unknownServers,
asyncapiYAMLorJSON,
initialFormat
);
const allValidationErrors = parameterValidationErrors.concat(nameValidationErrors).concat(serverValidationErrors);

//channel variable validation: throw exception if channel validation failes
if (notProvidedParams.size || invalidChannelName.size) {
if (notProvidedParams.size || invalidChannelName.size || unknownServers.size) {
throw new ParserError({
type: validationError,
title: 'Channel validation failed',
Expand Down
26 changes: 26 additions & 0 deletions lib/models/channel.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,32 @@ class Channel extends Base {
return !!this._json.parameters;
}

/**
* @returns {boolean}
*/
hasServers() {
return !!this._json.servers;
}

/**
* @returns {String[]}
*/
servers() {
if (!this._json.servers) return [];
return this._json.servers;
}

/**
* @param {number} index - Index of the server.
* @returns {String}
*/
server(index) {
if (!this._json.servers) return null;
if (typeof index !== 'number') return null;
if (index > this._json.servers.length - 1) return null;
return this._json.servers[+index];
}

/**
* @returns {PublishOperation}
*/
Expand Down
38 changes: 31 additions & 7 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const findNodeInAST = (ast, location) => {
if (!Array.isArray(obj.children)) return;
let childArray;

const child = obj.children.find(c => {
const child = obj.children.find(c => {
if (!c) return;

if (c.type === 'Object') return childArray = c.children.find(a => a.key.value === utils.untilde(key));
Expand All @@ -44,7 +44,7 @@ const findNodeInAST = (ast, location) => {

const findLocationOf = (keys, ast, initialFormat) => {
if (initialFormat === 'js') return { jsonPointer: `/${keys.join('/')}` };

let node;
if (initialFormat === 'yaml') {
node = findNode(ast, keys);
Expand Down Expand Up @@ -111,7 +111,7 @@ utils.toJS = (asyncapiYAMLorJSON) => {
parsedJSON: asyncapiYAMLorJSON,
};
}

if (typeof asyncapiYAMLorJSON !== 'string') {
throw new ParserError({
type: 'invalid-document-type',
Expand Down Expand Up @@ -205,7 +205,7 @@ utils.improveAjvErrors = (errors, asyncapiYAMLorJSON, initialFormat) => {
utils.parseUrlVariables = str => {
if (typeof str !== 'string') return;

return str.match(/{(.+?)}/g);
return str.match(/{(.+?)}/g);
};

/**
Expand All @@ -215,8 +215,8 @@ utils.parseUrlVariables = str => {
*/
utils.parseUrlQueryParameters = str => {
if (typeof str !== 'string') return;
return str.match(/\?((.*=.*)(&?))/g);

return str.match(/\?((.*=.*)(&?))/g);
};

/**
Expand All @@ -228,7 +228,7 @@ utils.getMissingProps = (arr, obj) => {
arr = arr.map(val => val.replace(/[{}]/g, ''));

if (!obj) return arr;

return arr.filter(val => {
return !obj.hasOwnProperty(val);
});
Expand Down Expand Up @@ -285,6 +285,30 @@ utils.setNotProvidedParams = (variables, val, key, notProvidedChannelParams, not
}
};

/**
* Returns an array of server names listed in a channel's servers list that are not declared in the top-level servers object.
*
* @param {Map} parsedJSON the parsed AsyncAPI document, with potentially a top-level map of servers (keys are server names)
* @param {Object} channel the channel object for which to validate the servers list (array elements are server names)
* @private
*/
utils.getUnknownServers = (parsedJSON, channel) => {
// servers list on channel
if (!channel) return []; // no channel: no unknown servers
const channelServers = channel.servers;
if (!channelServers || channelServers.length === 0) return []; // no servers listed on channel: no unknown servers

// top-level servers map
const servers = parsedJSON.servers;
if (!servers) return channelServers; // servers list on channel but no top-level servers: all servers are unknown
const serversMap = new Map(Object.entries(servers));

// retain only servers listed on channel that are not defined in the top-level servers map
return channelServers.filter(serverName => {
return !serversMap.has(serverName);
});
};

/**
* returns default schema format for a given asyncapi version
*
Expand Down
11 changes: 5 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
},
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.6",
"@asyncapi/specs": "^2.8.1",
"@asyncapi/specs": "2.9.0",
"@fmvilas/pseudo-yaml-ast": "^0.3.1",
"ajv": "^6.10.1",
"js-yaml": "^3.13.1",
Expand Down
Loading

0 comments on commit 41e135b

Please sign in to comment.