Repository: asyncapi/modelina
Pull request #301 (2021-07-07 17:51:10)

feat: render pattern properties and additionalProperties as fields for Go struct
**Description**
This PR enables the rendering of `patternProperties` as well as `additionalProperties` for Go struct.

**Related issue(s)**
Related to #154 

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [2 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='2.8%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list) [2.8% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='2.8%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list) [2.8% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list)


coveralls: ## Pull Request Test Coverage Report for [Build 1008947852](https://coveralls.io/builds/41190052)

* **18** of **22**   **(81.82%)**  changed or added relevant lines in **3** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-0.04%**) to **93.362%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [src/generators/go/GoRenderer.ts](https://coveralls.io/builds/41190052/source?filename=src%2Fgenerators%2Fgo%2FGoRenderer.ts#L40) | 8 | 12 | 66.67%
<!-- | **Total:** | **18** | **22** | **81.82%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/41190052/badge)](https://coveralls.io/builds/41190052) |
| :-- | --: |
| Change from base [Build 1007894062](https://coveralls.io/builds/41179771): |  -0.04% |
| Covered Lines: | 1470 |
| Relevant Lines: | 1503 |

---
##### 💛  - [Coveralls](https://coveralls.io)

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='2.8%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list) [2.8% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list)


jonaslagoni: > Overall good, but please also add one tests for patternProperties, like in other languages :)

Completely forgot about it, added 👍 
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=301&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='2.8%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list) [2.8% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=301&metric=new_duplicated_lines_density&view=list)


jonaslagoni: Thanks 🥂 
magicmatatjahu: @smoya I don't remember some features of Golang tag, but probably If we put the additionalProperties and patternProperties as map we can have problem with this issue, am I right? https://github.com/asyncapi/modelina/issues/299
smoya: Before understanding the expectation around `additionalProperties` and `patternProperties` here, I would like to better understand what's the mission of Modelina. 

We've said that Modelina generates models from JSON Schema (among others). What is not clear enough for me is the main use cases. 
I see one use case is to use it inside our generators. But I also saw Modelina as a tool for generating domain model that users can use in their applications, for example, with the purpose of encoding/decoding a message to a model, etc. Correct me if I'm wrong so most of the following speech here should then be skipped.

In the second case, and talking, in particular, about the Go model generation, this is not gonna be possible that easy. As stated in https://github.com/asyncapi/modelina/issues/299, Go structs need some special tags (as @magicmatatjahu mentioned in the comment above) to be able to encode/decode (marshal/unmarshal) JSON, otherwise manual encoding/decoding should happen. It is also the way to go with any other kind of encoder/decoder such as Yaml, XML, etc.

In particular, Go [JSON marshaler/unmarshaler](https://golang.org/pkg/encoding/json/) only maps fields that are explicitly set in those tags. Any other fields are **discarded** otherwise. There are some other alternatives that can be used but that won't be then as standard, like using https://github.com/mitchellh/mapstructure which keeps all fields that were not mapped in a `map[string]interface{}` field so you can access later (This is how we will be doing mostly for the parsing in the event-gateway).

Having said that, I'm answering the following question: 

> @smoya I don't remember some features of Golang tag, but probably If we put the additionalProperties and patternProperties as map we can have problem with this issue, am I right? #299

We can generate whatever model we want, but if the mission is to use those for encoding/decoding, at least JSON, that won't work unless we either force users to go with something like https://github.com/mitchellh/mapstructure or rather provide our own encoder/decoder implementation. 

jonaslagoni: Thanks for the feedback @smoya 👍 

> We've said that Modelina generates models from JSON Schema (among others). What is not clear enough for me is the main use cases.

To me there is not a main use-case, it can be used for both `domain model´ and also just for the pure class definition. 

For the `domain model` use-case, it is expected that we are adding a custom [helper functions to un/marshal data models](https://github.com/asyncapi/modelina/issues/262), it has just not been added yet 😄 

I suspect that https://github.com/asyncapi/modelina/issues/299 will simply not be sufficient, because of the nature of the data models where properties do not map 1 to 1 with the JSON data. I.e. `additionalProperties` should be unwrapped and not be used as-is. But it is something we will see once we start those tasks 🙂 

But yea, this issue simply allows the user to specify the "correct" data, i.e. can set additional properties, as the nature of JSON Schema allows.

Hope that clarified it @smoya 🙂  


smoya: > I suspect that #299 will simply not be sufficient, because of the nature of the data models where properties do not map 1 to 1 with the JSON data. I.e. `additionalProperties` should be unwrapped and not be used as-is. But it is something we will see once we start those tasks 🙂

That's right. And as you mentioned it will be covered by https://github.com/asyncapi/modelina/issues/262 so as far as I see, this PR looks good to me then 👍 

Thanks for clarifying @jonaslagoni 🚀 

Patch:
diff --git a/src/generators/go/GoPreset.ts b/src/generators/go/GoPreset.ts
index df059574..8c48d1c4 100644
--- a/src/generators/go/GoPreset.ts
+++ b/src/generators/go/GoPreset.ts
@@ -4,9 +4,15 @@ import { Preset, CommonModel, CommonPreset, PresetArgs, EnumPreset } from '../..
 import { StructRenderer, GO_DEFAULT_STRUCT_PRESET } from './renderers/StructRenderer';
 import { EnumRenderer, GO_DEFAULT_ENUM_PRESET } from './renderers/EnumRenderer';
 
+export enum FieldType {
+  field,
+  additionalProperty,
+  patternProperties
+}
 export interface FieldArgs {
   fieldName: string;
   field: CommonModel;
+  type: FieldType;
 }
 
 export interface StructPreset<R extends AbstractRenderer, O extends object = any> extends CommonPreset<R, O> {
diff --git a/src/generators/go/GoRenderer.ts b/src/generators/go/GoRenderer.ts
index b5802aa4..417f5f7f 100644
--- a/src/generators/go/GoRenderer.ts
+++ b/src/generators/go/GoRenderer.ts
@@ -2,6 +2,8 @@ import { AbstractRenderer } from '../AbstractRenderer';
 import { GoGenerator, GoOptions } from './GoGenerator';
 import { CommonModel, CommonInputModel, Preset } from '../../models';
 import { FormatHelpers } from '../../helpers/FormatHelpers';
+import { DefaultPropertyNames, getUniquePropertyName } from '../../helpers';
+import { FieldType } from './GoPreset';
 
 /**
  * Common renderer for Go types
@@ -28,6 +30,19 @@ export abstract class GoRenderer extends AbstractRenderer<GoOptions> {
       content.push(renderField);
     }
 
+    if (this.model.additionalProperties !== undefined) {
+      const propertyName = getUniquePropertyName(this.model, DefaultPropertyNames.additionalProperties);
+      const additionalProperty = await this.runFieldPreset(propertyName, this.model.additionalProperties, FieldType.additionalProperty);
+      content.push(additionalProperty);
+    }
+
+    if (this.model.patternProperties !== undefined) {
+      for (const [pattern, patternModel] of Object.entries(this.model.patternProperties)) {
+        const propertyName = getUniquePropertyName(this.model, `${pattern}${DefaultPropertyNames.patternProperties}`);
+        const renderedPatternProperty = await this.runFieldPreset(propertyName, patternModel, FieldType.patternProperties);
+        content.push(renderedPatternProperty);
+      }
+    }
     return this.renderBlock(content);
   }
 
@@ -57,8 +72,8 @@ export abstract class GoRenderer extends AbstractRenderer<GoOptions> {
       : fieldName || '';
   }
 
-  runFieldPreset(fieldName: string, field: CommonModel): Promise<string> {
-    return this.runPreset('field', { fieldName, field });
+  runFieldPreset(fieldName: string, field: CommonModel, type: FieldType = FieldType.field): Promise<string> {
+    return this.runPreset('field', { fieldName, field, type });
   }
 
   renderType(model: CommonModel): string {
diff --git a/src/generators/go/renderers/StructRenderer.ts b/src/generators/go/renderers/StructRenderer.ts
index 7228ab1b..e8fb1979 100644
--- a/src/generators/go/renderers/StructRenderer.ts
+++ b/src/generators/go/renderers/StructRenderer.ts
@@ -1,5 +1,5 @@
 import { GoRenderer } from '../GoRenderer';
-import { StructPreset } from '../GoPreset';
+import { FieldType, StructPreset } from '../GoPreset';
 
 /**
  * Renderer for Go's `struct` type
@@ -27,8 +27,12 @@ export const GO_DEFAULT_STRUCT_PRESET: StructPreset<StructRenderer> = {
   self({ renderer }) {
     return renderer.defaultSelf();
   },
-  field({ fieldName, field, renderer }) {
+  field({ fieldName, field, renderer, type }) {
     fieldName = renderer.nameField(fieldName, field);
-    return `${ fieldName } ${ renderer.renderType(field)}`;
+    let fieldType = renderer.renderType(field);
+    if (type === FieldType.additionalProperty || type === FieldType.patternProperties) {
+      fieldType = `map[string]${fieldType}`; 
+    }
+    return `${ fieldName } ${ fieldType }`;
   },
 };


Test patch:
diff --git a/test/generators/go/GoGenerator.spec.ts b/test/generators/go/GoGenerator.spec.ts
index 695f9bcd..f47a1835 100644
--- a/test/generators/go/GoGenerator.spec.ts
+++ b/test/generators/go/GoGenerator.spec.ts
@@ -20,6 +20,14 @@ describe('GoGenerator', () => {
         array_type: { type: 'array', items: { type: 'string' } },
       },
       required: ['street_name', 'city', 'state', 'house_number', 'array_type'],
+      additionalProperties: {
+        type: 'string'
+      },
+      patternProperties: {
+        '^S(.?*)test&': {
+          type: 'string'
+        }
+      },
     };
     const expected = `// Address represents a Address model.
 type Address struct {
@@ -31,6 +39,8 @@ type Address struct {
   Members []interface{}
   TupleType []interface{}
   ArrayType []string
+  AdditionalProperties map[string]string
+  STestPatternProperties map[string]string
 }`;
 
     const inputModel = await generator.process(doc);
@@ -51,11 +61,15 @@ type Address struct {
       type: 'object',
       properties: {
         property: { type: 'string' },
+      },
+      additionalProperties: {
+        type: 'string'
       }
     };
     const expected = `// CustomStruct represents a CustomStruct model.
 type CustomStruct struct {
   property string
+  additionalProperties string
 }`;
 
     generator = new GoGenerator({ presets: [