diff --git a/lib/templateConfigValidator.js b/lib/templateConfigValidator.js index bf39db25c..614185d07 100644 --- a/lib/templateConfigValidator.js +++ b/lib/templateConfigValidator.js @@ -5,6 +5,11 @@ const levenshtein = require('levenshtein-edit-distance'); const ajv = new Ajv({ allErrors: true }); +// See https://github.com/asyncapi/parser-api +const supportedParserAPIMajorVersions = [ + 'v1', +]; + /** * Validates the template configuration. * @@ -14,10 +19,10 @@ const ajv = new Ajv({ allErrors: true }); * @return {Boolean} */ module.exports.validateTemplateConfig = (templateConfig, templateParams, asyncapiDocument) => { - const { parameters, supportedProtocols, conditionalFiles, generator } = templateConfig; - + const { parameters, supportedProtocols, conditionalFiles, generator, apiVersion } = templateConfig; + validateConditionalFiles(conditionalFiles); - isTemplateCompatible(generator); + isTemplateCompatible(generator, apiVersion); isRequiredParamProvided(parameters, templateParams); isProvidedTemplateRendererSupported(templateConfig); if (asyncapiDocument) { @@ -34,24 +39,29 @@ module.exports.validateTemplateConfig = (templateConfig, templateParams, asyncap * Checks if template is compatible with the version of the generator that is used * @private * @param {String} generator Information about supported generator version that is part of the template configuration + * @param {String} generator Information about supported Parser-API version that is part of the template configuration */ -function isTemplateCompatible(generator) { +function isTemplateCompatible(generator, apiVersion) { const generatorVersion = getGeneratorVersion(); if (typeof generator === 'string' && !semver.satisfies(generatorVersion, generator, {includePrerelease: true})) { throw new Error(`This template is not compatible with the current version of the generator (${generatorVersion}). This template is compatible with the following version range: ${generator}.`); - } + } + + if (typeof apiVersion === 'string' && !supportedParserAPIMajorVersions.includes(apiVersion)) { + throw new Error(`The version specified in apiVersion is not supported by this Generator version. Supported versions are: ${supportedParserAPIMajorVersions.toString()}`); + } } /** * Checks if parameters described in template configuration as required are passed to the generator * @private * @param {Object} configParams Parameters specified in template configuration - * @param {Object} templateParams All parameters provided to generator + * @param {Object} templateParams All parameters provided to generator */ function isRequiredParamProvided(configParams, templateParams) { const missingParams = Object.keys(configParams || {}) .filter(key => configParams[key].required && !templateParams[key]); - + if (missingParams.length) { throw new Error(`This template requires the following missing params: ${missingParams}.`); } @@ -74,29 +84,29 @@ function getParamSuggestion(wrongParam, configParams) { * Checks if parameters provided to generator is supported by the template * @private * @param {Object} configParams Parameters specified in template configuration - * @param {Object} templateParams All parameters provided to generator + * @param {Object} templateParams All parameters provided to generator */ function isProvidedParameterSupported(configParams, templateParams) { const wrongParams = Object.keys(templateParams || {}).filter(key => !configParams || !configParams[key]); - + if (!wrongParams.length) return; if (!configParams) throw new Error('This template doesn\'t have any params.'); let suggestionsString = ''; - - wrongParams.forEach(wp => { + + wrongParams.forEach(wp => { suggestionsString += `\nDid you mean "${getParamSuggestion(wp,configParams)}" instead of "${wp}"?`; }); throw new Error(`This template doesn't have the following params: ${wrongParams}.${suggestionsString}`); } - + /** * Checks if given AsyncAPI document has servers with protocol that is supported by the template * @private * @param {Object} server Server object from AsyncAPI file * @param {String[]} supportedProtocols Supported protocols specified in template configuration - * @param {String} paramsServerName Name of the server specified as a param for the generator + * @param {String} paramsServerName Name of the server specified as a param for the generator */ function isServerProtocolSupported(server, supportedProtocols, paramsServerName) { if (server && Array.isArray(supportedProtocols) && !supportedProtocols.includes(server.protocol())) { @@ -106,7 +116,7 @@ function isServerProtocolSupported(server, supportedProtocols, paramsServerName) /** * Checks if the the provided renderer are supported (no renderer are also supported, defaults to nunjucks) - * + * * @param {Object} templateConfig Template configuration. */ function isProvidedTemplateRendererSupported(templateConfig) { @@ -114,7 +124,7 @@ function isProvidedTemplateRendererSupported(templateConfig) { if (supportedRenderers.includes(templateConfig.renderer)) { return; } - + throw new Error(`We do not support '${templateConfig.renderer}' as a renderer for a template. Only 'react' or 'nunjucks' are supported.`); } @@ -136,7 +146,7 @@ function isServerProvidedInDocument(server, paramsServerName) { function validateConditionalFiles(conditionalFiles) { if (typeof conditionalFiles === 'object') { const fileNames = Object.keys(conditionalFiles); - + fileNames.forEach(fileName => { const def = conditionalFiles[fileName]; if (typeof def.subject !== 'string') throw new Error(`Invalid conditional file subject for ${fileName}: ${def.subject}.`); @@ -144,4 +154,4 @@ function validateConditionalFiles(conditionalFiles) { conditionalFiles[fileName].validate = ajv.compile(conditionalFiles[fileName].validation); }); } -} \ No newline at end of file +} diff --git a/test/templateConfigValidator.test.js b/test/templateConfigValidator.test.js index 2044ee6f9..e366b52bc 100644 --- a/test/templateConfigValidator.test.js +++ b/test/templateConfigValidator.test.js @@ -14,7 +14,7 @@ describe('Template Configuration Validator', () => { const { document } = await parser.parse(dummyYAML); asyncapiDocument = document; }); - + it('Validation doesn\'t throw errors if params are not passed and template has no config', () => { const templateParams = {}; const templateConfig = {}; @@ -48,7 +48,7 @@ describe('Template Configuration Validator', () => { expect(() => validateTemplateConfig(templateConfig, templateParams)).toThrow('We do not support \'non_existing\' as a renderer for a template. Only \'react\' or \'nunjucks\' are supported.'); }); - it('Validation throw error if template is not compatible', () => { + it('Validation throw error if template is not compatible because of generator version', () => { const utils = require('../lib/utils'); utils.__generatorVersion = '1.0.0'; @@ -60,6 +60,18 @@ describe('Template Configuration Validator', () => { expect(() => validateTemplateConfig(templateConfig, templateParams)).toThrow('This template is not compatible with the current version of the generator (1.0.0). This template is compatible with the following version range: >1.0.1.'); }); + it('Validation throw error if template is not compatible because of non-supported apiVersion value', () => { + const utils = require('../lib/utils'); + utils.__generatorVersion = '1.0.0'; + + const templateParams = {}; + const templateConfig = { + apiVersion: '999999' + }; + + expect(() => validateTemplateConfig(templateConfig, templateParams)).toThrow('The version specified in apiVersion is not supported by this Generator version. Supported versions are: v1'); + }); + it('Validation throw error if required params not provided', () => { const templateParams = {}; const templateConfig = {