Repository: asyncapi/modelina
Pull request #677 (2022-03-08 20:43:15)

refactor: add CommonModel conversion to MetaModel
 **Description**
This PR adds the conversion of CommonModel to MetaModel.

The reason why I choose to not completely replace CommonModel is that we have to build the grammar schema version of the JSON Schema so it's no longer a rule-based schema. 

This for example means that we have to dynamically build it, adding and removing parts as we go because of the `not` keyword. We can always replace it at another time if we find it necessary. 

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=677&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=677&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=677&metric=duplicated_lines_density&view=list) No Duplication information


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=677&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=677&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=677&metric=duplicated_lines_density&view=list) No Duplication information


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=677&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=677&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=677&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=677&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=677&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=677&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=677) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=asyncapi_generator-model-sdk&pullRequest=677&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/src/helpers/CommonModelToMetaModel.ts b/src/helpers/CommonModelToMetaModel.ts
new file mode 100644
index 00000000..1bf196e1
--- /dev/null
+++ b/src/helpers/CommonModelToMetaModel.ts
@@ -0,0 +1,202 @@
+
+import { CommonModel, MetaModel, UnionModel, ObjectModel, DictionaryModel, StringModel, TupleModel, TupleValueModel, ArrayModel, BooleanModel, IntegerModel, FloatModel, EnumModel, EnumValueModel} from '../models';
+
+export function convertToMetaModel(jsonSchemaModel: CommonModel): MetaModel {
+  const modelName = jsonSchemaModel.$id || 'undefined';
+
+  const unionModel = convertToUnionModel(jsonSchemaModel, modelName);
+  if (unionModel !== undefined) {
+    return unionModel;
+  }
+  const stringModel = convertToStringModel(jsonSchemaModel, modelName);
+  if (stringModel !== undefined) {
+    return stringModel;
+  }
+  const floatModel = convertToFloatModel(jsonSchemaModel, modelName);
+  if (floatModel !== undefined) {
+    return floatModel;
+  }
+  const integerModel = convertToIntegerModel(jsonSchemaModel, modelName);
+  if (integerModel !== undefined) {
+    return integerModel;
+  }
+  const enumModel = convertToEnumModel(jsonSchemaModel, modelName);
+  if (enumModel !== undefined) {
+    return enumModel;
+  }
+  const booleanModel = convertToBooleanModel(jsonSchemaModel, modelName);
+  if (booleanModel !== undefined) {
+    return booleanModel;
+  }
+  const objectModel = convertToObjectModel(jsonSchemaModel, modelName);
+  if (objectModel !== undefined) {
+    return objectModel;
+  }
+  const tupleModel = convertToTupleModel(jsonSchemaModel, modelName);
+  if (tupleModel !== undefined) {
+    return tupleModel;
+  }
+  const arrayModel = convertToArrayModel(jsonSchemaModel, modelName);
+  if (arrayModel !== undefined) {
+    return arrayModel;
+  }
+  throw new Error('Failed to convert to MetaModel');
+}
+export function convertToUnionModel(jsonSchemaModel: CommonModel, name: string): UnionModel | undefined {
+  if (!Array.isArray(jsonSchemaModel.type) || jsonSchemaModel.type.length <= 1) {
+    return undefined;
+  }
+  // Has multiple types, so convert to union
+  const unionModel = new UnionModel(name, jsonSchemaModel.originalInput, []);
+  const stringModel = convertToStringModel(jsonSchemaModel, name);
+  if (stringModel !== undefined) {
+    unionModel.union.push(stringModel);
+  }
+  const floatModel = convertToFloatModel(jsonSchemaModel, name);
+  if (floatModel !== undefined) {
+    unionModel.union.push(floatModel);
+  }
+  const integerModel = convertToIntegerModel(jsonSchemaModel, name);
+  if (integerModel !== undefined) {
+    unionModel.union.push(integerModel);
+  }
+  const enumModel = convertToEnumModel(jsonSchemaModel, name);
+  if (enumModel !== undefined) {
+    unionModel.union.push(enumModel);
+  }
+  const booleanModel = convertToBooleanModel(jsonSchemaModel, name);
+  if (booleanModel !== undefined) {
+    unionModel.union.push(booleanModel);
+  }
+  const objectModel = convertToObjectModel(jsonSchemaModel, name);
+  if (objectModel !== undefined) {
+    unionModel.union.push(objectModel);
+  }
+  const tupleModel = convertToTupleModel(jsonSchemaModel, name);
+  if (tupleModel !== undefined) {
+    unionModel.union.push(tupleModel);
+  }
+  const arrayModel = convertToArrayModel(jsonSchemaModel, name);
+  if (arrayModel !== undefined) {
+    unionModel.union.push(arrayModel);
+  }
+  return unionModel;
+}
+export function convertToStringModel(jsonSchemaModel: CommonModel, name: string): StringModel | undefined {
+  if (!jsonSchemaModel.type?.includes('string')) {
+    return undefined;
+  }
+  return new StringModel(name, jsonSchemaModel.originalInput);
+}
+export function convertToIntegerModel(jsonSchemaModel: CommonModel, name: string): IntegerModel | undefined {
+  if (!jsonSchemaModel.type?.includes('integer')) {
+    return undefined;
+  }
+  return new IntegerModel(name, jsonSchemaModel.originalInput);
+}
+export function convertToFloatModel(jsonSchemaModel: CommonModel, name: string): FloatModel | undefined {
+  if (!jsonSchemaModel.type?.includes('number')) {
+    return undefined;
+  }
+  return new FloatModel(name, jsonSchemaModel.originalInput);
+}
+export function convertToEnumModel(jsonSchemaModel: CommonModel, name: string): EnumModel | undefined {
+  if (!Array.isArray(jsonSchemaModel.enum)) {
+    return undefined;
+  }
+  const metaModel = new EnumModel(name, jsonSchemaModel.originalInput, []);
+  for (const enumValue of jsonSchemaModel.enum) {
+    const enumValueModel = new EnumValueModel(JSON.stringify(enumValue), enumValue);
+    metaModel.values.push(enumValueModel);
+  }
+  return metaModel;
+}
+export function convertToBooleanModel(jsonSchemaModel: CommonModel, name: string): BooleanModel | undefined {
+  if (!jsonSchemaModel.type?.includes('boolean')) {
+    return undefined;
+  }
+  return new BooleanModel(name, jsonSchemaModel.originalInput);
+}
+export function convertToObjectModel(jsonSchemaModel: CommonModel, name: string): ObjectModel | undefined {
+  if (!jsonSchemaModel.type?.includes('object')) {
+    return undefined;
+  }
+  const metaModel = new ObjectModel(name, jsonSchemaModel.originalInput, {});
+  for (const [propertyName, prop] of Object.entries(jsonSchemaModel.properties || {})) {
+    metaModel.properties[String(propertyName)] = convertToMetaModel(prop);
+  }
+
+  if (jsonSchemaModel.additionalProperties !== undefined) {
+    const propertyName = 'additionalProperties';
+    if (metaModel.properties[String(propertyName)] === undefined) {
+      const keyModel = new StringModel(propertyName, jsonSchemaModel.additionalProperties.originalInput);
+      const valueModel = convertToMetaModel(jsonSchemaModel.additionalProperties);
+      const dictionaryModel = new DictionaryModel(propertyName, jsonSchemaModel.additionalProperties.originalInput, keyModel, valueModel, 'unwrap');
+      metaModel.properties[String(propertyName)] = dictionaryModel;
+    } else {
+      throw new Error('Property already exists');
+    }
+  }
+
+  if (jsonSchemaModel.patternProperties !== undefined) {
+    for (const [pattern, patternModel] of Object.entries(jsonSchemaModel.patternProperties)) {
+      const propertyName = `${pattern}_PatternProperty`;
+      if (metaModel.properties[String(propertyName)] === undefined) {
+        const keyModel = new StringModel(propertyName, pattern);
+        const valueModel = convertToMetaModel(patternModel);
+        const dictionaryModel = new DictionaryModel(propertyName, patternModel.originalInput, keyModel, valueModel, 'unwrap');
+        metaModel.properties[String(propertyName)] = dictionaryModel;
+      } else {
+        throw new Error('Property already exists');
+      }
+    }
+  }
+  return metaModel;
+}
+
+export function convertToArrayModel(jsonSchemaModel: CommonModel, name: string): ArrayModel | undefined {
+  if (!jsonSchemaModel.type?.includes('array')) {
+    return undefined;
+  }
+
+  const isNormalArray = !Array.isArray(jsonSchemaModel.items) && jsonSchemaModel.additionalItems === undefined && jsonSchemaModel.items !== undefined;
+  //item multiple types + additionalItems sat = both count, as normal array
+  //item single type + additionalItems sat = contradicting, only items count, as normal array
+  //item not sat + additionalItems sat = anything is allowed, as normal array
+  //item single type + additionalItems not sat = normal array
+  //item not sat + additionalItems not sat = normal array, any type
+  if (isNormalArray) {
+    const valueModel = convertToMetaModel(jsonSchemaModel.items as CommonModel);
+    return new ArrayModel(name, jsonSchemaModel.originalInput, valueModel);
+  }
+
+  const valueModel = new UnionModel('union', jsonSchemaModel.originalInput, []);
+  if (jsonSchemaModel.items !== undefined) {
+    for (const itemModel of Array.isArray(jsonSchemaModel.items) ? jsonSchemaModel.items : [jsonSchemaModel.items]) {
+      const itemsModel = convertToMetaModel(itemModel);
+      valueModel.union.push(itemsModel);
+    }
+  }
+  if (jsonSchemaModel.additionalItems !== undefined) {
+    const itemsModel = convertToMetaModel(jsonSchemaModel.additionalItems);
+    valueModel.union.push(itemsModel);
+  }
+  return new ArrayModel(name, jsonSchemaModel.originalInput, valueModel);
+}
+export function convertToTupleModel(jsonSchemaModel: CommonModel, name: string): TupleModel | undefined {
+  const isTuple = jsonSchemaModel.type?.includes('array') && Array.isArray(jsonSchemaModel.items) && jsonSchemaModel.additionalItems === undefined;
+  if (!isTuple) {
+    return undefined;
+  }
+
+  const items = jsonSchemaModel.items as CommonModel[];
+  //item multiple types + additionalItems not sat = tuple of item type
+  const tupleModel = new TupleModel(name, jsonSchemaModel.originalInput, []);
+  for (let i = 0; i < items.length; i++) {
+    const item = items[Number(i)];
+    const valueModel = convertToMetaModel(item);
+    const tupleValueModel = new TupleValueModel(i, valueModel);
+    tupleModel.tuple[Number(i)] = tupleValueModel;
+  }
+  return tupleModel;
+}
diff --git a/src/helpers/index.ts b/src/helpers/index.ts
index 2e5cfb8c..c5f8de00 100644
--- a/src/helpers/index.ts
+++ b/src/helpers/index.ts
@@ -2,4 +2,5 @@ export * from './FormatHelpers';
 export * from './TypeHelpers';
 export * from './NameHelpers';
 export * from './FileHelpers';
