diff --git a/.archivist/config.json b/.archivist/config.json new file mode 100644 index 000000000..ab1ddae63 --- /dev/null +++ b/.archivist/config.json @@ -0,0 +1,22 @@ +{ + "projectId": "b4228f2e-a928-445e-83d8-6bc7a05c420e", + "ignoredFiles": [ + ".DS_Store", + ".env", + ".archivist/", + ".idea/", + ".vscode/", + "env/", + "venv/", + ".git/", + ".gitignore", + "__pycache__/", + "__init__.py", + "dist/", + "node_modules/", + "package-lock.json", + "yarn.lock", + "*.config.js", + ".next/" + ] +} \ No newline at end of file diff --git a/.changeset/config.json b/.changeset/config.json index d86fcec82..2396f0ca7 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -6,7 +6,6 @@ "linked": [], "access": "public", "baseBranch": "master", - "ignore": ["@asyncapi/nunjucks-filters"], "updateInternalDependencies": "patch", "privatePackages": { "version": true, diff --git a/.changeset/proud-brooms-accept.md b/.changeset/proud-brooms-accept.md deleted file mode 100644 index 8a8feff94..000000000 --- a/.changeset/proud-brooms-accept.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@asyncapi/generator": patch ---- - -Updated the method for importing the Nunjucks filter dependency \ No newline at end of file diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index 93f6615eb..82366d8a8 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -47,11 +47,15 @@ jobs: platforms: linux/amd64,linux/arm64 cache-from: type=gha cache-to: type=gha - + + - name: Check out the repository + uses: actions/checkout@v4 + - name: Update Docker Hub Readme uses: meeDamian/sync-readme@v1.0.6 with: user: ${{ secrets.DOCKER_USERNAME }} pass: ${{ secrets.DOCKER_PASSWORD }} slug: asyncapi/generator + readme: ./apps/generator/README.md description: Use your AsyncAPI definition to generate literally anything. Markdown documentation, Node.js code, HTML documentation, anything! diff --git a/.gitignore b/.gitignore index ecb69486e..a53c05bd1 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ coverage # Turbo .turbo +/.idea diff --git a/apps/generator/CHANGELOG.md b/apps/generator/CHANGELOG.md index ea79756ba..d83655139 100644 --- a/apps/generator/CHANGELOG.md +++ b/apps/generator/CHANGELOG.md @@ -1,5 +1,23 @@ # @asyncapi/generator +## 2.3.0 + +### Minor Changes + +- 44fcc33: ts-node is registered only when it's actually needed + +## 2.2.0 + +### Minor Changes + +- 81dfd0c: Enable `noOverwriteGlobs` option for templates based on react rendering engine. + +## 2.1.3 + +### Patch Changes + +- 93fb8e8: Updated the method for importing the Nunjucks filter dependency + ## 2.1.2 ### Patch Changes diff --git a/apps/generator/README.md b/apps/generator/README.md new file mode 100644 index 000000000..13f9ba7b3 --- /dev/null +++ b/apps/generator/README.md @@ -0,0 +1,28 @@ +Generator is a tool that you can use to generate whatever you want basing on the AsyncAPI specification file as an input. For more information [read the docs](https://www.asyncapi.com/docs/tools/generator). + +There is a large number of templates that are ready to use and are officially supported by the AsyncAPI Initiative. + +## List of official generator templates + + + + +| Template Name | Description | Source code | +| --------------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------- | +| `@asyncapi/nodejs-template` | Generates Nodejs service that uses Hermes package | [click here](https://github.com/asyncapi/nodejs-template) | +| `@asyncapi/nodejs-ws-template` | Generates Nodejs service that supports WebSockets protocol only | [click here](https://github.com/asyncapi/nodejs-ws-template) | +| `@asyncapi/java-template` | Generates Java JMS application | [click here](https://github.com/asyncapi/java-template) | +| `@asyncapi/java-spring-template` | Generates Java Spring service | [click here](https://github.com/asyncapi/java-spring-template) | +| `@asyncapi/java-spring-cloud-stream-template` | Generates Java Spring Cloud Stream service | [click here](https://github.com/asyncapi/java-spring-cloud-stream-template) | +| `@asyncapi/python-paho-template` | Generates Python service that uses Paho library | [click here](https://github.com/asyncapi/python-paho-template) | +| `@asyncapi/html-template` | Generates HTML documentation site | [click here](https://github.com/asyncapi/html-template) | +| `@asyncapi/markdown-template` | Generates documentation in Markdown file | [click here](https://github.com/asyncapi/markdown-template) | +| `@asyncapi/ts-nats-template` | Generates TypeScript NATS client | [click here](https://github.com/asyncapi/ts-nats-template/) | +| `@asyncapi/go-watermill-template` | Generates Go client using Watermill | [click here](https://github.com/asyncapi/go-watermill-template) | +| `@asyncapi/dotnet-nats-template` | Generates .NET C# client using NATS | [click here](https://github.com/asyncapi/dotnet-nats-template) | +| `@asyncapi/php-template` | Generates PHP client using RabbitMQ | [click here](https://github.com/asyncapi/php-template) | +| `@asyncapi/dotnet-rabbitmq-template` | Generates .NET C# client using RabbitMQ | [click here](https://github.com/asyncapi/dotnet-rabbitmq-template) | + + + +You can find above templates and the ones provided by the community in **[this list](https://github.com/search?q=topic%3Aasyncapi+topic%3Agenerator+topic%3Atemplate)** diff --git a/apps/generator/docs/depreciate-nunjucks.md b/apps/generator/docs/depreciate-nunjucks.md new file mode 100644 index 000000000..ab06950ee --- /dev/null +++ b/apps/generator/docs/depreciate-nunjucks.md @@ -0,0 +1,121 @@ +--- +title: "Depreciation of nunjucks render engine" +weight: 170 +--- + +# Migration Guide from nunjucks render engine to react render engine + +## Introduction + +AsyncAPI Generator is moving away from Nunjucks templates in favor of React templates. This guide will help you migrate your existing Nunjucks templates to React. + +## Step-by-Step Migration Guide + +### 1. Update package.json + +Change your template configuration in `package.json`: + +```json +{ +"generator": { +"renderer": "react" +} +} +``` + +### 2. Install Dependencies + +Install the necessary React dependencies: + +```bash +npm install @asyncapi/generator-react-sdk +``` + +### 3. Basic Template Structure + +Nunjucks: +```jsx +

{{ asyncapi.info().title() }}

+

{{ asyncapi.info().description() }}

+``` + +React: +```jsx +import { File } from '@asyncapi/generator-react-sdk'; + +export default function({ asyncapi }) { + return ( + +

{asyncapi.info().title()}

+

{asyncapi.info().description()}

+
+ ); +} +``` + +### 4. Macros + +Replace macros with React components: + +Nunjucks: +```jsx +{% macro renderChannel(channel) %} +
+

{{ channel.address() }}

+

{{ channel.description() }}

+
+{% endmacro %} + +{{ renderChannel(someChannel) }} +``` + +React: +```jsx +// components/Channel.js +import { Text } from '@asyncapi/generator-react-sdk'; + +export function Channel({ channel }) { + return ( + +
+

{channel.address()}

+

{channel.description()}

+
+
+ ); +} + +// Main template +import { File, Text } from '@asyncapi/generator-react-sdk'; +import { Channel } from './components/Channel'; + +export default function({ asyncapi }) { + return ( + + +

