-
-
Notifications
You must be signed in to change notification settings - Fork 238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: generate function refactored to reduce cognitive complexity #1047
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -136,67 +136,174 @@ class Generator { | |
}); | ||
} | ||
|
||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
|
||
/** | ||
* Generates files from a given template and an AsyncAPIDocument object. | ||
* | ||
* @async | ||
* @example | ||
* generator | ||
* .generate(myAsyncAPIdocument) | ||
* .then(() => { | ||
* console.log('Done!'); | ||
* }) | ||
* .catch(console.error); | ||
* | ||
* @example <caption>Using async/await</caption> | ||
* try { | ||
* await generator.generate(myAsyncAPIdocument); | ||
* console.log('Done!'); | ||
* } catch (e) { | ||
* console.error(e); | ||
* } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can leave the different examples, no need to remove it 🙂 |
||
* | ||
* @param {AsyncAPIDocument | string} asyncapiDocument AsyncAPIDocument object to use as source. | ||
* @param {Object} [parseOptions={}] AsyncAPI Parser parse options. Check out {@link https://www.github.com/asyncapi/parser-js|@asyncapi/parser} for more information. Remember to use the right options to the right parser depending on the template you are using. | ||
* @return {Promise} | ||
* await generator.generate(myAsyncAPIdocument); | ||
* console.log('Done!'); | ||
* | ||
* @param {AsyncAPIDocument | string} asyncapiDocument - AsyncAPIDocument object to use as source. | ||
* @param {Object} [parseOptions={}] - AsyncAPI Parser parse options. | ||
* Check out {@link https://www.github.com/asyncapi/parser-js|@asyncapi/parser} for more information. | ||
* Remember to use the right options for the right parser depending on the template you are using. | ||
* @return {Promise<void>} A Promise that resolves when the generation is completed. | ||
*/ | ||
// eslint-disable-next-line sonarjs/cognitive-complexity | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No new lines between the jsdoc and function 🙂 |
||
async generate(asyncapiDocument, parseOptions = {}) { | ||
this.validateAsyncAPIDocument(asyncapiDocument); | ||
this.setupOutput(); | ||
this.setLogLevel(); | ||
|
||
await this.installAndSetupTemplate(); | ||
await this.configureTemplateWorkflow(parseOptions); | ||
await this.handleEntrypoint(); | ||
await this.executeAfterHook(); | ||
} | ||
|
||
/** | ||
* Validates the provided AsyncAPI document. | ||
* | ||
* @param {*} asyncapiDocument - The AsyncAPI document to be validated. | ||
* @throws {Error} Throws an error if the document is not valid. | ||
* @since 10/9/2023 - 4:26:33 PM | ||
*/ | ||
validateAsyncAPIDocument(asyncapiDocument) { | ||
const isAlreadyParsedDocument = isAsyncAPIDocument(asyncapiDocument); | ||
const isParsableCompatible = asyncapiDocument && typeof asyncapiDocument === 'string'; | ||
|
||
if (!isAlreadyParsedDocument && !isParsableCompatible) { | ||
throw new Error('Parameter "asyncapiDocument" must be a non-empty string or an already parsed AsyncAPI document.'); | ||
} | ||
|
||
this.asyncapi = this.originalAsyncAPI = asyncapiDocument; | ||
} | ||
|
||
// Setup the output based on the configured options | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need for this. |
||
/** | ||
* Sets up the output configuration based on the specified output type. | ||
* | ||
* @example | ||
* const generator = new Generator(); | ||
* generator.setupOutput(); | ||
* | ||
* @throws {Error} If 'output' is set to 'string' without providing 'entrypoint'. | ||
*/ | ||
setupOutput() { | ||
if (this.output === 'fs') { | ||
xfs.mkdirpSync(this.targetDir); | ||
if (!this.forceWrite) await this.verifyTargetDir(this.targetDir); | ||
this.setupFSOutput(); | ||
} else if (this.output === 'string' && this.entrypoint === undefined) { | ||
throw new Error('Parameter entrypoint is required when using output = "string"'); | ||
} | ||
} | ||
|
||
/** | ||
* Sets up the file system (FS) output configuration. | ||
* | ||
* This function creates the target directory if it does not exist and verifies | ||
* the target directory if forceWrite is not enabled. | ||
* | ||
* @async | ||
* @returns {Promise<void>} A promise that fulfills when the setup is complete. | ||
* | ||
* @throws {Error} If verification of the target directory fails and forceWrite is not enabled. | ||
*/ | ||
async setupFSOutput() { | ||
// Create directory if not exists | ||
xfs.mkdirpSync(this.targetDir); | ||
|
||
// Verify target directory if forceWrite is not enabled | ||
if (!this.forceWrite) { | ||
await this.verifyTargetDir(this.targetDir); | ||
} | ||
} | ||
|
||
/** | ||
* Sets the log level based on the debug option. | ||
* | ||
* If the debug option is enabled, the log level is set to 'debug'. | ||
* | ||
* @returns {void} | ||
*/ | ||
setLogLevel() { | ||
if (this.debug) log.setLevel('debug'); | ||
} | ||
|
||
/** | ||
* Installs and sets up the template for code generation. | ||
* | ||
* This function installs the specified template using the provided installation option, | ||
* sets up the necessary directory paths, loads the template configuration, and returns | ||
* information about the installed template. | ||
* | ||
* @async | ||
* @returns {Promise<{ templatePkgName: string, templatePkgPath: string }>} | ||
* A promise that resolves to an object containing the name and path of the installed template. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect indentation 🙂 |
||
async installAndSetupTemplate() { | ||
const { name: templatePkgName, path: templatePkgPath } = await this.installTemplate(this.install); | ||
|
||
this.templateDir = templatePkgPath; | ||
this.templateName = templatePkgName; | ||
this.templateContentDir = path.resolve(this.templateDir, TEMPLATE_CONTENT_DIRNAME); | ||
|
||
await this.loadTemplateConfig(); | ||
|
||
await this.parseInput(this.asyncapi, parseOptions); | ||
return { templatePkgName, templatePkgPath }; | ||
} | ||
|
||
/** | ||
* Configures the template workflow based on provided parsing options. | ||
* | ||
* This function performs the following steps: | ||
* 1. Parses the input AsyncAPI document using the specified parse options. | ||
* 2. Validates the template configuration and parameters. | ||
* 3. Configures the template based on the parsed AsyncAPI document. | ||
* 4. Registers filters, hooks, and launches the 'generate:before' hook if applicable. | ||
* | ||
* @async | ||
* @param {*} parseOptions - Options for parsing the AsyncAPI document. | ||
* @returns {Promise<void>} A promise that resolves when the configuration is completed. | ||
*/ | ||
async configureTemplateWorkflow(parseOptions) { | ||
// Parse input and validate template configuration | ||
await this.parseInput(this.asyncapi, parseOptions); | ||
validateTemplateConfig(this.templateConfig, this.templateParams, this.asyncapi); | ||
await this.configureTemplate(); | ||
|
||
if (!isReactTemplate(this.templateConfig)) { | ||
await registerFilters(this.nunjucks, this.templateConfig, this.templateDir, FILTERS_DIRNAME); | ||
} | ||
|
||
await registerHooks(this.hooks, this.templateConfig, this.templateDir, HOOKS_DIRNAME); | ||
await this.launchHook('generate:before'); | ||
} | ||
|
||
/** | ||
* Handles the logic for the template entrypoint. | ||
* | ||
* If an entrypoint is specified: | ||
* - Resolves the absolute path of the entrypoint file. | ||
* - Throws an error if the entrypoint file doesn't exist. | ||
* - Generates a file or renders content based on the output type. | ||
* - Launches the 'generate:after' hook if the output is 'fs'. | ||
* | ||
* If no entrypoint is specified, generates the directory structure. | ||
* | ||
* @async | ||
* @returns {Promise<void>} A promise that resolves when the entrypoint logic is completed. | ||
*/ | ||
async handleEntrypoint() { | ||
if (this.entrypoint) { | ||
const entrypointPath = path.resolve(this.templateContentDir, this.entrypoint); | ||
if (!(await exists(entrypointPath))) throw new Error(`Template entrypoint "${entrypointPath}" couldn't be found.`); | ||
|
||
if (!(await exists(entrypointPath))) { | ||
throw new Error(`Template entrypoint "${entrypointPath}" couldn't be found.`); | ||
} | ||
|
||
if (this.output === 'fs') { | ||
await this.generateFile(this.asyncapi, path.basename(entrypointPath), path.dirname(entrypointPath)); | ||
await this.launchHook('generate:after'); | ||
|
@@ -205,10 +312,21 @@ class Generator { | |
} | ||
} else { | ||
await this.generateDirectoryStructure(this.asyncapi); | ||
await this.launchHook('generate:after'); | ||
} | ||
} | ||
|
||
/** | ||
* Executes the 'generate:after' hook. | ||
* | ||
* Launches the after-hook to perform additional actions after code generation. | ||
* | ||
* @async | ||
* @returns {Promise<void>} A promise that resolves when the after-hook execution is completed. | ||
*/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect indentation |
||
async executeAfterHook() { | ||
await this.launchHook('generate:after'); | ||
} | ||
|
||
/** | ||
* Parse the generator input based on the template `templateConfig.apiVersion` value. | ||
*/ | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this 🙂