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..ed22309164 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render Go Models and should log expected output to console 1`] = ` +Array [ + "// 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 new file mode 100644 index 0000000000..41d9908c10 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.spec.ts @@ -0,0 +1,16 @@ +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(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 new file mode 100644 index 0000000000..d241cf0a36 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.ts @@ -0,0 +1,116 @@ +import { + GoGenerator, + GO_DESCRIPTION_PRESET, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../src'; + +const options: GoCommonPresetOptions = { addJsonTag: true }; +const generator = new GoGenerator({ + presets: [GO_DESCRIPTION_PRESET, { preset: GO_COMMON_PRESET, options }] +}); + +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 models = await generator.generate(asyncAPIDocument); + 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/README.md b/modelina-cli/README.md index 2d10340083..33ae961910 100644 --- a/modelina-cli/README.md +++ b/modelina-cli/README.md @@ -162,7 +162,7 @@ $ npm install -g @asyncapi/modelina-cli $ modelina COMMAND running command... $ modelina (--version) -@asyncapi/modelina-cli/4.0.0-next.62 linux-x64 node-v18.20.4 +@asyncapi/modelina-cli/4.0.0-next.63 linux-x64 node-v18.20.5 $ modelina --help [COMMAND] USAGE $ modelina COMMAND @@ -240,7 +240,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/index.ts)_ ## `modelina config context` @@ -254,7 +254,7 @@ DESCRIPTION Manage short aliases for full paths to inputs ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/index.ts)_ ## `modelina config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -276,7 +276,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/add.ts)_ ## `modelina config context current` @@ -293,7 +293,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/current.ts)_ ## `modelina config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -314,7 +314,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/edit.ts)_ ## `modelina config context init [CONTEXT-FILE-PATH]` @@ -337,7 +337,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/init.ts)_ ## `modelina config context list` @@ -354,7 +354,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/list.ts)_ ## `modelina config context remove CONTEXT-NAME` @@ -374,7 +374,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/remove.ts)_ ## `modelina config context use CONTEXT-NAME` @@ -394,7 +394,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/config/context/use.ts)_ ## `modelina generate LANGUAGE FILE` @@ -456,7 +456,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.62/modelina-cli/src/commands/generate.ts)_ +_See code: [src/commands/generate.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.63/modelina-cli/src/commands/generate.ts)_ ## `modelina help [COMMAND]` diff --git a/modelina-cli/package-lock.json b/modelina-cli/package-lock.json index 6df8bbabcb..966c961ccb 100644 --- a/modelina-cli/package-lock.json +++ b/modelina-cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina-cli", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@asyncapi/modelina-cli", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "license": "Apache-2.0", "dependencies": { "@asyncapi/modelina": "^4.0.0-next.47", diff --git a/modelina-cli/package.json b/modelina-cli/package.json index f5d4e8d69a..b793132783 100644 --- a/modelina-cli/package.json +++ b/modelina-cli/package.json @@ -1,7 +1,7 @@ { "name": "@asyncapi/modelina-cli", "description": "CLI to work with Modelina", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "bin": { "modelina": "./bin/run_bin" }, diff --git a/package-lock.json b/package-lock.json index 96e5e3e37e..83fa0eca46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.1.0", diff --git a/package.json b/package.json index c74bb7ff92..9cc98fc6fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "4.0.0-next.63", + "version": "4.0.0-next.64", "description": "Library for generating data models based on inputs such as AsyncAPI, OpenAPI, or JSON Schema documents", "license": "Apache-2.0", "homepage": "https://www.modelina.org", 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/presets/DescriptionPreset.ts b/src/generators/go/presets/DescriptionPreset.ts new file mode 100644 index 0000000000..f6b9c63e66 --- /dev/null +++ b/src/generators/go/presets/DescriptionPreset.ts @@ -0,0 +1,42 @@ +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(); + let formattedDesc = ''; + if (desc) { + formattedDesc = renderer.renderComments(desc); + formattedDesc += '\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/EnumRenderer.ts b/src/generators/go/renderers/EnumRenderer.ts index 05ac22417f..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 = this.renderCommentForEnumType(this.model.name, this.model.type); 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 b75bf8716d..7d8cdf1695 100644 --- a/src/generators/go/renderers/StructRenderer.ts +++ b/src/generators/go/renderers/StructRenderer.ts @@ -20,19 +20,12 @@ export class StructRenderer extends GoRenderer { await this.renderFields(), await this.runAdditionalContentPreset() ]; - - const doc = this.renderComments( - `${this.model.name} represents a ${this.model.name} model.` - ); - let discriminator = ''; - if (this.model.options.parents?.length) { discriminator = await this.runDiscriminatorFuncPreset(); } - return `${doc} -type ${this.model.name} struct { + return `type ${this.model.name} struct { ${this.indent(this.renderBlock(content, 2))} }${ discriminator && diff --git a/src/generators/go/renderers/UnionRenderer.ts b/src/generators/go/renderers/UnionRenderer.ts index 1c941fc25a..7455775309 100644 --- a/src/generators/go/renderers/UnionRenderer.ts +++ b/src/generators/go/renderers/UnionRenderer.ts @@ -28,15 +28,10 @@ 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.` - ); - 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))} }`; } @@ -46,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..40292efcea 100644 --- a/test/generators/go/GoGenerator.spec.ts +++ b/test/generators/go/GoGenerator.spec.ts @@ -1,4 +1,8 @@ -import { GoGenerator } from '../../../src/generators'; +import { + GoGenerator, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../../src/generators'; describe('GoGenerator', () => { let generator: GoGenerator; @@ -46,6 +50,66 @@ describe('GoGenerator', () => { expect(models[3].result).toMatchSnapshot(); }); + test('should render `required` for required properties', async () => { + 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 models = await generatorWithTags.generate(asyncAPIDocument); + 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 +}" +`;