From c53aeb78da669add4dced30ff9e188fd2dedac14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Mon, 4 Nov 2024 01:29:43 +0300 Subject: [PATCH 1/7] feat golang: added data tags to have camelCase names in json, added comments from description --- modelina-cli/src/commands/generate.ts | 13 +++++- modelina-cli/src/helpers/generate.ts | 5 +++ modelina-cli/src/helpers/go.ts | 20 +++++++--- .../go/presets/DescriptionPreset.ts | 40 +++++++++++++++++++ src/generators/go/presets/index.ts | 1 + src/generators/go/renderers/StructRenderer.ts | 6 ++- 6 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 src/generators/go/presets/DescriptionPreset.ts diff --git a/modelina-cli/src/commands/generate.ts b/modelina-cli/src/commands/generate.ts index 3117df74d4..17b8053a5a 100644 --- a/modelina-cli/src/commands/generate.ts +++ b/modelina-cli/src/commands/generate.ts @@ -14,9 +14,18 @@ export default class Models extends ModelinaCommand { try { document = await readFile(file, 'utf8'); } catch { - throw new Error('Unable to read input file content.'); + if (flags.input) { + try { + document = await readFile(flags.input ? flags.input : "", 'utf8'); + } catch { + throw new Error('Unable to read input file content: "' + flags.input + '"'); + } + } + else { + throw new Error('Unable to read input file content: "' + file + '"'); + } } - + const logger = { info: (message: string) => { this.log(message); diff --git a/modelina-cli/src/helpers/generate.ts b/modelina-cli/src/helpers/generate.ts index ab3c34cae3..4b7fde1704 100644 --- a/modelina-cli/src/helpers/generate.ts +++ b/modelina-cli/src/helpers/generate.ts @@ -60,6 +60,11 @@ export const ModelinaFlags = { description: 'The output directory where the models should be written to. Omitting this flag will write the models to `stdout`.', required: false }), + input: Flags.string({ + char: 'i', + description: 'The input file with the API definition.', + required: false + }), /** * Go and Java specific package name to use for the generated models */ diff --git a/modelina-cli/src/helpers/go.ts b/modelina-cli/src/helpers/go.ts index ffd3a58d91..592c47d552 100644 --- a/modelina-cli/src/helpers/go.ts +++ b/modelina-cli/src/helpers/go.ts @@ -1,7 +1,14 @@ -import { GoFileGenerator } from "@asyncapi/modelina"; +import { GO_DESCRIPTION_PRESET, GoFileGenerator } from "@asyncapi/modelina"; import { BuilderReturnType } from "./generate"; +import { Flags } from "@oclif/core"; -export const GoOclifFlags = { } +export const GoOclifFlags = { + goIncludeComments: Flags.boolean({ + description: 'Golang specific, if enabled add comments while generating models.', + required: false, + default: false, + }), +} /** * This function builds all the relevant information for the main generate command @@ -10,13 +17,14 @@ export const GoOclifFlags = { } * @returns */ export function buildGoGenerator(flags: any): BuilderReturnType { - const { packageName } = flags; - + const { packageName, goIncludeComments } = flags; + if (packageName === undefined) { throw new Error('In order to generate models to Go, we need to know which package they are under. Add `--packageName=PACKAGENAME` to set the desired package name.'); } - - const fileGenerator = new GoFileGenerator(); + const presets = [] + if (goIncludeComments) { presets.push(GO_DESCRIPTION_PRESET); } + const fileGenerator = new GoFileGenerator({ presets }); const fileOptions = { packageName }; diff --git a/src/generators/go/presets/DescriptionPreset.ts b/src/generators/go/presets/DescriptionPreset.ts new file mode 100644 index 0000000000..3e2391aae2 --- /dev/null +++ b/src/generators/go/presets/DescriptionPreset.ts @@ -0,0 +1,40 @@ +import { ConstrainedMetaModel } from '../../../models'; +import { GoPreset } from '../GoPreset'; +import { GoRenderer } from '../GoRenderer'; + +const renderDescription = ({ + renderer, + content, + item +}: { + renderer: GoRenderer; + content: string; + item: ConstrainedMetaModel; +}): string => { + + const desc = item.originalInput.description?.trim(); + const formattedDesc = desc ? renderer.renderComments(desc) + '\n' : ''; + return formattedDesc + content; +}; + +/** + * Preset which adds descriptions + * + * @implements {GoPreset} + */ +export const GO_DESCRIPTION_PRESET: GoPreset = { + + struct: { + self({ renderer, model, content }) { + return renderDescription({ renderer, content, item: model }); + }, + field({ renderer, field, content }) { + return renderDescription({ renderer, content, item: field.property }); + } + }, + enum: { + self({ renderer, model, content }) { + return renderDescription({ renderer, content, item: model }); + } + } +}; diff --git a/src/generators/go/presets/index.ts b/src/generators/go/presets/index.ts index 58c93bfea2..e3563f5b88 100644 --- a/src/generators/go/presets/index.ts +++ b/src/generators/go/presets/index.ts @@ -1 +1,2 @@ export * from './CommonPreset'; +export * from './DescriptionPreset'; diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts index b75bf8716d..29c34004f2 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -78,7 +78,11 @@ export const GO_DEFAULT_STRUCT_PRESET: StructPresetType = { ) { fieldType = `*${fieldType}`; } - return `${field.propertyName} ${fieldType}`; + const jsonTag = field.required + ? `\`json:"${field.unconstrainedPropertyName},required"\`` + : `\`json:"${field.unconstrainedPropertyName},omitempty"\``; + + return `${field.propertyName} ${fieldType} ${jsonTag}`; }, discriminator({ model }) { const { parents } = model.options; From 01c21725671454c9f52bc01fb78ca95b9ce1b276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Mon, 4 Nov 2024 02:03:20 +0300 Subject: [PATCH 2/7] feat golang: fixed building data tags and enabled them in modelina cli --- modelina-cli/src/helpers/go.ts | 4 +++- src/generators/go/presets/CommonPreset.ts | 3 +++ src/generators/go/renderers/StructRenderer.ts | 11 +++-------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modelina-cli/src/helpers/go.ts b/modelina-cli/src/helpers/go.ts index 592c47d552..e07f08b77c 100644 --- a/modelina-cli/src/helpers/go.ts +++ b/modelina-cli/src/helpers/go.ts @@ -1,4 +1,4 @@ -import { GO_DESCRIPTION_PRESET, GoFileGenerator } from "@asyncapi/modelina"; +import { GO_DESCRIPTION_PRESET, GO_COMMON_PRESET, GoCommonPresetOptions, GoFileGenerator } from "@asyncapi/modelina"; import { BuilderReturnType } from "./generate"; import { Flags } from "@oclif/core"; @@ -23,6 +23,8 @@ export function buildGoGenerator(flags: any): BuilderReturnType { throw new Error('In order to generate models to Go, we need to know which package they are under. Add `--packageName=PACKAGENAME` to set the desired package name.'); } const presets = [] + const options: GoCommonPresetOptions = { addJsonTag: true }; + presets.push({ preset: GO_COMMON_PRESET, options }) if (goIncludeComments) { presets.push(GO_DESCRIPTION_PRESET); } const fileGenerator = new GoFileGenerator({ presets }); const fileOptions = { diff --git a/src/generators/go/presets/CommonPreset.ts b/src/generators/go/presets/CommonPreset.ts index f6303116e6..b506212df7 100644 --- a/src/generators/go/presets/CommonPreset.ts +++ b/src/generators/go/presets/CommonPreset.ts @@ -21,6 +21,9 @@ function renderJSONTag({ ) { return `json:"-,omitempty"`; } + if (field.required) { + return `json:"${field.unconstrainedPropertyName}" binding:"required"`; + } return `json:"${field.unconstrainedPropertyName},omitempty"`; } diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts index 29c34004f2..fef649b25f 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -34,13 +34,12 @@ export class StructRenderer extends GoRenderer { return `${doc} type ${this.model.name} struct { ${this.indent(this.renderBlock(content, 2))} -}${ - discriminator && +}${discriminator && ` ${discriminator} ` - }`; + }`; } async renderFields(): Promise { @@ -78,11 +77,7 @@ export const GO_DEFAULT_STRUCT_PRESET: StructPresetType = { ) { fieldType = `*${fieldType}`; } - const jsonTag = field.required - ? `\`json:"${field.unconstrainedPropertyName},required"\`` - : `\`json:"${field.unconstrainedPropertyName},omitempty"\``; - - return `${field.propertyName} ${fieldType} ${jsonTag}`; + return `${field.propertyName} ${fieldType}`; }, discriminator({ model }) { const { parents } = model.options; From 5ba930fc11f4f321f70a0b4e0ceedab96ea9cea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Mon, 4 Nov 2024 02:18:04 +0300 Subject: [PATCH 3/7] feat golang: removed useless default comments --- src/generators/go/renderers/EnumRenderer.ts | 2 +- src/generators/go/renderers/StructRenderer.ts | 7 +------ src/generators/go/renderers/UnionRenderer.ts | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/generators/go/renderers/EnumRenderer.ts b/src/generators/go/renderers/EnumRenderer.ts index 05ac22417f..3b04277d2e 100644 --- a/src/generators/go/renderers/EnumRenderer.ts +++ b/src/generators/go/renderers/EnumRenderer.ts @@ -16,7 +16,7 @@ import { GoOptions } from '../GoGenerator'; */ export class EnumRenderer extends GoRenderer { public async defaultSelf(): Promise { - const doc = this.renderCommentForEnumType(this.model.name, this.model.type); + const doc = ''; const enumValues = await this.renderItems(); const valuesToEnumMap = this.model.values.map((value) => { return `${this.model.name}Values[${value.key}]: ${value.key},`; diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts index fef649b25f..ab1fadaa41 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -20,13 +20,8 @@ export class StructRenderer extends GoRenderer { await this.renderFields(), await this.runAdditionalContentPreset() ]; - - const doc = this.renderComments( - `${this.model.name} represents a ${this.model.name} model.` - ); - + const doc = ''; let discriminator = ''; - if (this.model.options.parents?.length) { discriminator = await this.runDiscriminatorFuncPreset(); } diff --git a/src/generators/go/renderers/UnionRenderer.ts b/src/generators/go/renderers/UnionRenderer.ts index 1c941fc25a..f28114106e 100644 --- a/src/generators/go/renderers/UnionRenderer.ts +++ b/src/generators/go/renderers/UnionRenderer.ts @@ -28,10 +28,7 @@ const unionIncludesDiscriminator = (model: ConstrainedUnionModel): boolean => { */ export class UnionRenderer extends GoRenderer { public async defaultSelf(): Promise { - const doc = this.renderComments( - `${this.model.name} represents a ${this.model.name} model.` - ); - + const doc = ''; if (unionIncludesDiscriminator(this.model)) { const content: string[] = [await this.runDiscriminatorAccessorPreset()]; From ddf971cf73bc26a0e1232d8d5133a800129ee130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Mon, 4 Nov 2024 02:56:03 +0300 Subject: [PATCH 4/7] feat golang: linter issues fixed --- modelina-cli/src/commands/generate.ts | 11 ++++++++--- modelina-cli/src/helpers/go.ts | 1 + src/generators/go/presets/DescriptionPreset.ts | 8 +++++--- src/generators/go/renderers/StructRenderer.ts | 12 ++++++------ 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/modelina-cli/src/commands/generate.ts b/modelina-cli/src/commands/generate.ts index 17b8053a5a..d5955ed375 100644 --- a/modelina-cli/src/commands/generate.ts +++ b/modelina-cli/src/commands/generate.ts @@ -16,13 +16,18 @@ export default class Models extends ModelinaCommand { } catch { if (flags.input) { try { - document = await readFile(flags.input ? flags.input : "", 'utf8'); + let fname = "" + if (flags.input) { + fname = flags.input + } + + document = await readFile(fname, 'utf8'); } catch { - throw new Error('Unable to read input file content: "' + flags.input + '"'); + throw new Error(`Unable to read input file content: ${flags.input}`); } } else { - throw new Error('Unable to read input file content: "' + file + '"'); + throw new Error(`Unable to read input file content: ${file}`); } } diff --git a/modelina-cli/src/helpers/go.ts b/modelina-cli/src/helpers/go.ts index e07f08b77c..a373a6572b 100644 --- a/modelina-cli/src/helpers/go.ts +++ b/modelina-cli/src/helpers/go.ts @@ -22,6 +22,7 @@ export function buildGoGenerator(flags: any): BuilderReturnType { if (packageName === undefined) { throw new Error('In order to generate models to Go, we need to know which package they are under. Add `--packageName=PACKAGENAME` to set the desired package name.'); } + const presets = [] const options: GoCommonPresetOptions = { addJsonTag: true }; presets.push({ preset: GO_COMMON_PRESET, options }) diff --git a/src/generators/go/presets/DescriptionPreset.ts b/src/generators/go/presets/DescriptionPreset.ts index 3e2391aae2..f6b9c63e66 100644 --- a/src/generators/go/presets/DescriptionPreset.ts +++ b/src/generators/go/presets/DescriptionPreset.ts @@ -11,9 +11,12 @@ const renderDescription = ({ content: string; item: ConstrainedMetaModel; }): string => { - const desc = item.originalInput.description?.trim(); - const formattedDesc = desc ? renderer.renderComments(desc) + '\n' : ''; + let formattedDesc = ''; + if (desc) { + formattedDesc = renderer.renderComments(desc); + formattedDesc += '\n'; + } return formattedDesc + content; }; @@ -23,7 +26,6 @@ const renderDescription = ({ * @implements {GoPreset} */ export const GO_DESCRIPTION_PRESET: GoPreset = { - struct: { self({ renderer, model, content }) { return renderDescription({ renderer, content, item: model }); diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts index ab1fadaa41..bf066ec93e 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -27,13 +27,13 @@ export class StructRenderer extends GoRenderer { } return `${doc} -type ${this.model.name} struct { -${this.indent(this.renderBlock(content, 2))} -}${discriminator && + type ${this.model.name} struct { + ${this.indent(this.renderBlock(content, 2))} + }${discriminator && ` - -${discriminator} -` + + ${discriminator} + ` }`; } From 9c471cefb70dda51f08d71a77a0b758346ffb759 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 5 Nov 2024 15:15:55 +0300 Subject: [PATCH 5/7] feat golang: fixed all the tests, added 'goIncludeTags' flag, added test for go description, removed previously added -i flag, removed unused code and fixed formatting, added modelina_cli/test/fixtures/generate to linter exclusions --- docs/languages/Go.md | 19 +++-- .../generate-go-asyncapi-comments/README.md | 17 ++++ .../__snapshots__/index.spec.ts.snap | 14 ++++ .../index.spec.ts | 15 ++++ .../generate-go-asyncapi-comments/index.ts | 64 +++++++++++++++ .../package-lock.json | 10 +++ .../package.json | 12 +++ .../__snapshots__/index.spec.ts.snap | 9 +-- .../__snapshots__/index.spec.ts.snap | 3 +- .../__snapshots__/index.spec.ts.snap | 9 +-- .../__snapshots__/index.spec.ts.snap | 15 ++-- modelina-cli/.eslintignore | 3 +- modelina-cli/src/commands/generate.ts | 16 +--- modelina-cli/src/helpers/generate.ts | 5 -- modelina-cli/src/helpers/go.ts | 14 +++- src/generators/go/renderers/EnumRenderer.ts | 9 +-- src/generators/go/renderers/StructRenderer.ts | 17 ++-- src/generators/go/renderers/UnionRenderer.ts | 7 +- test/generators/go/GoGenerator.spec.ts | 53 ++++++++++++- .../go/__snapshots__/GoGenerator.spec.ts.snap | 78 +++++++------------ .../go/presets/DescriptionPreset.spec.ts | 38 +++++++++ .../__snapshots__/CommonPreset.spec.ts.snap | 6 +- .../DescriptionPreset.spec.ts.snap | 18 +++++ 23 files changed, 319 insertions(+), 132 deletions(-) create mode 100644 examples/generate-go-asyncapi-comments/README.md create mode 100644 examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap create mode 100644 examples/generate-go-asyncapi-comments/index.spec.ts create mode 100644 examples/generate-go-asyncapi-comments/index.ts create mode 100644 examples/generate-go-asyncapi-comments/package-lock.json create mode 100644 examples/generate-go-asyncapi-comments/package.json create mode 100644 test/generators/go/presets/DescriptionPreset.spec.ts create mode 100644 test/generators/go/presets/__snapshots__/DescriptionPreset.spec.ts.snap diff --git a/docs/languages/Go.md b/docs/languages/Go.md index 305b56ea6e..a3c537df3c 100644 --- a/docs/languages/Go.md +++ b/docs/languages/Go.md @@ -4,10 +4,13 @@ There are special use-cases that each language supports; this document pertains -- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) - * [To and from JSON](#to-and-from-json) - * [To and from XML](#to-and-from-xml) - * [To and from binary](#to-and-from-binary) +- [Go](#go) + - [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + - [To and from JSON](#to-and-from-json) + - [JSON Tags](#json-tags) + - [To and from XML](#to-and-from-xml) + - [To and from binary](#to-and-from-binary) + - [Rendering comments from description and example fields](#rendering-comments-from-description-and-example-fields) @@ -24,7 +27,7 @@ Here are all the supported presets and the libraries they use for converting to #### JSON Tags -To generate go models that work correctly with JSON marshal functions we need to generate appropriate JSON `struct-tags`, use the preset `GO_COMMON_PRESET` and provide the option `addJsonTag: true`. +To generate go models that work correctly with JSON marshal functions we need to generate appropriate JSON `struct-tags`, use the preset `GO_COMMON_PRESET` and provide the option `addJsonTag: true` (added in CLI by default). check out this [example for a live demonstration](../../examples/go-json-tags/) @@ -33,3 +36,9 @@ Currently not supported, [let everyone know you need it](https://github.com/asyn ### To and from binary Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +## Rendering comments from description and example fields + +You can use the `GO_DESCRIPTION_PRESET` to generate comments from description fields in your model. + +See [this example](../../examples/generate-go-asyncapi-comments) for how this can be used. diff --git a/examples/generate-go-asyncapi-comments/README.md b/examples/generate-go-asyncapi-comments/README.md new file mode 100644 index 0000000000..78bc37a44b --- /dev/null +++ b/examples/generate-go-asyncapi-comments/README.md @@ -0,0 +1,17 @@ +# Go Data Models from AsyncAPI + +A basic example of how to use Modelina and output a Go data model from AsyncAPI, including data tags and comments from description. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..f545cd5d42 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap @@ -0,0 +1,14 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render Go Models and should log expected output to console 1`] = ` +Array [ + "// this is an object +type ExampleStruct struct { + Id int \`json:\\"id,omitempty\\"\` + // this is example msg uid + MsgUid string \`json:\\"msgUid\\" binding:\\"required\\"\` + // this is example event name + EvtName string \`json:\\"evtName,omitempty\\"\` +}", +] +`; diff --git a/examples/generate-go-asyncapi-comments/index.spec.ts b/examples/generate-go-asyncapi-comments/index.spec.ts new file mode 100644 index 0000000000..d1dd8cee68 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { + return; +}); +import { generate } from './index'; + +describe('Should be able to render Go Models', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/generate-go-asyncapi-comments/index.ts b/examples/generate-go-asyncapi-comments/index.ts new file mode 100644 index 0000000000..c5a03eea62 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.ts @@ -0,0 +1,64 @@ +import { + GoGenerator, + GO_DESCRIPTION_PRESET, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../src'; +import { Parser } from '@asyncapi/parser'; +import { TypeScriptGenerator } from '../../src'; +const generatorts = new TypeScriptGenerator(); +const options: GoCommonPresetOptions = { addJsonTag: true }; +const generator = new GoGenerator({ + presets: [GO_DESCRIPTION_PRESET, { preset: GO_COMMON_PRESET, options }] +}); + +const AsyncAPIDocumentText = ` +asyncapi: 3.0.0 +info: + title: example + version: 0.0.1 +channels: + root: + address: / + messages: + exampleRequest: + summary: example operation + payload: + title: exampleStruct + type: object + description: this is an object + required: + - msgUid + additionalProperties: false + properties: + id: + type: integer + msgUid: + type: string + description: this is example msg uid + evtName: + type: string + description: this is example event name +operations: + exampleOperation: + title: This is an example operation + summary: To do something + channel: + $ref: '#/channels/root' + action: send + messages: + - $ref: '#/channels/root/messages/exampleRequest' +`; + +export async function generate(): Promise { + const parser = new Parser(); + const { document } = await parser.parse(AsyncAPIDocumentText); + const models = await generator.generate(document); + for (const model of models) { + console.log(model.result); + } +} + +if (require.main === module) { + generate(); +} diff --git a/examples/generate-go-asyncapi-comments/package-lock.json b/examples/generate-go-asyncapi-comments/package-lock.json new file mode 100644 index 0000000000..b1b6acf134 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "generate-go-asyncapi-comments", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/generate-go-asyncapi-comments/package.json b/examples/generate-go-asyncapi-comments/package.json new file mode 100644 index 0000000000..928aa251a0 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "generate-go-asyncapi-comments" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} \ No newline at end of file diff --git a/examples/generate-go-enums/__snapshots__/index.spec.ts.snap b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap index 63a132b10e..88e4541c0f 100644 --- a/examples/generate-go-enums/__snapshots__/index.spec.ts.snap +++ b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ exports[`Should be able to render Go Enums and should log expected output to console 1`] = ` Array [ - "// Root represents a Root model. -type Root struct { + "type Root struct { Cities *Cities Options *Options }", @@ -12,8 +11,7 @@ type Root struct { exports[`Should be able to render Go Enums and should log expected output to console 2`] = ` Array [ - "// Cities represents an enum of Cities. -type Cities uint + "type Cities uint const ( CitiesLondon Cities = iota @@ -41,8 +39,7 @@ var ValuesToCities = map[any]Cities{ exports[`Should be able to render Go Enums and should log expected output to console 3`] = ` Array [ - "// Options represents an enum of Options. -type Options uint + "type Options uint const ( OptionsNumber_123 Options = iota diff --git a/examples/generate-go-models/__snapshots__/index.spec.ts.snap b/examples/generate-go-models/__snapshots__/index.spec.ts.snap index 36a43dc738..f3029176fc 100644 --- a/examples/generate-go-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-go-models/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ exports[`Should be able to render Go Models and should log expected output to console 1`] = ` Array [ - "// Root represents a Root model. -type Root struct { + "type Root struct { Email string }", ] diff --git a/examples/go-json-tags/__snapshots__/index.spec.ts.snap b/examples/go-json-tags/__snapshots__/index.spec.ts.snap index fb55f5d97a..de241b60c2 100644 --- a/examples/go-json-tags/__snapshots__/index.spec.ts.snap +++ b/examples/go-json-tags/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ exports[`Should be able to render json-tags in struct and should log expected output to console 1`] = ` Array [ - "// Root represents a Root model. -type Root struct { + "type Root struct { Cities *Cities \`json:\\"cities,omitempty\\"\` Options *Options \`json:\\"options,omitempty\\"\` }", @@ -12,8 +11,7 @@ type Root struct { exports[`Should be able to render json-tags in struct and should log expected output to console 2`] = ` Array [ - "// Cities represents an enum of Cities. -type Cities uint + "type Cities uint const ( CitiesLondon Cities = iota @@ -54,8 +52,7 @@ func (op Cities) MarshalJSON() ([]byte, error) { exports[`Should be able to render json-tags in struct and should log expected output to console 3`] = ` Array [ - "// Options represents an enum of Options. -type Options uint + "type Options uint const ( OptionsNumber_123 Options = iota diff --git a/examples/go-union-type/__snapshots__/index.spec.ts.snap b/examples/go-union-type/__snapshots__/index.spec.ts.snap index 0bf56369a4..a1088359ed 100644 --- a/examples/go-union-type/__snapshots__/index.spec.ts.snap +++ b/examples/go-union-type/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ exports[`Should be able to render union types and should log expected output to console 1`] = ` Array [ - "// AdditionalProperty represents a AdditionalProperty model. -type AdditionalProperty struct { + "type AdditionalProperty struct { AdditionalPropertyOneOf_0 AdditionalPropertyOneOf_1 string @@ -17,8 +16,7 @@ type AdditionalProperty struct { exports[`Should be able to render union types and should log expected output to console 2`] = ` Array [ - "// Union represents a Union model. -type Union struct { + "type Union struct { string float64 ModelinaAnyType interface{} @@ -28,8 +26,7 @@ type Union struct { exports[`Should be able to render union types and should log expected output to console 3`] = ` Array [ - "// AdditionalPropertyOneOf_6 represents a AdditionalPropertyOneOf_6 model. -type AdditionalPropertyOneOf_6 struct { + "type AdditionalPropertyOneOf_6 struct { string float64 bool @@ -45,8 +42,7 @@ Array [ exports[`Should be able to render union types and should log expected output to console 5`] = ` Array [ - "// AdditionalPropertyOneOf_0 represents a AdditionalPropertyOneOf_0 model. -type AdditionalPropertyOneOf_0 struct { + "type AdditionalPropertyOneOf_0 struct { Ref string AdditionalProperties map[string]interface{} }", @@ -55,8 +51,7 @@ type AdditionalPropertyOneOf_0 struct { exports[`Should be able to render union types and should log expected output to console 6`] = ` Array [ - "// AdditionalPropertyOneOf_1 represents a AdditionalPropertyOneOf_1 model. -type AdditionalPropertyOneOf_1 struct { + "type AdditionalPropertyOneOf_1 struct { Id string AdditionalProperties map[string]interface{} }", diff --git a/modelina-cli/.eslintignore b/modelina-cli/.eslintignore index 06a195ae67..0430133d29 100644 --- a/modelina-cli/.eslintignore +++ b/modelina-cli/.eslintignore @@ -1,4 +1,5 @@ /lib /tmp /scripts -/test/helpers/init.js \ No newline at end of file +/test/helpers/init.js +/test/fixtures/generate \ No newline at end of file diff --git a/modelina-cli/src/commands/generate.ts b/modelina-cli/src/commands/generate.ts index d5955ed375..0091dd2f39 100644 --- a/modelina-cli/src/commands/generate.ts +++ b/modelina-cli/src/commands/generate.ts @@ -14,21 +14,7 @@ export default class Models extends ModelinaCommand { try { document = await readFile(file, 'utf8'); } catch { - if (flags.input) { - try { - let fname = "" - if (flags.input) { - fname = flags.input - } - - document = await readFile(fname, 'utf8'); - } catch { - throw new Error(`Unable to read input file content: ${flags.input}`); - } - } - else { - throw new Error(`Unable to read input file content: ${file}`); - } + throw new Error(`Unable to read input file content: ${file}`); } const logger = { diff --git a/modelina-cli/src/helpers/generate.ts b/modelina-cli/src/helpers/generate.ts index 4b7fde1704..ab3c34cae3 100644 --- a/modelina-cli/src/helpers/generate.ts +++ b/modelina-cli/src/helpers/generate.ts @@ -60,11 +60,6 @@ export const ModelinaFlags = { description: 'The output directory where the models should be written to. Omitting this flag will write the models to `stdout`.', required: false }), - input: Flags.string({ - char: 'i', - description: 'The input file with the API definition.', - required: false - }), /** * Go and Java specific package name to use for the generated models */ diff --git a/modelina-cli/src/helpers/go.ts b/modelina-cli/src/helpers/go.ts index a373a6572b..ac09dce990 100644 --- a/modelina-cli/src/helpers/go.ts +++ b/modelina-cli/src/helpers/go.ts @@ -8,6 +8,11 @@ export const GoOclifFlags = { required: false, default: false, }), + goIncludeTags: Flags.boolean({ + description: 'Golang specific, if enabled add tags while generating models.', + required: false, + default: false, + }), } /** @@ -17,15 +22,18 @@ export const GoOclifFlags = { * @returns */ export function buildGoGenerator(flags: any): BuilderReturnType { - const { packageName, goIncludeComments } = flags; + const { packageName, goIncludeComments, goIncludeTags } = flags; if (packageName === undefined) { throw new Error('In order to generate models to Go, we need to know which package they are under. Add `--packageName=PACKAGENAME` to set the desired package name.'); } const presets = [] - const options: GoCommonPresetOptions = { addJsonTag: true }; - presets.push({ preset: GO_COMMON_PRESET, options }) + if (goIncludeTags) { + const options: GoCommonPresetOptions = { addJsonTag: true }; + presets.push({ preset: GO_COMMON_PRESET, options }) + } + if (goIncludeComments) { presets.push(GO_DESCRIPTION_PRESET); } const fileGenerator = new GoFileGenerator({ presets }); const fileOptions = { diff --git a/src/generators/go/renderers/EnumRenderer.ts b/src/generators/go/renderers/EnumRenderer.ts index 3b04277d2e..d174d1d5f8 100644 --- a/src/generators/go/renderers/EnumRenderer.ts +++ b/src/generators/go/renderers/EnumRenderer.ts @@ -16,7 +16,6 @@ import { GoOptions } from '../GoGenerator'; */ export class EnumRenderer extends GoRenderer { public async defaultSelf(): Promise { - const doc = ''; const enumValues = await this.renderItems(); const valuesToEnumMap = this.model.values.map((value) => { return `${this.model.name}Values[${value.key}]: ${value.key},`; @@ -29,8 +28,7 @@ export class EnumRenderer extends GoRenderer { }) .join(','); - return `${doc} -type ${this.model.name} uint + return `type ${this.model.name} uint const ( ${this.indent(enumValues)} @@ -63,11 +61,6 @@ ${additionalContent}`; return this.renderBlock(items); } - renderCommentForEnumType(name: string, type: string): string { - const globalType = type === 'interface{}' ? 'mixed types' : type; - return this.renderComments(`${name} represents an enum of ${globalType}.`); - } - runItemPreset( item: ConstrainedEnumValueModel, index: number diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts index bf066ec93e..7d8cdf1695 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -20,21 +20,20 @@ export class StructRenderer extends GoRenderer { await this.renderFields(), await this.runAdditionalContentPreset() ]; - const doc = ''; let discriminator = ''; if (this.model.options.parents?.length) { discriminator = await this.runDiscriminatorFuncPreset(); } - return `${doc} - type ${this.model.name} struct { - ${this.indent(this.renderBlock(content, 2))} - }${discriminator && + return `type ${this.model.name} struct { +${this.indent(this.renderBlock(content, 2))} +}${ + discriminator && ` - - ${discriminator} - ` - }`; + +${discriminator} +` + }`; } async renderFields(): Promise { diff --git a/src/generators/go/renderers/UnionRenderer.ts b/src/generators/go/renderers/UnionRenderer.ts index f28114106e..7455775309 100644 --- a/src/generators/go/renderers/UnionRenderer.ts +++ b/src/generators/go/renderers/UnionRenderer.ts @@ -28,12 +28,10 @@ const unionIncludesDiscriminator = (model: ConstrainedUnionModel): boolean => { */ export class UnionRenderer extends GoRenderer { public async defaultSelf(): Promise { - const doc = ''; if (unionIncludesDiscriminator(this.model)) { const content: string[] = [await this.runDiscriminatorAccessorPreset()]; - return `${doc} -type ${this.model.name} interface { + return `type ${this.model.name} interface { ${this.indent(this.renderBlock(content, 2))} }`; } @@ -43,8 +41,7 @@ ${this.indent(this.renderBlock(content, 2))} await this.runAdditionalContentPreset() ]; - return `${doc} -type ${this.model.name} struct { + return `type ${this.model.name} struct { ${this.indent(this.renderBlock(content, 2))} }`; } diff --git a/test/generators/go/GoGenerator.spec.ts b/test/generators/go/GoGenerator.spec.ts index 60dff28b92..e0aabcb0a1 100644 --- a/test/generators/go/GoGenerator.spec.ts +++ b/test/generators/go/GoGenerator.spec.ts @@ -1,4 +1,9 @@ -import { GoGenerator } from '../../../src/generators'; +import { + GoGenerator, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../../src/generators'; +import { Parser } from '@asyncapi/parser'; describe('GoGenerator', () => { let generator: GoGenerator; @@ -46,6 +51,52 @@ describe('GoGenerator', () => { expect(models[3].result).toMatchSnapshot(); }); + test('should render `required` for required properties', async () => { + const AsyncAPIDocumentText = ` +asyncapi: 3.0.0 +info: + title: example + version: 0.0.1 +channels: + root: + address: / + messages: + exampleRequest: + summary: example operation + payload: + title: exampleStruct + type: object + required: + - msgUid + additionalProperties: false + properties: + id: + type: integer + msgUid: + type: string + evtName: + type: string +operations: + exampleOperation: + title: This is an example operation + summary: To do something + channel: + $ref: '#/channels/root' + action: send + messages: + - $ref: '#/channels/root/messages/exampleRequest' +`; + const options: GoCommonPresetOptions = { addJsonTag: true }; + const generatorWithTags = new GoGenerator({ + presets: [{ preset: GO_COMMON_PRESET, options }] + }); + const parser = new Parser(); + const { document } = await parser.parse(AsyncAPIDocumentText); + const models = await generatorWithTags.generate(document); + expect(models).toHaveLength(1); + expect(models[0].result).toMatchSnapshot(); + }); + test('should render `union` type for primitives', async () => { const doc = { $id: '_address', diff --git a/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap index 1ce9dade56..43553fedbf 100644 --- a/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap +++ b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap @@ -4,7 +4,6 @@ exports[`GoGenerator generateCompleteModels() should render dependencies 1`] = ` " package some_package -// Members represents a Members model. type Members struct { string float64 @@ -16,7 +15,6 @@ exports[`GoGenerator generateCompleteModels() should render dependencies 2`] = ` " package some_package -// Union represents a Union model. type Union struct { string float64 @@ -28,7 +26,6 @@ exports[`GoGenerator generateCompleteModels() should render dependencies 3`] = ` " package some_package -// AdditionalProperties represents a AdditionalProperties model. type AdditionalProperties struct { ModelinaAnyType interface{} string @@ -41,7 +38,6 @@ package some_package import ( \\"time\\" ) -// Address represents a Address model. type Address struct { StreetName string City string @@ -61,7 +57,6 @@ package some_package import ( \\"time\\" ) -// OtherModel represents a OtherModel model. type OtherModel struct { StreetName string AdditionalProperties map[string]interface{} @@ -72,7 +67,6 @@ exports[`GoGenerator generateCompleteModels() should render models 1`] = ` " package some_package -// Members represents a Members model. type Members struct { string float64 @@ -84,7 +78,6 @@ exports[`GoGenerator generateCompleteModels() should render models 2`] = ` " package some_package -// Union represents a Union model. type Union struct { string float64 @@ -96,7 +89,6 @@ exports[`GoGenerator generateCompleteModels() should render models 3`] = ` " package some_package -// AdditionalProperties represents a AdditionalProperties model. type AdditionalProperties struct { ModelinaAnyType interface{} string @@ -107,7 +99,6 @@ exports[`GoGenerator generateCompleteModels() should render models 4`] = ` " package some_package -// Address represents a Address model. type Address struct { StreetName interface{} City string @@ -125,7 +116,6 @@ exports[`GoGenerator generateCompleteModels() should render models 5`] = ` " package some_package -// OtherModel represents a OtherModel model. type OtherModel struct { StreetName string AdditionalProperties map[string]interface{} @@ -134,20 +124,17 @@ type OtherModel struct { exports[`GoGenerator oneOf/discriminator handle setting title with const 1`] = ` Array [ - "// Pet represents a Pet model. -type Pet interface { + "type Pet interface { IsPetType() }", - "// Dog represents a Dog model. -type Dog struct { + "type Dog struct { ReservedType *DogType AdditionalProperties map[string]interface{} } func (r Dog) IsPetType() {} ", - "// DogType represents an enum of DogType. -type DogType uint + "type DogType uint const ( DogTypeDog DogType = iota @@ -166,16 +153,14 @@ var ValuesToDogType = map[any]DogType{ DogTypeValues[DogTypeDog]: DogTypeDog, } ", - "// Cat represents a Cat model. -type Cat struct { + "type Cat struct { ReservedType *CatType AdditionalProperties map[string]interface{} } func (r Cat) IsPetType() {} ", - "// CatType represents an enum of CatType. -type CatType uint + "type CatType uint const ( CatTypeCat CatType = iota @@ -199,17 +184,14 @@ var ValuesToCatType = map[any]CatType{ exports[`GoGenerator oneOf/discriminator should render interfaces for objects with discriminator 1`] = ` Array [ - "// Vehicle represents a Vehicle model. -type Vehicle interface { + "type Vehicle interface { IsVehicleVehicleType() }", - "// Cargo represents a Cargo model. -type Cargo struct { + "type Cargo struct { Vehicle Vehicle AdditionalProperties map[string]interface{} }", - "// Car represents a Car model. -type Car struct { + "type Car struct { VehicleType *VehicleType RegistrationPlate string AdditionalProperties map[string]interface{} @@ -217,8 +199,7 @@ type Car struct { func (r Car) IsVehicleVehicleType() {} ", - "// VehicleType represents an enum of VehicleType. -type VehicleType uint + "type VehicleType uint const ( VehicleTypeCar VehicleType = iota @@ -239,8 +220,7 @@ var ValuesToVehicleType = map[any]VehicleType{ VehicleTypeValues[VehicleTypeTruck]: VehicleTypeTruck, } ", - "// Truck represents a Truck model. -type Truck struct { + "type Truck struct { VehicleType *VehicleType RegistrationPlate string AdditionalProperties map[string]interface{} @@ -252,8 +232,7 @@ func (r Truck) IsVehicleVehicleType() {} `; exports[`GoGenerator should render \`enum\` with mixed types 1`] = ` -"// Things represents an enum of Things. -type Things uint +"type Things uint const ( ThingsTexas Things = iota @@ -282,9 +261,16 @@ var ValuesToThings = map[any]Things{ " `; +exports[`GoGenerator should render \`required\` for required properties 1`] = ` +"type ExampleStruct struct { + Id int \`json:\\"id,omitempty\\"\` + MsgUid string \`json:\\"msgUid\\" binding:\\"required\\"\` + EvtName string \`json:\\"evtName,omitempty\\"\` +}" +`; + exports[`GoGenerator should render \`struct\` type 1`] = ` -"// Members represents a Members model. -type Members struct { +"type Members struct { string float64 bool @@ -292,8 +278,7 @@ type Members struct { `; exports[`GoGenerator should render \`struct\` type 2`] = ` -"// Union represents a Union model. -type Union struct { +"type Union struct { string float64 ModelinaAnyType interface{} @@ -301,15 +286,13 @@ type Union struct { `; exports[`GoGenerator should render \`struct\` type 3`] = ` -"// AdditionalProperties represents a AdditionalProperties model. -type AdditionalProperties struct { +"type AdditionalProperties struct { string }" `; exports[`GoGenerator should render \`struct\` type 4`] = ` -"// Address represents a Address model. -type Address struct { +"type Address struct { StreetName string City string State string @@ -323,28 +306,23 @@ type Address struct { `; exports[`GoGenerator should render \`union\` type for primitives 1`] = ` -"// Members represents a Members model. -type Members struct { +"type Members struct { string float64 bool } -// Union represents a Union model. type Union struct { string float64 ModelinaAnyType interface{} } -// LocationAdditionalProperty represents a LocationAdditionalProperty model. type LocationAdditionalProperty struct { LocationAdditionalPropertyOneOf_0 LocationAdditionalPropertyOneOf_1 } -// AdditionalProperties represents a AdditionalProperties model. type AdditionalProperties struct { string } -// Address represents a Address model. type Address struct { StreetName string City string @@ -357,12 +335,10 @@ type Address struct { Location map[string]LocationAdditionalProperty AdditionalProperties map[string]AdditionalProperties } -// LocationAdditionalPropertyOneOf_0 represents a LocationAdditionalPropertyOneOf_0 model. type LocationAdditionalPropertyOneOf_0 struct { Ref string AdditionalProperties map[string]interface{} } -// LocationAdditionalPropertyOneOf_1 represents a LocationAdditionalPropertyOneOf_1 model. type LocationAdditionalPropertyOneOf_1 struct { Id string AdditionalProperties map[string]interface{} @@ -370,8 +346,7 @@ type LocationAdditionalPropertyOneOf_1 struct { `; exports[`GoGenerator should work custom preset for \`enum\` type 1`] = ` -"// CustomEnum represents an enum of CustomEnum. -type CustomEnum uint +"type CustomEnum uint const ( test 0 @@ -397,8 +372,7 @@ additionalContent" `; exports[`GoGenerator should work custom preset for \`struct\` type 1`] = ` -"// CustomStruct represents a CustomStruct model. -type CustomStruct struct { +"type CustomStruct struct { field Property field AdditionalProperties diff --git a/test/generators/go/presets/DescriptionPreset.spec.ts b/test/generators/go/presets/DescriptionPreset.spec.ts new file mode 100644 index 0000000000..a3eedfc674 --- /dev/null +++ b/test/generators/go/presets/DescriptionPreset.spec.ts @@ -0,0 +1,38 @@ +import { GO_DESCRIPTION_PRESET, GoGenerator } from '../../../../src'; + +const doc = { + $id: 'Test', + type: 'object', + additionalProperties: false, + required: ['string prop'], + description: 'Main Description', + properties: { + 'string prop': { type: 'string' }, + numberProp: { + type: 'number', + description: 'Description' + }, + objectProp: { + type: 'object', + additionalProperties: false, + $id: 'NestedTest', + properties: { stringProp: { type: 'string', description: 'string prop' } } + } + } +}; + +describe('Description generation', () => { + let generator: GoGenerator; + beforeEach(() => { + generator = new GoGenerator({ + presets: [GO_DESCRIPTION_PRESET] + }); + }); + + test('should render example function for model', async () => { + const models = await generator.generate(doc); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); +}); diff --git a/test/generators/go/presets/__snapshots__/CommonPreset.spec.ts.snap b/test/generators/go/presets/__snapshots__/CommonPreset.spec.ts.snap index 0d35ec5083..2556a9e369 100644 --- a/test/generators/go/presets/__snapshots__/CommonPreset.spec.ts.snap +++ b/test/generators/go/presets/__snapshots__/CommonPreset.spec.ts.snap @@ -1,8 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`GO_COMMON_PRESET should render json tags for structs 1`] = ` -"// Root represents a Root model. -type Root struct { +"type Root struct { StringProp string \`json:\\"stringProp,omitempty\\"\` NumberProp float64 \`json:\\"numberProp,omitempty\\"\` BooleanProp bool \`json:\\"booleanProp,omitempty\\"\` @@ -10,8 +9,7 @@ type Root struct { `; exports[`GO_COMMON_PRESET should render the marshal functions for enum 1`] = ` -"// Root represents an enum of Root. -type Root uint +"type Root uint const ( RootNumber_2Dot_6Dot_0 Root = iota diff --git a/test/generators/go/presets/__snapshots__/DescriptionPreset.spec.ts.snap b/test/generators/go/presets/__snapshots__/DescriptionPreset.spec.ts.snap new file mode 100644 index 0000000000..fcfee51a1c --- /dev/null +++ b/test/generators/go/presets/__snapshots__/DescriptionPreset.spec.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Description generation should render example function for model 1`] = ` +"// Main Description +type Test struct { + StringProp string + // Description + NumberProp float64 + ObjectProp *NestedTest +}" +`; + +exports[`Description generation should render example function for model 2`] = ` +"type NestedTest struct { + // string prop + StringProp string +}" +`; From b95d20f479b2824f6429b4dd4e218bbd5f4ce5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 5 Nov 2024 15:36:57 +0300 Subject: [PATCH 6/7] feat golang: fixed tests for go-asyncapi-comments example --- .../__snapshots__/index.spec.ts.snap | 27 +++++-- .../index.spec.ts | 3 +- .../generate-go-asyncapi-comments/index.ts | 73 +++++++++++++------ 3 files changed, 74 insertions(+), 29 deletions(-) diff --git a/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap index f545cd5d42..ed22309164 100644 --- a/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap +++ b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap @@ -2,13 +2,26 @@ exports[`Should be able to render Go Models and should log expected output to console 1`] = ` Array [ - "// this is an object -type ExampleStruct struct { - Id int \`json:\\"id,omitempty\\"\` - // this is example msg uid - MsgUid string \`json:\\"msgUid\\" binding:\\"required\\"\` - // this is example event name - EvtName string \`json:\\"evtName,omitempty\\"\` + "// Payload for updating stock information +type StockUpdatePayload struct { + ProductId string \`json:\\"productId\\" binding:\\"required\\"\` + // The updated quantity of the product + Quantity int \`json:\\"quantity,omitempty\\"\` + // Warehouse location of the product + Location string \`json:\\"location,omitempty\\"\` +}", +] +`; + +exports[`Should be able to render Go Models and should log expected output to console 2`] = ` +Array [ + "// Payload for low stock alerts +type LowStockPayload struct { + ProductId string \`json:\\"productId\\" binding:\\"required\\"\` + // The stock level threshold + Threshold int \`json:\\"threshold\\" binding:\\"required\\"\` + // The current stock level + CurrentStock int \`json:\\"currentStock,omitempty\\"\` }", ] `; diff --git a/examples/generate-go-asyncapi-comments/index.spec.ts b/examples/generate-go-asyncapi-comments/index.spec.ts index d1dd8cee68..41d9908c10 100644 --- a/examples/generate-go-asyncapi-comments/index.spec.ts +++ b/examples/generate-go-asyncapi-comments/index.spec.ts @@ -9,7 +9,8 @@ describe('Should be able to render Go Models', () => { }); test('and should log expected output to console', async () => { await generate(); - expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls.length).toEqual(2); expect(spy.mock.calls[0]).toMatchSnapshot(); + expect(spy.mock.calls[1]).toMatchSnapshot(); }); }); diff --git a/examples/generate-go-asyncapi-comments/index.ts b/examples/generate-go-asyncapi-comments/index.ts index c5a03eea62..63a9d022c5 100644 --- a/examples/generate-go-asyncapi-comments/index.ts +++ b/examples/generate-go-asyncapi-comments/index.ts @@ -5,8 +5,6 @@ import { GoCommonPresetOptions } from '../../src'; import { Parser } from '@asyncapi/parser'; -import { TypeScriptGenerator } from '../../src'; -const generatorts = new TypeScriptGenerator(); const options: GoCommonPresetOptions = { addJsonTag: true }; const generator = new GoGenerator({ presets: [GO_DESCRIPTION_PRESET, { preset: GO_COMMON_PRESET, options }] @@ -15,41 +13,74 @@ const generator = new GoGenerator({ const AsyncAPIDocumentText = ` asyncapi: 3.0.0 info: - title: example - version: 0.0.1 + title: inventoryService + version: 2.1.0 channels: - root: - address: / + inventory: + address: /inventory messages: - exampleRequest: - summary: example operation + updateStock: + summary: Update stock levels payload: - title: exampleStruct + title: stockUpdatePayload type: object - description: this is an object + description: Payload for updating stock information required: - - msgUid + - productId additionalProperties: false properties: - id: + productId: + type: string + quantity: type: integer - msgUid: + description: The updated quantity of the product + location: type: string - description: this is example msg uid - evtName: + description: Warehouse location of the product + alerts: + address: /alerts + messages: + lowStockAlert: + summary: Low stock level alert + payload: + title: lowStockPayload + type: object + description: Payload for low stock alerts + required: + - productId + - threshold + additionalProperties: false + properties: + productId: type: string - description: this is example event name + threshold: + type: integer + description: The stock level threshold + currentStock: + type: integer + description: The current stock level operations: - exampleOperation: - title: This is an example operation - summary: To do something + updateInventory: + title: Update Inventory Operation + summary: Operation to update inventory stock levels channel: - $ref: '#/channels/root' + $ref: '#/channels/inventory' action: send messages: - - $ref: '#/channels/root/messages/exampleRequest' + - $ref: '#/channels/inventory/messages/updateStock' + + notifyLowStock: + title: Notify Low Stock Operation + summary: Operation to notify when stock is low + channel: + $ref: '#/channels/alerts' + action: receive + messages: + - $ref: '#/channels/alerts/messages/lowStockAlert' `; + + export async function generate(): Promise { const parser = new Parser(); const { document } = await parser.parse(AsyncAPIDocumentText); From bae0c8c0515ce100278b7765283f9be9c0d9c11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=9C=D1=83=D1=80=D0=B0=D0=BD=D0=BE=D0=B2?= Date: Tue, 5 Nov 2024 16:57:11 +0300 Subject: [PATCH 7/7] feat golang: moved test objects from string literal to object --- .../generate-go-asyncapi-comments/index.ts | 169 ++++++++++-------- test/generators/go/GoGenerator.spec.ts | 89 +++++---- 2 files changed, 146 insertions(+), 112 deletions(-) diff --git a/examples/generate-go-asyncapi-comments/index.ts b/examples/generate-go-asyncapi-comments/index.ts index 63a9d022c5..d241cf0a36 100644 --- a/examples/generate-go-asyncapi-comments/index.ts +++ b/examples/generate-go-asyncapi-comments/index.ts @@ -4,87 +4,108 @@ import { GO_COMMON_PRESET, GoCommonPresetOptions } from '../../src'; -import { Parser } from '@asyncapi/parser'; + const options: GoCommonPresetOptions = { addJsonTag: true }; const generator = new GoGenerator({ presets: [GO_DESCRIPTION_PRESET, { preset: GO_COMMON_PRESET, options }] }); -const AsyncAPIDocumentText = ` -asyncapi: 3.0.0 -info: - title: inventoryService - version: 2.1.0 -channels: - inventory: - address: /inventory - messages: - updateStock: - summary: Update stock levels - payload: - title: stockUpdatePayload - type: object - description: Payload for updating stock information - required: - - productId - additionalProperties: false - properties: - productId: - type: string - quantity: - type: integer - description: The updated quantity of the product - location: - type: string - description: Warehouse location of the product - alerts: - address: /alerts - messages: - lowStockAlert: - summary: Low stock level alert - payload: - title: lowStockPayload - type: object - description: Payload for low stock alerts - required: - - productId - - threshold - additionalProperties: false - properties: - productId: - type: string - threshold: - type: integer - description: The stock level threshold - currentStock: - type: integer - description: The current stock level -operations: - updateInventory: - title: Update Inventory Operation - summary: Operation to update inventory stock levels - channel: - $ref: '#/channels/inventory' - action: send - messages: - - $ref: '#/channels/inventory/messages/updateStock' - - notifyLowStock: - title: Notify Low Stock Operation - summary: Operation to notify when stock is low - channel: - $ref: '#/channels/alerts' - action: receive - messages: - - $ref: '#/channels/alerts/messages/lowStockAlert' -`; - - +const asyncAPIDocument = { + asyncapi: '3.0.0', + info: { + title: 'inventoryService', + version: '2.1.0' + }, + channels: { + inventory: { + address: '/inventory', + messages: { + updateStock: { + summary: 'Update stock levels', + payload: { + title: 'stockUpdatePayload', + type: 'object', + description: 'Payload for updating stock information', + required: ['productId'], + additionalProperties: false, + properties: { + productId: { + type: 'string' + }, + quantity: { + type: 'integer', + description: 'The updated quantity of the product' + }, + location: { + type: 'string', + description: 'Warehouse location of the product' + } + } + } + } + } + }, + alerts: { + address: '/alerts', + messages: { + lowStockAlert: { + summary: 'Low stock level alert', + payload: { + title: 'lowStockPayload', + type: 'object', + description: 'Payload for low stock alerts', + required: ['productId', 'threshold'], + additionalProperties: false, + properties: { + productId: { + type: 'string' + }, + threshold: { + type: 'integer', + description: 'The stock level threshold' + }, + currentStock: { + type: 'integer', + description: 'The current stock level' + } + } + } + } + } + } + }, + operations: { + updateInventory: { + title: 'Update Inventory Operation', + summary: 'Operation to update inventory stock levels', + channel: { + $ref: '#/channels/inventory' + }, + action: 'send', + messages: [ + { + $ref: '#/channels/inventory/messages/updateStock' + } + ] + }, + notifyLowStock: { + title: 'Notify Low Stock Operation', + summary: 'Operation to notify when stock is low', + channel: { + $ref: '#/channels/alerts' + }, + action: 'receive', + messages: [ + { + $ref: '#/channels/alerts/messages/lowStockAlert' + } + ] + } + } +}; export async function generate(): Promise { - const parser = new Parser(); - const { document } = await parser.parse(AsyncAPIDocumentText); - const models = await generator.generate(document); + const models = await generator.generate(asyncAPIDocument); for (const model of models) { console.log(model.result); } diff --git a/test/generators/go/GoGenerator.spec.ts b/test/generators/go/GoGenerator.spec.ts index e0aabcb0a1..40292efcea 100644 --- a/test/generators/go/GoGenerator.spec.ts +++ b/test/generators/go/GoGenerator.spec.ts @@ -3,7 +3,6 @@ import { GO_COMMON_PRESET, GoCommonPresetOptions } from '../../../src/generators'; -import { Parser } from '@asyncapi/parser'; describe('GoGenerator', () => { let generator: GoGenerator; @@ -52,47 +51,61 @@ describe('GoGenerator', () => { }); test('should render `required` for required properties', async () => { - const AsyncAPIDocumentText = ` -asyncapi: 3.0.0 -info: - title: example - version: 0.0.1 -channels: - root: - address: / - messages: - exampleRequest: - summary: example operation - payload: - title: exampleStruct - type: object - required: - - msgUid - additionalProperties: false - properties: - id: - type: integer - msgUid: - type: string - evtName: - type: string -operations: - exampleOperation: - title: This is an example operation - summary: To do something - channel: - $ref: '#/channels/root' - action: send - messages: - - $ref: '#/channels/root/messages/exampleRequest' -`; + const asyncAPIDocument = { + asyncapi: '3.0.0', + info: { + title: 'example', + version: '0.0.1' + }, + channels: { + root: { + address: '/', + messages: { + exampleRequest: { + summary: 'example operation', + payload: { + title: 'exampleStruct', + type: 'object', + required: ['msgUid'], + additionalProperties: false, + properties: { + id: { + type: 'integer' + }, + msgUid: { + type: 'string' + }, + evtName: { + type: 'string' + } + } + } + } + } + } + }, + operations: { + exampleOperation: { + title: 'This is an example operation', + summary: 'To do something', + channel: { + $ref: '#/channels/root' + }, + action: 'send', + messages: [ + { + $ref: '#/channels/root/messages/exampleRequest' + } + ] + } + } + }; + const options: GoCommonPresetOptions = { addJsonTag: true }; const generatorWithTags = new GoGenerator({ presets: [{ preset: GO_COMMON_PRESET, options }] }); - const parser = new Parser(); - const { document } = await parser.parse(AsyncAPIDocumentText); - const models = await generatorWithTags.generate(document); + const models = await generatorWithTags.generate(asyncAPIDocument); expect(models).toHaveLength(1); expect(models[0].result).toMatchSnapshot(); });