Skip to content

Commit

Permalink
Merge branch 'master' into readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Florence-Njeri authored Sep 9, 2024
2 parents 0b477f9 + 0ab1a3d commit aad8980
Show file tree
Hide file tree
Showing 26 changed files with 573 additions and 324 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
5 changes: 0 additions & 5 deletions .changeset/proud-brooms-accept.md

This file was deleted.

6 changes: 5 additions & 1 deletion .github/workflows/release-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
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!
8 changes: 4 additions & 4 deletions .github/workflows/update-docs-in-website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
branches:
- 'master'
paths:
- 'docs/*.md'
- 'apps/generator/docs/*.md'

jobs:
Make-PR:
Expand Down Expand Up @@ -37,10 +37,10 @@ jobs:
run: |
rm -r ./markdown/docs/tools/generator
mkdir -p ./markdown/docs/tools/generator
rm ../generator/docs/README.md
rm -r ../generator/docs/jsdoc2md-handlebars
rm ../generator/apps/generator/docs/README.md
rm -r ../generator/apps/generator/docs/jsdoc2md-handlebars
printf "%s\ntitle: Generator\nweight: 3\n%s" "---" "---"> ../generator/docs/_section.md
mv ../generator/docs/*.md ./markdown/docs/tools/generator
mv ../generator/apps/generator/docs/*.md ./markdown/docs/tools/generator
- name: Commit and push
working-directory: ./website
run: |
Expand Down
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
1 change: 1 addition & 0 deletions apps/generator/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ output
out/
coverage
test/temp/integrationTestResult
test/temp/reactTemplate
test/test-project/package-lock.json
test/test-project/verdaccio/storage/
test/test-project/storage/
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.4.1

### Patch Changes

- 3a372c4: Removed the source-map-support package from the AsyncAPI Generator, as it is no longer required for version 2, which now supports Node.js version 18.12.0 and above.

## 2.4.0

### Minor Changes

- 46114d8: Add `compile` option to enable rerun of transpilation of templates build with react engine. It is set to `true` by default. In future major releases it will be set to `false` and we will explain how to publish template to include transpilation files by default. Transpiled files are already included in [`html-template`](https://github.com/asyncapi/html-template/pull/575). It means that you can run generator for `html-template` (it's latest version) with `compile=false` and this will improve the speed of HTML generation for you.

## 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
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)**
81 changes: 76 additions & 5 deletions apps/generator/docs/file-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ title: "File templates"
weight: 140
---

It is possible to generate files for each specific object in your AsyncAPI documentation. For example, you can specify a filename like `$$channel$$.js` to generate a file for each channel defined in your AsyncAPI. The following file-template names and extra variables in them are available:
## Generating files with the Nunjucks render engine

> **Note**: This section applies only to the Nunjucks render engine. For information on using the React render engine, refer to the [Generating files with the React render engine](#generating-files-with-the-react-render-engine) section below.
It is possible to generate files for each specific object in your AsyncAPI documentation using the Nunjucks render engine. For example, you can specify a filename like `$$channel$$.js` to generate a file for each channel defined in your AsyncAPI. The following file-template names and extra variables are available:

- `$$channel$$`, within the template-file you have access to two variables [`channel`](https://github.com/asyncapi/parser-api/blob/master/docs/api.md#channel) and [`channelName`](https://github.com/asyncapi/parser-api/blob/master/docs/api.md#channels). Where the `channel` contains the current channel being rendered.
- `$$message$$`, within the template-file you have access to two variables [`message`](https://github.com/asyncapi/parser-api/blob/master/docs/api.md#message) and [`messageName`](https://github.com/asyncapi/parser-api/blob/master/docs/api.md#message). Where `message` contains the current message being rendered.
Expand All @@ -25,7 +29,7 @@ Schema name is '{{schemaName}}' and properties are:
{% endfor %}
```

With following AsyncAPI:
With the following AsyncAPI:
```
components:
schemas:
Expand Down Expand Up @@ -53,15 +57,82 @@ Schema name is 'people' and properties are:
- id
```

### React
> You can see an example of a file template that uses the Nunjucks render engine [here](https://github.com/asyncapi/template-for-generator-templates/tree/nunjucks/template/schemas).
## Generating files with the React render engine

The above way of rendering **file templates** works for both `nunjucks` and `react` render engines, but `react` also has another, more generic way to render multiple files. It is enough to return an array of `File` components in the rendering component. See the following example:
The above method of rendering **file templates** only works for the Nunjucks render engine. To use the React render engine, you need to follow a different approach. The React render engine allows for a more generic way to render multiple files by returning an array of `File` components in the rendering component. This can be particularly useful for complex templates or when you need to generate a large number of files with varying content.

### Example 1: Rendering hardcoded files

The following is a simple hardcoded example of how to render multiple files using the React render engine:

```tsx
import { File} from "@asyncapi/generator-react-sdk";

export default function({ asyncapi }) {
return [
<File name={`file1.html`}>Content</File>,
<File name={`file2.html`}>Content</File>
]
}
```
```

### Example 2: Rendering files based on the AsyncAPI Schema

In practice, to render the multiple files, that are generated from the data defined in your AsyncAPI, you'll iterate over the array of schemas and generate a file for each schema as shown in the example below:

```js
import { File} from "@asyncapi/generator-react-sdk";

/*
* To render multiple files, it is enough to return an array of `File` components in the rendering component, like in following example.
*/
export default function({ asyncapi }) {
const schemas = asyncapi.allSchemas();
const files = [];
// schemas is an instance of the Map
schemas.forEach((schema) => {

files.push(
// We return a react file component and each time we do it, the name of the generated file will be a schema name
// Content of the file will be a variable representing schema
<File name={`${schema.id()}.js`}>
const { schema.id() } = { JSON.stringify(schema._json, null, 2) }
</File>
);
});
return files;
}
```

### Example 3: Rendering files for each channel

Additionally, you can generate multiple files for each channel defined in your AsyncAPI specification using the React render engine as shown in the example below:

```js
import { File, Text } from "@asyncapi/generator-react-sdk";


