Repository: asyncapi/modelina
Pull request #337 (2021-09-01 10:16:45)

fix: un/marshal TS class functions did not render references correctly
**Description**
This PR fixes a couple of things: 
1. When enums are referenced, they should be un/marshaled as is, and not through helper functions
2. Ensured that pattern properties and additional properties render the correct un/marshal functionality based on type.

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; ![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')

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

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337) No Coverage information  
[![0.1%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.1%')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list) [0.1% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list)


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

* **36** of **36**   **(100.0%)**  changed or added relevant lines in **1** file are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage increased (+**0.1%**) to **93.478%**

---



|  Totals | [![Coverage Status](https://coveralls.io/builds/42573485/badge)](https://coveralls.io/builds/42573485) |
| :-- | --: |
| Change from base [Build 1185548622](https://coveralls.io/builds/42536692): |  0.1% |
| Covered Lines: | 1769 |
| Relevant Lines: | 1805 |

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

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; ![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')

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

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337) No Coverage information  
[![0.1%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.1%')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list) [0.1% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; ![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')

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

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337) No Coverage information  
[![0.1%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.1%')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list) [0.1% Duplication](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=337&metric=new_duplicated_lines_density&view=list)


jonaslagoni: Thanks, @magicmatatjahu!

Patch:
diff --git a/src/generators/typescript/presets/CommonPreset.ts b/src/generators/typescript/presets/CommonPreset.ts
index 1b29fed1..353dd0f9 100644
--- a/src/generators/typescript/presets/CommonPreset.ts
+++ b/src/generators/typescript/presets/CommonPreset.ts
@@ -1,7 +1,7 @@
 import { TypeScriptRenderer } from '../TypeScriptRenderer';
 import { TypeScriptPreset } from '../TypeScriptPreset';
-import { getUniquePropertyName, DefaultPropertyNames } from '../../../helpers';
-import { CommonModel } from '../../../models';
+import { getUniquePropertyName, DefaultPropertyNames, TypeHelpers, ModelKind } from '../../../helpers';
+import { CommonInputModel, CommonModel } from '../../../models';
 import renderExampleFunction from './utils/ExampleFunction';
 
 export interface TypeScriptCommonPresetOptions {
@@ -12,36 +12,46 @@ export interface TypeScriptCommonPresetOptions {
 function realizePropertyFactory(prop: string) {
   return `$\{typeof ${prop} === 'number' || typeof ${prop} === 'boolean' ? ${prop} : JSON.stringify(${prop})}`;
 }
-
-function renderMarshalProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderMarshalProperty(modelInstanceVariable: string, model: CommonModel, inputModel: CommonInputModel) {
+  if (model.$ref) {
+    const resolvedModel = inputModel.models[model.$ref];
+    const propertyModelKind = TypeHelpers.extractKind(resolvedModel);
+    //Referenced enums only need standard marshalling, so lets filter those away
+    if (propertyModelKind !== ModelKind.ENUM) {
+      return `$\{${modelInstanceVariable}.marshal()}`;
+    }
+  }
+  return realizePropertyFactory(modelInstanceVariable);
+}
+function renderMarshalProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   const properties = model.properties || {};
   const propertyKeys = [...Object.entries(properties)];
   const marshalProperties = propertyKeys.map(([prop, propModel]) => {
     const formattedPropertyName = renderer.nameProperty(prop, propModel);
     const modelInstanceVariable = `this.${formattedPropertyName}`;
-    const propMarshalReference = `json += \`"${prop}": $\{this.${formattedPropertyName}.marshal()},\`;`;
-    const propMarshal = `json += \`"${prop}": ${realizePropertyFactory(modelInstanceVariable)},\`;`;
-    const propMarshalCode = propModel.$ref !== undefined ? propMarshalReference : propMarshal;
-    return `if(this.${formattedPropertyName} !== undefined) {
-  ${propMarshalCode} 
+    const propMarshalCode = renderMarshalProperty(modelInstanceVariable, propModel, inputModel);
+    const marshalCode = `json += \`"${prop}": ${propMarshalCode},\`;`;
+    return `if(${modelInstanceVariable} !== undefined) {
+  ${marshalCode} 
 }`;
   });
   return marshalProperties.join('\n');
 }
 
-function renderMarshalPatternProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderMarshalPatternProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   let marshalPatternProperties = '';
   if (model.patternProperties !== undefined) {
     for (const [pattern, patternModel] of Object.entries(model.patternProperties)) {
       let patternPropertyName = getUniquePropertyName(model, `${pattern}${DefaultPropertyNames.patternProperties}`);
       patternPropertyName = renderer.nameProperty(patternPropertyName, patternModel);
-      const patternPropertyMarshalReference = 'json += `"${key}": ${value.marshal()},`;';
-      const patternPropertyMarshal = `json += \`"$\{key}": ${realizePropertyFactory('value')},\`;`;
+      const modelInstanceVariable = 'value';
+      const patternPropertyMarshalCode = renderMarshalProperty(modelInstanceVariable, patternModel, inputModel);
+      const marshalCode = `json += \`"$\{key}": ${patternPropertyMarshalCode},\`;`;
       marshalPatternProperties += `if(this.${patternPropertyName} !== undefined) { 
   for (const [key, value] of this.${patternPropertyName}.entries()) {
     //Only render pattern properties which are not already a property
     if(Object.keys(this).includes(String(key))) continue;
-    ${patternModel.$ref !== undefined ? patternPropertyMarshalReference : patternPropertyMarshal}
+    ${marshalCode}
   }
 }`;
     }
@@ -49,18 +59,19 @@ function renderMarshalPatternProperties(model: CommonModel, renderer: TypeScript
   return marshalPatternProperties;
 }
 
-function renderMarshalAdditionalProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderMarshalAdditionalProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   let marshalAdditionalProperties = '';
   if (model.additionalProperties !== undefined) {
     let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties);
     additionalPropertyName = renderer.nameProperty(additionalPropertyName, model.additionalProperties);
-    const additionalPropertyMarshalReference = 'json += `"${key}": ${value.marshal()},`;';
-    const additionalPropertyMarshal = `json += \`"$\{key}": ${realizePropertyFactory('value')},\`;`;
+    const modelInstanceVariable = 'value';
+    const patternPropertyMarshalCode = renderMarshalProperty(modelInstanceVariable, model.additionalProperties, inputModel);
+    const marshalCode = `json += \`"$\{key}": ${patternPropertyMarshalCode},\`;`;
     marshalAdditionalProperties = `if(this.${additionalPropertyName} !== undefined) { 
   for (const [key, value] of this.${additionalPropertyName}.entries()) {
     //Only render additionalProperties which are not already a property
     if(Object.keys(this).includes(String(key))) continue;
-    ${model.additionalProperties.$ref !== undefined ? additionalPropertyMarshalReference : additionalPropertyMarshal}    
+    ${marshalCode}
   }
 }`;
   }
@@ -70,45 +81,60 @@ function renderMarshalAdditionalProperties(model: CommonModel, renderer: TypeScr
 /**
  * Render `marshal` function based on model
  */
-function renderMarshal({ renderer, model }: {
+function renderMarshal({ renderer, model, inputModel }: {
   renderer: TypeScriptRenderer,
   model: CommonModel,
+  inputModel: CommonInputModel
 }): string {
   return `public marshal() : string {
   let json = '{'
-${renderer.indent(renderMarshalProperties(model, renderer))}
-${renderer.indent(renderMarshalPatternProperties(model, renderer))}
-${renderer.indent(renderMarshalAdditionalProperties(model, renderer))}
+${renderer.indent(renderMarshalProperties(model, renderer, inputModel))}
+${renderer.indent(renderMarshalPatternProperties(model, renderer, inputModel))}
+${renderer.indent(renderMarshalAdditionalProperties(model, renderer, inputModel))}
 
   //Remove potential last comma 
   return \`$\{json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}\`;
 }`;
 } 
 
-function renderUnmarshalProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderUnmarshalProperty(modelInstanceVariable: string, model: CommonModel, inputModel: CommonInputModel, renderer: TypeScriptRenderer) {
+  if (model.$ref) {
+    const resolvedModel = inputModel.models[model.$ref];
+    const propertyModelKind = TypeHelpers.extractKind(resolvedModel);
+    //Referenced enums only need standard marshalling, so lets filter those away
+    if (propertyModelKind !== ModelKind.ENUM) {
+      return `${renderer.nameType(model.$ref)}.unmarshal(${modelInstanceVariable})`;
+    }
+  }
+  return `${modelInstanceVariable}`;
+}
+function renderUnmarshalProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   const properties = model.properties || {};
   const propertyKeys = [...Object.entries(properties)];
   const unmarshalProperties = propertyKeys.map(([prop, propModel]) => {
     const formattedPropertyName = renderer.nameProperty(prop, propModel);
-    const propUnmarshal = propModel.$ref !== undefined ? `${renderer.nameType(propModel.$ref)}.unmarshal(obj["${prop}"])` : `obj["${prop}"]`;
-    return `if (obj["${prop}"] !== undefined) {
-  instance.${formattedPropertyName} = ${propUnmarshal};
+    const modelInstanceVariable = `obj["${prop}"]`;
+    const unmarshalCode = renderUnmarshalProperty(modelInstanceVariable, propModel, inputModel, renderer);
+    return `if (${modelInstanceVariable} !== undefined) {
+  instance.${formattedPropertyName} = ${unmarshalCode};
 }`;
   });
   return unmarshalProperties.join('\n');
 }
 
-function renderUnmarshalPatternProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderUnmarshalPatternProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   let unmarshalPatternProperties = '';
   let setPatternPropertiesMap = '';
   if (model.patternProperties !== undefined) {
     for (const [pattern, patternModel] of Object.entries(model.patternProperties)) {
       let patternPropertyName = getUniquePropertyName(model, `${pattern}${DefaultPropertyNames.patternProperties}`);
       patternPropertyName = renderer.nameProperty(patternPropertyName, patternModel);
-      setPatternPropertiesMap = `if (instance.${patternPropertyName} === undefined) {instance.${patternPropertyName} = new Map();}`;
+      const modelInstanceVariable = 'value as any';
+      const unmarshalCode = renderUnmarshalProperty(modelInstanceVariable, patternModel, inputModel, renderer);
+      setPatternPropertiesMap += `if (instance.${patternPropertyName} === undefined) {instance.${patternPropertyName} = new Map();}\n`;
       unmarshalPatternProperties += `//Check all pattern properties
 if (key.match(new RegExp('${pattern}'))) {
-  instance.${patternPropertyName}.set(key, value as any);
+  instance.${patternPropertyName}.set(key, ${unmarshalCode});
   continue;
 }`;
     }
@@ -116,15 +142,16 @@ if (key.match(new RegExp('${pattern}'))) {
   return {unmarshalPatternProperties, setPatternPropertiesMap};
 }
 
-function renderUnmarshalAdditionalProperties(model: CommonModel, renderer: TypeScriptRenderer) {
+function renderUnmarshalAdditionalProperties(model: CommonModel, renderer: TypeScriptRenderer, inputModel: CommonInputModel) {
   let unmarshalAdditionalProperties = '';
   let setAdditionalPropertiesMap = '';
   if (model.additionalProperties !== undefined) {
     let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties);
     additionalPropertyName = renderer.nameProperty(additionalPropertyName, model.additionalProperties);
-    const additionalPropertiesCast = model.additionalProperties.$ref !== undefined ? `${renderer.nameType(model.$id)}.unmarshal(value)` : 'value as any';
+    const modelInstanceVariable = 'value as any';
+    const unmarshalCode = renderUnmarshalProperty(modelInstanceVariable, model.additionalProperties, inputModel, renderer);
     setAdditionalPropertiesMap = `if (instance.${additionalPropertyName} === undefined) {instance.${additionalPropertyName} = new Map();}`;
-    unmarshalAdditionalProperties = `instance.${additionalPropertyName}.set(key, ${additionalPropertiesCast});`;
+    unmarshalAdditionalProperties = `instance.${additionalPropertyName}.set(key, ${unmarshalCode});`;
   }
   return {unmarshalAdditionalProperties, setAdditionalPropertiesMap};
 }
@@ -132,20 +159,22 @@ function renderUnmarshalAdditionalProperties(model: CommonModel, renderer: TypeS
 /**
  * Render `unmarshal` function based on model
  */
-function renderUnmarshal({ renderer, model }: {
+function renderUnmarshal({ renderer, model, inputModel }: {
   renderer: TypeScriptRenderer,
   model: CommonModel,
+  inputModel: CommonInputModel
 }): string {
   const properties = model.properties || {};
-  const {unmarshalPatternProperties, setPatternPropertiesMap} = renderUnmarshalPatternProperties(model, renderer);
-  const {unmarshalAdditionalProperties, setAdditionalPropertiesMap} = renderUnmarshalAdditionalProperties(model, renderer);
+  const {unmarshalPatternProperties, setPatternPropertiesMap} = renderUnmarshalPatternProperties(model, renderer, inputModel);
+  const {unmarshalAdditionalProperties, setAdditionalPropertiesMap} = renderUnmarshalAdditionalProperties(model, renderer, inputModel);
+  const unmarshalProperties = renderUnmarshalProperties(model, renderer, inputModel);
   const formattedModelName = renderer.nameType(model.$id);
   const propertyNames = Object.keys(properties).map((prop => `"${prop}"`));
   return `public static unmarshal(json: string | object): ${formattedModelName} {
   const obj = typeof json === "object" ? json : JSON.parse(json);
   const instance = new ${formattedModelName}({} as any);
 
-${renderer.indent(renderUnmarshalProperties(model, renderer))}
+${renderer.indent(unmarshalProperties)}
 
   //Not part of core properties
   ${setPatternPropertiesMap}
@@ -165,13 +194,13 @@ ${renderer.indent(unmarshalAdditionalProperties, 4)}
  */
 export const TS_COMMON_PRESET: TypeScriptPreset = {
   class: {
-    additionalContent({ renderer, model, content, options }) {
+    additionalContent({ renderer, model, content, options, inputModel }) {
       options = options || {};
       const blocks: string[] = [];
       
       if (options.marshalling === true) {
-        blocks.push(renderMarshal({ renderer, model }));
-        blocks.push(renderUnmarshal({ renderer, model }));
+        blocks.push(renderMarshal({ renderer, model, inputModel }));
+        blocks.push(renderUnmarshal({ renderer, model, inputModel }));
       }
 
       if (options.example === true) {


Test patch:
diff --git a/test/blackbox/Dummy.spec.ts b/test/blackbox/Dummy.spec.ts
index 96dd5fe8..b0167fe1 100644
--- a/test/blackbox/Dummy.spec.ts
+++ b/test/blackbox/Dummy.spec.ts
@@ -36,7 +36,7 @@ describe('Dummy JSON Schema file', () => {
       const renderOutputPath = path.resolve(__dirname, './output/ts/class/output.ts');
       await renderModels(generatedModels, renderOutputPath);
       const transpiledOutputPath = path.resolve(__dirname, './output/ts/class/output.js');
-      const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`;
+      const transpileAndRunCommand = `tsc --downlevelIteration -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`;
       await execCommand(transpileAndRunCommand);
     });
 
diff --git a/test/generators/typescript/preset/MarshallingPreset.spec.ts b/test/generators/typescript/preset/MarshallingPreset.spec.ts
index 157df794..d4d99d6b 100644
--- a/test/generators/typescript/preset/MarshallingPreset.spec.ts
+++ b/test/generators/typescript/preset/MarshallingPreset.spec.ts
@@ -3,19 +3,24 @@
 import { TypeScriptGenerator, TS_COMMON_PRESET } from '../../../../src/generators'; 
 import Ajv from 'ajv';
 const doc = {
+  definitions: {
+    'NestedTest': {
+      type: 'object', $id: 'NestedTest', properties: {stringProp: { type: 'string' }}
+    }
+  },
   $id: 'Test',
   type: 'object',
-  additionalProperties: true,
+  additionalProperties: {$ref: '#/definitions/NestedTest'},
   required: ['string prop'],
   properties: {
     'string prop': { type: 'string' },
+    enumProp: { $id: 'EnumTest', enum: ['Some enum String', "some other enum string"]},
     numberProp: { type: 'number' },
-    objectProp: { type: 'object', $id: 'NestedTest', properties: {stringProp: { type: 'string' }}}
+    objectProp: { $ref: '#/definitions/NestedTest' }
   },
   patternProperties: {
-    '^S(.?)test': {
-      type: 'string'
-    }
+    '^S(.?)test': { type: 'string' },
+    '^S(.?)AnotherTest': { $ref: '#/definitions/NestedTest' },
   },
 };
 describe('Marshalling preset', () => {
@@ -31,6 +36,7 @@ describe('Marshalling preset', () => {
       ]
     });
     const inputModel = await generator.process(doc);
+
     const testModel = inputModel.models['Test'];
     const nestedTestModel = inputModel.models['NestedTest'];
 
@@ -42,50 +48,52 @@ describe('Marshalling preset', () => {
   });
 
   test('should provide a two way conversion', async () => {
+    enum EnumTest {
+      SOME_ENUM_STRING = "Some enum String",
+      SOME_OTHER_ENUM_STRING = "some other enum string"
+    }
     class NestedTest {
       private _stringProp?: string;
       private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null | number>;
-
+    
       constructor(input: {
         stringProp?: string,
       }) {
         this._stringProp = input.stringProp;
       }
-
+    
       get stringProp(): string | undefined { return this._stringProp; }
       set stringProp(stringProp: string | undefined) { this._stringProp = stringProp; }
-
+    
       get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined { return this._additionalProperties; }
       set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined) { this._additionalProperties = additionalProperties; }
-
+    
       public marshal() : string {
         let json = '{'
         if(this.stringProp !== undefined) {
-          json += `\"stringProp\": ${typeof this.stringProp === 'number' || typeof this.stringProp === 'boolean' ? this.stringProp : JSON.stringify(this.stringProp)},`; 
+          json += `"stringProp": ${typeof this.stringProp === 'number' || typeof this.stringProp === 'boolean' ? this.stringProp : JSON.stringify(this.stringProp)},`; 
         }
-
       
-
         if(this.additionalProperties !== undefined) { 
           for (const [key, value] of this.additionalProperties.entries()) {
             //Only render additionalProperties which are not already a property
             if(Object.keys(this).includes(String(key))) continue;
-            json += `\"${key}\": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`;    
+            json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`;
           }
         }
-
+    
         //Remove potential last comma 
         return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`;
       }
-
+    
       public static unmarshal(json: string | object): NestedTest {
         const obj = typeof json === "object" ? json : JSON.parse(json);
         const instance = new NestedTest({} as any);
-
-        if (obj.stringProp !== undefined) {
-          instance.stringProp = obj["stringProp"];
+    
+        if (obj["stringProp"] !== undefined) {
+          instance.stringProp = obj["stringProp"] as any;
         }
-
+    
         //Not part of core properties
       
         if (instance.additionalProperties === undefined) {instance.additionalProperties = new Map();}
@@ -98,92 +106,118 @@ describe('Marshalling preset', () => {
     }
     class Test {
       private _stringProp: string;
+      private _enumProp?: EnumTest;
       private _numberProp?: number;
       private _objectProp?: NestedTest;
-      private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null | number>;
+      private _additionalProperties?: Map<String, NestedTest>;
       private _sTestPatternProperties?: Map<String, string>;
-
+      private _sAnotherTestPatternProperties?: Map<String, NestedTest>;
+    
       constructor(input: {
         stringProp: string,
+        enumProp?: EnumTest,
         numberProp?: number,
         objectProp?: NestedTest,
       }) {
         this._stringProp = input.stringProp;
+        this._enumProp = input.enumProp;
         this._numberProp = input.numberProp;
         this._objectProp = input.objectProp;
       }
-
+    
       get stringProp(): string { return this._stringProp; }
       set stringProp(stringProp: string) { this._stringProp = stringProp; }
-
+    
+      get enumProp(): EnumTest | undefined { return this._enumProp; }
+      set enumProp(enumProp: EnumTest | undefined) { this._enumProp = enumProp; }
+    
       get numberProp(): number | undefined { return this._numberProp; }
       set numberProp(numberProp: number | undefined) { this._numberProp = numberProp; }
-
+    
       get objectProp(): NestedTest | undefined { return this._objectProp; }
       set objectProp(objectProp: NestedTest | undefined) { this._objectProp = objectProp; }
-
-      get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined { return this._additionalProperties; }
-      set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined) { this._additionalProperties = additionalProperties; }
-
+    
+      get additionalProperties(): Map<String, NestedTest> | undefined { return this._additionalProperties; }
+      set additionalProperties(additionalProperties: Map<String, NestedTest> | undefined) { this._additionalProperties = additionalProperties; }
+    
       get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
       set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
-
+    
+      get sAnotherTestPatternProperties(): Map<String, NestedTest> | undefined { return this._sAnotherTestPatternProperties; }
+      set sAnotherTestPatternProperties(sTest2PatternProperties: Map<String, NestedTest> | undefined) { this._sAnotherTestPatternProperties = sTest2PatternProperties; }
+    
       public marshal() : string {
         let json = '{'
         if(this.stringProp !== undefined) {
-          json += `\"string prop\": ${typeof this.stringProp === 'number' || typeof this.stringProp === 'boolean' ? this.stringProp : JSON.stringify(this.stringProp)},`; 
+          json += `"string prop": ${typeof this.stringProp === 'number' || typeof this.stringProp === 'boolean' ? this.stringProp : JSON.stringify(this.stringProp)},`; 
+        }
+        if(this.enumProp !== undefined) {
+          json += `"enumProp": ${typeof this.enumProp === 'number' || typeof this.enumProp === 'boolean' ? this.enumProp : JSON.stringify(this.enumProp)},`; 
         }
         if(this.numberProp !== undefined) {
-          json += `\"numberProp\": ${typeof this.numberProp === 'number' || typeof this.numberProp === 'boolean' ? this.numberProp : JSON.stringify(this.numberProp)},`; 
+          json += `"numberProp": ${typeof this.numberProp === 'number' || typeof this.numberProp === 'boolean' ? this.numberProp : JSON.stringify(this.numberProp)},`; 
         }
         if(this.objectProp !== undefined) {
-          json += `\"objectProp\": ${this.objectProp.marshal()},`; 
+          json += `"objectProp": ${this.objectProp.marshal()},`; 
         }
-
         if(this.sTestPatternProperties !== undefined) { 
           for (const [key, value] of this.sTestPatternProperties.entries()) {
             //Only render pattern properties which are not already a property
             if(Object.keys(this).includes(String(key))) continue;
-            json += `\"${key}\": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`;
+            json += `"${key}": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`;
+          }
+        }if(this.sAnotherTestPatternProperties !== undefined) { 
+          for (const [key, value] of this.sAnotherTestPatternProperties.entries()) {
+            //Only render pattern properties which are not already a property
+            if(Object.keys(this).includes(String(key))) continue;
+            json += `"${key}": ${value.marshal()},`;
           }
         }
-
         if(this.additionalProperties !== undefined) { 
           for (const [key, value] of this.additionalProperties.entries()) {
             //Only render additionalProperties which are not already a property
             if(Object.keys(this).includes(String(key))) continue;
-            json += `\"${key}\": ${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},`;    
+            json += `"${key}": ${value.marshal()},`;
           }
         }
-
+    
         //Remove potential last comma 
         return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`;
       }
-
+    
       public static unmarshal(json: string | object): Test {
         const obj = typeof json === "object" ? json : JSON.parse(json);
         const instance = new Test({} as any);
-
+    
         if (obj["string prop"] !== undefined) {
           instance.stringProp = obj["string prop"];
         }
-        if (obj.numberProp !== undefined) {
+        if (obj["enumProp"] !== undefined) {
+          instance.enumProp = obj["enumProp"];
+        }
+        if (obj["numberProp"] !== undefined) {
           instance.numberProp = obj["numberProp"];
         }
-        if (obj.objectProp !== undefined) {
+        if (obj["objectProp"] !== undefined) {
           instance.objectProp = NestedTest.unmarshal(obj["objectProp"]);
         }
-
+    
         //Not part of core properties
         if (instance.sTestPatternProperties === undefined) {instance.sTestPatternProperties = new Map();}
+      if (instance.sAnotherTestPatternProperties === undefined) {instance.sAnotherTestPatternProperties = new Map();}
+    
         if (instance.additionalProperties === undefined) {instance.additionalProperties = new Map();}
-        for (const [key, value] of Object.entries(obj).filter((([key,]) => {return !["string prop","numberProp","objectProp"].includes(key);}))) {
+        for (const [key, value] of Object.entries(obj).filter((([key,]) => {return !["string prop","enumProp","numberProp","objectProp"].includes(key);}))) {
           //Check all pattern properties
           if (key.match(new RegExp('^S(.?)test'))) {
             instance.sTestPatternProperties.set(key, value as any);
             continue;
+          }//Check all pattern properties
+          if (key.match(new RegExp('^S(.?)AnotherTest'))) {
+            instance.sAnotherTestPatternProperties.set(key, NestedTest.unmarshal(value as any));
+            continue;
           }
-          instance.additionalProperties.set(key, value as any);
+          instance.additionalProperties.set(key, NestedTest.unmarshal(value as any));
         }
         return instance;
       }
@@ -191,18 +225,21 @@ describe('Marshalling preset', () => {
     const ajv = new Ajv();
     const nestedTestInstance = new NestedTest({stringProp: "SomeTestString"});
     nestedTestInstance.additionalProperties = new Map();
-    const testInstance = new Test({numberProp: 0, stringProp: "SomeTestString", objectProp: nestedTestInstance});
+    nestedTestInstance.additionalProperties.set("someProp", "someValue");
+    const testInstance = new Test({numberProp: 0, stringProp: "SomeTestString", objectProp: nestedTestInstance, enumProp: EnumTest.SOME_ENUM_STRING});
     testInstance.additionalProperties = new Map();
-    testInstance.additionalProperties.set('additionalProp', ['Some test value']);
+    testInstance.additionalProperties.set('additionalProp', nestedTestInstance);
     testInstance.sTestPatternProperties = new Map();
     testInstance.sTestPatternProperties.set('Stest', 'Some pattern value');
+    testInstance.sAnotherTestPatternProperties = new Map();
+    testInstance.sAnotherTestPatternProperties.set('SAnotherTest', nestedTestInstance);
 
 
     const marshalContent = testInstance.marshal();
     const unmarshalInstance = Test.unmarshal(marshalContent);
     const validationResult = ajv.validate(doc, JSON.parse(marshalContent));
 
-    expect(marshalContent).toEqual("{\"string prop\": \"SomeTestString\",\"numberProp\": 0,\"objectProp\": {\"stringProp\": \"SomeTestString\"},\"Stest\": \"Some pattern value\",\"additionalProp\": [\"Some test value\"]}");
+    expect(marshalContent).toEqual("{\"string prop\": \"SomeTestString\",\"enumProp\": \"Some enum String\",\"numberProp\": 0,\"objectProp\": {\"stringProp\": \"SomeTestString\",\"someProp\": \"someValue\"},\"Stest\": \"Some pattern value\",\"SAnotherTest\": {\"stringProp\": \"SomeTestString\",\"someProp\": \"someValue\"},\"additionalProp\": {\"stringProp\": \"SomeTestString\",\"someProp\": \"someValue\"}}");
     expect(validationResult).toEqual(true);
     expect(unmarshalInstance).toEqual(testInstance);
   });
diff --git a/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap b/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap
index 852c6c11..bcba6ece 100644
--- a/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap
+++ b/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap
@@ -3,17 +3,21 @@
 exports[`Marshalling preset should render un/marshal code 1`] = `
 "export class Test {
   private _stringProp: string;
+  private _enumProp?: EnumTest;
   private _numberProp?: number;
   private _objectProp?: NestedTest;
-  private _additionalProperties?: Map<String, object | string | number | Array<unknown> | boolean | null | number>;
+  private _additionalProperties?: Map<String, NestedTest>;
   private _sTestPatternProperties?: Map<String, string>;
+  private _sAnotherTestPatternProperties?: Map<String, NestedTest>;
 
   constructor(input: {
     stringProp: string,
+    enumProp?: EnumTest,
     numberProp?: number,
     objectProp?: NestedTest,
   }) {
     this._stringProp = input.stringProp;
+    this._enumProp = input.enumProp;
     this._numberProp = input.numberProp;
     this._objectProp = input.objectProp;
   }
@@ -21,23 +25,32 @@ exports[`Marshalling preset should render un/marshal code 1`] = `
   get stringProp(): string { return this._stringProp; }
   set stringProp(stringProp: string) { this._stringProp = stringProp; }
 
+  get enumProp(): EnumTest | undefined { return this._enumProp; }
+  set enumProp(enumProp: EnumTest | undefined) { this._enumProp = enumProp; }
+
   get numberProp(): number | undefined { return this._numberProp; }
   set numberProp(numberProp: number | undefined) { this._numberProp = numberProp; }
 
   get objectProp(): NestedTest | undefined { return this._objectProp; }
   set objectProp(objectProp: NestedTest | undefined) { this._objectProp = objectProp; }
 
-  get additionalProperties(): Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined { return this._additionalProperties; }
-  set additionalProperties(additionalProperties: Map<String, object | string | number | Array<unknown> | boolean | null | number> | undefined) { this._additionalProperties = additionalProperties; }
+  get additionalProperties(): Map<String, NestedTest> | undefined { return this._additionalProperties; }
+  set additionalProperties(additionalProperties: Map<String, NestedTest> | undefined) { this._additionalProperties = additionalProperties; }
 
   get sTestPatternProperties(): Map<String, string> | undefined { return this._sTestPatternProperties; }
   set sTestPatternProperties(sTestPatternProperties: Map<String, string> | undefined) { this._sTestPatternProperties = sTestPatternProperties; }
 
+  get sAnotherTestPatternProperties(): Map<String, NestedTest> | undefined { return this._sAnotherTestPatternProperties; }
+  set sAnotherTestPatternProperties(sAnotherTestPatternProperties: Map<String, NestedTest> | undefined) { this._sAnotherTestPatternProperties = sAnotherTestPatternProperties; }
+
   public marshal() : string {
     let json = '{'
     if(this.stringProp !== undefined) {
       json += \`\\"string prop\\": \${typeof this.stringProp === 'number' || typeof this.stringProp === 'boolean' ? this.stringProp : JSON.stringify(this.stringProp)},\`; 
     }
+    if(this.enumProp !== undefined) {
+      json += \`\\"enumProp\\": \${typeof this.enumProp === 'number' || typeof this.enumProp === 'boolean' ? this.enumProp : JSON.stringify(this.enumProp)},\`; 
+    }
     if(this.numberProp !== undefined) {
       json += \`\\"numberProp\\": \${typeof this.numberProp === 'number' || typeof this.numberProp === 'boolean' ? this.numberProp : JSON.stringify(this.numberProp)},\`; 
     }
@@ -50,12 +63,18 @@ exports[`Marshalling preset should render un/marshal code 1`] = `
         if(Object.keys(this).includes(String(key))) continue;
         json += \`\\"\${key}\\": \${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},\`;
       }
+    }if(this.sAnotherTestPatternProperties !== undefined) { 
+      for (const [key, value] of this.sAnotherTestPatternProperties.entries()) {
+        //Only render pattern properties which are not already a property
+        if(Object.keys(this).includes(String(key))) continue;
+        json += \`\\"\${key}\\": \${value.marshal()},\`;
+      }
     }
     if(this.additionalProperties !== undefined) { 
       for (const [key, value] of this.additionalProperties.entries()) {
         //Only render additionalProperties which are not already a property
         if(Object.keys(this).includes(String(key))) continue;
-        json += \`\\"\${key}\\": \${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},\`;    
+        json += \`\\"\${key}\\": \${value.marshal()},\`;
       }
     }
 
@@ -70,6 +89,9 @@ exports[`Marshalling preset should render un/marshal code 1`] = `
     if (obj[\\"string prop\\"] !== undefined) {
       instance.stringProp = obj[\\"string prop\\"];
     }
+    if (obj[\\"enumProp\\"] !== undefined) {
+      instance.enumProp = obj[\\"enumProp\\"];
+    }
     if (obj[\\"numberProp\\"] !== undefined) {
       instance.numberProp = obj[\\"numberProp\\"];
     }
@@ -79,14 +101,20 @@ exports[`Marshalling preset should render un/marshal code 1`] = `
 
     //Not part of core properties
     if (instance.sTestPatternProperties === undefined) {instance.sTestPatternProperties = new Map();}
+  if (instance.sAnotherTestPatternProperties === undefined) {instance.sAnotherTestPatternProperties = new Map();}
+
     if (instance.additionalProperties === undefined) {instance.additionalProperties = new Map();}
-    for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![\\"string prop\\",\\"numberProp\\",\\"objectProp\\"].includes(key);}))) {
+    for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![\\"string prop\\",\\"enumProp\\",\\"numberProp\\",\\"objectProp\\"].includes(key);}))) {
       //Check all pattern properties
       if (key.match(new RegExp('^S(.?)test'))) {
         instance.sTestPatternProperties.set(key, value as any);
         continue;
+      }//Check all pattern properties
+      if (key.match(new RegExp('^S(.?)AnotherTest'))) {
+        instance.sAnotherTestPatternProperties.set(key, NestedTest.unmarshal(value as any));
+        continue;
       }
-      instance.additionalProperties.set(key, value as any);
+      instance.additionalProperties.set(key, NestedTest.unmarshal(value as any));
     }
     return instance;
   }
@@ -120,7 +148,7 @@ exports[`Marshalling preset should render un/marshal code 2`] = `
       for (const [key, value] of this.additionalProperties.entries()) {
         //Only render additionalProperties which are not already a property
         if(Object.keys(this).includes(String(key))) continue;
-        json += \`\\"\${key}\\": \${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},\`;    
+        json += \`\\"\${key}\\": \${typeof value === 'number' || typeof value === 'boolean' ? value : JSON.stringify(value)},\`;
       }
     }