+export * from './CommonModelToMetaModel';
 export * from './Splitter';


Test patch:
diff --git a/test/helpers/CommonModelToMetaModel.spec.ts b/test/helpers/CommonModelToMetaModel.spec.ts
new file mode 100644
index 00000000..cbbf4d95
--- /dev/null
+++ b/test/helpers/CommonModelToMetaModel.spec.ts
@@ -0,0 +1,171 @@
+import { ArrayModel, BooleanModel, CommonModel, FloatModel, IntegerModel, ObjectModel, StringModel, TupleModel, UnionModel } from '../../src';
+import { convertToMetaModel } from '../../src/helpers';
+describe('CommonModelToMetaModel', () => {
+  afterEach(() => {
+    jest.restoreAllMocks();
+  });
+  test('should convert to string model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'string';
+    cm.$id = 'test';
+
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof StringModel).toEqual(true);
+  });
+  test('should convert to float model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'number';
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof FloatModel).toEqual(true);
+  });
+  test('should convert to integer model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'integer';
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof IntegerModel).toEqual(true);
+  });
+  test('should convert to boolean model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'boolean';
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof BooleanModel).toEqual(true);
+  });
+  test('should convert to model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'object';
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ObjectModel).toEqual(true);
+  });
+  test('should convert to array model', () => { 
+    const cm = new CommonModel();
+    cm.type = 'array';
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ArrayModel).toEqual(true);
+  });
+  test('should convert to object model', () => { 
+    const spm = new CommonModel();
+    spm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'object';
+    cm.$id = 'test';
+    cm.properties = {
+      test: spm
+    };
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ObjectModel).toEqual(true);
+  });
+  test('should convert to object model with additional properties', () => { 
+    const spm = new CommonModel();
+    spm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'object';
+    cm.$id = 'test';
+    cm.properties = {
+      test: spm
+    };
+    cm.additionalProperties = spm;
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ObjectModel).toEqual(true);
+    expect((model as ObjectModel).properties['additionalProperties']).not.toBeUndefined();
+  });
+  test('should convert to object model with pattern properties', () => { 
+    const spm = new CommonModel();
+    spm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'object';
+    cm.$id = 'test';
+    cm.properties = {
+      test: spm
+    };
+    cm.patternProperties = {
+      test: spm
+    };
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ObjectModel).toEqual(true);
+    expect((model as ObjectModel).properties['test_PatternProperty']).not.toBeUndefined();
+  });
+  test('should convert normal array to array model', () => { 
+    const spm = new CommonModel();
+    spm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'array';
+    cm.$id = 'test';
+    cm.items = spm;
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ArrayModel).toEqual(true);
+  });
+  test('should convert array with additional items to array model as union type', () => { 
+    const spm = new CommonModel();
+    spm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'array';
+    cm.$id = 'test';
+    cm.items = spm;
+    cm.additionalItems = spm;
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof ArrayModel).toEqual(true);
+    expect((model as ArrayModel).valueModel instanceof UnionModel).toEqual(true); 
+  });
+  test('should convert array of types to union model', () => { 
+    const cm = new CommonModel();
+    cm.type = ['string', 'number'];
+    cm.$id = 'test';
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof UnionModel).toEqual(true);
+    expect((model as UnionModel).union.length).toEqual(2); 
+  });
+  test('should convert tuple to tuple model', () => { 
+    const scm = new CommonModel();
+    scm.type = 'string';
+    const cm = new CommonModel();
+    cm.type = 'array';
+    cm.$id = 'test';
+    cm.items = [scm, scm];
+    
+    const model = convertToMetaModel(cm);
+
+    expect(model).not.toBeUndefined();
+    expect(model instanceof TupleModel).toEqual(true);
+    expect((model as TupleModel).tuple.length).toEqual(2); 
+  });
+});