diff --git a/lib/parser.js b/lib/parser.js index f756fcae9..e70fa1e7d 100644 --- a/lib/parser.js +++ b/lib/parser.js @@ -46,12 +46,12 @@ module.exports = { /** * Parses and validate an AsyncAPI document from YAML or JSON. - * + * * @param {(String | Object)} asyncapiYAMLorJSON An AsyncAPI document in JSON or YAML format. * @param {ParserOptions=} options Configuration options object {@link #asyncapiparserparseroptions--object|ParserOptions} * @returns {Promise} The parsed AsyncAPI document. */ -async function parse(asyncapiYAMLorJSON, options = {}) { +async function parse(asyncapiYAMLorJSON, options = {}, urlRegExped) { let parsedJSON; let initialFormat; @@ -67,7 +67,7 @@ async function parse(asyncapiYAMLorJSON, options = {}) { detail: 'Most probably the AsyncAPI document contains invalid YAML or YAML features not supported in JSON.' }); } - + if (!parsedJSON.asyncapi) { throw new ParserError({ type: 'missing-asyncapi-field', @@ -75,7 +75,7 @@ async function parse(asyncapiYAMLorJSON, options = {}) { parsedJSON, }); } - + if (parsedJSON.asyncapi.startsWith('1.') || !asyncapi[parsedJSON.asyncapi]) { throw new ParserError({ type: 'unsupported-version', @@ -121,7 +121,7 @@ async function parse(asyncapiYAMLorJSON, options = {}) { /** * Fetches an AsyncAPI document from the given URL and passes its content to the `parse` method. - * + * * @param {String} url URL where the AsyncAPI document is located. * @param {Object=} [fetchOptions] Configuration to pass to the {@link https://developer.mozilla.org/en-US/docs/Web/API/Request|fetch} call. * @param {ParserOptions=} [options] Configuration to pass to the {@link #asyncapiparserparseroptions--object|ParserOptions} method. @@ -133,10 +133,22 @@ function parseFromUrl(url, fetchOptions, options) { //To not break the API by changing argument position and to silet the linter it is just better to move adding if (!fetchOptions) fetchOptions = {}; + // RegExp to choose name of YAML file in the URL string is created. + const regexp = /[^/]+$/g; + // When executed in multiple async calls, 'checkErrorWrapper' passes URL + // string as object by reference. In this case 'String.replace()' method + // mutates original URL string causing test with multiple async calls to fail. + // Thus fully independent object containing URL string is created for future + // manipulation. + const urlCopy = new String(url); + // In the copy of the URL string name of a YAML file with spec is replaced + // with zero, leaving only part of absolute URL before final slash. + const urlRegExped = urlCopy.replace(regexp.exec(urlCopy), ''); + return new Promise((resolve, reject) => { fetch(url, fetchOptions) .then(res => res.text()) - .then(doc => parse(doc, options)) + .then(doc => parse(doc, options, urlRegExped)) .then(result => resolve(result)) .catch(e => { if (e instanceof ParserError) return reject(e); @@ -178,7 +190,7 @@ async function handleCircularRefs(refParser, parsedJSON, initialFormat, asyncapi /** * Creates (or reuses) a function that validates an AsyncAPI document based on the passed AsyncAPI version. - * + * * @private * @param {Object} version AsyncAPI version. * @returns {Function} Function that validates an AsyncAPI document based on the passed AsyncAPI version. @@ -219,7 +231,7 @@ async function validateAndConvertMessage(msg, originalAsyncAPIDocument, fileForm defaultSchemaFormat, originalAsyncAPIDocument, parsedAsyncAPIDocument, - fileFormat, + fileFormat, pathToPayload }); @@ -229,12 +241,12 @@ async function validateAndConvertMessage(msg, originalAsyncAPIDocument, fileForm /** * Registers a new schema parser. Schema parsers are in charge of parsing and transforming payloads to AsyncAPI Schema format. - * + * * @param {Object} parserModule The schema parser module containing parse() and getMimeTypes() functions. */ function registerSchemaParser(parserModule) { - if (typeof parserModule !== 'object' - || typeof parserModule.parse !== 'function' + if (typeof parserModule !== 'object' + || typeof parserModule.parse !== 'function' || typeof parserModule.getMimeTypes !== 'function') throw new ParserError({ type: 'impossible-to-register-parser', @@ -263,7 +275,7 @@ function applyTraits(js) { * Triggers additional operations on the AsyncAPI channels like traits application or message validation and conversion * * @private - * + * * @param {Object} parsedJSON parsed AsyncAPI document * @param {String} asyncapiYAMLorJSON AsyncAPI document in string * @param {String} initialFormat information of the document was originally JSON or YAML @@ -277,7 +289,7 @@ async function customChannelsOperations(parsedJSON, asyncapiYAMLorJSON, initialF if (!op) return; const messages = op.message ? (op.message.oneOf || [op.message]) : []; - if (options.applyTraits) { + if (options.applyTraits) { applyTraits(op); messages.forEach(m => applyTraits(m)); } @@ -294,7 +306,7 @@ async function customChannelsOperations(parsedJSON, asyncapiYAMLorJSON, initialF * Triggers additional operations on the AsyncAPI messages located in the components section of the document. It triggers operations like traits application, validation and conversion * * @private - * + * * @param {Object} parsedJSON parsed AsyncAPI document * @param {String} asyncapiYAMLorJSON AsyncAPI document in string * @param {String} initialFormat information of the document was originally JSON or YAML