Repository: asyncapi/modelina (ts)

Issue:
TypeScript: attribute mapping in generated interface is incorrect
#### Describe the bug
I have attributes in my AsyncApi file that are of the format:
`aa_00_fooBar`

After using `TypeScriptGenerator` to generate the interfaces, the outputs in the generated interface are of the format:
`aa_00FooBar`

As visible, the second `_` is missing, with the following string title-cased instead of camel-cased. 

#### How to Reproduce

Version `1.9.0`

##### Code to generate a typescript file with the generated interfaces:

```
import { TypeScriptGenerator } from "@asyncapi/modelina";
import { createWriteStream, readFileSync, unlinkSync } from "fs";

const OUTPUT_FILE = "output.ts";

const generator = new TypeScriptGenerator({ modelType: "interface" });
const contractJsonString = readFileSync("contract.json", { encoding: "utf-8" });
const contract = JSON.parse(contractJsonString);

export async function generate(): Promise<void> {
  const models = await generator.generate(contract);
  unlinkSync(OUTPUT_FILE);
  var stream = createWriteStream(OUTPUT_FILE, { flags: "a" });
  for (const model of models) {
    stream.write(model.result + "\n");
  }
  stream.end();
}

if (require.main === module) {
  generate();
}
```

##### contract.json
```
{
  "asyncapi": "2.6.0",
  "info": {
    "title": "Test",
    "version": "0.0.1"
  },
  "channels": {
    "test/test": {
      "publish": {
        "message": {
          "$ref": "#/components/messages/test"
        }
      }
    }
  },
  "components": {
    "messages": {
      "test": {
        "payload": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "aa_00_testAttribute": {
              "type": "string"
            },
            "aa_01_testAttribute": {
              "type": "string"
            },
            "aa_02_testAttribute": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}
```

##### output.ts
```
interface AnonymousSchema_1 {
  aa_00TestAttribute?: string;
  aa_01TestAttribute?: string;
  aa_02TestAttribute?: string;
}
```

#### Expected behavior
Attributes in `AnonymousSchema_1` should be as such:
```
interface AnonymousSchema_1 {
  aa_00_testAttribute?: string;
  aa_01_testAttribute?: string;
  aa_02_testAttribute?: string;
}
```

Pull request description:
fix!: handle edge case in toCamelCase FormatHelper
## Description
The `toCamelCase` helper produced wrong outputs in some edge cases, where there was a numeric followed by "_" and a lowercase letter. This PR aims to fix that.

## Related Issue
Fixes #1503 

## Checklist
- [x] The code follows the project's coding standards and is properly linted (`npm run lint`).
- [x] Tests have been added or updated to cover the changes.
- [ ] Documentation has been updated to reflect the changes.
- [ ] All tests pass successfully locally.(`npm run test`).


Patch:
diff --git a/docs/migrations/version-3-to-4.md b/docs/migrations/version-3-to-4.md
new file mode 100644
index 00000000..8bdafbb2
--- /dev/null
+++ b/docs/migrations/version-3-to-4.md
@@ -0,0 +1,31 @@
+# Migration from v3 to v4
+This document contain all the breaking changes and migrations guidelines for adapting your code to the new version.
+
+## Fixed edge cases for camel case names
+
+Naming such as object properties using camel case formatting had an edge case where if they contained a number followed by an underscore and a letter it would be incorrectly formatted. This has been fixed in this version, which might mean properties, model names, etc that use camel case might be renamed. 
+
+This example contains such a string:
+
+```yaml
+type: object
+properties:
+  aa_00_testAttribute:
+    type: string
+```
+
+This used to generate:
+
+```ts
+interface AnonymousSchema_1 {
+  aa_00TestAttribute?: string;
+}
+```
+
+but will now generate:
+
+```ts
+interface AnonymousSchema_1 {
+  aa_00_testAttribute?: string;
+}
+```
\ No newline at end of file
diff --git a/src/helpers/FormatHelpers.ts b/src/helpers/FormatHelpers.ts
index d073df62..5c350450 100644
--- a/src/helpers/FormatHelpers.ts
+++ b/src/helpers/FormatHelpers.ts
@@ -77,7 +77,20 @@ export class FormatHelpers {
    * @param {string} value to transform
    * @returns {string}
    */
-  static toCamelCase = camelCase;
+  static toCamelCase(renderName: string): string {
+    const splt = renderName.split(/([0-9]_)/g);
+    if (splt.length > 1) {
+      return splt
+        .map((part) => {
+          if (part.match(/[0-9]_/g)) {
+            return part;
+          }
+          return camelCase(part);
+        })
+        .join('');
+    }
+    return camelCase(renderName);
+  }
 
   /**
    * Transform into a string of capitalized words without separators.


Test patch:
diff --git a/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
index e893e40a..62289460 100644
--- a/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
+++ b/test/generators/typescript/constrainer/PropertyKeyConstrainer.spec.ts
@@ -58,6 +58,10 @@ describe('PropertyKeyConstrainer', () => {
     const constrainedKey = constrainPropertyName('some weird_value!"#2');
     expect(constrainedKey).toEqual('someWeirdValueExclamationQuotationHash_2');
   });
+  test('should correctly handle casing with numbers', () => {
+    const constrainedKey = constrainPropertyName('aa_00_testAttribute');
+    expect(constrainedKey).toEqual('aa_00_testAttribute');
+  });
   test('should not contain duplicate properties', () => {
     const objectModel = new ObjectModel('test', undefined, {}, {});
     const constrainedObjectModel = new ConstrainedObjectModel(