export default function ({ asyncapi }) {
const files = [];

// Generate files for channels
asyncapi.channels().forEach((channel) => {
const channelName = channel.id();

files.push(
<File name={`${channelName}.md`}>
<Text newLines={2}># Channel: {channelName}</Text>
<Text>
{channel.hasDescription() && `${channel.description()}`}
</Text>
</File>
);
});
return files;
}
```
The code snippet above uses the `Text` component to write file content to the `.md` markdown file. The `newline` property is used to ensure that the content isn't all rendered in one line in the markdown file. In summary, the code snippet above is a practical guide on generating properly formatted multiline Markdown files for each channel in an AsyncAPI document.

> You can see an example of a file template that uses the React render engine [here](https://github.com/asyncapi/template-for-generator-templates/blob/master/template/schemas/schema.js).
9 changes: 7 additions & 2 deletions apps/generator/lib/filtersRegistry.js
Original file line number Diff line number Diff line change
@@ -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');

/**
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
17 changes: 7 additions & 10 deletions apps/generator/lib/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ const {
fetchSpec,
isReactTemplate,
isJsFile,
registerSourceMap,
registerTypeScript,
getTemplateDetails,
convertCollectionToObject,
} = require('./utils');
Expand All @@ -48,7 +46,7 @@ const DEFAULT_TEMPLATES_DIR = path.resolve(ROOT_DIR, 'node_modules');

const TRANSPILED_TEMPLATE_LOCATION = '__transpiled';
const TEMPLATE_CONTENT_DIRNAME = 'template';
const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder', 'url', 'auth', 'token', 'registry'];
const GENERATOR_OPTIONS = ['debug', 'disabledHooks', 'entrypoint', 'forceWrite', 'install', 'noOverwriteGlobs', 'output', 'templateParams', 'mapBaseUrlToFolder', 'url', 'auth', 'token', 'registry', 'compile'];
const logMessage = require('./logMessages');

const shouldIgnoreFile = filePath =>
Expand All @@ -58,9 +56,6 @@ const shouldIgnoreDir = dirPath =>
dirPath === '.git'
|| dirPath.startsWith(`.git${path.sep}`);

registerSourceMap();
registerTypeScript();

class Generator {
/**
* Instantiates a new Generator object.
Expand Down Expand Up @@ -88,20 +83,22 @@ class Generator {
* @param {Boolean} [options.forceWrite=false] Force writing of the generated files to given directory even if it is a git repo with unstaged files or not empty dir. Default is set to false.
* @param {Boolean} [options.install=false] Install the template and its dependencies, even when the template has already been installed.
* @param {Boolean} [options.debug=false] Enable more specific errors in the console. At the moment it only shows specific errors about filters. Keep in mind that as a result errors about template are less descriptive.
* @param {Boolean} [options.compile=true] Whether to compile the template or use the cached transpiled version provided by template in '__transpiled' folder
* @param {Object<String, String>} [options.mapBaseUrlToFolder] Optional parameter to map schema references from a base url to a local base folder e.g. url=https://schema.example.com/crm/ folder=./test/docs/ .
* @param {Object} [options.registry] Optional parameter with private registry configuration
* @param {String} [options.registry.url] Parameter to pass npm registry url
* @param {String} [options.registry.auth] Optional parameter to pass npm registry username and password encoded with base64, formatted like username:password value should be encoded
* @param {String} [options.registry.token] Optional parameter to pass npm registry auth token that you can grab from .npmrc file
*/

constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry = {}} = {}) {
constructor(templateName, targetDir, { templateParams = {}, entrypoint, noOverwriteGlobs, disabledHooks, output = 'fs', forceWrite = false, install = false, debug = false, mapBaseUrlToFolder = {}, registry = {}, compile = true } = {}) {
const options = arguments[arguments.length - 1];
this.verifyoptions(options);
if (!templateName) throw new Error('No template name has been specified.');
if (!entrypoint && !targetDir) throw new Error('No target directory has been specified.');
if (!['fs', 'string'].includes(output)) throw new Error(`Invalid output type ${output}. Valid values are 'fs' and 'string'.`);

/** @type {Boolean} Whether to compile the template or use the cached transpiled version provided by template in '__transpiled' folder. */
this.compile = compile;
/** @type {Object} Npm registry information. */
this.registry = registry;
/** @type {String} Name of the template to generate. */
Expand Down Expand Up @@ -395,7 +392,7 @@ class Generator {
* Configure the templates based the desired renderer.
*/
async configureTemplate() {
if (isReactTemplate(this.templateConfig)) {
if (isReactTemplate(this.templateConfig) && this.compile) {
await configureReact(this.templateDir, this.templateContentDir, TRANSPILED_TEMPLATE_LOCATION);
} else {
this.nunjucks = configureNunjucks(this.debug, this.templateDir);
Expand Down Expand Up @@ -852,7 +849,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
Loading

0 comments on commit aad8980

Please sign in to comment.