Channels

+
+ {asyncapi.channels().map(channel => ( + + ))} +
+ ); +} +``` + +### 5. File template + +//TODO: we can add a link to Florence docs once it is merged + +## Testing Your Migration + +After migrating, test your template thoroughly: + +1. Run the generator with your new React template +2. Compare the output with the previous Nunjucks template output +3. Check for any missing or incorrectly rendered content + +## Conclusion + +Migrating from Nunjucks to React templates may require some initial effort, but it will result in more maintainable. You can read why we introduced react render engine [here](https://www.asyncapi.com/blog/react-as-generator-engine) + diff --git a/apps/generator/hello.js b/apps/generator/hello.js new file mode 100644 index 000000000..831276c55 --- /dev/null +++ b/apps/generator/hello.js @@ -0,0 +1,50 @@ +const path = require("path"); +const Generator = require("./lib/generator"); +const { promises: fsPromise } = require("fs"); +const reactTemplate = 'test/test-templates/react-template'; + +// const reactTemplate = path.resolve(__dirname, "./test/test-templates/react-template"); +// console.log("reactTemplate", reactTemplate); +const dummySpecPath = path.resolve(__dirname, './test/docs/dummy.yml'); + +async function main() { + const outputDir = path.resolve(__dirname, "test/hello"); + console.log("outputDir", outputDir); + // await fsPromise.mkdir(outputDir, { recursive: true }); + + // Create temp.md.js file dynamically + const tempJsContent = ` + import { File, Text } from '@asyncapi/generator-react-sdk'; + + export default function() { + return ( + + Test + + ); +} +`; +// const reactTemplate = path.resolve(__dirname, "./test/test-templates/react-template"); +console.log("reactTemplate", reactTemplate); + const transpiledPath = path.join(reactTemplate, '__transpiled'); + + // await fsPromise.unlink(path.join(transpiledPath, 'temp.md.js')) + // await fsPromise.unlink(path.join(transpiledPath, 'temp.md.js.map')) + + const tempJsPath = path.join(reactTemplate, "template","temp.md.js"); + await fsPromise.writeFile(tempJsPath, tempJsContent); + console.log("tempJsPath", tempJsPath); + + const generator = new Generator(reactTemplate, outputDir, { + forceWrite: true, + debug: true, + compile: false, + }); + await generator.generateFromFile(dummySpecPath); + + // Check if temp.md is created in the output directory + const tempMdPath = path.join(outputDir, "temp.md"); + console.log("tempMdPath", tempMdPath); +} + +main() \ No newline at end of file diff --git a/apps/generator/lib/filtersRegistry.js b/apps/generator/lib/filtersRegistry.js index 4c90aed31..6659960ed 100644 --- a/apps/generator/lib/filtersRegistry.js +++ b/apps/generator/lib/filtersRegistry.js @@ -1,7 +1,7 @@ const path = require('path'); const fs = require('fs'); const xfs = require('fs.extra'); -const { isAsyncFunction } = require('./utils'); +const { isAsyncFunction, registerTypeScript } = require('./utils'); const nunjucksFilters = require('@asyncapi/nunjucks-filters'); /** @@ -38,7 +38,12 @@ function registerLocalFilters(nunjucks, templateDir, filtersDir) { walker.on('file', async (root, stats, next) => { try { - const filePath = path.resolve(templateDir, path.resolve(root, stats.name)); + const filePath = path.resolve( + templateDir, + path.resolve(root, stats.name) + ); + + registerTypeScript(filePath); // If it's a module constructor, inject dependencies to ensure consistent usage in remote templates in other projects or plain directories. delete require.cache[require.resolve(filePath)]; const mod = require(filePath); diff --git a/apps/generator/lib/generator.js b/apps/generator/lib/generator.js index 837414c7c..edbaa9f07 100644 --- a/apps/generator/lib/generator.js +++ b/apps/generator/lib/generator.js @@ -28,7 +28,6 @@ const { isReactTemplate, isJsFile, registerSourceMap, - registerTypeScript, getTemplateDetails, convertCollectionToObject, } = require('./utils'); @@ -59,7 +58,6 @@ const shouldIgnoreDir = dirPath => || dirPath.startsWith(`.git${path.sep}`); registerSourceMap(); -registerTypeScript(); class Generator { /** @@ -854,7 +852,7 @@ class Generator { if (renderContent === undefined) { return; } else if (isReactTemplate(this.templateConfig)) { - await saveRenderedReactContent(renderContent, outputpath); + await saveRenderedReactContent(renderContent, outputpath, this.noOverwriteGlobs); } else { await writeFile(outputpath, renderContent); } @@ -933,9 +931,11 @@ class Generator { async renderFile(asyncapiDocument, filePath, extraTemplateData = {}) { if (isReactTemplate(this.templateConfig)) { return await renderReact(asyncapiDocument, filePath, extraTemplateData, this.templateDir, this.templateContentDir, TRANSPILED_TEMPLATE_LOCATION, this.templateParams, this.debug, this.originalAsyncAPI); + } else { + console.warn('Deprecation Warning: Nunjucks templates are deprecated. Please migrate to React templates.'); + const templateString = await readFile(filePath, 'utf8'); + return renderNunjucks(asyncapiDocument, templateString, filePath, extraTemplateData, this.templateParams, this.originalAsyncAPI, this.nunjucks); } - const templateString = await readFile(filePath, 'utf8'); - return renderNunjucks(asyncapiDocument, templateString, filePath, extraTemplateData, this.templateParams, this.originalAsyncAPI, this.nunjucks); } /** diff --git a/apps/generator/lib/hooksRegistry.js b/apps/generator/lib/hooksRegistry.js index bde5c919c..2c21389fb 100644 --- a/apps/generator/lib/hooksRegistry.js +++ b/apps/generator/lib/hooksRegistry.js @@ -1,6 +1,6 @@ const path = require('path'); const xfs = require('fs.extra'); -const { exists } = require('./utils'); +const { exists, registerTypeScript } = require('./utils'); /** * Registers all template hooks. @@ -37,6 +37,9 @@ async function registerLocalHooks(hooks, templateDir, hooksDir) { walker.on('file', async (root, stats, next) => { try { const filePath = path.resolve(templateDir, path.resolve(root, stats.name)); + + registerTypeScript(filePath); + delete require.cache[require.resolve(filePath)]; const mod = require(filePath); diff --git a/apps/generator/lib/logMessages.js b/apps/generator/lib/logMessages.js index 13ac04c7e..5d28bf8f0 100644 --- a/apps/generator/lib/logMessages.js +++ b/apps/generator/lib/logMessages.js @@ -6,22 +6,22 @@ const NODE_MODULES_INSTALL ='Remember that your local template must have its own const NPM_INSTALL_TRIGGER = 'Installation of template located on disk technically means symlink creation betweed node_modules of the generator and template sources. Your local template must have its own node_modules, "npm install" is not triggered.'; -function templateVersion(ver) { +function templateVersion(ver) { return `Version of used template is ${ver}.`; -} +} function templateSource(localHtmlTemplate) { return `Template sources taken from ${localHtmlTemplate}.`; -} +} function templateNotFound(templateName) { return `${templateName} not found in local dependencies but found it installed as a global package.`; -} +} function packageNotAvailable(packageDetails) { if (packageDetails && packageDetails.pkgPath) { return `Unable to resolve template location at ${packageDetails.pkgPath}. Package is not available locally.`; - } + } return `Template is not available locally and expected location is undefined. Known details are: ${JSON.stringify(packageDetails, null, 2)}`; } @@ -38,6 +38,10 @@ function relativeSourceFileNotGenerated(relativeSourceFile , subject) { return `${relativeSourceFile} was not generated because ${subject} specified in template configuration in conditionalFiles was not found in provided AsyncAPI specification file.`; } +function skipOverwrite(testFilePath) { + return `Skipping overwrite for: ${testFilePath}`; +} + function conditionalFilesMatched(relativeSourceFile) { return `${relativeSourceFile} was not generated because condition specified for this file in template configuration in conditionalFiles matched.`; } @@ -59,5 +63,7 @@ module.exports = { templateSuccessfullyInstalled, relativeSourceFileNotGenerated, conditionalFilesMatched, - compileEnabled -}; \ No newline at end of file + compileEnabled, + compileEnabled, + skipOverwrite +}; diff --git a/apps/generator/lib/renderer/nunjucks.js b/apps/generator/lib/renderer/nunjucks.js index 410b8d945..7b2a0f51c 100644 --- a/apps/generator/lib/renderer/nunjucks.js +++ b/apps/generator/lib/renderer/nunjucks.js @@ -9,6 +9,7 @@ const nunjucksExport = module.exports; * @param {string} templateDir path */ nunjucksExport.configureNunjucks = (debug, templateDir) => { + console.warn('Deprecation Warning: Nunjucks support is being phased out. Please migrate to React templates.'); const config = {}; if (debug) config.dev = true; diff --git a/apps/generator/lib/renderer/react.js b/apps/generator/lib/renderer/react.js index 4aad213fc..19d176719 100644 --- a/apps/generator/lib/renderer/react.js +++ b/apps/generator/lib/renderer/react.js @@ -1,16 +1,17 @@ const path = require('path'); -const AsyncReactSDK = require('@asyncapi/generator-react-sdk'); +const AsyncReactSDK = require('../../../../../generator-react-sdk/lib/index.js'); +const minimatch = require('minimatch'); +const logMessage = require('../logMessages.js'); +const log = require('loglevel'); const { writeFile } = require('../utils'); -const logMessage = require('../logMessages'); -const log = require('loglevel'); const reactExport = module.exports; /** * Configures React templating system, this handles all the transpilation work. - * + * * @private * @param {string} templateLocation located for thetemplate * @param {string} templateContentDir where the template content are located @@ -27,9 +28,9 @@ reactExport.configureReact = async (templateLocation, templateContentDir, transp /** * Renders the template with react and returns the content and meta data for the file. - * + * * @private - * @param {AsyncAPIDocument} asyncapiDocument + * @param {AsyncAPIDocument} asyncapiDocument * @param {string} filePath path to the template file * @param {Object} extraTemplateData Extra data to pass to the template. * @param {string} templateLocation located for thetemplate @@ -37,34 +38,41 @@ reactExport.configureReact = async (templateLocation, templateContentDir, transp * @param {string} transpiledTemplateLocation folder for the transpiled code * @param {Object} templateParams provided template parameters * @param {boolean} debug flag - * @param {string} originalAsyncAPI + * @param {string} originalAsyncAPI * @return {Promise} */ -reactExport.renderReact = async (asyncapiDocument, filePath, extraTemplateData, templateLocation, templateContentDir, transpiledTemplateLocation, templateParams, debug, originalAsyncAPI) => { +reactExport.renderReact = async (asyncapiDocument, filePath, extraTemplateData, templateLocation, templateContentDir, transpiledTemplateLocation, templateParams, debug, originalAsyncAPI, compile) => { extraTemplateData = extraTemplateData || {}; + let fileToRender; + if (compile) { + fileToRender = filePath.replace(templateContentDir, path.resolve(templateLocation, transpiledTemplateLocation)); + } else { + fileToRender = filePath; + } + console.log('Attempting to render file:', fileToRender); filePath = filePath.replace(templateContentDir, path.resolve(templateLocation, transpiledTemplateLocation)); return await AsyncReactSDK.renderTemplate( - filePath, + filePath, { asyncapi: asyncapiDocument, params: templateParams, originalAsyncAPI, ...extraTemplateData - }, + }, debug ); }; /** * Save the single rendered react content based on the meta data available. - * + * * @private * @param {TemplateRenderResult} renderedContent the react content rendered * @param {String} outputPath Path to the file being rendered. */ -const saveContentToFile = async (renderedContent, outputPath) => { +const saveContentToFile = async (renderedContent, outputPath, noOverwriteGlobs = []) => { let filePath = outputPath; - // Might be the same as in the `fs` package, but is an active choice for our default file permission for any rendered files. + // Might be the same as in the `fs` package, but is an active choice for our default file permission for any rendered files. let permissions = 0o666; const content = renderedContent.content; @@ -82,21 +90,32 @@ const saveContentToFile = async (renderedContent, outputPath) => { } } - await writeFile(filePath, content, { - mode: permissions - }); + // get the final file name of the file + const finalFileName = path.basename(filePath); + // check whether the filename should be ignored based on user's inputs + const shouldOverwrite = !noOverwriteGlobs.some(globExp => minimatch(finalFileName, globExp)); + + // Write the file only if it should not be skipped + if (shouldOverwrite) { + await writeFile(filePath, content, { + mode: permissions + }); + } else { + await log.debug(logMessage.skipOverwrite(filePath)); + } }; /** * Save the rendered react content based on the meta data available. - * + * * @private * @param {TemplateRenderResult[] | TemplateRenderResult} renderedContent the react content rendered * @param {String} outputPath Path to the file being rendered. + * @param noOverwriteGlobs Array of globs to skip overwriting files. */ -reactExport.saveRenderedReactContent = async (renderedContent, outputPath) => { +reactExport.saveRenderedReactContent = async (renderedContent, outputPath, noOverwriteGlobs = []) => { if (Array.isArray(renderedContent)) { - return Promise.all(renderedContent.map(content => saveContentToFile(content, outputPath))); + return Promise.all(renderedContent.map(content => saveContentToFile(content, outputPath, noOverwriteGlobs))); } - return saveContentToFile(renderedContent, outputPath); + return await saveContentToFile(renderedContent, outputPath, noOverwriteGlobs); }; diff --git a/apps/generator/lib/utils.js b/apps/generator/lib/utils.js index f7026b166..27e26de0f 100644 --- a/apps/generator/lib/utils.js +++ b/apps/generator/lib/utils.js @@ -149,7 +149,13 @@ utils.registerSourceMap = () => { * * @private */ -utils.registerTypeScript = () => { +utils.registerTypeScript = (filePath) => { + const isTypescriptFile = filePath.endsWith('.ts'); + + if (!isTypescriptFile) { + return; + } + const { REGISTER_INSTANCE, register } = require('ts-node'); // if the ts-node has already been registered before, do not register it again. // Check the env. TS_NODE_ENV if ts-node started via ts-node-dev package diff --git a/apps/generator/package.json b/apps/generator/package.json index 19aacaa8b..b83e72ffd 100644 --- a/apps/generator/package.json +++ b/apps/generator/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/generator", - "version": "2.1.2", + "version": "2.3.0", "description": "The AsyncAPI generator. It can generate documentation, code, anything!", "main": "./lib/generator.js", "bin": { @@ -15,8 +15,8 @@ "test": "npm run test:unit && npm run test:integration && npm run test:cli", "test:unit": "jest --coverage --testPathIgnorePatterns=integration --testPathIgnorePatterns=test-project", "test:dev": "npm run test:unit -- --watchAll", - "test:integration": "npm run test:cleanup && jest --testPathPattern=integration --modulePathIgnorePatterns='./__mocks__'", - "test:integration:update": "jest --updateSnapshot --testPathPattern=integration --modulePathIgnorePatterns='./__mocks__'", + "test:integration": "npm run test:cleanup && jest --testPathPattern=integration --modulePathIgnorePatterns='./__mocks__(?!\\/loglevel\\.js$)'", + "test:integration:update": "jest --updateSnapshot --testPathPattern=integration --modulePathIgnorePatterns='./__mocks__(?!\\/loglevel\\.js$)'", "test:cli": "node cli.js ./test/docs/dummy.yml ./test/test-templates/react-template -o test/output --force-write --debug && test -e test/output/test-file.md", "test:cleanup": "rimraf \"test/temp\"", "docs": "jsdoc2md --partial docs/jsdoc2md-handlebars/custom-sig-name.hbs docs/jsdoc2md-handlebars/main.hbs docs/jsdoc2md-handlebars/docs.hbs docs/jsdoc2md-handlebars/header.hbs docs/jsdoc2md-handlebars/defaultvalue.hbs docs/jsdoc2md-handlebars/link.hbs docs/jsdoc2md-handlebars/params-table.hbs --files lib/generator.js > docs/api.md", diff --git a/apps/generator/test/integration.test.js b/apps/generator/test/integration.test.js index b4f86499e..949253a96 100644 --- a/apps/generator/test/integration.test.js +++ b/apps/generator/test/integration.test.js @@ -3,7 +3,7 @@ */ const path = require('path'); -const { readFile, writeFile, access } = require('fs').promises; +const { readFile, writeFile, access, unlink, mkdir } = require('fs').promises; const Generator = require('../lib/generator'); const dummySpecPath = path.resolve(__dirname, './docs/dummy.yml'); const refSpecPath = path.resolve(__dirname, './docs/apiwithref.json'); @@ -22,9 +22,21 @@ describe('Integration testing generateFromFile() to make sure the result of the jest.setTimeout(100000); const testOutputFile = 'test-file.md'; + const tempJsContent = ` + import { File, Text } from '@asyncapi/generator-react-sdk'; + + export default function() { + return ( + + Test + + ); + } + `; + it('generated using Nunjucks template', async () => { const outputDir = generateFolderName(); - const generator = new Generator(nunjucksTemplate, outputDir, { + const generator = new Generator(nunjucksTemplate, outputDir, { forceWrite: true, templateParams: { version: 'v1', mode: 'production' } }); @@ -35,7 +47,7 @@ describe('Integration testing generateFromFile() to make sure the result of the it('generate using React template', async () => { const outputDir = generateFolderName(); - const generator = new Generator(reactTemplate, outputDir, { + const generator = new Generator(reactTemplate, outputDir, { forceWrite: true , templateParams: { version: 'v1', mode: 'production' } }); @@ -60,17 +72,6 @@ describe('Integration testing generateFromFile() to make sure the result of the const outputDir = generateFolderName(); // Create temp.md.js file dynamically - const tempJsContent = ` - import { File, Text } from '@asyncapi/generator-react-sdk'; - - export default function() { - return ( - - Test - - ); - } - `; const tempJsPath = path.join(reactTemplate, 'template/temp.md.js'); await writeFile(tempJsPath, tempJsContent); @@ -90,19 +91,13 @@ describe('Integration testing generateFromFile() to make sure the result of the it('check if the temp.md file is not created when compile option is false', async () => { const outputDir = generateFolderName(); - + + // first we need to do cleanup of the react template `__transpiled` folder as from previous test it will have the transpiled files + const transpiledPath = path.join(reactTemplate, '__transpiled'); + await unlink(path.join(transpiledPath, 'temp.md.js')); + await unlink(path.join(transpiledPath, 'temp.md.js.map')); + // Create temp.md.js file dynamically - const tempJsContent = ` - import { File, Text } from '@asyncapi/generator-react-sdk'; - - export default function() { - return ( - - Test - - ); - } - `; const tempJsPath = path.join(reactTemplate, 'template/temp.md.js'); await writeFile(tempJsPath, tempJsContent); @@ -118,4 +113,33 @@ describe('Integration testing generateFromFile() to make sure the result of the const tempMdExists = await access(tempMdPath).then(() => true).catch(() => false); expect(tempMdExists).toBe(false); }); + + it('should ignore specified files with noOverwriteGlobs', async () => { + const outputDir = generateFolderName(); + // Manually create a file to test if it's not overwritten + await mkdir(outputDir, { recursive: true }); + // Create a variable to store the file content + const testContent = ''; + // eslint-disable-next-line sonarjs/no-duplicate-string + const testFilePath = path.normalize(path.resolve(outputDir, testOutputFile)); + await writeFile(testFilePath, testContent); + + // Manually create an output first, before generation, with additional custom file to validate if later it is still there, not overwritten + const generator = new Generator(reactTemplate, outputDir, { + forceWrite: true, + noOverwriteGlobs: [`**/${testOutputFile}`], + debug: true, + }); + + await generator.generateFromFile(dummySpecPath); + + // Read the file to confirm it was not overwritten + const fileContent = await readFile(testFilePath, 'utf8'); + // Check if the files have been overwritten + expect(fileContent).toBe(testContent); + // Check if the log debug message was printed + /*TODO: + Include log message test in the future to ensure that the log.debug for skipping overwrite is called + */ + }); }); diff --git a/apps/generator/test/test-templates/react-template/template/temp.md.js b/apps/generator/test/test-templates/react-template/template/temp.md.js new file mode 100644 index 000000000..911686c2a --- /dev/null +++ b/apps/generator/test/test-templates/react-template/template/temp.md.js @@ -0,0 +1,10 @@ + + import { File, Text } from '@asyncapi/generator-react-sdk'; + + export default function() { + return ( + + Test + + ); +} diff --git a/package-lock.json b/package-lock.json index 5f3b1b082..b2eac8b6f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ }, "apps/generator": { "name": "@asyncapi/generator", - "version": "2.1.2", + "version": "2.3.0", "license": "Apache-2.0", "dependencies": { "@asyncapi/generator-react-sdk": "^1.0.18",