Skip to content

Commit

Permalink
Merge branch 'master' into 1199-file-template-improvement
Browse files Browse the repository at this point in the history
  • Loading branch information
Florence-Njeri authored Aug 13, 2024
2 parents faba732 + 9d60902 commit 1e55f14
Show file tree
Hide file tree
Showing 22 changed files with 1,721 additions and 4,167 deletions.
1 change: 0 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"linked": [],
"access": "public",
"baseBranch": "master",
"ignore": ["@asyncapi/nunjucks-filters"],
"updateInternalDependencies": "patch",
"privatePackages": {
"version": true,
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/release-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
id: version
run: |
VERSION=${{github.event.release.tag_name}}
VERSION_WITHOUT_V=${VERSION:1}
VERSION_WITHOUT_V=${VERSION##*@}
echo "value=${VERSION_WITHOUT_V}" >> $GITHUB_OUTPUT
- name: Set Up QEMU
Expand All @@ -36,7 +36,7 @@ jobs:
- name: Build Image
uses: docker/build-push-action@v4
with:
context: './apps/generator'
context: "{{defaultContext}}:apps/generator"
push: true
load: false
build-args: |
Expand All @@ -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!
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ coverage
# Turbo
.turbo

/.idea
30 changes: 30 additions & 0 deletions apps/generator/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# @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

- a3e93ef: update the git context for the docker versioning.

## 2.1.1

### Patch Changes

- 36ee8a8: Fix docker image publishing. Removed package name from version tag for Docker tagging.

## 2.1.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion apps/generator/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ARG ASYNCAPI_GENERATOR_VERSION=1.10.9

FROM node:14-alpine
FROM node:18-alpine

WORKDIR /app

Expand Down
28 changes: 28 additions & 0 deletions apps/generator/README.md
Original file line number Diff line number Diff line change
@@ -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

<!-- templates list is validated with GitHub Actions do not remove list markers -->
<!-- TEMPLATES-LIST:START -->

| 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) |

<!-- TEMPLATES-LIST:END -->

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)**
2 changes: 1 addition & 1 deletion apps/generator/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ module.exports = {
moduleNameMapper: {
'^nimma/legacy$': '<rootDir>../../node_modules/nimma/dist/legacy/cjs/index.js',
'^nimma/(.*)': '<rootDir>../../node_modules/nimma/dist/cjs/$1',
'^nunjucks-filters$': path.resolve(__dirname, '../nunjucks-filters'),
'^@asyncapi/nunjucks-filters$': path.resolve(__dirname, '../nunjucks-filters'),
},
};
11 changes: 8 additions & 3 deletions apps/generator/lib/filtersRegistry.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const path = require('path');
const fs = require('fs');
const xfs = require('fs.extra');
const { isAsyncFunction } = require('./utils');
const nunjucksFilters = require('nunjucks-filters');
const { isAsyncFunction, registerTypeScript } = require('./utils');
const nunjucksFilters = require('@asyncapi/nunjucks-filters');

/**
* Registers all template filters.
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 1 addition & 3 deletions apps/generator/lib/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const {
isReactTemplate,
isJsFile,
registerSourceMap,
registerTypeScript,
getTemplateDetails,
convertCollectionToObject,
} = require('./utils');
Expand Down Expand Up @@ -59,7 +58,6 @@ const shouldIgnoreDir = dirPath =>
|| dirPath.startsWith(`.git${path.sep}`);

registerSourceMap();
registerTypeScript();

class Generator {
/**
Expand Down Expand Up @@ -852,7 +850,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);
}
Expand Down
5 changes: 4 additions & 1 deletion apps/generator/lib/hooksRegistry.js
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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);

Expand Down
20 changes: 12 additions & 8 deletions apps/generator/lib/logMessages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`;
}
Expand All @@ -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.`;
}
Expand All @@ -54,6 +58,6 @@ module.exports = {
installationDebugMessage,
templateSuccessfullyInstalled,
relativeSourceFileNotGenerated,
conditionalFilesMatched

};
conditionalFilesMatched,
skipOverwrite
};
2 changes: 1 addition & 1 deletion apps/generator/lib/parser.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require('fs');
const { convertToOldAPI } = require('@asyncapi/parser');
const { ConvertDocumentParserAPIVersion, NewParser } = require('@smoya/multi-parser');
const { ConvertDocumentParserAPIVersion, NewParser } = require('@asyncapi/multi-parser');

const parser = module.exports;

Expand Down
46 changes: 30 additions & 16 deletions apps/generator/lib/renderer/react.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const path = require('path');
const AsyncReactSDK = require('@asyncapi/generator-react-sdk');
const minimatch = require('minimatch');
const logMessage = require('../logMessages.js');
const log = require('loglevel');
const {
writeFile
} = require('../utils');
Expand All @@ -8,7 +11,7 @@ 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
Expand All @@ -23,44 +26,44 @@ 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
* @param {string} templateContentDir where the template content are located
* @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<TemplateRenderResult>}
*/
reactExport.renderReact = async (asyncapiDocument, filePath, extraTemplateData, templateLocation, templateContentDir, transpiledTemplateLocation, templateParams, debug, originalAsyncAPI) => {
extraTemplateData = extraTemplateData || {};
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;

Expand All @@ -78,21 +81,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);
};
8 changes: 7 additions & 1 deletion apps/generator/lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 1e55f14

Please sign in to comment.