diff --git a/apps/generator/lib/__mocks__/templateConfigValidator.js b/apps/generator/lib/__mocks__/templateConfigValidator.js index 4e90cd138d..645e521615 100644 --- a/apps/generator/lib/__mocks__/templateConfigValidator.js +++ b/apps/generator/lib/__mocks__/templateConfigValidator.js @@ -1,3 +1,3 @@ -const templateConfigValidator = jest.genMockFromModule('../templateConfigValidator'); +const templateConfigValidator = jest.genMockFromModule('../templateConfig/validator'); module.exports = templateConfigValidator; diff --git a/apps/generator/lib/generator.js b/apps/generator/lib/generator.js index 3a06b87928..50a22f47f4 100644 --- a/apps/generator/lib/generator.js +++ b/apps/generator/lib/generator.js @@ -13,7 +13,8 @@ const { isAsyncAPIDocument } = require('@asyncapi/parser/cjs/document'); const { configureReact, renderReact, saveRenderedReactContent } = require('./renderer/react'); const { configureNunjucks, renderNunjucks } = require('./renderer/nunjucks'); -const { validateTemplateConfig } = require('./templateConfigValidator'); +const { validateTemplateConfig } = require('./templateConfig/validator'); +const { loadTemplateConfig, loadDefaultValues } = require('./templateConfig/loader'); const { isGenerationConditionMet } = require('./conditionalGeneration'); const { convertMapToObject, @@ -36,7 +37,6 @@ const { definitions, flatten, shorthands } = require('@npmcli/config/lib/definit const FILTERS_DIRNAME = 'filters'; const HOOKS_DIRNAME = 'hooks'; -const CONFIG_FILENAME = 'package.json'; const PACKAGE_JSON_FILENAME = 'package.json'; const GIT_IGNORE_FILENAME = '{.gitignore}'; const NPM_IGNORE_FILENAME = '{.npmignore}'; @@ -1005,57 +1005,21 @@ class Generator { * Loads the template configuration. * @private */ - async loadTemplateConfig() { - this.templateConfig = {}; - - // Try to load config from .ageneratorrc - try { - const rcConfigPath = path.resolve(this.templateDir, '.ageneratorrc'); - const yaml = await readFile(rcConfigPath, { encoding: 'utf8' }); - const yamlConfig = require('js-yaml').load(yaml); - this.templateConfig = yamlConfig || {}; - - await this.loadDefaultValues(); - return; - } catch (rcError) { - // console.error('Could not load .ageneratorrc file:', rcError); - log.debug('Could not load .ageneratorrc file:', rcError); - // Continue to try package.json if .ageneratorrc fails - } - - // Try to load config from package.json - try { - const configPath = path.resolve(this.templateDir, CONFIG_FILENAME); - const json = await readFile(configPath, { encoding: 'utf8' }); - const generatorProp = JSON.parse(json).generator; - this.templateConfig = generatorProp || {}; - } catch (packageError) { - // console.error('Could not load generator config from package.json:', packageError); - log.debug('Could not load generator config from package.json:', packageError); - } - - await this.loadDefaultValues(); + loadTemplateConfig() { + return loadTemplateConfig(this.templateDir).then(config => { + this.templateConfig = config; + return this.loadDefaultValues(); + }); } /** - * Loads default values of parameters from template config. If value was already set as parameter it will not be - * overriden. + * Loads default values of parameters from template config using the external loader. * @private */ - async loadDefaultValues() { - const parameters = this.templateConfig.parameters; - const defaultValues = Object.keys(parameters || {}).filter(key => parameters[key].default); - - defaultValues.filter(dv => this.templateParams[dv] === undefined).forEach(dv => - Object.defineProperty(this.templateParams, dv, { - enumerable: true, - get() { - return parameters[dv].default; - } - }) - ); + loadDefaultValues() { + loadDefaultValues(this.templateConfig, this.templateParams); } - + /** * Launches all the hooks registered at a given hook point/name. * diff --git a/apps/generator/lib/templateConfig/loader.js b/apps/generator/lib/templateConfig/loader.js new file mode 100644 index 0000000000..38da488f6d --- /dev/null +++ b/apps/generator/lib/templateConfig/loader.js @@ -0,0 +1,82 @@ +const path = require('path'); +const { readFile } = require('../utils'); +const log = require('loglevel'); +const fs = require('fs'); + +const CONFIG_FILENAME = 'package.json'; + +/** + * Loads template configuration from either .ageneratorrc or package.json + * @param {string} templateDir - Path to the template directory + * @returns {Promise} Template configuration object + * @throws {Error} If templateDir is invalid or directory doesn't exist + */ +async function loadTemplateConfig(templateDir) { + if (!templateDir || typeof templateDir !== 'string') { + throw new Error('templateDir must be a valid string path'); + } + + if (!fs.existsSync(templateDir)) { + throw new Error(`Template directory does not exist: ${templateDir}`); + } + + if (!fs.statSync(templateDir).isDirectory()) { + throw new Error(`Path is not a directory: ${templateDir}`); + } + + let templateConfig = {}; + + // Try to load config from .ageneratorrc + try { + const rcConfigPath = path.resolve(templateDir, '.ageneratorrc'); + const yaml = await readFile(rcConfigPath, { encoding: 'utf8' }); + const yamlConfig = require('js-yaml').load(yaml); + templateConfig = yamlConfig || {}; + + log.debug('Template configuration loaded from .ageneratorrc'); + return templateConfig; + } catch (rcError) { + log.debug('Could not load .ageneratorrc file:', rcError); + // Continue to try package.json if .ageneratorrc fails + } + + // Try to load config from package.json + try { + const configPath = path.resolve(templateDir, CONFIG_FILENAME); + const json = await readFile(configPath, { encoding: 'utf8' }); + const generatorProp = JSON.parse(json).generator; + templateConfig = generatorProp || {}; + + log.debug('Template configuration loaded from package.json'); + } catch (packageError) { + log.debug('Could not load generator config from package.json:', packageError); + } + + return templateConfig; +} + +/** + * Loads default values of parameters from template config + * @param {Object} templateConfig - The template configuration object + * @param {Object} templateParams - The template parameters object to modify + */ +function loadDefaultValues(templateConfig, templateParams) { + const parameters = templateConfig.parameters; + const defaultValues = Object.keys(parameters || {}).filter(key => parameters[key].default); + + defaultValues + .filter(dv => templateParams[dv] === undefined) + .forEach(dv => { + Object.defineProperty(templateParams, dv, { + enumerable: true, + get() { + return parameters[dv].default; + } + }); + }); +} + +module.exports = { + loadTemplateConfig, + loadDefaultValues +}; \ No newline at end of file diff --git a/apps/generator/lib/templateConfigValidator.js b/apps/generator/lib/templateConfig/validator.js similarity index 98% rename from apps/generator/lib/templateConfigValidator.js rename to apps/generator/lib/templateConfig/validator.js index 4492f794b5..445ce5620d 100644 --- a/apps/generator/lib/templateConfigValidator.js +++ b/apps/generator/lib/templateConfig/validator.js @@ -1,10 +1,10 @@ const semver = require('semver'); const Ajv = require('ajv'); -const { getGeneratorVersion } = require('./utils'); +const { getGeneratorVersion } = require('../utils'); const levenshtein = require('levenshtein-edit-distance'); // eslint-disable-next-line no-unused-vars const {AsyncAPIDocumentInterface, AsyncAPIDocument} = require('@asyncapi/parser'); -const { usesNewAPI } = require('./parser'); +const { usesNewAPI } = require('../parser'); const ajv = new Ajv({ allErrors: true }); diff --git a/apps/generator/test/generator.test.js b/apps/generator/test/generator.test.js index 29d63d8044..932985d9b9 100644 --- a/apps/generator/test/generator.test.js +++ b/apps/generator/test/generator.test.js @@ -11,7 +11,7 @@ const logMessage = require('./../lib/logMessages.js'); jest.mock('../lib/utils'); jest.mock('../lib/filtersRegistry'); jest.mock('../lib/hooksRegistry'); -jest.mock('../lib/templateConfigValidator'); +jest.mock('../lib/templateConfig/validator'); describe('Generator', () => { describe('constructor', () => { @@ -131,7 +131,7 @@ describe('Generator', () => { util = require('../lib/utils'); filtersRegistry = require('../lib/filtersRegistry'); hooksRegistry = require('../lib/hooksRegistry'); - templateConfigValidator = require('../lib/templateConfigValidator'); + templateConfigValidator = require('../lib/templateConfig/validator'); xfsMock = require('fs.extra'); const { AsyncAPIDocument } = require('@asyncapi/parser/cjs/models/v2/asyncapi'); asyncApiDocumentMock = new AsyncAPIDocument({ 'x-parser-api-version': 0 }); diff --git a/apps/generator/test/templateConfigValidator.test.js b/apps/generator/test/templateConfigValidator.test.js index ef70f7de27..d9398399cb 100644 --- a/apps/generator/test/templateConfigValidator.test.js +++ b/apps/generator/test/templateConfigValidator.test.js @@ -1,6 +1,6 @@ /* eslint-disable sonarjs/no-identical-functions */ /* eslint-disable sonarjs/no-duplicate-string */ -const { validateTemplateConfig } = require('../lib/templateConfigValidator'); +const { validateTemplateConfig } = require('../lib/templateConfig/validator'); const fs = require('fs'); const path = require('path'); const { parse } = require('../lib/parser');