Repository: asyncapi/modelina
Pull request #741 (2022-04-28 01:15:23)

refactor: convert JS to new constraint setup
**Description**
This PR converts the TS generator to the new constraint setup introduced in https://github.com/asyncapi/modelina/pull/725

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')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=741)

[![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=741&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=741&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741) 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=741&metric=duplicated_lines_density&view=list) No Duplication information


Samridhi-98: @jonaslagoni when I tested this PR locally, all tests have been passed (2 skipped) but here black-box testing is failed why so? 🤔
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')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=741)

[![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=741&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=741&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741) 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=741&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')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=741)

[![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=741&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=741&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741) 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=741&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')](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk&pullRequest=741)

[![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=741&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=741&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=asyncapi_generator-model-sdk&pullRequest=741&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=741&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=741&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=asyncapi_generator-model-sdk&pullRequest=741&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=741) 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=741&metric=duplicated_lines_density&view=list) No Duplication information



Patch:
diff --git a/src/generators/javascript/JavaScriptConstrainer.ts b/src/generators/javascript/JavaScriptConstrainer.ts
index cb2c1427..0a428571 100644
--- a/src/generators/javascript/JavaScriptConstrainer.ts
+++ b/src/generators/javascript/JavaScriptConstrainer.ts
@@ -1,121 +1,51 @@
-import { ConstrainedAnyModel, ConstrainedBooleanModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedMetaModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedTupleValueModel, ConstrainedArrayModel, ConstrainedUnionModel, ConstrainedEnumModel, ConstrainedDictionaryModel, ConstrainedEnumValueModel } from '../../models/ConstrainedMetaModel';
-import { AnyModel, BooleanModel, FloatModel, IntegerModel, MetaModel, ObjectModel, ReferenceModel, StringModel, TupleModel, ArrayModel, UnionModel, EnumModel, DictionaryModel } from '../../models/MetaModel';
-import { defaultPropertyKeyConstraints, PropertyKeyConstraintType } from './constrainer/PropertyKeyConstrainer';
-import { defaultModelNameConstraints, ModelNameConstraintType } from './constrainer/ModelNameConstrainer';
-import { defaultEnumKeyConstraints, EnumConstraintType } from './constrainer/EnumConstrainer';
-import { Logger } from '../../utils';
+import { defaultPropertyKeyConstraints } from './constrainer/PropertyKeyConstrainer';
+import { defaultModelNameConstraints } from './constrainer/ModelNameConstrainer';
+import { defaultEnumKeyConstraints, defaultEnumValueConstraints } from './constrainer/EnumConstrainer';
+import { TypeMapping } from '../../helpers';
+import { JavaScriptRenderer } from './JavaScriptRenderer';
 
-export interface JavaScriptConstraints {
-  enumKey: EnumConstraintType,
-  modelName: ModelNameConstraintType,
-  propertyKey: PropertyKeyConstraintType,
-}
+export const JavaScriptDefaultTypeMapping: TypeMapping<JavaScriptRenderer> = {
+  Object (): string {
+    return ''; 
+  },
+  Reference (): string {
+    return ''; 
+  },
+  Any (): string {
+    return ''; 
+  },
+  Float (): string {
+    return ''; 
+  },
+  Integer (): string {
+    return ''; 
+  },
+  String (): string {
+    return ''; 
+  },
+  Boolean (): string {
+    return ''; 
+  },
+  Tuple (): string {
+    return ''; 
+  },
+  Array (): string {
+    return ''; 
+  },
+  Enum (): string {
+    return ''; 
+  },
+  Union (): string {
+    return ''; 
+  },
+  Dictionary (): string {
+    return '';
+  }
+};
 
-export const DefaultJavaScriptConstraints: JavaScriptConstraints = {
+export const JavaScriptDefaultConstraints = {
   enumKey: defaultEnumKeyConstraints(),
+  enumValue: defaultEnumValueConstraints(),
   modelName: defaultModelNameConstraints(),
   propertyKey: defaultPropertyKeyConstraints()
 };
-
-function constrainTupleModel(constrainedName: string, metaModel: TupleModel, constrainRules: JavaScriptConstraints): ConstrainedTupleModel {
-  const constrainedTupleModels = metaModel.tuple.map((tupleValue) => {
-    const tupleType = constrainMetaModel(tupleValue.value, constrainRules);
-    return new ConstrainedTupleValueModel(tupleValue.index, tupleType);
-  });
-  return new ConstrainedTupleModel(constrainedName, metaModel.originalInput, '', constrainedTupleModels);
-}
-function constrainArrayModel(constrainedName: string, metaModel: ArrayModel, constrainRules: JavaScriptConstraints): ConstrainedArrayModel {
-  const constrainedValueModel = constrainMetaModel(metaModel.valueModel, constrainRules);
-  return new ConstrainedArrayModel(constrainedName, metaModel.originalInput, '', constrainedValueModel);
-}
-function constrainUnionModel(constrainedName: string, metaModel: UnionModel, constrainRules: JavaScriptConstraints): ConstrainedUnionModel {
-  const constrainedUnionModels = metaModel.union.map((unionValue) => {
-    return constrainMetaModel(unionValue, constrainRules);
-  });
-  return new ConstrainedUnionModel(constrainedName, metaModel.originalInput, '', constrainedUnionModels);
-}
-function constrainDictionaryModel(constrainedName: string, metaModel: DictionaryModel, constrainRules: JavaScriptConstraints): ConstrainedDictionaryModel {
-  let keyModel;    
-  //There is some restrictions on what can be used as keys for dictionaries.
-  if (metaModel.key instanceof UnionModel) {
-    Logger.error('Key for dictionary is not allowed to be union type, falling back to any model.');
-    const anyModel = new AnyModel(metaModel.key.name, metaModel.key.originalInput);
-    keyModel = constrainMetaModel(anyModel, constrainRules);
-  } else {
-    keyModel = constrainMetaModel(metaModel.key, constrainRules);
-  }
-  const valueModel = constrainMetaModel(metaModel.value, constrainRules);
-  return new ConstrainedDictionaryModel(constrainedName, metaModel.originalInput, '', keyModel, valueModel, metaModel.serializationType);
-}
-
-function constrainObjectModel(constrainedName: string, objectModel: ObjectModel, constrainRules: JavaScriptConstraints): ConstrainedObjectModel {
-  const constrainedObjectModel = new ConstrainedObjectModel(constrainedName, objectModel.originalInput, '', {});
-  for (const [propertyKey, propertyMetaModel] of Object.entries(objectModel.properties)) {
-    const constrainedPropertyName = constrainRules.propertyKey({propertyKey, constrainedObjectModel, objectModel});
-    const constrainedProperty = constrainMetaModel(propertyMetaModel, constrainRules);
-    constrainedObjectModel.properties[String(constrainedPropertyName)] = constrainedProperty;
-  }
-  return constrainedObjectModel;
-}
-
-export function ConstrainEnumModel(constrainedName: string, enumModel: EnumModel, constrainRules: JavaScriptConstraints): ConstrainedEnumModel {
-  const constrainedModel = new ConstrainedEnumModel(constrainedName, enumModel.originalInput, '', []);
-
-  for (const enumValue of enumModel.values) {
-    const constrainedEnumKey = constrainRules.enumKey({enumKey: String(enumValue.key), enumModel, constrainedEnumModel: constrainedModel});
-    let normalizedEnumValue;
-    switch (typeof enumValue.value) {
-    case 'string':
-    case 'boolean':
-      normalizedEnumValue = `"${enumValue.value}"`;
-      break;
-    case 'bigint':
-    case 'number': {
-      normalizedEnumValue = enumValue.value;
-      break;
-    }
-    case 'object': {
-      normalizedEnumValue = `'${JSON.stringify(enumValue.value)}'`;
-      break;
-    }
-    default: {
-      normalizedEnumValue = String(enumValue.value);
-    }
-    }
-    const constrainedEnumValueModel = new ConstrainedEnumValueModel(constrainedEnumKey, normalizedEnumValue);
-    constrainedModel.values.push(constrainedEnumValueModel);
-  }
-  return constrainedModel;
-}
-
-export function constrainMetaModel(metaModel: MetaModel, constrainRules: JavaScriptConstraints): ConstrainedMetaModel {
-  const constrainedName = constrainRules.modelName({modelName: metaModel.name});
-  
-  if (metaModel instanceof ObjectModel) {
-    return constrainObjectModel(constrainedName, metaModel, constrainRules);
-  } else if (metaModel instanceof ReferenceModel) {
-    const constrainedRefModel = constrainMetaModel(metaModel.ref, constrainRules);
-    return new ConstrainedReferenceModel(constrainedName, metaModel.originalInput, '', constrainedRefModel);
-  } else if (metaModel instanceof AnyModel) {
-    return new ConstrainedAnyModel(constrainedName, metaModel.originalInput, '');
-  } else if (metaModel instanceof FloatModel) {
-    return new ConstrainedFloatModel(constrainedName, metaModel.originalInput, '');
-  } else if (metaModel instanceof IntegerModel) {
-    return new ConstrainedIntegerModel(constrainedName, metaModel.originalInput, '');
-  } else if (metaModel instanceof StringModel) {
-    return new ConstrainedStringModel(constrainedName, metaModel.originalInput, '');
-  } else if (metaModel instanceof BooleanModel) {
-    return new ConstrainedBooleanModel(constrainedName, metaModel.originalInput, '');
-  } else if (metaModel instanceof TupleModel) {
-    return constrainTupleModel(constrainedName, metaModel, constrainRules);
-  } else if (metaModel instanceof ArrayModel) {
-    return constrainArrayModel(constrainedName, metaModel, constrainRules);
-  } else if (metaModel instanceof UnionModel) {
-    return constrainUnionModel(constrainedName, metaModel, constrainRules);
-  } else if (metaModel instanceof EnumModel) {
-    return ConstrainEnumModel(constrainedName, metaModel, constrainRules);
-  } else if (metaModel instanceof DictionaryModel) {
-    return constrainDictionaryModel(constrainedName, metaModel, constrainRules);
-  }
-  throw new Error('Could not constrain model');
-}
diff --git a/src/generators/javascript/JavaScriptGenerator.ts b/src/generators/javascript/JavaScriptGenerator.ts
index 397e2149..3edf49e7 100644
--- a/src/generators/javascript/JavaScriptGenerator.ts
+++ b/src/generators/javascript/JavaScriptGenerator.ts
@@ -4,12 +4,16 @@ import {
   defaultGeneratorOptions
 } from '../AbstractGenerator';
 import { CommonModel, CommonInputModel, RenderOutput } from '../../models';
-import { TypeHelpers, ModelKind, CommonNamingConvention, CommonNamingConventionImplementation } from '../../helpers';
+import { TypeHelpers, ModelKind, CommonNamingConvention, CommonNamingConventionImplementation, TypeMapping, Constraints } from '../../helpers';
 import { JavaScriptPreset, JS_DEFAULT_PRESET } from './JavaScriptPreset';
 import { ClassRenderer } from './renderers/ClassRenderer';
 import { Logger } from '../../';
+import { JavaScriptRenderer } from './JavaScriptRenderer';
+import { JavaScriptDefaultConstraints, JavaScriptDefaultTypeMapping } from './JavaScriptConstrainer';
 export interface JavaScriptOptions extends CommonGeneratorOptions<JavaScriptPreset> {
-  namingConvention?: CommonNamingConvention
+  namingConvention?: CommonNamingConvention;
+  typeMapping: TypeMapping<JavaScriptRenderer>;
+  constraints: Constraints;
 }
 
 export interface JavaScriptRenderCompleteModelOptions {
@@ -23,13 +27,17 @@ export class JavaScriptGenerator extends AbstractGenerator<JavaScriptOptions, Ja
   static defaultOptions: JavaScriptOptions = {
     ...defaultGeneratorOptions,
     defaultPreset: JS_DEFAULT_PRESET,
-    namingConvention: CommonNamingConventionImplementation
+    namingConvention: CommonNamingConventionImplementation,
+    typeMapping: JavaScriptDefaultTypeMapping,
+    constraints: JavaScriptDefaultConstraints
   };
 
   constructor(
-    options: JavaScriptOptions = JavaScriptGenerator.defaultOptions,
+    options: Partial<JavaScriptOptions> = JavaScriptGenerator.defaultOptions,
   ) {
-    super('JavaScript', JavaScriptGenerator.defaultOptions, options);
+    const mergedOptions = {...JavaScriptGenerator.defaultOptions, ...options};
+
+    super('JavaScript', JavaScriptGenerator.defaultOptions, mergedOptions);
   }
   
   /**
diff --git a/src/generators/javascript/constrainer/EnumConstrainer.ts b/src/generators/javascript/constrainer/EnumConstrainer.ts
index 746c0b05..994eb914 100644
--- a/src/generators/javascript/constrainer/EnumConstrainer.ts
+++ b/src/generators/javascript/constrainer/EnumConstrainer.ts
@@ -1,7 +1,6 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedEnumModel, EnumModel } from '../../../models';
 import { NO_NUMBER_START_CHAR, NO_DUPLICATE_ENUM_KEYS, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { EnumKeyConstraint, EnumValueConstraint, FormatHelpers } from '../../../helpers';
 import { isReservedJavaScriptKeyword } from '../Constants';
 
 export type ModelEnumKeyConstraints = {
@@ -27,40 +26,42 @@ export const DefaultEnumKeyConstraints: ModelEnumKeyConstraints = {
   }
 };
 
-export type EnumKeyContext = {
-  enumKey: string,
-  constrainedEnumModel: ConstrainedEnumModel,
-  enumModel: EnumModel
+export function defaultEnumKeyConstraints(customConstraints?: Partial<ModelEnumKeyConstraints>): EnumKeyConstraint {
+  const constraints = {...DefaultEnumKeyConstraints, ...customConstraints};
+
+  return ({enumKey, enumModel, constrainedEnumModel}) => {
+    let constrainedEnumKey = enumKey;
+    constrainedEnumKey = constraints.NO_SPECIAL_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_EMPTY_VALUE(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS(constrainedEnumKey);
+    constrainedEnumKey = constraints.NAMING_FORMATTER(constrainedEnumKey);
+    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER);
+    return constrainedEnumKey;
+  };
 }
-export type EnumConstraintType = (context: EnumKeyContext, constraints?: ModelEnumKeyConstraints) => string;
 
-export function defaultEnumKeyConstraints(customConstraints?: ModelEnumKeyConstraints): EnumConstraintType {
-  const constraints = DefaultEnumKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
+export function defaultEnumValueConstraints(): EnumValueConstraint {
+  return ({enumValue}) => {
+    let normalizedEnumValue;
+    switch (typeof enumValue) {
+    case 'string':
+    case 'boolean':
+      normalizedEnumValue = `"${enumValue}"`;
+      break;
+    case 'bigint':
+    case 'number': {
+      normalizedEnumValue = `${enumValue}`;
+      break;
     }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
+    case 'object': {
+      normalizedEnumValue = `'${JSON.stringify(enumValue)}'`;
+      break;
     }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
+    default: {
+      normalizedEnumValue = String(enumValue);
     }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NO_RESERVED_KEYWORDS = customConstraints.NO_RESERVED_KEYWORDS;
     }
-    if (customConstraints.NO_DUPLICATE_KEYS !== undefined) {
-      constraints.NO_DUPLICATE_KEYS = customConstraints.NO_DUPLICATE_KEYS;
-    }
-  }
-  return ({enumKey, enumModel, constrainedEnumModel}) => {
-    let constrainedEnumKey = enumKey;
-    constrainedEnumKey = constraints.NO_SPECIAL_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_NUMBER_START_CHAR!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_EMPTY_VALUE!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_RESERVED_KEYWORDS!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NAMING_FORMATTER!(constrainedEnumKey);
-    constrainedEnumKey = constraints.NO_DUPLICATE_KEYS!(constrainedEnumModel, enumModel, constrainedEnumKey, constraints.NAMING_FORMATTER!);
-    return constrainedEnumKey;
+    return normalizedEnumValue;
   };
 }
diff --git a/src/generators/javascript/constrainer/ModelNameConstrainer.ts b/src/generators/javascript/constrainer/ModelNameConstrainer.ts
index d94fc7b4..5cc9c267 100644
--- a/src/generators/javascript/constrainer/ModelNameConstrainer.ts
+++ b/src/generators/javascript/constrainer/ModelNameConstrainer.ts
@@ -1,14 +1,13 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { NO_NUMBER_START_CHAR, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { FormatHelpers, ModelNameConstraint } from '../../../helpers';
 import { isReservedJavaScriptKeyword } from '../Constants';
 
 export type ModelNameConstraints = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
-  NO_RESERVED_KEYWORDS?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultModelNameConstraints: ModelNameConstraints = {
@@ -26,38 +25,16 @@ export const DefaultModelNameConstraints: ModelNameConstraints = {
     return NO_RESERVED_KEYWORDS(value, isReservedJavaScriptKeyword); 
   }
 };
-export type ModelNameContext = {
-  modelName: string
-}
-export type ModelNameConstraintType = (context: ModelNameContext) => string;
-
-export function defaultModelNameConstraints(customConstraints?: ModelNameConstraints): ModelNameConstraintType {
-  const constraints = DefaultModelNameConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-  }
+export function defaultModelNameConstraints(customConstraints?: Partial<ModelNameConstraints>): ModelNameConstraint {
+  const constraints = {...DefaultModelNameConstraints, ...customConstraints};
 
   return ({modelName}) => {
     let constrainedValue = modelName;
-    constrainedValue = constraints.NO_SPECIAL_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_NUMBER_START_CHAR!(constrainedValue);
-    constrainedValue = constraints.NO_EMPTY_VALUE!(constrainedValue);
-    constrainedValue = constraints.NAMING_FORMATTER!(constrainedValue);
-    constrainedValue = constraints.NO_RESERVED_KEYWORDS!(constrainedValue);
+    constrainedValue = constraints.NO_SPECIAL_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_NUMBER_START_CHAR(constrainedValue);
+    constrainedValue = constraints.NO_EMPTY_VALUE(constrainedValue);
+    constrainedValue = constraints.NO_RESERVED_KEYWORDS(constrainedValue);
+    constrainedValue = constraints.NAMING_FORMATTER(constrainedValue);
     return constrainedValue;
   };
 }
diff --git a/src/generators/javascript/constrainer/PropertyKeyConstrainer.ts b/src/generators/javascript/constrainer/PropertyKeyConstrainer.ts
index ef349d36..95640786 100644
--- a/src/generators/javascript/constrainer/PropertyKeyConstrainer.ts
+++ b/src/generators/javascript/constrainer/PropertyKeyConstrainer.ts
@@ -1,16 +1,15 @@
-/* eslint-disable @typescript-eslint/no-non-null-assertion */
 import { ConstrainedObjectModel, ObjectModel } from '../../../models';
 import { NO_NUMBER_START_CHAR, NO_DUPLICATE_PROPERTIES, NO_EMPTY_VALUE, NO_RESERVED_KEYWORDS} from '../../../helpers/Constraints';
-import { FormatHelpers } from '../../../helpers';
+import { FormatHelpers, PropertyKeyConstraint } from '../../../helpers';
 import { isReservedJavaScriptKeyword } from '../Constants';
 
 export type PropertyKeyConstraintOptions = {
-  NO_SPECIAL_CHAR?: (value: string) => string;
-  NO_NUMBER_START_CHAR?: (value: string) => string;
-  NO_DUPLICATE_PROPERTIES?: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
-  NO_EMPTY_VALUE?: (value: string) => string;
-  NAMING_FORMATTER?: (value: string) => string;
-  NO_RESERVED_KEYWORDS?: (value: string) => string;
+  NO_SPECIAL_CHAR: (value: string) => string;
+  NO_NUMBER_START_CHAR: (value: string) => string;
+  NO_DUPLICATE_PROPERTIES: (constrainedObjectModel: ConstrainedObjectModel, objectModel: ObjectModel, propertyName: string, namingFormatter: (value: string) => string) => string;
+  NO_EMPTY_VALUE: (value: string) => string;
+  NAMING_FORMATTER: (value: string) => string;
+  NO_RESERVED_KEYWORDS: (value: string) => string;
 };
 
 export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
@@ -28,45 +27,18 @@ export const DefaultPropertyKeyConstraints: PropertyKeyConstraintOptions = {
   }
 };
 
-export type PropertyKeyContext = {
-  propertyKey: string,
-  constrainedObjectModel: ConstrainedObjectModel,
-  objectModel: ObjectModel
-}
-
-export type PropertyKeyConstraintType = (context: PropertyKeyContext) => string;
+export function defaultPropertyKeyConstraints(customConstraints?: Partial<PropertyKeyConstraintOptions>): PropertyKeyConstraint {
+  const constraints = {...DefaultPropertyKeyConstraints, ...customConstraints};
 
-export function defaultPropertyKeyConstraints(customConstraints?: PropertyKeyConstraintOptions): PropertyKeyConstraintType {
-  const constraints = DefaultPropertyKeyConstraints;
-  if (customConstraints !== undefined) {
-    if (customConstraints.NAMING_FORMATTER !== undefined) {
-      constraints.NAMING_FORMATTER = customConstraints.NAMING_FORMATTER;
-    }
-    if (customConstraints.NO_SPECIAL_CHAR !== undefined) {
-      constraints.NO_SPECIAL_CHAR = customConstraints.NO_SPECIAL_CHAR;
-    }
-    if (customConstraints.NO_NUMBER_START_CHAR !== undefined) {
-      constraints.NO_NUMBER_START_CHAR = customConstraints.NO_NUMBER_START_CHAR;
-    }
-    if (customConstraints.NO_EMPTY_VALUE !== undefined) {
-      constraints.NO_EMPTY_VALUE = customConstraints.NO_EMPTY_VALUE;
-    }
-    if (customConstraints.NO_RESERVED_KEYWORDS !== undefined) {
-      constraints.NO_RESERVED_KEYWORDS = customConstraints.NO_RESERVED_KEYWORDS;
-    }
-    if (customConstraints.NO_DUPLICATE_PROPERTIES !== undefined) {
-      constraints.NO_DUPLICATE_PROPERTIES = customConstraints.NO_DUPLICATE_PROPERTIES;
-    }
-  }
-  return ({propertyKey, constrainedObjectModel, objectModel}: PropertyKeyContext) => {
+  return ({propertyKey, constrainedObjectModel, objectModel}) => {
     let constrainedPropertyKey = propertyKey;
 
-    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_EMPTY_VALUE!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NAMING_FORMATTER!(constrainedPropertyKey);
-    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES!(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER!);
+    constrainedPropertyKey = constraints.NO_SPECIAL_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_NUMBER_START_CHAR(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_EMPTY_VALUE(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_RESERVED_KEYWORDS(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NAMING_FORMATTER(constrainedPropertyKey);
+    constrainedPropertyKey = constraints.NO_DUPLICATE_PROPERTIES(constrainedObjectModel, objectModel, constrainedPropertyKey, constraints.NAMING_FORMATTER);
     return constrainedPropertyKey;
   };
 }


Test patch:
diff --git a/test/TestUtils/TestRenderers.ts b/test/TestUtils/TestRenderers.ts
index 358e85e3..1a3e4d32 100644
--- a/test/TestUtils/TestRenderers.ts
+++ b/test/TestUtils/TestRenderers.ts
@@ -2,6 +2,7 @@ import { AbstractRenderer, CommonInputModel, CommonModel, RenderOutput } from '.
 import { GoRenderer } from '../../src/generators/go/GoRenderer';
 import { CSharpRenderer } from '../../src/generators/csharp/CSharpRenderer';
 import { JavaRenderer } from '../../src/generators/java/JavaRenderer';
+import { JavaScriptRenderer } from '../../src/generators/javascript/JavaScriptRenderer';
 import { TypeScriptRenderer } from '../../src/generators/typescript/TypeScriptRenderer';
 import {testOptions, TestGenerator} from './TestGenerator';
 
@@ -18,4 +19,4 @@ export class MockJavaRenderer extends JavaRenderer {}
 export class MockTypeScriptRenderer extends TypeScriptRenderer {}
 export class MockGoRenderer extends GoRenderer {}
 export class MockCSharpRenderer extends CSharpRenderer {}
-
+export class MockJavaScriptRenderer extends JavaScriptRenderer {}
diff --git a/test/generators/javascript/JavaScriptConstrainer.spec.ts b/test/generators/javascript/JavaScriptConstrainer.spec.ts
new file mode 100644
index 00000000..b13585ca
--- /dev/null
+++ b/test/generators/javascript/JavaScriptConstrainer.spec.ts
@@ -0,0 +1,103 @@
+import {JavaScriptDefaultTypeMapping } from '../../../src/generators/javascript/JavaScriptConstrainer';
+import {MockJavaScriptRenderer} from '../../TestUtils/TestRenderers';
+import { JavaScriptRenderer } from '../../../src/generators/javascript/JavaScriptRenderer';
+import { CommonInputModel, CommonModel, ConstrainedAnyModel, ConstrainedArrayModel, ConstrainedBooleanModel, ConstrainedDictionaryModel, ConstrainedEnumModel, ConstrainedFloatModel, ConstrainedIntegerModel, ConstrainedObjectModel, ConstrainedReferenceModel, ConstrainedStringModel, ConstrainedTupleModel, ConstrainedUnionModel, JavaScriptGenerator } from '../../../src';
+describe('JavaScriptConstrainer', () => {
+  let renderer: JavaScriptRenderer;
+  beforeEach(() => {
+    renderer = new MockJavaScriptRenderer(JavaScriptGenerator.defaultOptions, new JavaScriptGenerator(), [], new CommonModel(), new CommonInputModel());
+  });
+  describe('ObjectModel', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedObjectModel('test', undefined, '', {});
+      const type = JavaScriptDefaultTypeMapping.Object({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('Reference', () => { 
+    test('should have no type', () => {
+      const refModel = new ConstrainedAnyModel('test', undefined, '');
+      const model = new ConstrainedReferenceModel('test', undefined, '', refModel);
+      const type = JavaScriptDefaultTypeMapping.Reference({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('Any', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedAnyModel('test', undefined, '');
+      const type = JavaScriptDefaultTypeMapping.Any({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('Float', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedFloatModel('test', undefined, '');
+      const type = JavaScriptDefaultTypeMapping.Float({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('Integer', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedIntegerModel('test', undefined, '');
+      const type = JavaScriptDefaultTypeMapping.Integer({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('String', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedStringModel('test', undefined, '');
+      const type = JavaScriptDefaultTypeMapping.String({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+  describe('Boolean', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedBooleanModel('test', undefined, '');
+      const type = JavaScriptDefaultTypeMapping.Boolean({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+
+  describe('Tuple', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedTupleModel('test', undefined, '', []);
+      const type = JavaScriptDefaultTypeMapping.Tuple({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+
+  describe('Array', () => { 
+    test('should have no type', () => {
+      const arrayModel = new ConstrainedStringModel('test', undefined, 'String');
+      const model = new ConstrainedArrayModel('test', undefined, '', arrayModel);
+      const type = JavaScriptDefaultTypeMapping.Array({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+
+  describe('Enum', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedEnumModel('test', undefined, '', []);
+      const type = JavaScriptDefaultTypeMapping.Enum({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+
+  describe('Union', () => { 
+    test('should have no type', () => {
+      const model = new ConstrainedUnionModel('test', undefined, '', []);
+      const type = JavaScriptDefaultTypeMapping.Union({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+
+  describe('Dictionary', () => { 
+    test('should have no type', () => {
+      const keyModel = new ConstrainedStringModel('test', undefined, 'String');
+      const valueModel = new ConstrainedStringModel('test', undefined, 'String');
+      const model = new ConstrainedDictionaryModel('test', undefined, '', keyModel, valueModel);
+      const type = JavaScriptDefaultTypeMapping.Dictionary({constrainedModel: model, renderer});
+      expect(type).toEqual('');
+    });
+  });
+});
diff --git a/test/generators/javascript/constrainer/EnumConstrainer.spec.ts b/test/generators/javascript/constrainer/EnumConstrainer.spec.ts
new file mode 100644
index 00000000..c9fa4a33
--- /dev/null
+++ b/test/generators/javascript/constrainer/EnumConstrainer.spec.ts
@@ -0,0 +1,94 @@
+import { JavaScriptDefaultConstraints } from '../../../../src/generators/javascript/JavaScriptConstrainer';
+import {EnumModel} from '../../../../src/models/MetaModel';
+import { ConstrainedEnumModel, ConstrainedEnumValueModel } from '../../../../src';
+import { defaultEnumKeyConstraints, ModelEnumKeyConstraints, DefaultEnumKeyConstraints } from '../../../../src/generators/javascript/constrainer/EnumConstrainer';
+describe('EnumConstrainer', () => {
+  const enumModel = new EnumModel('test', undefined, []);
+  const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', []);
+
+  describe('enum keys', () => {
+    test('should never render special chars', () => {
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '%'});
+      expect(constrainedKey).toEqual('PERCENT');
+    });
+    test('should not render number as start char', () => {
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: '1'});
+      expect(constrainedKey).toEqual('NUMBER_1');
+    });
+    test('should not contain duplicate keys', () => {
+      const existingConstrainedEnumValueModel = new ConstrainedEnumValueModel('TEST', 'test');
+      const constrainedEnumModel = new ConstrainedEnumModel('test', undefined, '', [existingConstrainedEnumValueModel]);
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'TEST'});
+      expect(constrainedKey).toEqual('RESERVED_TEST');
+    });
+    test('should never contain empty keys', () => {
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedKey).toEqual('EMPTY');
+    });
+    test('should use constant naming format', () => {
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'some weird_value!"#2'});
+      expect(constrainedKey).toEqual('SOME_SPACE_WEIRD_VALUE_EXCLAMATION_QUOTATION_HASH_2');
+    });
+    test('should never render reserved keywords', () => {
+      const constrainedKey = JavaScriptDefaultConstraints.enumKey({enumModel, constrainedEnumModel, enumKey: 'return'});
+      expect(constrainedKey).toEqual('RESERVED_RETURN');
+    });
+  });
+  describe('enum values', () => {
+    test('should render string values', () => {
+      const constrainedValue = JavaScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 'string value'});
+      expect(constrainedValue).toEqual('"string value"');
+    });
+    test('should render boolean values', () => {
+      const constrainedValue = JavaScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: true});
+      expect(constrainedValue).toEqual('"true"');
+    });
+    test('should render numbers', () => {
+      const constrainedValue = JavaScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: 123});
+      expect(constrainedValue).toEqual('123');
+    });
+    test('should render object', () => {
+      const constrainedValue = JavaScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: {test: 'test'}});
+      expect(constrainedValue).toEqual('\'{"test":"test"}\'');
+    });
+    test('should render unknown value', () => {
+      const constrainedValue = JavaScriptDefaultConstraints.enumValue({enumModel, constrainedEnumModel, enumValue: undefined});
+      expect(constrainedValue).toEqual('undefined');
+    });
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks for enum key', () => {
+      const mockedConstraintCallbacks: ModelEnumKeyConstraints = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_DUPLICATE_KEYS: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultEnumKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks for enum key', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_DUPLICATE_KEYS'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultEnumKeyConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultEnumKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({enumModel, constrainedEnumModel, enumKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/javascript/constrainer/ModelNameConstrainer.spec.ts b/test/generators/javascript/constrainer/ModelNameConstrainer.spec.ts
new file mode 100644
index 00000000..2e805a03
--- /dev/null
+++ b/test/generators/javascript/constrainer/ModelNameConstrainer.spec.ts
@@ -0,0 +1,57 @@
+import { JavaScriptDefaultConstraints } from '../../../../src/generators/javascript/JavaScriptConstrainer';
+import { DefaultModelNameConstraints, defaultModelNameConstraints, ModelNameConstraints } from '../../../../src/generators/javascript/constrainer/ModelNameConstrainer';
+describe('ModelNameConstrainer', () => {
+  test('should never render special chars', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.modelName({modelName: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should never render number as start char', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.modelName({modelName: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.modelName({modelName: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.modelName({modelName: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.modelName({modelName: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: ModelNameConstraints = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultModelNameConstraints(mockedConstraintCallbacks);
+      constrainFunction({modelName: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultModelNameConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultModelNameConstraints, 'NO_RESERVED_KEYWORDS')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultModelNameConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({modelName: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});
diff --git a/test/generators/javascript/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/javascript/constrainer/PropertyKeyConstrainer.spec.ts
new file mode 100644
index 00000000..5f0bfc62
--- /dev/null
+++ b/test/generators/javascript/constrainer/PropertyKeyConstrainer.spec.ts
@@ -0,0 +1,70 @@
+import { JavaScriptDefaultConstraints } from '../../../../src/generators/javascript/JavaScriptConstrainer';
+import { ConstrainedObjectModel, ObjectModel } from '../../../../src';
+import { DefaultPropertyKeyConstraints, defaultPropertyKeyConstraints, PropertyKeyConstraintOptions } from '../../../../src/generators/javascript/constrainer/PropertyKeyConstrainer';
+describe('PropertyKeyConstrainer', () => {
+  const objectModel = new ObjectModel('test', undefined, {});
+  const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {});
+
+  test('should never render special chars', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '%'});
+    expect(constrainedKey).toEqual('Percent');
+  });
+  test('should not render number as start char', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: '1'});
+    expect(constrainedKey).toEqual('Number_1');
+  });
+  test('should never contain empty name', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: ''});
+    expect(constrainedKey).toEqual('Empty');
+  });
+  test('should use constant naming format', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'some weird_value!"#2'});
+    expect(constrainedKey).toEqual('SomeWeirdValueExclamationQuotationHash_2');
+  });
+  test('should not contain duplicate properties', () => {
+    const objectModel = new ObjectModel('test', undefined, {});
+    const propertyModel = new ConstrainedObjectModel('SomeProperty', undefined, '', {});
+    const constrainedObjectModel = new ConstrainedObjectModel('test', undefined, '', {SomeProperty: propertyModel});
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'SomeProperty'});
+    expect(constrainedKey).toEqual('ReservedSomeProperty');
+  });
+  test('should never render reserved keywords', () => {
+    const constrainedKey = JavaScriptDefaultConstraints.propertyKey({constrainedObjectModel, objectModel, propertyKey: 'return'});
+    expect(constrainedKey).toEqual('ReservedReturn');
+  });
+  describe('custom constraints', () => {
+    test('should be able to overwrite all hooks', () => {
+      const mockedConstraintCallbacks: PropertyKeyConstraintOptions = {
+        NAMING_FORMATTER: jest.fn().mockReturnValue(''),
+        NO_SPECIAL_CHAR: jest.fn().mockReturnValue(''),
+        NO_NUMBER_START_CHAR: jest.fn().mockReturnValue(''),
+        NO_EMPTY_VALUE: jest.fn().mockReturnValue(''),
+        NO_RESERVED_KEYWORDS: jest.fn().mockReturnValue(''),
+        NO_DUPLICATE_PROPERTIES: jest.fn().mockReturnValue('')
+      };
+      const constrainFunction = defaultPropertyKeyConstraints(mockedConstraintCallbacks);
+      constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      //Expect all callbacks to be called
+      for (const jestMockCallback of Object.values(mockedConstraintCallbacks)) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+    test('should be able to overwrite one hooks', () => {
+      //All but NAMING_FORMATTER, as we customize that
+      const spies = [
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_SPECIAL_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_NUMBER_START_CHAR'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_EMPTY_VALUE'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_RESERVED_KEYWORDS'),
+        jest.spyOn(DefaultPropertyKeyConstraints, 'NO_DUPLICATE_PROPERTIES')
+      ];
+      const jestCallback = jest.fn().mockReturnValue('');
+      const constrainFunction = defaultPropertyKeyConstraints({NAMING_FORMATTER: jestCallback});
+      const constrainedValue = constrainFunction({constrainedObjectModel, objectModel, propertyKey: ''});
+      expect(constrainedValue).toEqual('');
+      for (const jestMockCallback of spies) {
+        expect(jestMockCallback).toHaveBeenCalled();
+      }
+    });
+  });
+});