From e7fdf4637ee663d07e20b6802b5f287e5c4002f1 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 15 Dec 2021 19:43:36 +0100 Subject: [PATCH 01/82] docs: add quadrrem as a contributor for code, test --- .all-contributorsrc | 12 +++++++++++- README.md | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index ec4a3a2595..e55b618f8f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -173,6 +173,16 @@ "contributions": [ "bug" ] + }, + { + "login": "quadrrem", + "name": "quadrrem", + "avatar_url": "https://avatars.githubusercontent.com/u/8450873?v=4", + "profile": "https://github.com/quadrrem", + "contributions": [ + "code", + "test" + ] } ], "contributorsPerLine": 7, @@ -180,6 +190,6 @@ "projectOwner": "asyncapi", "repoType": "github", "repoHost": "https://github.com", - "skipCi": true, + "skipCi": false, "commitConvention": "none" } diff --git a/README.md b/README.md index 9f2cba2695..926b900d91 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-15-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors-) --- @@ -153,6 +153,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Marco

πŸ› +
quadrrem

πŸ’» ⚠️ From 593a6e83740827444d7e72746a8feec8a82f3a78 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 16 Dec 2021 15:01:27 +0100 Subject: [PATCH 02/82] ci: update global workflows --- ...e-for-humans-add-ready-to-merge-or-do-not-merge-label.yml | 5 ++++- .github/workflows/help-command.yml | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml index a606fed3a5..68f3960312 100644 --- a/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml +++ b/.github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml @@ -4,7 +4,10 @@ #Purpose of this workflow is to enable anyone to label PR with `ready-to-merge` and `do-not-merge` labels to get stuff merged or blocked from merging name: Add ready-to-merge or do-not-merge label # if proper comment added -on: issue_comment +on: + issue_comment: + types: + - created jobs: parse-comment-and-add-ready: # for handling cases when you want to mark as ready to merge diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 2544f07388..0fac866f4a 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -3,7 +3,10 @@ name: Create help comment -on: [issue_comment] +on: + issue_comment: + types: + - created jobs: create_help_comment: From cf8c9223fb40eb8cf9a940154de62bc453c56355 Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Mon, 3 Jan 2022 18:04:21 +0530 Subject: [PATCH 03/82] docs: generate java data models --- docs/usage.md | 2 +- examples/README.md | 1 + examples/generate-java-models/README.md | 17 ++++++++++++++ .../__snapshots__/index.spec.ts.snap | 12 ++++++++++ examples/generate-java-models/index.spec.ts | 13 +++++++++++ examples/generate-java-models/index.ts | 22 +++++++++++++++++++ .../generate-java-models/package-lock.json | 10 +++++++++ examples/generate-java-models/package.json | 12 ++++++++++ 8 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 examples/generate-java-models/README.md create mode 100644 examples/generate-java-models/__snapshots__/index.spec.ts.snap create mode 100644 examples/generate-java-models/index.spec.ts create mode 100644 examples/generate-java-models/index.ts create mode 100644 examples/generate-java-models/package-lock.json create mode 100644 examples/generate-java-models/package.json diff --git a/docs/usage.md b/docs/usage.md index a668ee006a..bd388919e2 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -66,7 +66,7 @@ TODO TODO ## Generate Java models -TODO +Java is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-java-models) ## Generate TypeScript models TypeScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-typescript-models) and the following [TypeScript documentation for more advanced use-cases](./languages/TypeScript.md). diff --git a/examples/README.md b/examples/README.md index 95965a711a..a366461ef5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,3 +20,4 @@ This directory contains a series of self-contained examples that you can use as - [java-generate-tostring](./java-generate-tostring) - A basic example that shows how to generate models that overwrite the `toString` method - [csharp-generate-equals-and-hashcode](./csharp-generate-equals-and-hashcode) - A basic example on how to generate models that overwrite the `Equal` and `GetHashCode` methods - [generate-javascript-models](./generate-javascript-models) - A basic example to generate JavaScript data models +- [generate-java-models](./generate-java-models) - A basic example to generate Java data models \ No newline at end of file diff --git a/examples/generate-java-models/README.md b/examples/generate-java-models/README.md new file mode 100644 index 0000000000..2d318fc8b4 --- /dev/null +++ b/examples/generate-java-models/README.md @@ -0,0 +1,17 @@ +# Java Data Models + +A basic example of how to use Modelina and output a Java data model. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/generate-java-models/__snapshots__/index.spec.ts.snap b/examples/generate-java-models/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..4ddb7e1482 --- /dev/null +++ b/examples/generate-java-models/__snapshots__/index.spec.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render Java Models and should log expected output to console 1`] = ` +Array [ + "public class Root { + private Object email; + + public Object getEmail() { return this.email; } + public void setEmail(Object email) { this.email = email; } +}", +] +`; diff --git a/examples/generate-java-models/index.spec.ts b/examples/generate-java-models/index.spec.ts new file mode 100644 index 0000000000..3784c9d664 --- /dev/null +++ b/examples/generate-java-models/index.spec.ts @@ -0,0 +1,13 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render Java Models', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/generate-java-models/index.ts b/examples/generate-java-models/index.ts new file mode 100644 index 0000000000..7909d85845 --- /dev/null +++ b/examples/generate-java-models/index.ts @@ -0,0 +1,22 @@ +import { JavaGenerator } from '../../src'; + +const generator = new JavaGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/generate-java-models/package-lock.json b/examples/generate-java-models/package-lock.json new file mode 100644 index 0000000000..14da986af3 --- /dev/null +++ b/examples/generate-java-models/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "generate-java-models", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/generate-java-models/package.json b/examples/generate-java-models/package.json new file mode 100644 index 0000000000..731a855249 --- /dev/null +++ b/examples/generate-java-models/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "generate-java-models" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From d659d80f658ee6ac346e5d0acc4ebf31356632ae Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 3 Jan 2022 14:00:58 +0100 Subject: [PATCH 04/82] fix: model dependencies are not accurately resolved --- src/models/CommonModel.ts | 32 ++++++++++++++++---------------- test/models/CommonModel.spec.ts | 5 +++++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/models/CommonModel.ts b/src/models/CommonModel.ts index bcd95e8462..f3c0ac39df 100644 --- a/src/models/CommonModel.ts +++ b/src/models/CommonModel.ts @@ -321,8 +321,13 @@ export class CommonModel { // eslint-disable-next-line sonarjs/cognitive-complexity getNearestDependencies(): string[] { const dependsOn = []; - if (this.additionalProperties?.$ref !== undefined) { - dependsOn.push(this.additionalProperties.$ref); + + if (this.$ref !== undefined) { + return [this.$ref]; + } + + if (this.additionalProperties !== undefined) { + dependsOn.push(...this.additionalProperties.getNearestDependencies()); } if (this.extend !== undefined) { dependsOn.push(...this.extend); @@ -330,26 +335,21 @@ export class CommonModel { if (this.items !== undefined) { const items = Array.isArray(this.items) ? this.items : [this.items]; for (const item of items) { - const itemRef = item.$ref; - if (itemRef !== undefined) { - dependsOn.push(itemRef); - } + dependsOn.push(...item.getNearestDependencies()); } } if (this.properties !== undefined && Object.keys(this.properties).length) { - const referencedProperties = Object.values(this.properties) - .filter((propertyModel: CommonModel) => propertyModel.$ref !== undefined) - .map((propertyModel: CommonModel) => String(propertyModel.$ref)); - dependsOn.push(...referencedProperties); + for (const property of Object.values(this.properties)) { + dependsOn.push(...property.getNearestDependencies()); + } } if (this.patternProperties !== undefined && Object.keys(this.patternProperties).length) { - const referencedPatternProperties = Object.values(this.patternProperties) - .filter((patternPropertyModel: CommonModel) => patternPropertyModel.$ref !== undefined) - .map((patternPropertyModel: CommonModel) => String(patternPropertyModel.$ref)); - dependsOn.push(...referencedPatternProperties); + for (const patternProperty of Object.values(this.patternProperties)) { + dependsOn.push(...patternProperty.getNearestDependencies()); + } } - if (this.additionalItems?.$ref !== undefined) { - dependsOn.push(this.additionalItems.$ref); + if (this.additionalItems !== undefined) { + dependsOn.push(...this.additionalItems.getNearestDependencies()); } return dependsOn; } diff --git a/test/models/CommonModel.spec.ts b/test/models/CommonModel.spec.ts index 19d1385cb1..9a8db8785f 100644 --- a/test/models/CommonModel.spec.ts +++ b/test/models/CommonModel.spec.ts @@ -897,6 +897,11 @@ describe('CommonModel', () => { const doc = { additionalProperties: { $ref: '1' }, extend: ['2'], items: { $ref: '3' }, properties: { testProp: { $ref: '4' } }, patternProperties: {testPattern: {$ref: '5'}}, additionalItems: { $ref: '6' } }; const d = CommonModel.toCommonModel(doc); expect(d.getNearestDependencies()).toEqual(['1', '2', '3', '4', '5', '6']); + }); + test('should work with nested items', () => { + const doc = {properties: { testProp: { items: { $ref: '1' } } }, patternProperties: { testPattern: { items: { $ref: '2' } } } }; + const d = CommonModel.toCommonModel(doc); + expect(d.getNearestDependencies()).toEqual(['1', '2']); }); test('check that no dependencies is returned if there are none', () => { const doc = { }; From 7b6010e5f398e4ce8ea1eee1b4e68cef7210824b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Jane=C4=8Dek?= Date: Mon, 3 Jan 2022 14:33:20 +0100 Subject: [PATCH 05/82] fix: wrong property name in JavaCommonPresetOptions interface (#544) --- src/generators/java/presets/CommonPreset.ts | 2 +- .../java/presets/CommonPreset.spec.ts | 23 +++++++++++++- .../__snapshots__/CommonPreset.spec.ts.snap | 30 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/generators/java/presets/CommonPreset.ts b/src/generators/java/presets/CommonPreset.ts index cca414498f..7955989247 100644 --- a/src/generators/java/presets/CommonPreset.ts +++ b/src/generators/java/presets/CommonPreset.ts @@ -6,7 +6,7 @@ import { CommonModel } from '../../../models'; export interface JavaCommonPresetOptions { equal: boolean; - hash: boolean; + hashCode: boolean; classToString: boolean; } diff --git a/test/generators/java/presets/CommonPreset.spec.ts b/test/generators/java/presets/CommonPreset.spec.ts index a27bda35cc..62529a4902 100644 --- a/test/generators/java/presets/CommonPreset.spec.ts +++ b/test/generators/java/presets/CommonPreset.spec.ts @@ -1,4 +1,4 @@ -import { JavaGenerator, JAVA_COMMON_PRESET } from '../../../../src/generators'; +import {JavaGenerator, JAVA_COMMON_PRESET, JavaCommonPresetOptions} from '../../../../src/generators'; describe('JAVA_COMMON_PRESET', () => { const doc = { @@ -50,6 +50,27 @@ describe('JAVA_COMMON_PRESET', () => { expect(classModel.result).toMatchSnapshot(); expect(classModel.dependencies.includes('import java.util.Objects;')).toEqual(true); }); + test('should not render any functions when all 3 options are disabled', async () => { + const options: JavaCommonPresetOptions = { + equal: false, + hashCode: false, + classToString: false, + }; + + const generator = new JavaGenerator( + { + presets: [{ + preset: JAVA_COMMON_PRESET, + options + }] + } + ); + const inputModel = await generator.process(doc); + const model = inputModel.models['Clazz']; + + const classModel = await generator.renderClass(model, inputModel); + expect(classModel.result).toMatchSnapshot(); + }); test('should render equals', async () => { const generator = new JavaGenerator( { diff --git a/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap index 345da494e3..5a057d129c 100644 --- a/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap +++ b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap @@ -219,6 +219,36 @@ exports[`JAVA_COMMON_PRESET with option should render all functions 1`] = ` }" `; + +exports[`JAVA_COMMON_PRESET with option should not render any functions when all 3 options are disabled 1`] = ` +"public class Clazz { + private Boolean requiredProp; + private String stringProp; + private Double numberProp; + private Boolean booleanProp; + private String[] arrayProp; + private Map additionalProperties; + + public Boolean getRequiredProp() { return this.requiredProp; } + public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; } + + public String getStringProp() { return this.stringProp; } + public void setStringProp(String stringProp) { this.stringProp = stringProp; } + + public Double getNumberProp() { return this.numberProp; } + public void setNumberProp(Double numberProp) { this.numberProp = numberProp; } + + public Boolean getBooleanProp() { return this.booleanProp; } + public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; } + + public String[] getArrayProp() { return this.arrayProp; } + public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; } + + public Map getAdditionalProperties() { return this.additionalProperties; } + public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } +}" +`; + exports[`JAVA_COMMON_PRESET with option should render classToString 1`] = ` "public class Clazz { private Boolean requiredProp; From 3d1208af928f0d907203579e76f56c5172d2a7c8 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 3 Jan 2022 14:48:07 +0100 Subject: [PATCH 06/82] chore(release): v0.39.10 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cfe50201ec..7ee1f36a39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.39.8", + "version": "0.39.10", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.39.8", + "version": "0.39.10", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index f024dff21c..a93a56456b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.39.8", + "version": "0.39.10", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From b4770ea0ae4a9d255e343b0e7f1008beeec57f2f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 15:15:45 +0100 Subject: [PATCH 07/82] docs: add mahakporwal02 as a contributor for example, test, doc (#549) --- .all-contributorsrc | 11 +++++++++++ README.md | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index e55b618f8f..5f324604e5 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -183,6 +183,17 @@ "code", "test" ] + }, + { + "login": "mahakporwal02", + "name": "mahakporwal02", + "avatar_url": "https://avatars.githubusercontent.com/u/56486682?v=4", + "profile": "https://github.com/mahakporwal02", + "contributions": [ + "example", + "test", + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 926b900d91..c6a05f180c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors-) --- @@ -154,6 +154,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Marco

πŸ›
quadrrem

πŸ’» ⚠️ +
mahakporwal02

πŸ’‘ ⚠️ πŸ“– From b85e11e8ba01c995b59888170e824a4ffb7e5bf5 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 3 Jan 2022 15:44:53 +0100 Subject: [PATCH 08/82] docs: add kamko as a contributor for test, bug, code (#552) --- .all-contributorsrc | 11 +++++++++++ README.md | 3 ++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 5f324604e5..efdb4c695e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -184,6 +184,17 @@ "test" ] }, + { + "login": "kamko", + "name": "Kamil Janeček", + "avatar_url": "https://avatars.githubusercontent.com/u/17074375?v=4", + "profile": "https://kamko.dev", + "contributions": [ + "test", + "bug", + "code" + ] + }, { "login": "mahakporwal02", "name": "mahakporwal02", diff --git a/README.md b/README.md index c6a05f180c..3fff1eadc1 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-17-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-) --- @@ -154,6 +154,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Marco

πŸ›
quadrrem

πŸ’» ⚠️ +
Kamil Janeček

⚠️ πŸ› πŸ’»
mahakporwal02

πŸ’‘ ⚠️ πŸ“– From 2b48a05732d2222ac97b766a23f983372d7f8ead Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 3 Jan 2022 15:58:16 +0100 Subject: [PATCH 09/82] docs: add OpenAPI input as example --- README.md | 8 +-- docs/usage.md | 14 ++++- examples/openapi-from-object/README.md | 17 +++++ .../__snapshots__/index.spec.ts.snap | 35 +++++++++++ examples/openapi-from-object/index.spec.ts | 14 +++++ examples/openapi-from-object/index.ts | 62 +++++++++++++++++++ .../openapi-from-object/package-lock.json | 10 +++ examples/openapi-from-object/package.json | 10 +++ 8 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 examples/openapi-from-object/README.md create mode 100644 examples/openapi-from-object/__snapshots__/index.spec.ts.snap create mode 100644 examples/openapi-from-object/index.spec.ts create mode 100644 examples/openapi-from-object/index.ts create mode 100644 examples/openapi-from-object/package-lock.json create mode 100644 examples/openapi-from-object/package.json diff --git a/README.md b/README.md index 3fff1eadc1..64159750a0 100644 --- a/README.md +++ b/README.md @@ -66,16 +66,16 @@ To see the complete feature list for each language, please click the individual description - AsyncAPI + AsyncAPI We support the following AsyncAPI versions: 2.0.0, 2.1.0 and 2.2.0, which generates models for all the defined message payloads. - JSON Schema + JSON Schema We support the following JSON Schema versions: Draft-4, Draft-6 and Draft-7 - OpenAPI - We support the following OpenAPI versions: Swagger 2.0 and OpenAPI 3.0, which generates models for all the defined path request and responses. + OpenAPI + We support the following OpenAPI versions: Swagger 2.0 and OpenAPI 3.0, which generates models for all the defined request and response payloads. diff --git a/docs/usage.md b/docs/usage.md index bd388919e2..6ff873b38e 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -13,6 +13,7 @@ For more specific integration options, please check out the [integration documen - [Generate models from AsyncAPI documents](#generate-models-from-asyncapi-documents) - [Generate models from JSON Schema documents](#generate-models-from-json-schema-documents) - [Generate models from Swagger 2.0 documents](#generate-models-from-swagger-20-documents) +- [Generate models from OpenAPI documents](#generate-models-from-openapi-documents) - [Generate Go models](#generate-go-models) - [Generate C# models](#generate-c%23-models) - [Generate Java models](#generate-java-models) @@ -48,8 +49,6 @@ We support both draft-4, draft-6, and draft-7 documents. The library expects the `$schema` property for the document to be set in order to understand the input format. By default, if no other inputs are detected, it defaults to `JSON Schema draft 7`. The process of interpreting a JSON Schema to a model can be read [here](./interpretation_of_JSON_Schema.md). ## Generate models from Swagger 2.0 documents -When providing an AsyncAPI document, Modelina iterates the entire document and generate models for all defined `body` parameters and responses. If any other kind of iteration is wanted, feel free to create a [feature request](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md). - There are one way to generate models from a Swagger 2.0 document - [Generate from a pure JS object](../examples/swagger2.0-from-object) @@ -58,6 +57,14 @@ The Swagger input processor expects that the property `swagger` is defined in or The response payload and `body` parameters, since it is a JSON Schema variant, is [interpreted as a such](./interpretation_of_JSON_Schema.md). +## Generate models from OpenAPI documents +There are one way to generate models from an OpenAPI document + +- [Generate from a pure JS object](../examples/openapi-from-object) + +The OpenAPI input processor expects that the property `openapi` is defined in order to know it should be processed. + +The response and request payloads, since it is a JSON Schema variant, is [interpreted as a such](./interpretation_of_JSON_Schema.md). ## Generate Go models TODO @@ -72,4 +79,5 @@ Java is one of the many output languages we support. Check out this [basic examp TypeScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-typescript-models) and the following [TypeScript documentation for more advanced use-cases](./languages/TypeScript.md). ## Generate JavaScript models -JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) \ No newline at end of file +JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) + diff --git a/examples/openapi-from-object/README.md b/examples/openapi-from-object/README.md new file mode 100644 index 0000000000..eab19088d3 --- /dev/null +++ b/examples/openapi-from-object/README.md @@ -0,0 +1,17 @@ +# OpenAPI from object + +A basic example of how to use Modelina with a basic OpenAPI object. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/openapi-from-object/__snapshots__/index.spec.ts.snap b/examples/openapi-from-object/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..774d1ca3a5 --- /dev/null +++ b/examples/openapi-from-object/__snapshots__/index.spec.ts.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to process a pure OpenAPI object and should log expected output to console 1`] = ` +Array [ + "export class TestPost_200ApplicationJson { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } +}", +] +`; + +exports[`Should be able to process a pure OpenAPI object and should log expected output to console 2`] = ` +Array [ + "export class TestPostApplicationJson { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } +}", +] +`; diff --git a/examples/openapi-from-object/index.spec.ts b/examples/openapi-from-object/index.spec.ts new file mode 100644 index 0000000000..771d530e6b --- /dev/null +++ b/examples/openapi-from-object/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import { generate } from './index'; +describe('Should be able to process a pure OpenAPI object', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 2 models, we double it + expect(spy.mock.calls.length).toEqual(4); + expect(spy.mock.calls[2]).toMatchSnapshot(); + expect(spy.mock.calls[3]).toMatchSnapshot(); + }); +}); diff --git a/examples/openapi-from-object/index.ts b/examples/openapi-from-object/index.ts new file mode 100644 index 0000000000..92a3c9db7d --- /dev/null +++ b/examples/openapi-from-object/index.ts @@ -0,0 +1,62 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator(); +const swaggerDocument = { + openapi: '3.0.3', + info: { + version: '0.1', + title: 'Simple basic api' + }, + paths: { + '/test': { + post: { + requestBody: { + content: { + 'application/json': { + schema: { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } + }, + required: true + }, + responses: { + 200: { + content: { + 'application/json': { + schema: { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } + } + } + } + } + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(swaggerDocument); + for (const model of models) { + console.log(model.result); + } +} + +generate(); diff --git a/examples/openapi-from-object/package-lock.json b/examples/openapi-from-object/package-lock.json new file mode 100644 index 0000000000..dff57b6bf9 --- /dev/null +++ b/examples/openapi-from-object/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "asyncapi-from-object", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/openapi-from-object/package.json b/examples/openapi-from-object/package.json new file mode 100644 index 0000000000..96391cc04e --- /dev/null +++ b/examples/openapi-from-object/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "openapi-from-object" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From f0676376123d6466a184cf52ac5595ec1b7f5455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Jane=C4=8Dek?= Date: Tue, 4 Jan 2022 14:27:46 +0100 Subject: [PATCH 10/82] fix: correctly store already converted schemas while parsing AsyncApi schema (#554) --- src/processors/AsyncAPIInputProcessor.ts | 6 +-- .../processors/AsyncAPIInputProcessor.spec.ts | 9 ++++ ...h_2_properties_referencing_one_schema.json | 49 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 test/processors/AsyncAPIInputProcessor/schema_with_2_properties_referencing_one_schema.json diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index 00bb813cd9..78eabd7ef5 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -55,10 +55,10 @@ export class AsyncAPIInputProcessor extends AbstractInputProcessor { if (alreadyIteratedSchemas.has(schemaUid)) { return alreadyIteratedSchemas.get(schemaUid) as AsyncapiV2Schema; } - let convertedSchema = new AsyncapiV2Schema(); - alreadyIteratedSchemas.set(schemaUid, convertedSchema); - convertedSchema = Object.assign({}, schema.json()); + + const convertedSchema = Object.assign(new AsyncapiV2Schema(), schema.json()); convertedSchema[this.MODELGEN_INFFERED_NAME] = schemaUid; + alreadyIteratedSchemas.set(schemaUid, convertedSchema); if (schema.allOf() !== null) { convertedSchema.allOf = schema.allOf().map((item) => this.convertToInternalSchema(item, alreadyIteratedSchemas)); diff --git a/test/processors/AsyncAPIInputProcessor.spec.ts b/test/processors/AsyncAPIInputProcessor.spec.ts index d9f4be263c..f23001c261 100644 --- a/test/processors/AsyncAPIInputProcessor.spec.ts +++ b/test/processors/AsyncAPIInputProcessor.spec.ts @@ -130,5 +130,14 @@ describe('AsyncAPIInputProcessor', () => { expect(expected.anyOf[1]['x-modelgen-inferred-name']).toEqual(''); expect(expected.anyOf[1].properties.prop['x-modelgen-inferred-name']).toEqual(''); }); + test('should correctly convert when schema has more than one properties referencing one other schema', async () => { + const basicDocString = fs.readFileSync(path.resolve(__dirname, './AsyncAPIInputProcessor/schema_with_2_properties_referencing_one_schema.json'), 'utf8'); + const doc = await parse(basicDocString, {} as ParserOptions); + const schema = doc.channels()['/user/signedup'].subscribe().message().payload(); + const result = AsyncAPIInputProcessor.convertToInternalSchema(schema) as any; + + expect(result.properties['lastName']).not.toEqual({}); + expect(result.properties['firstName']).toEqual(result.properties['lastName']); + }); }); }); diff --git a/test/processors/AsyncAPIInputProcessor/schema_with_2_properties_referencing_one_schema.json b/test/processors/AsyncAPIInputProcessor/schema_with_2_properties_referencing_one_schema.json new file mode 100644 index 0000000000..00c565f0fc --- /dev/null +++ b/test/processors/AsyncAPIInputProcessor/schema_with_2_properties_referencing_one_schema.json @@ -0,0 +1,49 @@ +{ + "asyncapi": "2.2.0", + "info": { + "title": "Account Service", + "version": "1.0.0", + "description": "This service is in charge of processing user signups" + }, + "channels": { + "/user/signedup": { + "subscribe": { + "message": { + "$ref": "#/components/messages/UserSignedUp" + } + } + } + }, + "components": { + "messages": { + "UserSignedUp": { + "payload": { + "type": "object", + "properties": { + "firstName": { + "$ref": "#/components/schemas/PersonName" + }, + "lastName": { + "$ref": "#/components/schemas/PersonName" + }, + "email": { + "type": "string", + "format": "email", + "description": "Email of the user" + } + } + } + } + }, + "schemas": { + "PersonName": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + } + } + } +} From 65efaea859d4505b5f055a0089951fbdc05ae0dc Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 4 Jan 2022 14:43:02 +0100 Subject: [PATCH 11/82] chore(release): v0.39.11 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ee1f36a39..d12c851ec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.39.10", + "version": "0.39.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.39.10", + "version": "0.39.11", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index a93a56456b..c51c2f92d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.39.10", + "version": "0.39.11", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 99b5b441ef3786c8b022ba4a8fe0c4fd2af0ba22 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 4 Jan 2022 14:53:15 +0100 Subject: [PATCH 12/82] feat: complete model rendering and file output for JavaScript generator --- docs/advanced.md | 4 +- docs/languages/JavaScript.md | 16 +- examples/README.md | 4 +- examples/javascript-use-cjs/README.md | 17 ++ .../__snapshots__/index.spec.ts.snap | 37 +++++ examples/javascript-use-cjs/index.spec.ts | 15 ++ examples/javascript-use-cjs/index.ts | 33 ++++ examples/javascript-use-cjs/package-lock.json | 10 ++ examples/javascript-use-cjs/package.json | 10 ++ examples/javascript-use-esm/README.md | 17 ++ .../__snapshots__/index.spec.ts.snap | 35 ++++ examples/javascript-use-esm/index.spec.ts | 15 ++ examples/javascript-use-esm/index.ts | 33 ++++ examples/javascript-use-esm/package-lock.json | 10 ++ examples/javascript-use-esm/package.json | 10 ++ package.json | 2 +- .../javascript/JavaScriptFileGenerator.ts | 24 +++ .../javascript/JavaScriptGenerator.ts | 34 +++- src/generators/javascript/index.ts | 1 + .../JavaScriptFileGenerator.spec.ts | 51 ++++++ .../javascript/JavaScriptGenerator.spec.ts | 53 ++++++ .../JavaScriptGenerator.spec.ts.snap | 157 ++++++++++++++++++ 22 files changed, 581 insertions(+), 7 deletions(-) create mode 100644 examples/javascript-use-cjs/README.md create mode 100644 examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap create mode 100644 examples/javascript-use-cjs/index.spec.ts create mode 100644 examples/javascript-use-cjs/index.ts create mode 100644 examples/javascript-use-cjs/package-lock.json create mode 100644 examples/javascript-use-cjs/package.json create mode 100644 examples/javascript-use-esm/README.md create mode 100644 examples/javascript-use-esm/__snapshots__/index.spec.ts.snap create mode 100644 examples/javascript-use-esm/index.spec.ts create mode 100644 examples/javascript-use-esm/index.ts create mode 100644 examples/javascript-use-esm/package-lock.json create mode 100644 examples/javascript-use-esm/package.json create mode 100644 src/generators/javascript/JavaScriptFileGenerator.ts create mode 100644 test/generators/javascript/JavaScriptFileGenerator.spec.ts create mode 100644 test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap diff --git a/docs/advanced.md b/docs/advanced.md index 8c7e41b6e0..1d22d8cc60 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -31,7 +31,9 @@ The reason for splitting the functionality is because in certain environments (l The file generators all follow the same pattern regardless of output language, which is the following format - `FileGenerator`. -Currently only supported for `Java`. +Supported by: +- Java +- JavaScript > Not support in browsers. diff --git a/docs/languages/JavaScript.md b/docs/languages/JavaScript.md index 42974ca5e1..091c1f28f2 100644 --- a/docs/languages/JavaScript.md +++ b/docs/languages/JavaScript.md @@ -1,4 +1,18 @@ # JavaScript There are special use-cases that each language supports; this document pertains to **JavaScript models**. -At the moment, JavaScript models have no specific features. \ No newline at end of file + + + + +- [JavaScript](#javascript) + - [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) + + + +## Rendering complete models to a specific module system +In some cases you might need to render the complete models to a specific module system such as ESM and CJS. + +Check out this [example for a live demonstration how to generate the complete JavaScript models to use ESM module system](../../examples/javascript-use-esm). + +Check out this [example for a live demonstration how to generate the complete JavaScript models to use CJS module system](../../examples/javascript-use-cjs). \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index a366461ef5..354dd6ebe9 100644 --- a/examples/README.md +++ b/examples/README.md @@ -20,4 +20,6 @@ This directory contains a series of self-contained examples that you can use as - [java-generate-tostring](./java-generate-tostring) - A basic example that shows how to generate models that overwrite the `toString` method - [csharp-generate-equals-and-hashcode](./csharp-generate-equals-and-hashcode) - A basic example on how to generate models that overwrite the `Equal` and `GetHashCode` methods - [generate-javascript-models](./generate-javascript-models) - A basic example to generate JavaScript data models -- [generate-java-models](./generate-java-models) - A basic example to generate Java data models \ No newline at end of file +- [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. +- [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. +- [generate-java-models](./generate-java-models) - A basic example to generate Java data models. diff --git a/examples/javascript-use-cjs/README.md b/examples/javascript-use-cjs/README.md new file mode 100644 index 0000000000..59c5f7dda5 --- /dev/null +++ b/examples/javascript-use-cjs/README.md @@ -0,0 +1,17 @@ +# JavaScript models use CJS module system + +This example shows how you can generate the models to use CJS module system. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..9651cb4b30 --- /dev/null +++ b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap @@ -0,0 +1,37 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = ` +Array [ + " + +class Person { + email; + + constructor(input) { + this.email = input.email; + } + + get email() { return this.email; } + set email(email) { this.email = email; } +} +module.exports = Person;", +] +`; + +exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = ` +Array [ + "const Person = require('./Person'); + +class Root { + person; + + constructor(input) { + this.person = input.person; + } + + get person() { return this.person; } + set person(person) { this.person = person; } +} +module.exports = Root;", +] +`; diff --git a/examples/javascript-use-cjs/index.spec.ts b/examples/javascript-use-cjs/index.spec.ts new file mode 100644 index 0000000000..1bdece5160 --- /dev/null +++ b/examples/javascript-use-cjs/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render models to ESM module system', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 2 models, we double it + expect(spy.mock.calls.length).toEqual(4); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + }); +}); diff --git a/examples/javascript-use-cjs/index.ts b/examples/javascript-use-cjs/index.ts new file mode 100644 index 0000000000..9aba8f2323 --- /dev/null +++ b/examples/javascript-use-cjs/index.ts @@ -0,0 +1,33 @@ +import { JavaScriptGenerator } from '../../src'; + +const generator = new JavaScriptGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + person: { + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } +}; + +export async function generate() : Promise { + const models = await generator.generateCompleteModels( + jsonSchemaDraft7, + { + moduleSystem: 'CJS' + } + ); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/javascript-use-cjs/package-lock.json b/examples/javascript-use-cjs/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/javascript-use-cjs/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/javascript-use-cjs/package.json b/examples/javascript-use-cjs/package.json new file mode 100644 index 0000000000..889fa77f6b --- /dev/null +++ b/examples/javascript-use-cjs/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "javascript-use-cjs" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/examples/javascript-use-esm/README.md b/examples/javascript-use-esm/README.md new file mode 100644 index 0000000000..098d633fe6 --- /dev/null +++ b/examples/javascript-use-esm/README.md @@ -0,0 +1,17 @@ +# JavaScript models use ESM module system + +This example shows how you can generate the models to use ESM module system. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..db83a4c71e --- /dev/null +++ b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = ` +Array [ + " + +export default class Person { + email; + + constructor(input) { + this.email = input.email; + } + + get email() { return this.email; } + set email(email) { this.email = email; } +}", +] +`; + +exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = ` +Array [ + "import Person from './Person'; + +export default class Root { + person; + + constructor(input) { + this.person = input.person; + } + + get person() { return this.person; } + set person(person) { this.person = person; } +}", +] +`; diff --git a/examples/javascript-use-esm/index.spec.ts b/examples/javascript-use-esm/index.spec.ts new file mode 100644 index 0000000000..1bdece5160 --- /dev/null +++ b/examples/javascript-use-esm/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render models to ESM module system', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 2 models, we double it + expect(spy.mock.calls.length).toEqual(4); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + }); +}); diff --git a/examples/javascript-use-esm/index.ts b/examples/javascript-use-esm/index.ts new file mode 100644 index 0000000000..24a7bc17f0 --- /dev/null +++ b/examples/javascript-use-esm/index.ts @@ -0,0 +1,33 @@ +import { JavaScriptGenerator } from '../../src'; + +const generator = new JavaScriptGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + person: { + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } +}; + +export async function generate() : Promise { + const models = await generator.generateCompleteModels( + jsonSchemaDraft7, + { + moduleSystem: 'ESM' + } + ); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/javascript-use-esm/package-lock.json b/examples/javascript-use-esm/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/javascript-use-esm/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/javascript-use-esm/package.json b/examples/javascript-use-esm/package.json new file mode 100644 index 0000000000..f353147d0d --- /dev/null +++ b/examples/javascript-use-esm/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "javascript-module-system" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/package.json b/package.json index c51c2f92d9..d36853626e 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "lint": "eslint --max-warnings 0 --config .eslintrc .", "lint:fix": "eslint --max-warnings 0 --config .eslintrc . --fix", "release": "semantic-release", - "generate:readme:toc": "markdown-toc -i README.md && markdown-toc -i ./docs/usage.md && markdown-toc -i ./docs/integration.md && markdown-toc -i ./docs/advanced.md && markdown-toc -i ./docs/languages/TypeScript.md && markdown-toc -i ./docs/languages/Java.md && markdown-toc -i ./docs/languages/Csharp.md && markdown-toc -i ./docs/README.md && markdown-toc -i ./docs/generators.md", + "generate:readme:toc": "markdown-toc -i README.md && markdown-toc -i ./docs/usage.md && markdown-toc -i ./docs/integration.md && markdown-toc -i ./docs/advanced.md && markdown-toc -i ./docs/languages/TypeScript.md && markdown-toc -i ./docs/languages/Java.md && markdown-toc -i ./docs/languages/JavaScript.md && markdown-toc -i ./docs/languages/Csharp.md && markdown-toc -i ./docs/README.md && markdown-toc -i ./docs/generators.md", "generate:assets": "npm run build:prod && npm run docs && npm run generate:readme:toc", "bump:version": "npm --no-git-tag-version --allow-same-version version $VERSION", "prepublishOnly": "npm run build:prod && npm run generate:readme:toc" diff --git a/src/generators/javascript/JavaScriptFileGenerator.ts b/src/generators/javascript/JavaScriptFileGenerator.ts new file mode 100644 index 0000000000..39af296e4a --- /dev/null +++ b/src/generators/javascript/JavaScriptFileGenerator.ts @@ -0,0 +1,24 @@ +import { JavaScriptGenerator, JavaScriptRenderCompleteModelOptions } from './'; +import { CommonInputModel, OutputModel } from '../../models'; +import * as path from 'path'; +import { AbstractFileGenerator } from '../AbstractFileGenerator'; +import { FileHelpers } from '../../helpers'; + +export class JavaScriptFileGenerator extends JavaScriptGenerator implements AbstractFileGenerator { + /** + * Generates all the models to an output directory each model with their own separate files. + * + * @param input + * @param outputDirectory where you want the models generated to + * @param options + */ + public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options?: JavaScriptRenderCompleteModelOptions): Promise { + let generatedModels = await this.generateCompleteModels(input, options || {}); + generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== undefined; }); + for (const outputModel of generatedModels) { + const filePath = path.resolve(outputDirectory, `${outputModel.modelName}.js`); + await FileHelpers.writerToFileSystem(outputModel.result, filePath); + } + return generatedModels; + } +} diff --git a/src/generators/javascript/JavaScriptGenerator.ts b/src/generators/javascript/JavaScriptGenerator.ts index 0801c1a8f1..9ae436230c 100644 --- a/src/generators/javascript/JavaScriptGenerator.ts +++ b/src/generators/javascript/JavaScriptGenerator.ts @@ -12,10 +12,14 @@ export interface JavaScriptOptions extends CommonGeneratorOptions { +export class JavaScriptGenerator extends AbstractGenerator { static defaultOptions: JavaScriptOptions = { ...defaultGeneratorOptions, defaultPreset: JS_DEFAULT_PRESET, @@ -27,9 +31,33 @@ export class JavaScriptGenerator extends AbstractGenerator { ) { super('JavaScript', JavaScriptGenerator.defaultOptions, options); } + + /** + * Render a complete model result where the model code, library and model dependencies are all bundled appropriately. + * + * @param model + * @param inputModel + * @param options + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async renderCompleteModel(model: CommonModel, inputModel: CommonInputModel, options: JavaScriptRenderCompleteModelOptions): Promise { + const outputModel = await this.render(model, inputModel); + const modelDependencies = model.getNearestDependencies().map((dependencyModelName) => { + const formattedDependencyModelName = this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { inputModel, model: inputModel.models[String(dependencyModelName)] }) : dependencyModelName; + if (options.moduleSystem === 'CJS') { + return `const ${formattedDependencyModelName} = require('./${formattedDependencyModelName}');`; + } + return `import ${formattedDependencyModelName} from './${formattedDependencyModelName}';`; + }); + let modelCode = `export default ${outputModel.result}`; + if (options.moduleSystem === 'CJS') { + modelCode = `${outputModel.result} +module.exports = ${outputModel.renderedName};`; + } + const outputContent = `${[...modelDependencies, ...outputModel.dependencies].join('\n')} - renderCompleteModel(): Promise { - throw new Error('Method not implemented.'); +${modelCode}`; + return RenderOutput.toRenderOutput({ result: outputContent, renderedName: outputModel.renderedName, dependencies: outputModel.dependencies }); } render(model: CommonModel, inputModel: CommonInputModel): Promise { diff --git a/src/generators/javascript/index.ts b/src/generators/javascript/index.ts index 60badf1b36..e9839415f3 100644 --- a/src/generators/javascript/index.ts +++ b/src/generators/javascript/index.ts @@ -1,3 +1,4 @@ export * from './JavaScriptGenerator'; +export * from './JavaScriptFileGenerator'; export { JS_DEFAULT_PRESET } from './JavaScriptPreset'; export type { JavaScriptPreset } from './JavaScriptPreset'; diff --git a/test/generators/javascript/JavaScriptFileGenerator.spec.ts b/test/generators/javascript/JavaScriptFileGenerator.spec.ts new file mode 100644 index 0000000000..69a4803f9c --- /dev/null +++ b/test/generators/javascript/JavaScriptFileGenerator.spec.ts @@ -0,0 +1,51 @@ +import { CommonInputModel, CommonModel, FileHelpers, JavaScriptFileGenerator, OutputModel } from '../../../src'; +import * as path from 'path'; + +describe('JavaScriptFileGenerator', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('generateToFile()', () => { + const doc = { + $id: 'CustomClass', + type: 'object', + additionalProperties: true, + properties: { + someProp: { type: 'string' }, + someEnum: { + $id: 'CustomEnum', + type: 'string', + enum: ['Texas', 'Alabama', 'California'], + } + } + }; + test('should throw accurate error if file cannot be written', async () => { + const generator = new JavaScriptFileGenerator(); + const expectedError = new Error('write error'); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockRejectedValue(expectedError); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + + await expect(generator.generateToFiles(doc, '/test/')).rejects.toEqual(expectedError); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + }); + test('should try and generate models to files', async () => { + const generator = new JavaScriptFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + const expectedOutputFilePath = path.resolve(`${outputDir}/Test.js`); + const expectedWriteToFileParameters = [ + 'content', + expectedOutputFilePath, + ]; + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); + + await generator.generateToFiles(doc, expectedOutputDirPath); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + expect((FileHelpers.writerToFileSystem as jest.Mock).mock.calls[0]).toEqual(expectedWriteToFileParameters); + }); + }); +}); diff --git a/test/generators/javascript/JavaScriptGenerator.spec.ts b/test/generators/javascript/JavaScriptGenerator.spec.ts index 44da7d15a5..185e8ef129 100644 --- a/test/generators/javascript/JavaScriptGenerator.spec.ts +++ b/test/generators/javascript/JavaScriptGenerator.spec.ts @@ -188,4 +188,57 @@ describe('JavaScriptGenerator', () => { expect(classModel.result).toEqual(expected); expect(classModel.dependencies).toEqual([]); }); + + test('should render models and their dependencies for CJS module system', async () => { + const doc = { + $id: 'Address', + type: 'object', + properties: { + street_name: { type: 'string' }, + city: { type: 'string', description: 'City description' }, + state: { type: 'string' }, + house_number: { type: 'number' }, + marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, + members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, + array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } } }, + }, + patternProperties: { + '^S(.?*)test&': { + type: 'string' + } + }, + required: ['street_name', 'city', 'state', 'house_number', 'array_type'], + }; + const models = await generator.generateCompleteModels(doc, {moduleSystem: 'CJS'}); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); + test('should render models and their dependencies for ESM module system', async () => { + const doc = { + $id: 'Address', + type: 'object', + properties: { + street_name: { type: 'string' }, + city: { type: 'string', description: 'City description' }, + state: { type: 'string' }, + house_number: { type: 'number' }, + marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, + members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, + array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } } }, + }, + patternProperties: { + '^S(.?*)test&': { + type: 'string' + } + }, + required: ['street_name', 'city', 'state', 'house_number', 'array_type'], + }; + const models = await generator.generateCompleteModels(doc, {moduleSystem: 'ESM'}); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); }); diff --git a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap new file mode 100644 index 0000000000..8ff9e784e6 --- /dev/null +++ b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap @@ -0,0 +1,157 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`JavaScriptGenerator should render models and their dependencies for CJS module system 1`] = ` +"const OtherModel = require('./OtherModel'); + +class Address { + streetName; + city; + state; + houseNumber; + marriage; + members; + arrayType; + otherModel; + additionalProperties; + sTestPatternProperties; + + constructor(input) { + this.streetName = input.streetName; + this.city = input.city; + this.state = input.state; + this.houseNumber = input.houseNumber; + this.marriage = input.marriage; + this.members = input.members; + this.arrayType = input.arrayType; + this.otherModel = input.otherModel; + } + + get streetName() { return this.streetName; } + set streetName(streetName) { this.streetName = streetName; } + + get city() { return this.city; } + set city(city) { this.city = city; } + + get state() { return this.state; } + set state(state) { this.state = state; } + + get houseNumber() { return this.houseNumber; } + set houseNumber(houseNumber) { this.houseNumber = houseNumber; } + + get marriage() { return this.marriage; } + set marriage(marriage) { this.marriage = marriage; } + + get members() { return this.members; } + set members(members) { this.members = members; } + + get arrayType() { return this.arrayType; } + set arrayType(arrayType) { this.arrayType = arrayType; } + + get otherModel() { return this.otherModel; } + set otherModel(otherModel) { this.otherModel = otherModel; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + get sTestPatternProperties() { return this.sTestPatternProperties; } + set sTestPatternProperties(sTestPatternProperties) { this.sTestPatternProperties = sTestPatternProperties; } +} +module.exports = Address;" +`; + +exports[`JavaScriptGenerator should render models and their dependencies for CJS module system 2`] = ` +" + +class OtherModel { + streetName; + additionalProperties; + + constructor(input) { + this.streetName = input.streetName; + } + + get streetName() { return this.streetName; } + set streetName(streetName) { this.streetName = streetName; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } +} +module.exports = OtherModel;" +`; + +exports[`JavaScriptGenerator should render models and their dependencies for ESM module system 1`] = ` +"import OtherModel from './OtherModel'; + +export default class Address { + streetName; + city; + state; + houseNumber; + marriage; + members; + arrayType; + otherModel; + additionalProperties; + sTestPatternProperties; + + constructor(input) { + this.streetName = input.streetName; + this.city = input.city; + this.state = input.state; + this.houseNumber = input.houseNumber; + this.marriage = input.marriage; + this.members = input.members; + this.arrayType = input.arrayType; + this.otherModel = input.otherModel; + } + + get streetName() { return this.streetName; } + set streetName(streetName) { this.streetName = streetName; } + + get city() { return this.city; } + set city(city) { this.city = city; } + + get state() { return this.state; } + set state(state) { this.state = state; } + + get houseNumber() { return this.houseNumber; } + set houseNumber(houseNumber) { this.houseNumber = houseNumber; } + + get marriage() { return this.marriage; } + set marriage(marriage) { this.marriage = marriage; } + + get members() { return this.members; } + set members(members) { this.members = members; } + + get arrayType() { return this.arrayType; } + set arrayType(arrayType) { this.arrayType = arrayType; } + + get otherModel() { return this.otherModel; } + set otherModel(otherModel) { this.otherModel = otherModel; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + get sTestPatternProperties() { return this.sTestPatternProperties; } + set sTestPatternProperties(sTestPatternProperties) { this.sTestPatternProperties = sTestPatternProperties; } +}" +`; + +exports[`JavaScriptGenerator should render models and their dependencies for ESM module system 2`] = ` +" + +export default class OtherModel { + streetName; + additionalProperties; + + constructor(input) { + this.streetName = input.streetName; + } + + get streetName() { return this.streetName; } + set streetName(streetName) { this.streetName = streetName; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } +}" +`; From 4cf252c143cdb4dbbbdd4ee02ca6faf528f6e427 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 4 Jan 2022 16:00:31 +0100 Subject: [PATCH 13/82] chore(release): v0.40.0 (#556) Co-authored-by: asyncapi-bot --- docs/languages/JavaScript.md | 3 +-- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/languages/JavaScript.md b/docs/languages/JavaScript.md index 091c1f28f2..1d407bb2f0 100644 --- a/docs/languages/JavaScript.md +++ b/docs/languages/JavaScript.md @@ -5,8 +5,7 @@ There are special use-cases that each language supports; this document pertains -- [JavaScript](#javascript) - - [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) +- [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) diff --git a/package-lock.json b/package-lock.json index d12c851ec5..fdd4585ea8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.39.11", + "version": "0.40.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.39.11", + "version": "0.40.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index d36853626e..7dd62fa69c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.39.11", + "version": "0.40.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 17f8f7a587250b593f1b5599260c3acaddce93a5 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 4 Jan 2022 17:54:22 +0100 Subject: [PATCH 14/82] fix: removing TypeScript exported base model --- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 4 +- .../__snapshots__/index.spec.ts.snap | 4 +- .../__snapshots__/index.spec.ts.snap | 8 ++-- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../typescript/renderers/ClassRenderer.ts | 4 +- .../typescript/renderers/EnumRenderer.ts | 4 +- .../typescript/renderers/InterfaceRenderer.ts | 4 +- .../typescript/renderers/TypeRenderer.ts | 4 +- test/blackbox/blackbox.spec.ts | 44 +++++++++---------- .../typescript/TypeScriptGenerator.spec.ts | 31 +++++++------ .../TypeScriptGenerator.spec.ts.snap | 6 ++- .../__snapshots__/ExamplePreset.spec.ts.snap | 4 +- .../MarshallingPreset.spec.ts.snap | 4 +- 21 files changed, 70 insertions(+), 69 deletions(-) diff --git a/examples/asyncapi-from-object/__snapshots__/index.spec.ts.snap b/examples/asyncapi-from-object/__snapshots__/index.spec.ts.snap index 94c5dc2eef..d50053894c 100644 --- a/examples/asyncapi-from-object/__snapshots__/index.spec.ts.snap +++ b/examples/asyncapi-from-object/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to process a pure AsyncAPI object and should log expected output to console 1`] = ` Array [ - "export class AnonymousSchema_1 { + "class AnonymousSchema_1 { private _email?: string; constructor(input: { diff --git a/examples/asyncapi-from-parser/__snapshots__/index.spec.ts.snap b/examples/asyncapi-from-parser/__snapshots__/index.spec.ts.snap index 402852ef74..a7c5e5176a 100644 --- a/examples/asyncapi-from-parser/__snapshots__/index.spec.ts.snap +++ b/examples/asyncapi-from-parser/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to process AsyncAPI object from parser and should log expected output to console 1`] = ` Array [ - "export class AnonymousSchema_1 { + "class AnonymousSchema_1 { private _email?: string; constructor(input: { diff --git a/examples/custom-logging/__snapshots__/index.spec.ts.snap b/examples/custom-logging/__snapshots__/index.spec.ts.snap index 0835a7b705..9b5d515f7f 100644 --- a/examples/custom-logging/__snapshots__/index.spec.ts.snap +++ b/examples/custom-logging/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to use custom logging interface and should log expected output to console 1`] = ` Array [ - "export class Root { + "class Root { private _email?: string; constructor(input: { diff --git a/examples/generate-typescript-models/__snapshots__/index.spec.ts.snap b/examples/generate-typescript-models/__snapshots__/index.spec.ts.snap index 1f69c3bc80..bc58069bcd 100644 --- a/examples/generate-typescript-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-typescript-models/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to render TypeScript Models and should log expected output to console 1`] = ` Array [ - "export class Root { + "class Root { private _email?: string; constructor(input: { diff --git a/examples/indentation-type-and-size/__snapshots__/index.spec.ts.snap b/examples/indentation-type-and-size/__snapshots__/index.spec.ts.snap index c5c8c28020..98a9a1a2a1 100644 --- a/examples/indentation-type-and-size/__snapshots__/index.spec.ts.snap +++ b/examples/indentation-type-and-size/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should render the typescript class with 4 tabs as indentation and should log expected output to console 1`] = ` Array [ - "export class Root { + "class Root { private _email?: string; constructor(input: { diff --git a/examples/json-schema-draft7-from-object/__snapshots__/index.spec.ts.snap b/examples/json-schema-draft7-from-object/__snapshots__/index.spec.ts.snap index 47933875aa..8d9948cb8f 100644 --- a/examples/json-schema-draft7-from-object/__snapshots__/index.spec.ts.snap +++ b/examples/json-schema-draft7-from-object/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to process JSON Schema draft 7 object and should log expected output to console 1`] = ` Array [ - "export class Root { + "class Root { private _email?: string; constructor(input: { diff --git a/examples/openapi-from-object/__snapshots__/index.spec.ts.snap b/examples/openapi-from-object/__snapshots__/index.spec.ts.snap index 774d1ca3a5..87d3029a4b 100644 --- a/examples/openapi-from-object/__snapshots__/index.spec.ts.snap +++ b/examples/openapi-from-object/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to process a pure OpenAPI object and should log expected output to console 1`] = ` Array [ - "export class TestPost_200ApplicationJson { + "class TestPost_200ApplicationJson { private _email?: string; constructor(input: { @@ -19,7 +19,7 @@ Array [ exports[`Should be able to process a pure OpenAPI object and should log expected output to console 2`] = ` Array [ - "export class TestPostApplicationJson { + "class TestPostApplicationJson { private _email?: string; constructor(input: { diff --git a/examples/swagger2.0-from-object/__snapshots__/index.spec.ts.snap b/examples/swagger2.0-from-object/__snapshots__/index.spec.ts.snap index 1c3cb52560..7309e3df85 100644 --- a/examples/swagger2.0-from-object/__snapshots__/index.spec.ts.snap +++ b/examples/swagger2.0-from-object/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to process a pure Swagger 2.0 object and should log expected output to console 1`] = ` Array [ - "export class TestPost_200 { + "class TestPost_200 { private _email?: string; constructor(input: { @@ -19,7 +19,7 @@ Array [ exports[`Should be able to process a pure Swagger 2.0 object and should log expected output to console 2`] = ` Array [ - "export class TestPostBody { + "class TestPostBody { private _email?: string; constructor(input: { diff --git a/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap b/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap index 55a2597998..e624a61929 100644 --- a/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap +++ b/examples/typescript-enum-type/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to render correct enums based on options and should log expected output to console 1`] = ` "Generator output with Union: -export class Root { +class Root { private _event?: Event; constructor(input: { @@ -14,9 +14,9 @@ export class Root { get event(): Event | undefined { return this._event; } set event(event: Event | undefined) { this._event = event; } } -export type Event = \\"ping\\" | \\"pong\\"; +type Event = \\"ping\\" | \\"pong\\"; Generator output with Enum: -export class Root { +class Root { private _event?: Event; constructor(input: { @@ -28,7 +28,7 @@ export class Root { get event(): Event | undefined { return this._event; } set event(event: Event | undefined) { this._event = event; } } -export enum Event { +enum Event { PING = \\"ping\\", PONG = \\"pong\\", }" diff --git a/examples/typescript-generate-example/__snapshots__/index.spec.ts.snap b/examples/typescript-generate-example/__snapshots__/index.spec.ts.snap index 617c875f5e..bc8ad6faaa 100644 --- a/examples/typescript-generate-example/__snapshots__/index.spec.ts.snap +++ b/examples/typescript-generate-example/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to generate ts data model with example function and should log expected output to console 1`] = ` Array [ - "export class Root { + "class Root { private _email?: string; constructor(input: { diff --git a/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap b/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap index c6135807c4..af7b5b8984 100644 --- a/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap +++ b/examples/typescript-generate-marshalling/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to generate ts data model with marshal und unmarshal functions and should log expected output to console 1`] = ` Array [ - "export class Test { + "class Test { private _email?: string; constructor(input: { diff --git a/examples/typescript-interface/__snapshots__/index.spec.ts.snap b/examples/typescript-interface/__snapshots__/index.spec.ts.snap index 65098469c2..92587c47bc 100644 --- a/examples/typescript-interface/__snapshots__/index.spec.ts.snap +++ b/examples/typescript-interface/__snapshots__/index.spec.ts.snap @@ -2,7 +2,7 @@ exports[`Should be able to render typescript interface and should log expected output to console 1`] = ` Array [ - "export interface Root { + "interface Root { email?: string; }", ] diff --git a/src/generators/typescript/renderers/ClassRenderer.ts b/src/generators/typescript/renderers/ClassRenderer.ts index 069380c86a..a3f992007a 100644 --- a/src/generators/typescript/renderers/ClassRenderer.ts +++ b/src/generators/typescript/renderers/ClassRenderer.ts @@ -64,8 +64,8 @@ ${this.indent(this.renderBlock(content, 2))} } export const TS_DEFAULT_CLASS_PRESET: ClassPreset = { - async self({ renderer }): Promise { - return `export ${await renderer.defaultSelf()}`; + self({ renderer }) { + return renderer.defaultSelf(); }, ctor({ renderer, model }) : string { const properties = model.properties || {}; diff --git a/src/generators/typescript/renderers/EnumRenderer.ts b/src/generators/typescript/renderers/EnumRenderer.ts index ca1957ca72..045fb134cd 100644 --- a/src/generators/typescript/renderers/EnumRenderer.ts +++ b/src/generators/typescript/renderers/EnumRenderer.ts @@ -85,8 +85,8 @@ ${this.indent(this.renderBlock(content, 2))} } export const TS_DEFAULT_ENUM_PRESET: EnumPreset = { - async self({ renderer }) { - return `export ${await renderer.defaultSelf()}`; + self({ renderer }) { + return renderer.defaultSelf(); }, item({ item, renderer }): string { const key = renderer.normalizeKey(item); diff --git a/src/generators/typescript/renderers/InterfaceRenderer.ts b/src/generators/typescript/renderers/InterfaceRenderer.ts index b2f43b4c6e..53099afdf3 100644 --- a/src/generators/typescript/renderers/InterfaceRenderer.ts +++ b/src/generators/typescript/renderers/InterfaceRenderer.ts @@ -21,8 +21,8 @@ ${this.indent(this.renderBlock(content, 2))} } export const TS_DEFAULT_INTERFACE_PRESET: InterfacePreset = { - async self({ renderer }) { - return `export ${await renderer.defaultSelf()}`; + self({ renderer }) { + return renderer.defaultSelf(); }, property({ renderer, propertyName, property, type }) { return renderer.renderProperty(propertyName, property, type); diff --git a/src/generators/typescript/renderers/TypeRenderer.ts b/src/generators/typescript/renderers/TypeRenderer.ts index 3fc6513273..e0f81df7d5 100644 --- a/src/generators/typescript/renderers/TypeRenderer.ts +++ b/src/generators/typescript/renderers/TypeRenderer.ts @@ -29,7 +29,7 @@ export class TypeRenderer extends TypeScriptRenderer { } export const TS_DEFAULT_TYPE_PRESET: TypePreset = { - async self({ renderer }) { - return `export ${await renderer.defaultSelf()}`; + self({ renderer }) { + return renderer.defaultSelf(); }, }; diff --git a/test/blackbox/blackbox.spec.ts b/test/blackbox/blackbox.spec.ts index 511686e579..9498a93e06 100644 --- a/test/blackbox/blackbox.spec.ts +++ b/test/blackbox/blackbox.spec.ts @@ -138,29 +138,29 @@ describe.each(filesToTest)('Should be able to generate with inputs', ({file, out }); }); - describe('should be able to generate and transpile TS', () => { - test('class', async () => { - const generator = new TypeScriptGenerator(); - const generatedModels = await generateModels(fileToGenerateFor, generator); - expect(generatedModels).not.toHaveLength(0); - const renderOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.ts'); - await renderModels(generatedModels, renderOutputPath); - const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.js'); - const transpileAndRunCommand = `tsc --downlevelIteration -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; - await execCommand(transpileAndRunCommand); - }); + // describe('should be able to generate and transpile TS', () => { + // test('class', async () => { + // const generator = new TypeScriptGenerator(); + // const generatedModels = await generateModels(fileToGenerateFor, generator); + // expect(generatedModels).not.toHaveLength(0); + // const renderOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.ts'); + // await renderModels(generatedModels, renderOutputPath); + // const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.js'); + // const transpileAndRunCommand = `tsc --downlevelIteration -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; + // await execCommand(transpileAndRunCommand); + // }); - test('interface', async () => { - const generator = new TypeScriptGenerator({modelType: 'interface'}); - const generatedModels = await generateModels(fileToGenerateFor, generator); - expect(generatedModels).not.toHaveLength(0); - const renderOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.ts'); - await renderModels(generatedModels, renderOutputPath); - const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.js'); - const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; - await execCommand(transpileAndRunCommand); - }); - }); + // test('interface', async () => { + // const generator = new TypeScriptGenerator({modelType: 'interface'}); + // const generatedModels = await generateModels(fileToGenerateFor, generator); + // expect(generatedModels).not.toHaveLength(0); + // const renderOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.ts'); + // await renderModels(generatedModels, renderOutputPath); + // const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.js'); + // const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; + // await execCommand(transpileAndRunCommand); + // }); + // }); describe('should be able to generate JS', () => { test('class', async () => { diff --git a/test/generators/typescript/TypeScriptGenerator.spec.ts b/test/generators/typescript/TypeScriptGenerator.spec.ts index a98d5392ee..cb4e09e360 100644 --- a/test/generators/typescript/TypeScriptGenerator.spec.ts +++ b/test/generators/typescript/TypeScriptGenerator.spec.ts @@ -16,7 +16,7 @@ describe('TypeScriptGenerator', () => { }, additionalProperties: false }; - const expected = `export class Address { + const expected = `class Address { private _reservedReservedEnum?: string; private _reservedEnum?: string; @@ -67,7 +67,7 @@ describe('TypeScriptGenerator', () => { }, required: ['street_name', 'city', 'state', 'house_number', 'array_type'], }; - const expected = `export class Address { + const expected = `class Address { private _streetName: string; private _city: string; private _state: string; @@ -156,7 +156,7 @@ describe('TypeScriptGenerator', () => { property: { type: 'string' }, } }; - const expected = `export class CustomClass { + const expected = `class CustomClass { @JsonProperty("property") private _property?: string; @JsonProperty("additionalProperties") @@ -218,7 +218,7 @@ ${content}`; }, required: ['street_name', 'city', 'state', 'house_number', 'array_type'], }; - const expected = `export interface Address { + const expected = `interface Address { streetName: string; city: string; state: string; @@ -249,7 +249,7 @@ ${content}`; property: { type: 'string' }, } }; - const expected = `export interface CustomInterface { + const expected = `interface CustomInterface { property?: string; additionalProperties?: Map | boolean | null>; }`; @@ -280,7 +280,7 @@ ${content}`; type: 'string', enum: ['Texas', 'Alabama', 'California'], }; - const expected = `export enum States { + const expected = `enum States { TEXAS = "Texas", ALABAMA = "Alabama", CALIFORNIA = "California", @@ -304,7 +304,7 @@ ${content}`; type: 'string', enum: ['Texas', 'Alabama', 'California'], }; - const expected = 'export type States = "Texas" | "Alabama" | "California";'; + const expected = 'type States = "Texas" | "Alabama" | "California";'; const unionGenerator = new TypeScriptGenerator({ enumType: 'union' }); const inputModel = await unionGenerator.process(doc); @@ -324,7 +324,7 @@ ${content}`; $id: 'States', enum: [2, '2', 'test', true, { test: 'test' }] }; - const expected = `export enum States { + const expected = `enum States { NUMBER_2 = 2, STRING_2 = "2", TEST = "test", @@ -349,7 +349,7 @@ ${content}`; $id: 'States', enum: ['test+', 'test', 'test-', 'test?!', '*test'] }; - const expected = `export enum States { + const expected = `enum States { TEST_PLUS = "test+", TEST = "test", TEST_MINUS = "test-", @@ -375,7 +375,7 @@ ${content}`; type: 'string', enum: ['Texas', 'Alabama', 'California'], }; - const expected = `export enum CustomEnum { + const expected = `enum CustomEnum { TEXAS = "Texas", ALABAMA = "Alabama", CALIFORNIA = "California", @@ -410,7 +410,7 @@ ${content}`; $id: 'TypePrimitive', type: 'string', }; - const expected = 'export type TypePrimitive = string;'; + const expected = 'type TypePrimitive = string;'; const inputModel = await generator.process(doc); const model = inputModel.models['TypePrimitive']; @@ -429,7 +429,7 @@ ${content}`; $id: 'TypeEnum', enum: ['Texas', 'Alabama', 'California', 0, 1, false, true], }; - const expected = 'export type TypeEnum = "Texas" | "Alabama" | "California" | 0 | 1 | false | true;'; + const expected = 'type TypeEnum = "Texas" | "Alabama" | "California" | 0 | 1 | false | true;'; const inputModel = await generator.process(doc); const model = inputModel.models['TypeEnum']; @@ -444,7 +444,7 @@ ${content}`; $id: 'TypeUnion', type: ['string', 'number', 'boolean'], }; - const expected = 'export type TypeUnion = string | number | boolean;'; + const expected = 'type TypeUnion = string | number | boolean;'; const inputModel = await generator.process(doc); const model = inputModel.models['TypeUnion']; @@ -463,7 +463,7 @@ ${content}`; type: 'string', } }; - const expected = 'export type TypeArray = Array;'; + const expected = 'type TypeArray = Array;'; const inputModel = await generator.process(doc); const model = inputModel.models['TypeArray']; @@ -482,13 +482,12 @@ ${content}`; type: ['string', 'number', 'boolean'], } }; - const expected = 'export type TypeArray = Array;'; const inputModel = await generator.process(doc); const model = inputModel.models['TypeArray']; const arrayModel = await generator.renderType(model, inputModel); - expect(arrayModel.result).toEqual(expected); + expect(arrayModel.result).toMatchSnapshot(); expect(arrayModel.dependencies).toEqual([]); }); test('should render models and their dependencies', async () => { diff --git a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap index fbcb2cd8e7..be4bc80d81 100644 --- a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap +++ b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap @@ -1,9 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`TypeScriptGenerator should render \`type\` type - array of union type 1`] = `"type TypeArray = Array;"`; + exports[`TypeScriptGenerator should render models and their dependencies 1`] = ` "import ./OtherModel; -export class Address { +class Address { private _streetName: string; private _city: string; private _state: string; @@ -70,7 +72,7 @@ export class Address { exports[`TypeScriptGenerator should render models and their dependencies 2`] = ` " -export class OtherModel { +class OtherModel { private _streetName?: string; private _additionalProperties?: Map | boolean | null>; diff --git a/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap b/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap index cceb8847f5..72bb598db4 100644 --- a/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap +++ b/test/generators/typescript/preset/__snapshots__/ExamplePreset.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Example function generation should render example function for model 1`] = ` -"export class Test { +"class Test { private _stringProp: string; private _numberProp?: number; private _objectProp?: NestedTest; @@ -44,7 +44,7 @@ exports[`Example function generation should render example function for model 1` `; exports[`Example function generation should render example function for model 2`] = ` -"export class NestedTest { +"class NestedTest { private _stringProp?: string; private _additionalProperties?: Map | boolean | null>; diff --git a/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap b/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap index 2d63add859..fc1b58543f 100644 --- a/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap +++ b/test/generators/typescript/preset/__snapshots__/MarshallingPreset.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Marshalling preset should render un/marshal code 1`] = ` -"export class Test { +"class Test { private _stringProp: string; private _enumProp?: EnumTest; private _numberProp?: number; @@ -122,7 +122,7 @@ exports[`Marshalling preset should render un/marshal code 1`] = ` `; exports[`Marshalling preset should render un/marshal code 2`] = ` -"export class NestedTest { +"class NestedTest { private _stringProp?: string; private _additionalProperties?: Map | boolean | null>; From 120181d6a3de0c0e4f037acff87217f9e5e6dfab Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 4 Jan 2022 18:07:06 +0100 Subject: [PATCH 15/82] chore(release): v0.40.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdd4585ea8..2b6c1614c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.40.0", + "version": "0.40.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.40.0", + "version": "0.40.1", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 7dd62fa69c..4adc378b08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.40.0", + "version": "0.40.1", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From ef4c0b739f31893cd1320bc1e55c4f9dbc746eea Mon Sep 17 00:00:00 2001 From: Debajyoti Halder Date: Wed, 5 Jan 2022 01:45:41 +0530 Subject: [PATCH 16/82] fix: special cases in enum values for C# generator --- .../csharp/renderers/EnumRenderer.ts | 3 +- .../generators/csharp/CSharpGenerator.spec.ts | 29 ++++++-- .../CSharpGenerator.spec.ts.snap | 70 +++++++++++++++++++ 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/src/generators/csharp/renderers/EnumRenderer.ts b/src/generators/csharp/renderers/EnumRenderer.ts index c6bd978a50..75dd17504c 100644 --- a/src/generators/csharp/renderers/EnumRenderer.ts +++ b/src/generators/csharp/renderers/EnumRenderer.ts @@ -1,6 +1,7 @@ import { CSharpRenderer } from '../CSharpRenderer'; import { EnumPreset } from '../../../models'; import { pascalCase } from 'change-case'; +import { FormatHelpers } from '../../../helpers'; /** * Renderer for C#'s `enum` type @@ -107,7 +108,7 @@ export const CSHARP_DEFAULT_ENUM_PRESET: EnumPreset = { return renderer.defaultSelf(); }, item({ item }) { - let itemName = String(item); + let itemName = FormatHelpers.replaceSpecialCharacters(String(item), { exclude: [' '], separator: '_' }); if (typeof item === 'number' || typeof item === 'bigint') { itemName = `Number_${itemName}`; } else if (typeof item === 'object') { diff --git a/test/generators/csharp/CSharpGenerator.spec.ts b/test/generators/csharp/CSharpGenerator.spec.ts index f33fbdda12..a9e647a786 100644 --- a/test/generators/csharp/CSharpGenerator.spec.ts +++ b/test/generators/csharp/CSharpGenerator.spec.ts @@ -129,6 +129,25 @@ describe('CSharpGenerator', () => { enum: ['Texas', 'Alabama', 'California'], }; + const inputModel = await generator.process(doc); + const model = inputModel.models['CustomEnum']; + + let enumModel = await generator.render(model, inputModel); + expect(enumModel.result).toMatchSnapshot(); + expect(enumModel.dependencies).toEqual([]); + + enumModel = await generator.renderEnum(model, inputModel); + expect(enumModel.result).toMatchSnapshot(); + expect(enumModel.dependencies).toEqual([]); + }); + + test('should render enums with translated special characters', async () => { + const doc = { + $id: 'States', + type: 'string', + enum: ['test+', 'test', 'test-', 'test?!', '*test'] + }; + generator = new CSharpGenerator({ presets: [ { enum: { @@ -137,19 +156,20 @@ describe('CSharpGenerator', () => { }, } } - ] }); + ]}); const inputModel = await generator.process(doc); - const model = inputModel.models['CustomEnum']; - + const model = inputModel.models['States']; + let enumModel = await generator.render(model, inputModel); expect(enumModel.result).toMatchSnapshot(); expect(enumModel.dependencies).toEqual([]); - + enumModel = await generator.renderEnum(model, inputModel); expect(enumModel.result).toMatchSnapshot(); expect(enumModel.dependencies).toEqual([]); }); + test('should render models and their dependencies', async () => { const doc = { $id: 'Address', @@ -177,6 +197,7 @@ describe('CSharpGenerator', () => { expect(models[0].result).toMatchSnapshot(); expect(models[1].result).toMatchSnapshot(); }); + test('should throw error when reserved keyword is used for package name', async () => { const doc = { $id: 'Address', diff --git a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap index db1f0d2cd5..d20b4fa11a 100644 --- a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap +++ b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap @@ -320,6 +320,76 @@ public static class StatesExtensions { " `; +exports[`CSharpGenerator should render enums with translated special characters 1`] = ` +"public enum States { + TestPlus, Test, TestMinus, TestQuestionExclamation, AsteriskTest +} +public static class StatesExtensions { + public static dynamic GetValue(this States enumValue) + { + switch (enumValue) + { + case States.TestPlus: return \\"test+\\"; + case States.Test: return \\"test\\"; + case States.TestMinus: return \\"test-\\"; + case States.TestQuestionExclamation: return \\"test?!\\"; + case States.AsteriskTest: return \\"*test\\"; + } + return null; + } + + public static States? ToStates(dynamic value) + { + switch (value) + { + case \\"test+\\": return States.TestPlus; + case \\"test\\": return States.Test; + case \\"test-\\": return States.TestMinus; + case \\"test?!\\": return States.TestQuestionExclamation; + case \\"*test\\": return States.AsteriskTest; + } + return null; + } +} + +" +`; + +exports[`CSharpGenerator should render enums with translated special characters 2`] = ` +"public enum States { + TestPlus, Test, TestMinus, TestQuestionExclamation, AsteriskTest +} +public static class StatesExtensions { + public static dynamic GetValue(this States enumValue) + { + switch (enumValue) + { + case States.TestPlus: return \\"test+\\"; + case States.Test: return \\"test\\"; + case States.TestMinus: return \\"test-\\"; + case States.TestQuestionExclamation: return \\"test?!\\"; + case States.AsteriskTest: return \\"*test\\"; + } + return null; + } + + public static States? ToStates(dynamic value) + { + switch (value) + { + case \\"test+\\": return States.TestPlus; + case \\"test\\": return States.Test; + case \\"test-\\": return States.TestMinus; + case \\"test?!\\": return States.TestQuestionExclamation; + case \\"*test\\": return States.AsteriskTest; + } + return null; + } +} + +" +`; + exports[`CSharpGenerator should render models and their dependencies 1`] = ` "namespace Test.Package { From 8d9b7ffd11644e6af2d776ce8739254c09f9076d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 4 Jan 2022 21:24:52 +0100 Subject: [PATCH 17/82] docs: add ron-debajyoti as a contributor for code, test --- .all-contributorsrc | 10 ++++++++++ README.md | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index efdb4c695e..bbb7bc3b39 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -205,6 +205,16 @@ "test", "doc" ] + }, + { + "login": "ron-debajyoti", + "name": "Debajyoti Halder", + "avatar_url": "https://avatars.githubusercontent.com/u/22571664?v=4", + "profile": "https://github.com/ron-debajyoti", + "contributions": [ + "code", + "test" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 64159750a0..47e44bbddd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-18-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-) --- @@ -156,6 +156,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
quadrrem

πŸ’» ⚠️
Kamil Janeček

⚠️ πŸ› πŸ’»
mahakporwal02

πŸ’‘ ⚠️ πŸ“– +
Debajyoti Halder

πŸ’» ⚠️ From a897e07477ce39456b891df1f3fff868a9d66f3b Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Wed, 5 Jan 2022 08:29:27 +0100 Subject: [PATCH 18/82] chore(release): v0.40.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b6c1614c4..631e7f7147 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.40.1", + "version": "0.40.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.40.1", + "version": "0.40.2", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 4adc378b08..8480c44469 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.40.1", + "version": "0.40.2", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 11cc2c1b477ed7f3fe722dad739ea68936fcf5ae Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 5 Jan 2022 15:07:36 +0100 Subject: [PATCH 19/82] feat: add file output for C# generator (#537) --- docs/advanced.md | 4 +- src/generators/csharp/CSharpFileGenerator.ts | 24 +++++++++ src/generators/csharp/index.ts | 1 + .../csharp/CSharpFileGenerator.spec.ts | 51 +++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/generators/csharp/CSharpFileGenerator.ts create mode 100644 test/generators/csharp/CSharpFileGenerator.spec.ts diff --git a/docs/advanced.md b/docs/advanced.md index 1d22d8cc60..ada2edab6d 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -30,12 +30,12 @@ The reason for splitting the functionality is because in certain environments (l The file generators all follow the same pattern regardless of output language, which is the following format - `FileGenerator`. - Supported by: - Java +- C# - JavaScript -> Not support in browsers. +> It is not supported in browsers. Check out this [example out for a live demonstration](../examples/generate-to-files). diff --git a/src/generators/csharp/CSharpFileGenerator.ts b/src/generators/csharp/CSharpFileGenerator.ts new file mode 100644 index 0000000000..c8af7944d1 --- /dev/null +++ b/src/generators/csharp/CSharpFileGenerator.ts @@ -0,0 +1,24 @@ +import { CSharpGenerator, CSharpRenderCompleteModelOptions } from './'; +import { CommonInputModel, OutputModel } from '../../models'; +import * as path from 'path'; +import { AbstractFileGenerator } from '../AbstractFileGenerator'; +import { FileHelpers } from '../../helpers'; + +export class CSharpFileGenerator extends CSharpGenerator implements AbstractFileGenerator { + /** + * Generates all the models to an output directory each model with their own separate files. + * + * @param input + * @param outputDirectory where you want the models generated to + * @param options + */ + public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options: CSharpRenderCompleteModelOptions): Promise { + let generatedModels = await this.generateCompleteModels(input, options); + generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== undefined; }); + for (const outputModel of generatedModels) { + const filePath = path.resolve(outputDirectory, `${outputModel.modelName}.cs`); + await FileHelpers.writerToFileSystem(outputModel.result, filePath); + } + return generatedModels; + } +} diff --git a/src/generators/csharp/index.ts b/src/generators/csharp/index.ts index a65644089d..b0e1ace1b5 100644 --- a/src/generators/csharp/index.ts +++ b/src/generators/csharp/index.ts @@ -1,4 +1,5 @@ export * from './CSharpGenerator'; +export * from './CSharpFileGenerator'; export { CSHARP_DEFAULT_PRESET } from './CSharpPreset'; export type { CSharpPreset } from './CSharpPreset'; export * from './presets'; diff --git a/test/generators/csharp/CSharpFileGenerator.spec.ts b/test/generators/csharp/CSharpFileGenerator.spec.ts new file mode 100644 index 0000000000..181f3cb300 --- /dev/null +++ b/test/generators/csharp/CSharpFileGenerator.spec.ts @@ -0,0 +1,51 @@ +import { CommonInputModel, CommonModel, FileHelpers, CSharpFileGenerator, OutputModel } from '../../../src'; +import * as path from 'path'; + +describe('CSharpFileGenerator', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('generateToFile()', () => { + const doc = { + $id: 'CustomClass', + type: 'object', + additionalProperties: true, + properties: { + someProp: { type: 'string' }, + someEnum: { + $id: 'CustomEnum', + type: 'string', + enum: ['Texas', 'Alabama', 'California'], + } + } + }; + test('should throw accurate error if file cannot be written', async () => { + const generator = new CSharpFileGenerator(); + const expectedError = new Error('write error'); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockRejectedValue(expectedError); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + + await expect(generator.generateToFiles(doc, '/test/', {namespace: 'SomeNamespace'})).rejects.toEqual(expectedError); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + }); + test('should try and generate models to files', async () => { + const generator = new CSharpFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + const expectedOutputFilePath = path.resolve(`${outputDir}/Test.cs`); + const expectedWriteToFileParameters = [ + 'content', + expectedOutputFilePath, + ]; + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); + + await generator.generateToFiles(doc, expectedOutputDirPath, {namespace: 'SomeNamespace'}); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + expect((FileHelpers.writerToFileSystem as jest.Mock).mock.calls[0]).toEqual(expectedWriteToFileParameters); + }); + }); +}); From d4ed0e3f75b81179394a28a1764f8405b18df4a9 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Wed, 5 Jan 2022 15:20:05 +0100 Subject: [PATCH 20/82] chore(release): v0.41.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 631e7f7147..068bcd7871 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.40.2", + "version": "0.41.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.40.2", + "version": "0.41.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 8480c44469..405cf3e91e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.40.2", + "version": "0.41.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 5cbe3622d9f9081370a6139df0f7d27e7d9ed562 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Fri, 7 Jan 2022 14:30:05 +0100 Subject: [PATCH 21/82] feat: add file output for TypeScript generator (#536) --- docs/advanced.md | 1 + docs/languages/TypeScript.md | 9 ++ examples/README.md | 2 + .../__snapshots__/index.spec.ts.snap | 12 +- examples/javascript-use-esm/package.json | 2 +- examples/typescript-use-cjs/README.md | 17 +++ .../__snapshots__/index.spec.ts.snap | 41 +++++++ examples/typescript-use-cjs/index.spec.ts | 15 +++ examples/typescript-use-cjs/index.ts | 33 ++++++ examples/typescript-use-cjs/package-lock.json | 10 ++ examples/typescript-use-cjs/package.json | 10 ++ examples/typescript-use-esm/README.md | 17 +++ .../__snapshots__/index.spec.ts.snap | 43 ++++++++ examples/typescript-use-esm/index.spec.ts | 15 +++ examples/typescript-use-esm/index.ts | 33 ++++++ examples/typescript-use-esm/package-lock.json | 10 ++ examples/typescript-use-esm/package.json | 10 ++ .../javascript/JavaScriptFileGenerator.ts | 3 +- .../javascript/JavaScriptGenerator.ts | 17 ++- .../typescript/TypeScriptFileGenerator.ts | 25 +++++ .../typescript/TypeScriptGenerator.ts | 38 +++++-- src/generators/typescript/index.ts | 1 + src/models/CommonModel.ts | 4 +- test/blackbox/blackbox.spec.ts | 70 +++++++----- .../JavaScriptFileGenerator.spec.ts | 14 ++- .../JavaScriptGenerator.spec.ts.snap | 12 +- .../TypeScriptFileGenerator.spec.ts | 64 +++++++++++ .../typescript/TypeScriptGenerator.spec.ts | 30 ++++- .../TypeScriptGenerator.spec.ts.snap | 104 +++++++++++++++++- test/models/CommonModel.spec.ts | 5 + 30 files changed, 605 insertions(+), 62 deletions(-) create mode 100644 examples/typescript-use-cjs/README.md create mode 100644 examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap create mode 100644 examples/typescript-use-cjs/index.spec.ts create mode 100644 examples/typescript-use-cjs/index.ts create mode 100644 examples/typescript-use-cjs/package-lock.json create mode 100644 examples/typescript-use-cjs/package.json create mode 100644 examples/typescript-use-esm/README.md create mode 100644 examples/typescript-use-esm/__snapshots__/index.spec.ts.snap create mode 100644 examples/typescript-use-esm/index.spec.ts create mode 100644 examples/typescript-use-esm/index.ts create mode 100644 examples/typescript-use-esm/package-lock.json create mode 100644 examples/typescript-use-esm/package.json create mode 100644 src/generators/typescript/TypeScriptFileGenerator.ts create mode 100644 test/generators/typescript/TypeScriptFileGenerator.spec.ts diff --git a/docs/advanced.md b/docs/advanced.md index ada2edab6d..37828803bb 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -32,6 +32,7 @@ The file generators all follow the same pattern regardless of output language, w Supported by: - Java +- TypeScript - C# - JavaScript diff --git a/docs/languages/TypeScript.md b/docs/languages/TypeScript.md index 41cd299f74..a1c0f747a2 100644 --- a/docs/languages/TypeScript.md +++ b/docs/languages/TypeScript.md @@ -10,6 +10,7 @@ There are special use-cases that each language supports; this document pertains - [Generate union types instead of enums](#generate-union-types-instead-of-enums) - [Generate un/marshal functions for classes](#generate-unmarshal-functions-for-classes) - [Generate example data function](#generate-example-data-function) +- [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) @@ -50,3 +51,11 @@ You might stumble upon a user case (we had one in code generation) where you wan This can be done by including the preset `TS_COMMON_PRESET` using the option `example`. Check out this [example out for a live demonstration](../../examples/typescript-generate-example). + + +## Rendering complete models to a specific module system +In some cases you might need to render the complete models to a specific module system such as ESM and CJS. + +Check out this [example for a live demonstration how to generate the complete TypeScript models to use ESM module system](../../examples/typescript-use-esm). + +Check out this [example for a live demonstration how to generate the complete TypeScript models to use CJS module system](../../examples/typescript-use-cjs). \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 354dd6ebe9..31aad40eb8 100644 --- a/examples/README.md +++ b/examples/README.md @@ -7,6 +7,8 @@ This directory contains a series of self-contained examples that you can use as - [typescript-enum-type](./typescript-enum-type) - A basic example of how to use Modelina can output different types of enums in TypeScript. - [typescript-generate-marshalling](./typescript-generate-marshalling) - A basic example of how to use the un/marshalling functionality of the typescript class. - [typescript-generate-example](./typescript-generate-example) - A basic example of how to use Modelina and output a TypeScript class with an example function. +- [typescript-use-esm](./typescript-use-esm) - A basic example that generate the models to use ESM module system. +- [typescript-use-cjs](./typescript-use-cjs) - A basic example that generate the models to use CJS module system. - [indentation-type-and-size](./indentation-type-and-size) - This example shows how to change the indentation type and size of the generated model. - [asyncapi-from-object](./asyncapi-from-object) - A basic example where an AsyncAPI JS object is used to generate models. - [asyncapi-from-parser](./asyncapi-from-parser) - A basic example where an AsyncAPI JS object from the [parser-js](https://github.com/asyncapi/parser-js) is used to generate models. diff --git a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap index db83a4c71e..a3ac3f59c3 100644 --- a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap +++ b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap @@ -4,7 +4,7 @@ exports[`Should be able to render models to ESM module system and should log exp Array [ " -export default class Person { +class Person { email; constructor(input) { @@ -13,7 +13,9 @@ export default class Person { get email() { return this.email; } set email(email) { this.email = email; } -}", +} +export default Person; +", ] `; @@ -21,7 +23,7 @@ exports[`Should be able to render models to ESM module system and should log exp Array [ "import Person from './Person'; -export default class Root { +class Root { person; constructor(input) { @@ -30,6 +32,8 @@ export default class Root { get person() { return this.person; } set person(person) { this.person = person; } -}", +} +export default Root; +", ] `; diff --git a/examples/javascript-use-esm/package.json b/examples/javascript-use-esm/package.json index f353147d0d..1a007e3c7d 100644 --- a/examples/javascript-use-esm/package.json +++ b/examples/javascript-use-esm/package.json @@ -1,5 +1,5 @@ { - "config" : { "example_name" : "javascript-module-system" }, + "config" : { "example_name" : "javascript-use-esm" }, "scripts": { "install": "cd ../.. && npm i", "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", diff --git a/examples/typescript-use-cjs/README.md b/examples/typescript-use-cjs/README.md new file mode 100644 index 0000000000..9773c49608 --- /dev/null +++ b/examples/typescript-use-cjs/README.md @@ -0,0 +1,17 @@ +# TypeScript models use CJS module system + +This example shows how you can generate the models to use CJS module system. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap b/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..6945ed97ff --- /dev/null +++ b/examples/typescript-use-cjs/__snapshots__/index.spec.ts.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = ` +Array [ + " + +class Person { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } +} +module.exports = Person;", +] +`; + +exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = ` +Array [ + "const Person = require('./Person'); + +class Root { + private _person?: Person; + + constructor(input: { + person?: Person, + }) { + this._person = input.person; + } + + get person(): Person | undefined { return this._person; } + set person(person: Person | undefined) { this._person = person; } +} +module.exports = Root;", +] +`; diff --git a/examples/typescript-use-cjs/index.spec.ts b/examples/typescript-use-cjs/index.spec.ts new file mode 100644 index 0000000000..1bdece5160 --- /dev/null +++ b/examples/typescript-use-cjs/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render models to ESM module system', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 2 models, we double it + expect(spy.mock.calls.length).toEqual(4); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + }); +}); diff --git a/examples/typescript-use-cjs/index.ts b/examples/typescript-use-cjs/index.ts new file mode 100644 index 0000000000..99d4db931b --- /dev/null +++ b/examples/typescript-use-cjs/index.ts @@ -0,0 +1,33 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + person: { + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } +}; + +export async function generate() : Promise { + const models = await generator.generateCompleteModels( + jsonSchemaDraft7, + { + moduleSystem: 'CJS' + } + ); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/typescript-use-cjs/package-lock.json b/examples/typescript-use-cjs/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/typescript-use-cjs/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/typescript-use-cjs/package.json b/examples/typescript-use-cjs/package.json new file mode 100644 index 0000000000..ed80a11475 --- /dev/null +++ b/examples/typescript-use-cjs/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "typescript-use-cjs" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/examples/typescript-use-esm/README.md b/examples/typescript-use-esm/README.md new file mode 100644 index 0000000000..41374abd28 --- /dev/null +++ b/examples/typescript-use-esm/README.md @@ -0,0 +1,17 @@ +# TypeScript models use ESM module system + +This example shows how you can generate the models to use ESM module system. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap b/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..a8f1b84637 --- /dev/null +++ b/examples/typescript-use-esm/__snapshots__/index.spec.ts.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render models to ESM module system and should log expected output to console 1`] = ` +Array [ + " + +class Person { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } +} +export default Person; +", +] +`; + +exports[`Should be able to render models to ESM module system and should log expected output to console 2`] = ` +Array [ + "import Person from './Person'; + +class Root { + private _person?: Person; + + constructor(input: { + person?: Person, + }) { + this._person = input.person; + } + + get person(): Person | undefined { return this._person; } + set person(person: Person | undefined) { this._person = person; } +} +export default Root; +", +] +`; diff --git a/examples/typescript-use-esm/index.spec.ts b/examples/typescript-use-esm/index.spec.ts new file mode 100644 index 0000000000..1bdece5160 --- /dev/null +++ b/examples/typescript-use-esm/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render models to ESM module system', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 2 models, we double it + expect(spy.mock.calls.length).toEqual(4); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + }); +}); diff --git a/examples/typescript-use-esm/index.ts b/examples/typescript-use-esm/index.ts new file mode 100644 index 0000000000..dfda3d7cc0 --- /dev/null +++ b/examples/typescript-use-esm/index.ts @@ -0,0 +1,33 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + person: { + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } + } + } +}; + +export async function generate() : Promise { + const models = await generator.generateCompleteModels( + jsonSchemaDraft7, + { + moduleSystem: 'ESM' + } + ); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/typescript-use-esm/package-lock.json b/examples/typescript-use-esm/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/typescript-use-esm/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/typescript-use-esm/package.json b/examples/typescript-use-esm/package.json new file mode 100644 index 0000000000..82dbb498f8 --- /dev/null +++ b/examples/typescript-use-esm/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "typescript-use-esm" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/src/generators/javascript/JavaScriptFileGenerator.ts b/src/generators/javascript/JavaScriptFileGenerator.ts index 39af296e4a..b102a4fcd2 100644 --- a/src/generators/javascript/JavaScriptFileGenerator.ts +++ b/src/generators/javascript/JavaScriptFileGenerator.ts @@ -14,7 +14,8 @@ export class JavaScriptFileGenerator extends JavaScriptGenerator implements Abst */ public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options?: JavaScriptRenderCompleteModelOptions): Promise { let generatedModels = await this.generateCompleteModels(input, options || {}); - generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== undefined; }); + //Filter anything out that have not been successfully generated + generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== ''; }); for (const outputModel of generatedModels) { const filePath = path.resolve(outputDirectory, `${outputModel.modelName}.js`); await FileHelpers.writerToFileSystem(outputModel.result, filePath); diff --git a/src/generators/javascript/JavaScriptGenerator.ts b/src/generators/javascript/JavaScriptGenerator.ts index 9ae436230c..397e214912 100644 --- a/src/generators/javascript/JavaScriptGenerator.ts +++ b/src/generators/javascript/JavaScriptGenerator.ts @@ -42,14 +42,25 @@ export class JavaScriptGenerator extends AbstractGenerator { const outputModel = await this.render(model, inputModel); - const modelDependencies = model.getNearestDependencies().map((dependencyModelName) => { - const formattedDependencyModelName = this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { inputModel, model: inputModel.models[String(dependencyModelName)] }) : dependencyModelName; + let modelDependencies = model.getNearestDependencies(); + //Ensure model dependencies have their rendered name + modelDependencies = modelDependencies.map((dependencyModelName) => { + return this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { inputModel, model: inputModel.models[String(dependencyModelName)] }) : dependencyModelName; + }); + //Filter out any dependencies that is recursive to it'self + modelDependencies = modelDependencies.filter((dependencyModelName) => { + return dependencyModelName !== outputModel.renderedName; + }); + //Create the correct dependency imports + modelDependencies = modelDependencies.map((formattedDependencyModelName) => { if (options.moduleSystem === 'CJS') { return `const ${formattedDependencyModelName} = require('./${formattedDependencyModelName}');`; } return `import ${formattedDependencyModelName} from './${formattedDependencyModelName}';`; }); - let modelCode = `export default ${outputModel.result}`; + let modelCode = `${outputModel.result} +export default ${outputModel.renderedName}; +`; if (options.moduleSystem === 'CJS') { modelCode = `${outputModel.result} module.exports = ${outputModel.renderedName};`; diff --git a/src/generators/typescript/TypeScriptFileGenerator.ts b/src/generators/typescript/TypeScriptFileGenerator.ts new file mode 100644 index 0000000000..c594f3f511 --- /dev/null +++ b/src/generators/typescript/TypeScriptFileGenerator.ts @@ -0,0 +1,25 @@ +import { TypeScriptGenerator, TypeScriptRenderCompleteModelOptions } from './'; +import { CommonInputModel, OutputModel } from '../../models'; +import * as path from 'path'; +import { AbstractFileGenerator } from '../AbstractFileGenerator'; +import { FileHelpers } from '../../helpers'; + +export class TypeScriptFileGenerator extends TypeScriptGenerator implements AbstractFileGenerator { + /** + * Generates all the models to an output directory each model with their own separate files. + * + * @param input + * @param outputDirectory where you want the models generated to + * @param options + */ + public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options?: TypeScriptRenderCompleteModelOptions): Promise { + let generatedModels = await this.generateCompleteModels(input, options || {}); + //Filter anything out that have not been successfully generated + generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== ''; }); + for (const outputModel of generatedModels) { + const filePath = path.resolve(outputDirectory, `${outputModel.modelName}.ts`); + await FileHelpers.writerToFileSystem(outputModel.result, filePath); + } + return generatedModels; + } +} diff --git a/src/generators/typescript/TypeScriptGenerator.ts b/src/generators/typescript/TypeScriptGenerator.ts index 8d9bf8f8b8..e9ab9261fd 100644 --- a/src/generators/typescript/TypeScriptGenerator.ts +++ b/src/generators/typescript/TypeScriptGenerator.ts @@ -17,9 +17,8 @@ export interface TypeScriptOptions extends CommonGeneratorOptions { const outputModel = await this.render(model, inputModel); - const modelDependencies = model.getNearestDependencies().map((dependencyModelName) => { - const formattedDependencyModelName = this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { inputModel, model: inputModel.models[String(dependencyModelName)] }) : dependencyModelName; - return `import ./${formattedDependencyModelName};`; + let modelDependencies = model.getNearestDependencies(); + //Ensure model dependencies have their rendered name + modelDependencies = modelDependencies.map((dependencyModelName) => { + return this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, { inputModel, model: inputModel.models[String(dependencyModelName)] }) : dependencyModelName; + }); + //Filter out any dependencies that is recursive to itself + modelDependencies = modelDependencies.filter((dependencyModelName) => { + return dependencyModelName !== outputModel.renderedName; + }); + //Create the correct dependency imports + modelDependencies = modelDependencies.map((formattedDependencyModelName) => { + if (options.moduleSystem === 'CJS') { + return `const ${formattedDependencyModelName} = require('./${formattedDependencyModelName}');`; + } + return `import ${formattedDependencyModelName} from './${formattedDependencyModelName}';`; }); - const outputContent = `${modelDependencies.join('\n')} -${outputModel.dependencies.join('\n')} -${outputModel.result}`; + + //Ensure we expose the model correctly, based on the module system + let modelCode = `${outputModel.result} +export default ${outputModel.renderedName}; +`; + if (options.moduleSystem === 'CJS') { + modelCode = `${outputModel.result} +module.exports = ${outputModel.renderedName};`; + } + + const outputContent = `${[...modelDependencies, ...outputModel.dependencies].join('\n')} + +${modelCode}`; return RenderOutput.toRenderOutput({ result: outputContent, renderedName: outputModel.renderedName, dependencies: outputModel.dependencies }); } diff --git a/src/generators/typescript/index.ts b/src/generators/typescript/index.ts index 45d338aeeb..99b8ed1cf9 100644 --- a/src/generators/typescript/index.ts +++ b/src/generators/typescript/index.ts @@ -1,4 +1,5 @@ export * from './TypeScriptGenerator'; +export * from './TypeScriptFileGenerator'; export { TS_DEFAULT_PRESET } from './TypeScriptPreset'; export type { TypeScriptPreset } from './TypeScriptPreset'; export * from './presets'; diff --git a/src/models/CommonModel.ts b/src/models/CommonModel.ts index f3c0ac39df..58521bde7f 100644 --- a/src/models/CommonModel.ts +++ b/src/models/CommonModel.ts @@ -316,7 +316,7 @@ export class CommonModel { } /** - * This function returns an array of `$id`s from all the CommonModel's it immediate depends on. + * Returns an array of unique `$id`s from all the CommonModel's this model depends on. */ // eslint-disable-next-line sonarjs/cognitive-complexity getNearestDependencies(): string[] { @@ -351,7 +351,7 @@ export class CommonModel { if (this.additionalItems !== undefined) { dependsOn.push(...this.additionalItems.getNearestDependencies()); } - return dependsOn; + return [...new Set(dependsOn)]; } /** diff --git a/test/blackbox/blackbox.spec.ts b/test/blackbox/blackbox.spec.ts index 9498a93e06..0d0d6a71ff 100644 --- a/test/blackbox/blackbox.spec.ts +++ b/test/blackbox/blackbox.spec.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as fs from 'fs'; -import { TypeScriptGenerator, JavaScriptGenerator, GoGenerator, CSharpGenerator, JavaFileGenerator, JAVA_COMMON_PRESET } from '../../src'; +import { TypeScriptGenerator, JavaScriptGenerator, GoGenerator, CSharpGenerator, JavaFileGenerator, JAVA_COMMON_PRESET, TypeScriptFileGenerator, JavaScriptFileGenerator } from '../../src'; import { execCommand, generateModels, renderModels, renderModelsToSeparateFiles } from './utils/Utils'; /** @@ -138,39 +138,49 @@ describe.each(filesToTest)('Should be able to generate with inputs', ({file, out }); }); - // describe('should be able to generate and transpile TS', () => { - // test('class', async () => { - // const generator = new TypeScriptGenerator(); - // const generatedModels = await generateModels(fileToGenerateFor, generator); - // expect(generatedModels).not.toHaveLength(0); - // const renderOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.ts'); - // await renderModels(generatedModels, renderOutputPath); - // const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/class/output.js'); - // const transpileAndRunCommand = `tsc --downlevelIteration -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; - // await execCommand(transpileAndRunCommand); - // }); - - // test('interface', async () => { - // const generator = new TypeScriptGenerator({modelType: 'interface'}); - // const generatedModels = await generateModels(fileToGenerateFor, generator); - // expect(generatedModels).not.toHaveLength(0); - // const renderOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.ts'); - // await renderModels(generatedModels, renderOutputPath); - // const transpiledOutputPath = path.resolve(outputDirectoryPath, './ts/interface/output.js'); - // const transpileAndRunCommand = `tsc -t es5 ${renderOutputPath} && node ${transpiledOutputPath}`; - // await execCommand(transpileAndRunCommand); - // }); - // }); + describe('should be able to generate and transpile TS', () => { + test('class', async () => { + const generator = new TypeScriptFileGenerator({modelType: 'class'}); + const inputFileContent = await fs.promises.readFile(fileToGenerateFor); + const input = JSON.parse(String(inputFileContent)); + const renderOutputPath = path.resolve(outputDirectoryPath, './ts/class'); + + const generatedModels = await generator.generateToFiles(input, renderOutputPath); + expect(generatedModels).not.toHaveLength(0); + + const transpileCommand = `tsc --downlevelIteration -t es5 --baseUrl ${renderOutputPath}`; + await execCommand(transpileCommand); + }); + + test('interface', async () => { + const generator = new TypeScriptFileGenerator({modelType: 'interface'}); + const inputFileContent = await fs.promises.readFile(fileToGenerateFor); + const input = JSON.parse(String(inputFileContent)); + const renderOutputPath = path.resolve(outputDirectoryPath, './ts/interface'); + + const generatedModels = await generator.generateToFiles(input, renderOutputPath); + expect(generatedModels).not.toHaveLength(0); + + const transpileCommand = `tsc --downlevelIteration -t es5 --baseUrl ${renderOutputPath}`; + await execCommand(transpileCommand); + }); + }); describe('should be able to generate JS', () => { test('class', async () => { - const generator = new JavaScriptGenerator(); - const generatedModels = await generateModels(fileToGenerateFor, generator); + const generator = new JavaScriptFileGenerator(); + const inputFileContent = await fs.promises.readFile(fileToGenerateFor); + const input = JSON.parse(String(inputFileContent)); + const renderOutputPath = path.resolve(outputDirectoryPath, './js/class'); + + const generatedModels = await generator.generateToFiles(input, renderOutputPath, {moduleSystem: 'CJS'}); expect(generatedModels).not.toHaveLength(0); - const renderOutputPath = path.resolve(outputDirectoryPath, './js/class/output.js'); - await renderModels(generatedModels, renderOutputPath); - const transpileAndRunCommand = `node ${renderOutputPath}`; - await execCommand(transpileAndRunCommand); + + const files = fs.readdirSync(renderOutputPath); + for (const file of files) { + const transpileAndRunCommand = `node --check ${path.resolve(renderOutputPath, file)}`; + await execCommand(transpileAndRunCommand); + } }); }); diff --git a/test/generators/javascript/JavaScriptFileGenerator.spec.ts b/test/generators/javascript/JavaScriptFileGenerator.spec.ts index 69a4803f9c..074201be9e 100644 --- a/test/generators/javascript/JavaScriptFileGenerator.spec.ts +++ b/test/generators/javascript/JavaScriptFileGenerator.spec.ts @@ -24,7 +24,7 @@ describe('JavaScriptFileGenerator', () => { const generator = new JavaScriptFileGenerator(); const expectedError = new Error('write error'); jest.spyOn(FileHelpers, 'writerToFileSystem').mockRejectedValue(expectedError); - jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); await expect(generator.generateToFiles(doc, '/test/')).rejects.toEqual(expectedError); expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); @@ -47,5 +47,17 @@ describe('JavaScriptFileGenerator', () => { expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); expect((FileHelpers.writerToFileSystem as jest.Mock).mock.calls[0]).toEqual(expectedWriteToFileParameters); }); + test('should ignore models that have not been rendered', async () => { + const generator = new JavaScriptFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + + const models = await generator.generateToFiles(doc, expectedOutputDirPath); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(0); + expect(models).toHaveLength(0); + }); }); }); diff --git a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap index 8ff9e784e6..4148edbb30 100644 --- a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap +++ b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap @@ -82,7 +82,7 @@ module.exports = OtherModel;" exports[`JavaScriptGenerator should render models and their dependencies for ESM module system 1`] = ` "import OtherModel from './OtherModel'; -export default class Address { +class Address { streetName; city; state; @@ -134,13 +134,15 @@ export default class Address { get sTestPatternProperties() { return this.sTestPatternProperties; } set sTestPatternProperties(sTestPatternProperties) { this.sTestPatternProperties = sTestPatternProperties; } -}" +} +export default Address; +" `; exports[`JavaScriptGenerator should render models and their dependencies for ESM module system 2`] = ` " -export default class OtherModel { +class OtherModel { streetName; additionalProperties; @@ -153,5 +155,7 @@ export default class OtherModel { get additionalProperties() { return this.additionalProperties; } set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } -}" +} +export default OtherModel; +" `; diff --git a/test/generators/typescript/TypeScriptFileGenerator.spec.ts b/test/generators/typescript/TypeScriptFileGenerator.spec.ts new file mode 100644 index 0000000000..cad65e642b --- /dev/null +++ b/test/generators/typescript/TypeScriptFileGenerator.spec.ts @@ -0,0 +1,64 @@ +import { CommonInputModel, CommonModel, FileHelpers, TypeScriptFileGenerator, OutputModel } from '../../../src'; +import * as path from 'path'; + +describe('TypeScriptFileGenerator', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('generateToFile()', () => { + const doc = { + $id: 'CustomClass', + type: 'object', + additionalProperties: true, + properties: { + someProp: { type: 'string' }, + someEnum: { + $id: 'CustomEnum', + type: 'string', + enum: ['Texas', 'Alabama', 'California'], + } + } + }; + test('should throw accurate error if file cannot be written', async () => { + const generator = new TypeScriptFileGenerator(); + const expectedError = new Error('write error'); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockRejectedValue(expectedError); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); + + await expect(generator.generateToFiles(doc, '/test/')).rejects.toEqual(expectedError); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + }); + test('should try and generate models to files', async () => { + const generator = new TypeScriptFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + const expectedOutputFilePath = path.resolve(`${outputDir}/Test.ts`); + const expectedWriteToFileParameters = [ + 'content', + expectedOutputFilePath, + ]; + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); + + await generator.generateToFiles(doc, expectedOutputDirPath); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + expect((FileHelpers.writerToFileSystem as jest.Mock).mock.calls[0]).toEqual(expectedWriteToFileParameters); + }); + + test('should ignore models that have not been rendered', async () => { + const generator = new TypeScriptFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + + const models = await generator.generateToFiles(doc, expectedOutputDirPath); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(0); + expect(models).toHaveLength(0); + }); + }); +}); diff --git a/test/generators/typescript/TypeScriptGenerator.spec.ts b/test/generators/typescript/TypeScriptGenerator.spec.ts index cb4e09e360..0be7f7ae97 100644 --- a/test/generators/typescript/TypeScriptGenerator.spec.ts +++ b/test/generators/typescript/TypeScriptGenerator.spec.ts @@ -490,7 +490,7 @@ ${content}`; expect(arrayModel.result).toMatchSnapshot(); expect(arrayModel.dependencies).toEqual([]); }); - test('should render models and their dependencies', async () => { + test('should render models and their dependencies for CJS module system', async () => { const doc = { $id: 'Address', type: 'object', @@ -511,7 +511,33 @@ ${content}`; }, required: ['street_name', 'city', 'state', 'house_number', 'array_type'], }; - const models = await generator.generateCompleteModels(doc, {}); + const models = await generator.generateCompleteModels(doc, {moduleSystem: 'CJS'}); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); + test('should render models and their dependencies for ESM module system', async () => { + const doc = { + $id: 'Address', + type: 'object', + properties: { + street_name: { type: 'string' }, + city: { type: 'string', description: 'City description' }, + state: { type: 'string' }, + house_number: { type: 'number' }, + marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, + members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, + array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } } }, + }, + patternProperties: { + '^S(.?*)test&': { + type: 'string' + } + }, + required: ['street_name', 'city', 'state', 'house_number', 'array_type'], + }; + const models = await generator.generateCompleteModels(doc, {moduleSystem: 'ESM'}); expect(models).toHaveLength(2); expect(models[0].result).toMatchSnapshot(); expect(models[1].result).toMatchSnapshot(); diff --git a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap index be4bc80d81..7d5cebb9dd 100644 --- a/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap +++ b/test/generators/typescript/__snapshots__/TypeScriptGenerator.spec.ts.snap @@ -2,8 +2,8 @@ exports[`TypeScriptGenerator should render \`type\` type - array of union type 1`] = `"type TypeArray = Array;"`; -exports[`TypeScriptGenerator should render models and their dependencies 1`] = ` -"import ./OtherModel; +exports[`TypeScriptGenerator should render models and their dependencies for CJS module system 1`] = ` +"const OtherModel = require('./OtherModel'); class Address { private _streetName: string; @@ -66,10 +66,11 @@ class Address { get sTestPatternProperties(): Map | undefined { return this._sTestPatternProperties; } set sTestPatternProperties(sTestPatternProperties: Map | undefined) { this._sTestPatternProperties = sTestPatternProperties; } -}" +} +module.exports = Address;" `; -exports[`TypeScriptGenerator should render models and their dependencies 2`] = ` +exports[`TypeScriptGenerator should render models and their dependencies for CJS module system 2`] = ` " class OtherModel { @@ -87,5 +88,98 @@ class OtherModel { get additionalProperties(): Map | boolean | null> | undefined { return this._additionalProperties; } set additionalProperties(additionalProperties: Map | boolean | null> | undefined) { this._additionalProperties = additionalProperties; } -}" +} +module.exports = OtherModel;" +`; + +exports[`TypeScriptGenerator should render models and their dependencies for ESM module system 1`] = ` +"import OtherModel from './OtherModel'; + +class Address { + private _streetName: string; + private _city: string; + private _state: string; + private _houseNumber: number; + private _marriage?: boolean; + private _members?: string | number | boolean; + private _arrayType: [string, number, ...(object | string | number | Array | boolean | null)[]]; + private _otherModel?: OtherModel; + private _additionalProperties?: Map | boolean | null>; + private _sTestPatternProperties?: Map; + + constructor(input: { + streetName: string, + city: string, + state: string, + houseNumber: number, + marriage?: boolean, + members?: string | number | boolean, + arrayType: [string, number, ...(object | string | number | Array | boolean | null)[]], + otherModel?: OtherModel, + }) { + this._streetName = input.streetName; + this._city = input.city; + this._state = input.state; + this._houseNumber = input.houseNumber; + this._marriage = input.marriage; + this._members = input.members; + this._arrayType = input.arrayType; + this._otherModel = input.otherModel; + } + + get streetName(): string { return this._streetName; } + set streetName(streetName: string) { this._streetName = streetName; } + + get city(): string { return this._city; } + set city(city: string) { this._city = city; } + + get state(): string { return this._state; } + set state(state: string) { this._state = state; } + + get houseNumber(): number { return this._houseNumber; } + set houseNumber(houseNumber: number) { this._houseNumber = houseNumber; } + + get marriage(): boolean | undefined { return this._marriage; } + set marriage(marriage: boolean | undefined) { this._marriage = marriage; } + + get members(): string | number | boolean | undefined { return this._members; } + set members(members: string | number | boolean | undefined) { this._members = members; } + + get arrayType(): [string, number, ...(object | string | number | Array | boolean | null)[]] { return this._arrayType; } + set arrayType(arrayType: [string, number, ...(object | string | number | Array | boolean | null)[]]) { this._arrayType = arrayType; } + + get otherModel(): OtherModel | undefined { return this._otherModel; } + set otherModel(otherModel: OtherModel | undefined) { this._otherModel = otherModel; } + + get additionalProperties(): Map | boolean | null> | undefined { return this._additionalProperties; } + set additionalProperties(additionalProperties: Map | boolean | null> | undefined) { this._additionalProperties = additionalProperties; } + + get sTestPatternProperties(): Map | undefined { return this._sTestPatternProperties; } + set sTestPatternProperties(sTestPatternProperties: Map | undefined) { this._sTestPatternProperties = sTestPatternProperties; } +} +export default Address; +" +`; + +exports[`TypeScriptGenerator should render models and their dependencies for ESM module system 2`] = ` +" + +class OtherModel { + private _streetName?: string; + private _additionalProperties?: Map | boolean | null>; + + constructor(input: { + streetName?: string, + }) { + this._streetName = input.streetName; + } + + get streetName(): string | undefined { return this._streetName; } + set streetName(streetName: string | undefined) { this._streetName = streetName; } + + get additionalProperties(): Map | boolean | null> | undefined { return this._additionalProperties; } + set additionalProperties(additionalProperties: Map | boolean | null> | undefined) { this._additionalProperties = additionalProperties; } +} +export default OtherModel; +" `; diff --git a/test/models/CommonModel.spec.ts b/test/models/CommonModel.spec.ts index 9a8db8785f..d69522a2d6 100644 --- a/test/models/CommonModel.spec.ts +++ b/test/models/CommonModel.spec.ts @@ -908,6 +908,11 @@ describe('CommonModel', () => { const d = CommonModel.toCommonModel(doc); expect(d.getNearestDependencies()).toEqual([]); }); + test('should not return duplicate dependencies', () => { + const doc = { properties: { test1: { $ref: '1' }, test2: { $ref: '1' } } }; + const d = CommonModel.toCommonModel(doc); + expect(d.getNearestDependencies()).toEqual(['1']); + }); }); }); }); From 623dcb2fc66c4e6f2ec85b0339db84ee237c2113 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Fri, 7 Jan 2022 14:46:25 +0100 Subject: [PATCH 22/82] chore(release): v0.42.0 --- API.md | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/API.md b/API.md index d2bfdb5c06..d3748d4f06 100644 --- a/API.md +++ b/API.md @@ -466,7 +466,7 @@ It is only allowed to extend if the other model have $id and is not already bein ### commonModel.getNearestDependencies() -This function returns an array of `$id`s from all the CommonModel's it immediate depends on. +Returns an array of unique `$id`s from all the CommonModel's this model depends on. **Kind**: instance method of [CommonModel](#CommonModel) diff --git a/package-lock.json b/package-lock.json index 068bcd7871..4fec2d3539 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.41.0", + "version": "0.42.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.41.0", + "version": "0.42.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 405cf3e91e..4683316e20 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.41.0", + "version": "0.42.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 7b5966e19f9a568fb1d9375041d17b08831bace4 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 10 Jan 2022 14:51:32 +0100 Subject: [PATCH 23/82] ci: update global workflows --- .../workflows/add-good-first-issue-labels.yml | 68 +++++++++++++++++++ .github/workflows/help-command.yml | 23 +++++-- 2 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/add-good-first-issue-labels.yml diff --git a/.github/workflows/add-good-first-issue-labels.yml b/.github/workflows/add-good-first-issue-labels.yml new file mode 100644 index 0000000000..3b816b6314 --- /dev/null +++ b/.github/workflows/add-good-first-issue-labels.yml @@ -0,0 +1,68 @@ +#This workflow is centrally managed in https://github.com/asyncapi/.github/ +#Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +#Purpose of this workflow is to enable anyone to label issue with 'Good First Issue' and 'area/*' with a single command. +name: Add 'Good First Issue' and 'area/*' labels # if proper comment added + +on: + issue_comment: + types: + - created + +jobs: + add-labels: + if: github.event.issue && github.event.issue.state != 'closed' + runs-on: ubuntu-latest + steps: + - name: Add label + if: contains(github.event.comment.body, '/good-first-issue') || contains(github.event.comment.body, '/gfi' ) + uses: actions/github-script@v5 + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const areas = ['javascript', 'typescript', 'java' , 'go', 'docs', 'ci-cd', 'design']; + const values = context.payload.comment.body.split(" "); + switch(values[1]){ + case 'ts': + values[1] = 'typescript'; + break; + case 'js': + values[1] = 'javascript'; + case 'markdown': + values[1] = 'docs'; + } + if(values.length != 2 || !areas.includes(values[1])){ + const message = `Hey @${context.payload.sender.login}, something is wrong with your command please use \`/help\` for help.` + + await github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }) + } else { + + //remove complexity and areas if there are any before adding new labels; + const currentLabels = (await github.rest.issues.listLabelsOnIssue({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + })).data.map(label => label.name); + + const shouldBeRemoved = currentLabels.filter(label => (label.startsWith('area/') && !label.endsWith(values[1]))); + shouldBeRemoved.forEach(label => { + github.rest.issues.deleteLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: label, + }); + }); + + //add new labels + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['good first issue', `area/${values[1]}`] + }); + } diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index 0fac866f4a..eee7730184 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -9,12 +9,11 @@ on: - created jobs: - create_help_comment: - if: github.event.issue.pull_request + create_help_comment_pr: + if: github.event.issue.pull_request && contains(github.event.comment.body, '/help') runs-on: ubuntu-latest steps: - uses: actions-ecosystem/action-create-comment@v1 - if: contains(github.event.comment.body, '/help') with: github_token: ${{ secrets.GH_TOKEN }} body: | @@ -25,4 +24,20 @@ jobs: At the moment the following comments are supported in pull requests: - `/ready-to-merge` or `/rtm` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added - - `/do-not-merge` or `/dnm` - This comment will block automerging even if all conditions are met and ready-to-merge label is added \ No newline at end of file + - `/do-not-merge` or `/dnm` - This comment will block automerging even if all conditions are met and ready-to-merge label is added + create_help_comment_issue: + if: ${{ !github.event.issue.pull_request && contains(github.event.comment.body, '/help') }} + runs-on: ubuntu-latest + steps: + - uses: actions-ecosystem/action-create-comment@v1 + with: + github_token: ${{ secrets.GH_TOKEN }} + body: | + Hello, @${{ github.actor }}! πŸ‘‹πŸΌ + + I'm Genie from the magic lamp. Looks like somebody needs a hand! πŸ†˜ + + At the moment the following comments are supported in issues: + + - `/good-first-issue {js | ts | java | go | docs | design | ci-cd} ` or `/gfi {js | ts | java | go | docs | design | ci-cd} ` - label an issue as a `good first issue`. + example: `/gfi js` or `/good-first-issue ci-cd` From 49a534cd6cf7b57ffb809f962506fa5946ba70a7 Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Mon, 10 Jan 2022 21:22:24 +0530 Subject: [PATCH 24/82] docs: generate go data model (#568) --- docs/usage.md | 2 +- examples/README.md | 1 + examples/generate-go-models/README.md | 17 ++++++++++++++ .../__snapshots__/index.spec.ts.snap | 10 +++++++++ examples/generate-go-models/index.spec.ts | 13 +++++++++++ examples/generate-go-models/index.ts | 22 +++++++++++++++++++ examples/generate-go-models/package-lock.json | 10 +++++++++ examples/generate-go-models/package.json | 10 +++++++++ 8 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 examples/generate-go-models/README.md create mode 100644 examples/generate-go-models/__snapshots__/index.spec.ts.snap create mode 100644 examples/generate-go-models/index.spec.ts create mode 100644 examples/generate-go-models/index.ts create mode 100644 examples/generate-go-models/package-lock.json create mode 100644 examples/generate-go-models/package.json diff --git a/docs/usage.md b/docs/usage.md index 6ff873b38e..5cfb1458ce 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -67,7 +67,7 @@ The OpenAPI input processor expects that the property `openapi` is defined in or The response and request payloads, since it is a JSON Schema variant, is [interpreted as a such](./interpretation_of_JSON_Schema.md). ## Generate Go models -TODO +Go is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-go-models) ## Generate C# models TODO diff --git a/examples/README.md b/examples/README.md index 31aad40eb8..3a9887132e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,3 +25,4 @@ This directory contains a series of self-contained examples that you can use as - [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. - [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. +- [generate-go-models](./generate-go-models) - A basic example to generate Go data models \ No newline at end of file diff --git a/examples/generate-go-models/README.md b/examples/generate-go-models/README.md new file mode 100644 index 0000000000..83874e7b14 --- /dev/null +++ b/examples/generate-go-models/README.md @@ -0,0 +1,17 @@ +# Go Data Models + +A basic example of how to use Modelina and output a Go data model. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/generate-go-models/__snapshots__/index.spec.ts.snap b/examples/generate-go-models/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..36a43dc738 --- /dev/null +++ b/examples/generate-go-models/__snapshots__/index.spec.ts.snap @@ -0,0 +1,10 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render Go Models and should log expected output to console 1`] = ` +Array [ + "// Root represents a Root model. +type Root struct { + Email string +}", +] +`; diff --git a/examples/generate-go-models/index.spec.ts b/examples/generate-go-models/index.spec.ts new file mode 100644 index 0000000000..aec289cd64 --- /dev/null +++ b/examples/generate-go-models/index.spec.ts @@ -0,0 +1,13 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render Go Models', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/generate-go-models/index.ts b/examples/generate-go-models/index.ts new file mode 100644 index 0000000000..5401dc8f93 --- /dev/null +++ b/examples/generate-go-models/index.ts @@ -0,0 +1,22 @@ +import { GoGenerator } from '../../src'; + +const generator = new GoGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/generate-go-models/package-lock.json b/examples/generate-go-models/package-lock.json new file mode 100644 index 0000000000..b2134a6784 --- /dev/null +++ b/examples/generate-go-models/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "generate-go-models", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/generate-go-models/package.json b/examples/generate-go-models/package.json new file mode 100644 index 0000000000..f3a8d43bd8 --- /dev/null +++ b/examples/generate-go-models/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "generate-go-models" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From dc686466fff9817e6d50b3f3e4b5eb5651e0cbc6 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 10 Jan 2022 20:07:45 +0100 Subject: [PATCH 25/82] chore: fixing sonarcloud duplication problems (#570) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Maciej UrbaΕ„czyk --- .sonarcloud.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.sonarcloud.properties b/.sonarcloud.properties index 5bc8b8cdfe..f73e920289 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -1,2 +1,2 @@ # Disable specific duplicate code since it would introduce more complexity to reduce it. -sonar.cpd.exclusions=src/generators/javascript/renderers/ClassRenderer.ts,src/generators/typescript/renderers/ClassRenderer.ts,src/generators/javascript/JavaScriptRenderer.ts,src/generators/java/renderers/ClassRenderer.ts,src/generators/typescript/TypeScriptRenderer.ts,src/generators/typescript/renderers/EnumRenderer.ts,src/generators/java/renderers/EnumRenderer.ts +sonar.cpd.exclusions=src/generators/**/*.ts From cb81099c46b8d63aad8ceaa87e7469a9efdc66d1 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 10 Jan 2022 20:22:26 +0100 Subject: [PATCH 26/82] fix: model dependencies not needed for C# generator --- src/generators/csharp/CSharpGenerator.ts | 5 ----- test/blackbox/blackbox.spec.ts | 13 ++++++++----- test/generators/csharp/CSharpGenerator.spec.ts | 2 +- .../__snapshots__/CSharpGenerator.spec.ts.snap | 6 ++---- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/generators/csharp/CSharpGenerator.ts b/src/generators/csharp/CSharpGenerator.ts index a1770615b6..e4bd215489 100644 --- a/src/generators/csharp/CSharpGenerator.ts +++ b/src/generators/csharp/CSharpGenerator.ts @@ -50,13 +50,8 @@ export class CSharpGenerator extends AbstractGenerator { - const formattedDependencyModelName = this.options.namingConvention?.type ? this.options.namingConvention.type(dependencyModelName, {inputModel, model: inputModel.models[String(dependencyModelName)], reservedKeywordCallback: isReservedCSharpKeyword}) : dependencyModelName; - return `using ${options.namespace}.${formattedDependencyModelName};`; - }); const outputContent = `namespace ${options.namespace} { - ${modelDependencies.join('\n')} ${outputModel.dependencies.join('\n')} ${outputModel.result} }`; diff --git a/test/blackbox/blackbox.spec.ts b/test/blackbox/blackbox.spec.ts index 0d0d6a71ff..2751c56de8 100644 --- a/test/blackbox/blackbox.spec.ts +++ b/test/blackbox/blackbox.spec.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as fs from 'fs'; -import { TypeScriptGenerator, JavaScriptGenerator, GoGenerator, CSharpGenerator, JavaFileGenerator, JAVA_COMMON_PRESET, TypeScriptFileGenerator, JavaScriptFileGenerator } from '../../src'; +import { GoGenerator, CSharpFileGenerator, JavaFileGenerator, JAVA_COMMON_PRESET, TypeScriptFileGenerator, JavaScriptFileGenerator } from '../../src'; import { execCommand, generateModels, renderModels, renderModelsToSeparateFiles } from './utils/Utils'; /** @@ -128,11 +128,14 @@ describe.each(filesToTest)('Should be able to generate with inputs', ({file, out }); describe('should be able to generate and compile C#', () => { test('class', async () => { - const generator = new CSharpGenerator(); - const generatedModels = await generateModels(fileToGenerateFor, generator); - expect(generatedModels).not.toHaveLength(0); + const generator = new CSharpFileGenerator(); + const inputFileContent = await fs.promises.readFile(fileToGenerateFor); + const input = JSON.parse(String(inputFileContent)); const renderOutputPath = path.resolve(outputDirectoryPath, './csharp'); - await renderModelsToSeparateFiles(generatedModels, renderOutputPath, 'cs'); + + const generatedModels = await generator.generateToFiles(input, renderOutputPath, {namespace: 'TestNamespace'}); + expect(generatedModels).not.toHaveLength(0); + const compileCommand = `csc /target:library /out:${path.resolve(renderOutputPath, './compiled.dll')} ${path.resolve(renderOutputPath, '*.cs')}`; await execCommand(compileCommand); }); diff --git a/test/generators/csharp/CSharpGenerator.spec.ts b/test/generators/csharp/CSharpGenerator.spec.ts index a9e647a786..991dc1c59e 100644 --- a/test/generators/csharp/CSharpGenerator.spec.ts +++ b/test/generators/csharp/CSharpGenerator.spec.ts @@ -191,7 +191,7 @@ describe('CSharpGenerator', () => { }, required: ['street_name', 'city', 'state', 'house_number', 'array_type'], }; - const config = {namespace: 'Test.Package'}; + const config = {namespace: 'Test.Namespace'}; const models = await generator.generateCompleteModels(doc, config); expect(models).toHaveLength(2); expect(models[0].result).toMatchSnapshot(); diff --git a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap index d20b4fa11a..29533dc18c 100644 --- a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap +++ b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap @@ -391,9 +391,8 @@ public static class StatesExtensions { `; exports[`CSharpGenerator should render models and their dependencies 1`] = ` -"namespace Test.Package +"namespace Test.Namespace { - using Test.Package.OtherModel; using System.Collections.Generic; public class Address { private string streetName; @@ -471,9 +470,8 @@ exports[`CSharpGenerator should render models and their dependencies 1`] = ` `; exports[`CSharpGenerator should render models and their dependencies 2`] = ` -"namespace Test.Package +"namespace Test.Namespace { - using System.Collections.Generic; public class OtherModel { private string streetName; From b20375253c10fde826b365ca414a783fc63f242a Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 10 Jan 2022 21:13:50 +0100 Subject: [PATCH 27/82] chore(release): v0.42.1 (#571) Co-authored-by: asyncapi-bot --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4fec2d3539..8ab6f6fefa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.42.0", + "version": "0.42.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.42.0", + "version": "0.42.1", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 4683316e20..f789977e6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.42.0", + "version": "0.42.1", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From d84b8b514295092a469fc2ae42f39d5392c915e2 Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Tue, 11 Jan 2022 02:11:45 +0530 Subject: [PATCH 28/82] fix: non-required properties are required by constructor (#553) --- .../__snapshots__/index.spec.ts.snap | 2 +- .../javascript-use-cjs/__snapshots__/index.spec.ts.snap | 4 ++-- .../javascript-use-esm/__snapshots__/index.spec.ts.snap | 4 ++-- src/generators/javascript/renderers/ClassRenderer.ts | 2 +- test/generators/javascript/JavaScriptGenerator.spec.ts | 9 ++++----- .../__snapshots__/JavaScriptGenerator.spec.ts.snap | 6 ------ 6 files changed, 10 insertions(+), 17 deletions(-) diff --git a/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap b/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap index fe9627be1b..29c3ac7120 100644 --- a/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap @@ -6,7 +6,7 @@ Array [ email; constructor(input) { - this.email = input.email; + } get email() { return this.email; } diff --git a/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap index 9651cb4b30..1f7ab44a5a 100644 --- a/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap +++ b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap @@ -8,7 +8,7 @@ class Person { email; constructor(input) { - this.email = input.email; + } get email() { return this.email; } @@ -26,7 +26,7 @@ class Root { person; constructor(input) { - this.person = input.person; + } get person() { return this.person; } diff --git a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap index a3ac3f59c3..d012b39644 100644 --- a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap +++ b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap @@ -8,7 +8,7 @@ class Person { email; constructor(input) { - this.email = input.email; + } get email() { return this.email; } @@ -27,7 +27,7 @@ class Root { person; constructor(input) { - this.person = input.person; + } get person() { return this.person; } diff --git a/src/generators/javascript/renderers/ClassRenderer.ts b/src/generators/javascript/renderers/ClassRenderer.ts index a2f3007aa7..96408d2bcf 100644 --- a/src/generators/javascript/renderers/ClassRenderer.ts +++ b/src/generators/javascript/renderers/ClassRenderer.ts @@ -71,7 +71,7 @@ export const JS_DEFAULT_CLASS_PRESET: ClassPreset = { }, ctor({ renderer, model }) { const properties = model.properties || {}; - const assigments = Object.entries(properties).map(([propertyName, property]) => { + const assigments = Object.entries(properties).filter(([propertyName]) => model.isRequired(propertyName)).map(([propertyName, property]) => { propertyName = renderer.nameProperty(propertyName, property); return `this.${propertyName} = input.${propertyName};`; }); diff --git a/test/generators/javascript/JavaScriptGenerator.spec.ts b/test/generators/javascript/JavaScriptGenerator.spec.ts index 185e8ef129..504053a752 100644 --- a/test/generators/javascript/JavaScriptGenerator.spec.ts +++ b/test/generators/javascript/JavaScriptGenerator.spec.ts @@ -14,7 +14,8 @@ describe('JavaScriptGenerator', () => { enum: { type: 'string' }, reservedEnum: { type: 'string' } }, - additionalProperties: false + additionalProperties: false, + required: ['reservedEnum', 'enum'], }; const expected = `class Address { reservedReservedEnum; @@ -77,8 +78,6 @@ describe('JavaScriptGenerator', () => { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; - this.marriage = input.marriage; - this.members = input.members; this.arrayType = input.arrayType; } @@ -201,7 +200,7 @@ describe('JavaScriptGenerator', () => { marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, - other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } } }, + other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } }, required: ['street_name'] }, }, patternProperties: { '^S(.?*)test&': { @@ -227,7 +226,7 @@ describe('JavaScriptGenerator', () => { marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, - other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } } }, + other_model: { type: 'object', $id: 'OtherModel', properties: { street_name: { type: 'string' } }, required: ['street_name'] }, }, patternProperties: { '^S(.?*)test&': { diff --git a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap index 4148edbb30..d99548a50f 100644 --- a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap +++ b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap @@ -20,10 +20,7 @@ class Address { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; - this.marriage = input.marriage; - this.members = input.members; this.arrayType = input.arrayType; - this.otherModel = input.otherModel; } get streetName() { return this.streetName; } @@ -99,10 +96,7 @@ class Address { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; - this.marriage = input.marriage; - this.members = input.members; this.arrayType = input.arrayType; - this.otherModel = input.otherModel; } get streetName() { return this.streetName; } From e1fb4d7ce1ce7ff386aaf5a263729aa61d9b56e5 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 10 Jan 2022 23:53:18 +0100 Subject: [PATCH 29/82] chore(release): v0.42.2 (#572) Co-authored-by: asyncapi-bot --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ab6f6fefa..9ff3c788c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.42.1", + "version": "0.42.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.42.1", + "version": "0.42.2", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index f789977e6d..6fc4db4880 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.42.1", + "version": "0.42.2", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 07bcb3fa64ee64bf521b18094f55d677a5a76ac0 Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Tue, 11 Jan 2022 15:20:17 +0530 Subject: [PATCH 30/82] docs: example on how to include a custom function in the data model --- docs/advanced.md | 4 +- examples/README.md | 3 +- examples/include-custom-function/README.md | 17 +++++++ .../__snapshots__/index.spec.ts.snap | 45 +++++++++++++++++++ .../include-custom-function/index.spec.ts | 14 ++++++ examples/include-custom-function/index.ts | 35 +++++++++++++++ .../include-custom-function/package-lock.json | 10 +++++ examples/include-custom-function/package.json | 10 +++++ 8 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 examples/include-custom-function/README.md create mode 100644 examples/include-custom-function/__snapshots__/index.spec.ts.snap create mode 100644 examples/include-custom-function/index.spec.ts create mode 100644 examples/include-custom-function/index.ts create mode 100644 examples/include-custom-function/package-lock.json create mode 100644 examples/include-custom-function/package.json diff --git a/docs/advanced.md b/docs/advanced.md index 37828803bb..ffdf990d04 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -41,7 +41,9 @@ Supported by: Check out this [example out for a live demonstration](../examples/generate-to-files). ## Include a custom function in the data model -TODO +Sometimes you want to include custom functionality into the generated models, this can be done through a custom preset using the hook `additionalContent`. + +Check out this [example out for a live demonstration](../examples/include-custom-function). ## Use the models for data transfer TODO diff --git a/examples/README.md b/examples/README.md index 3a9887132e..59e4c2344a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,4 +25,5 @@ This directory contains a series of self-contained examples that you can use as - [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. - [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. -- [generate-go-models](./generate-go-models) - A basic example to generate Go data models \ No newline at end of file +- [generate-go-models](./generate-go-models) - A basic example to generate Go data models +- [include-custom-function](./include-custom-function) - A basic example where a custom function is included. diff --git a/examples/include-custom-function/README.md b/examples/include-custom-function/README.md new file mode 100644 index 0000000000..fc4ee2f781 --- /dev/null +++ b/examples/include-custom-function/README.md @@ -0,0 +1,17 @@ +# Custom Function + +A basic example of how to include custom function in data model. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/include-custom-function/__snapshots__/index.spec.ts.snap b/examples/include-custom-function/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..761c1e2bf2 --- /dev/null +++ b/examples/include-custom-function/__snapshots__/index.spec.ts.snap @@ -0,0 +1,45 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render custom function and should log expected output to console 1`] = ` +Array [ + "class Root { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } + + + public someAdditionalFunctionForClasses(): string { + return 'Some test'; + } +}", +] +`; + +exports[`Should be able to render custom function and should log expected output to console 1`] = ` +Array [ + "class Root { + private _email?: string; + + constructor(input: { + email?: string, + }) { + this._email = input.email; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } + + + public someAdditionalFunctionForClasses(): string { + return 'Some test'; + } +}", +] +`; diff --git a/examples/include-custom-function/index.spec.ts b/examples/include-custom-function/index.spec.ts new file mode 100644 index 0000000000..1efd876bca --- /dev/null +++ b/examples/include-custom-function/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render custom function', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/include-custom-function/index.ts b/examples/include-custom-function/index.ts new file mode 100644 index 0000000000..699deb716c --- /dev/null +++ b/examples/include-custom-function/index.ts @@ -0,0 +1,35 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator({ + presets: [ + { + class: { + additionalContent({ content }) { + return `${content} +public someAdditionalFunctionForClasses(): string { + return 'Some test'; +}`; + }, + } + } + ] +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/include-custom-function/package-lock.json b/examples/include-custom-function/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/include-custom-function/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/include-custom-function/package.json b/examples/include-custom-function/package.json new file mode 100644 index 0000000000..10cb17a124 --- /dev/null +++ b/examples/include-custom-function/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "include-custom-function" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From dd3163c22500ef29b458b7d50149fa0b7ca4f590 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:11:46 +0100 Subject: [PATCH 31/82] docs: add mahakporwal02 as a contributor for code --- .all-contributorsrc | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index bbb7bc3b39..f1496bdbee 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -203,7 +203,8 @@ "contributions": [ "example", "test", - "doc" + "doc", + "code" ] }, { diff --git a/README.md b/README.md index 47e44bbddd..594a1f51e7 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Marco

πŸ›
quadrrem

πŸ’» ⚠️
Kamil Janeček

⚠️ πŸ› πŸ’» -
mahakporwal02

πŸ’‘ ⚠️ πŸ“– +
mahakporwal02

πŸ’‘ ⚠️ πŸ“– πŸ’»
Debajyoti Halder

πŸ’» ⚠️ From cafc1ff97e7ccf1c1e24cf6621e250c14387f30b Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 11 Jan 2022 11:29:21 +0100 Subject: [PATCH 32/82] feat: complete model rendering and file output for Go generator (#540) --- docs/advanced.md | 1 + src/generators/go/GoFileGenerator.ts | 24 +++++++ src/generators/go/GoGenerator.ts | 31 +++++++-- src/generators/go/index.ts | 1 + .../java/renderers/ClassRenderer.ts | 1 - test/blackbox/blackbox.spec.ts | 15 +++-- test/generators/go/GoFileGenerator.spec.ts | 51 ++++++++++++++ test/generators/go/GoGenerator.spec.ts | 67 +++++++++++++++++++ .../go/__snapshots__/GoGenerator.spec.ts.snap | 65 ++++++++++++++++++ 9 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 src/generators/go/GoFileGenerator.ts create mode 100644 test/generators/go/GoFileGenerator.spec.ts create mode 100644 test/generators/go/__snapshots__/GoGenerator.spec.ts.snap diff --git a/docs/advanced.md b/docs/advanced.md index ffdf990d04..51bf63dc91 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -34,6 +34,7 @@ Supported by: - Java - TypeScript - C# +- Go - JavaScript > It is not supported in browsers. diff --git a/src/generators/go/GoFileGenerator.ts b/src/generators/go/GoFileGenerator.ts new file mode 100644 index 0000000000..e0ef44aae8 --- /dev/null +++ b/src/generators/go/GoFileGenerator.ts @@ -0,0 +1,24 @@ +import { GoGenerator, GoRenderCompleteModelOptions } from './GoGenerator'; +import { CommonInputModel, OutputModel } from '../../models'; +import * as path from 'path'; +import { AbstractFileGenerator } from '../AbstractFileGenerator'; +import { FileHelpers } from '../../helpers'; + +export class GoFileGenerator extends GoGenerator implements AbstractFileGenerator { + /** + * Generates all the models to an output directory each model with their own separate files. + * + * @param input + * @param outputDirectory where you want the models generated to + * @param options + */ + public async generateToFiles(input: Record | CommonInputModel, outputDirectory: string, options: GoRenderCompleteModelOptions): Promise { + let generatedModels = await this.generateCompleteModels(input, options); + generatedModels = generatedModels.filter((outputModel) => { return outputModel.modelName !== undefined; }); + for (const outputModel of generatedModels) { + const filePath = path.resolve(outputDirectory, `${outputModel.modelName}.go`); + await FileHelpers.writerToFileSystem(outputModel.result, filePath); + } + return generatedModels; + } +} diff --git a/src/generators/go/GoGenerator.ts b/src/generators/go/GoGenerator.ts index 164978fa82..6c31d4bc1b 100644 --- a/src/generators/go/GoGenerator.ts +++ b/src/generators/go/GoGenerator.ts @@ -9,7 +9,7 @@ import { GoPreset, GO_DEFAULT_PRESET } from './GoPreset'; import { StructRenderer } from './renderers/StructRenderer'; import { EnumRenderer } from './renderers/EnumRenderer'; import { pascalCaseTransformMerge } from 'change-case'; -import { Logger } from '../../'; +import { Logger } from '../../utils/LoggingInterface'; /** * The Go naming convention type @@ -37,10 +37,14 @@ export interface GoOptions extends CommonGeneratorOptions { namingConvention?: GoNamingConvention; } +export interface GoRenderCompleteModelOptions { + packageName: string +} + /** * Generator for Go */ -export class GoGenerator extends AbstractGenerator { +export class GoGenerator extends AbstractGenerator { static defaultOptions: GoOptions = { ...defaultGeneratorOptions, defaultPreset: GO_DEFAULT_PRESET, @@ -69,8 +73,27 @@ export class GoGenerator extends AbstractGenerator { return Promise.resolve(RenderOutput.toRenderOutput({ result: '', renderedName: '', dependencies: [] })); } - renderCompleteModel(): Promise { - throw new Error('Method not implemented.'); + /** + * Render a complete model result where the model code, library and model dependencies are all bundled appropriately. + * + * @param model + * @param inputModel + * @param options + */ + async renderCompleteModel(model: CommonModel, inputModel: CommonInputModel, options: GoRenderCompleteModelOptions): Promise { + const outputModel = await this.render(model, inputModel); + let importCode = ''; + if (outputModel.dependencies.length > 0) { + const dependencies = outputModel.dependencies.map((dependency) => {return `"${ dependency }"`;}).join('\n'); + importCode = `import ( + ${dependencies} +)`; + } + const outputContent = ` +package ${options.packageName} +${importCode} +${outputModel.result}`; + return RenderOutput.toRenderOutput({ result: outputContent, renderedName: outputModel.renderedName, dependencies: outputModel.dependencies }); } async renderEnum(model: CommonModel, inputModel: CommonInputModel): Promise { diff --git a/src/generators/go/index.ts b/src/generators/go/index.ts index defe967b04..e408d8ecc4 100644 --- a/src/generators/go/index.ts +++ b/src/generators/go/index.ts @@ -1,3 +1,4 @@ export * from './GoGenerator'; +export * from './GoFileGenerator'; export { GO_DEFAULT_PRESET } from './GoPreset'; export type { GoPreset } from './GoPreset'; diff --git a/src/generators/java/renderers/ClassRenderer.ts b/src/generators/java/renderers/ClassRenderer.ts index 03aa856582..f006a55ef3 100644 --- a/src/generators/java/renderers/ClassRenderer.ts +++ b/src/generators/java/renderers/ClassRenderer.ts @@ -1,5 +1,4 @@ import { JavaRenderer } from '../JavaRenderer'; - import { CommonModel, ClassPreset, PropertyType } from '../../../models'; import { DefaultPropertyNames, FormatHelpers, getUniquePropertyName } from '../../../helpers'; diff --git a/test/blackbox/blackbox.spec.ts b/test/blackbox/blackbox.spec.ts index 2751c56de8..5dcc37023e 100644 --- a/test/blackbox/blackbox.spec.ts +++ b/test/blackbox/blackbox.spec.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as fs from 'fs'; -import { GoGenerator, CSharpFileGenerator, JavaFileGenerator, JAVA_COMMON_PRESET, TypeScriptFileGenerator, JavaScriptFileGenerator } from '../../src'; +import { GoFileGenerator, CSharpFileGenerator, JavaFileGenerator, JAVA_COMMON_PRESET, TypeScriptFileGenerator, JavaScriptFileGenerator } from '../../src'; import { execCommand, generateModels, renderModels, renderModelsToSeparateFiles } from './utils/Utils'; /** @@ -189,12 +189,15 @@ describe.each(filesToTest)('Should be able to generate with inputs', ({file, out describe('should be able to generate Go', () => { test('struct', async () => { - const generator = new GoGenerator(); - const generatedModels = await generateModels(fileToGenerateFor, generator); + const generator = new GoFileGenerator(); + const inputFileContent = await fs.promises.readFile(fileToGenerateFor); + const input = JSON.parse(String(inputFileContent)); + const renderOutputPath = path.resolve(outputDirectoryPath, './go/struct/'); + + const generatedModels = await generator.generateToFiles(input, renderOutputPath, {packageName: 'test_package_name'}); expect(generatedModels).not.toHaveLength(0); - const renderOutputPath = path.resolve(outputDirectoryPath, './go/struct/main.go'); - await renderModels(generatedModels, renderOutputPath, ['package main\n', 'func main() {}']); - const compileCommand = `go build -o ${renderOutputPath.replace('.go', '')} ${renderOutputPath}`; + + const compileCommand = `gofmt ${renderOutputPath}`; await execCommand(compileCommand); }); }); diff --git a/test/generators/go/GoFileGenerator.spec.ts b/test/generators/go/GoFileGenerator.spec.ts new file mode 100644 index 0000000000..396e55b17d --- /dev/null +++ b/test/generators/go/GoFileGenerator.spec.ts @@ -0,0 +1,51 @@ +import { CommonInputModel, CommonModel, FileHelpers, GoFileGenerator, OutputModel } from '../../../src'; +import * as path from 'path'; + +describe('GoFileGenerator', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + describe('generateToFile()', () => { + const doc = { + $id: 'CustomClass', + type: 'object', + additionalProperties: true, + properties: { + someProp: { type: 'string' }, + someEnum: { + $id: 'CustomEnum', + type: 'string', + enum: ['Texas', 'Alabama', 'California'], + } + } + }; + test('should throw accurate error if file cannot be written', async () => { + const generator = new GoFileGenerator(); + const expectedError = new Error('write error'); + jest.spyOn(FileHelpers, 'writerToFileSystem').mockRejectedValue(expectedError); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), '', new CommonInputModel(), [])]); + + await expect(generator.generateToFiles(doc, '/test/', {packageName: 'some_package'})).rejects.toEqual(expectedError); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + }); + test('should try and generate models to files', async () => { + const generator = new GoFileGenerator(); + const outputDir = './test'; + const expectedOutputDirPath = path.resolve(outputDir); + const expectedOutputFilePath = path.resolve(`${outputDir}/Test.go`); + const expectedWriteToFileParameters = [ + 'content', + expectedOutputFilePath, + ]; + jest.spyOn(FileHelpers, 'writerToFileSystem').mockResolvedValue(undefined); + jest.spyOn(generator, 'generateCompleteModels').mockResolvedValue([new OutputModel('content', new CommonModel(), 'Test', new CommonInputModel(), [])]); + + await generator.generateToFiles(doc, expectedOutputDirPath, {packageName: 'some_package'}); + expect(generator.generateCompleteModels).toHaveBeenCalledTimes(1); + expect(FileHelpers.writerToFileSystem).toHaveBeenCalledTimes(1); + expect((FileHelpers.writerToFileSystem as jest.Mock).mock.calls[0]).toEqual(expectedWriteToFileParameters); + }); + }); +}); diff --git a/test/generators/go/GoGenerator.spec.ts b/test/generators/go/GoGenerator.spec.ts index 2f5de7471d..0560f257f5 100644 --- a/test/generators/go/GoGenerator.spec.ts +++ b/test/generators/go/GoGenerator.spec.ts @@ -155,4 +155,71 @@ type CustomEnum string`; expect(enumModel.result).toEqual(expected); expect(enumModel.dependencies).toEqual([]); }); + describe('generateCompleteModels()', () => { + test('should render models', async () => { + const doc = { + $id: 'Address', + type: 'object', + properties: { + street_name: { type: 'string' }, + city: { type: 'string', description: 'City description' }, + state: { type: 'string' }, + house_number: { type: 'number' }, + marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, + members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, + array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + other_model: { type: 'object', $id: 'OtherModel', properties: {street_name: { type: 'string' }} }, + }, + patternProperties: { + '^S(.?*)test&': { + type: 'string' + } + }, + required: ['street_name', 'city', 'state', 'house_number', 'array_type'], + }; + const config = {packageName: 'some_package'}; + const models = await generator.generateCompleteModels(doc, config); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); + + test('should render dependencies', async () => { + const doc = { + $id: 'Address', + type: 'object', + properties: { + street_name: { type: 'string' }, + city: { type: 'string', description: 'City description' }, + state: { type: 'string' }, + house_number: { type: 'number' }, + marriage: { type: 'boolean', description: 'Status if marriage live in given house' }, + members: { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], }, + array_type: { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + other_model: { type: 'object', $id: 'OtherModel', properties: {street_name: { type: 'string' }} }, + }, + patternProperties: { + '^S(.?*)test&': { + type: 'string' + } + }, + required: ['street_name', 'city', 'state', 'house_number', 'array_type'], + }; + generator = new GoGenerator({ presets: [ + { + struct: { + self({ renderer, content }) { + renderer.addDependency('time'); + return content; + }, + } + } + ] }); + const config = {packageName: 'some_package'}; + const models = await generator.generateCompleteModels(doc, config); + expect(models).toHaveLength(2); + expect(models[0].result).toMatchSnapshot(); + expect(models[1].result).toMatchSnapshot(); + }); + }); }); diff --git a/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap new file mode 100644 index 0000000000..4a89f5aca1 --- /dev/null +++ b/test/generators/go/__snapshots__/GoGenerator.spec.ts.snap @@ -0,0 +1,65 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`GoGenerator generateCompleteModels() should render dependencies 1`] = ` +" +package some_package +import ( + \\"time\\" +) +// Address represents a Address model. +type Address struct { + StreetName string + City string + State string + HouseNumber float64 + Marriage bool + Members []interface{} + ArrayType []interface{} + OtherModel *OtherModel + AdditionalProperties map[string][]interface{} + STestPatternProperties map[string]string +}" +`; + +exports[`GoGenerator generateCompleteModels() should render dependencies 2`] = ` +" +package some_package +import ( + \\"time\\" +) +// OtherModel represents a OtherModel model. +type OtherModel struct { + StreetName string + AdditionalProperties map[string][]interface{} +}" +`; + +exports[`GoGenerator generateCompleteModels() should render models 1`] = ` +" +package some_package + +// Address represents a Address model. +type Address struct { + StreetName string + City string + State string + HouseNumber float64 + Marriage bool + Members []interface{} + ArrayType []interface{} + OtherModel *OtherModel + AdditionalProperties map[string][]interface{} + STestPatternProperties map[string]string +}" +`; + +exports[`GoGenerator generateCompleteModels() should render models 2`] = ` +" +package some_package + +// OtherModel represents a OtherModel model. +type OtherModel struct { + StreetName string + AdditionalProperties map[string][]interface{} +}" +`; From b06c24242b8ad9fe0504d5692ded14573993d0c9 Mon Sep 17 00:00:00 2001 From: Debajyoti Halder Date: Tue, 11 Jan 2022 18:39:50 +0530 Subject: [PATCH 33/82] docs: example of csharp example serializer --- docs/languages/Csharp.md | 9 +- examples/README.md | 1 + examples/csharp-generate-serializer/README.md | 17 ++++ .../__snapshots__/index.spec.ts.snap | 88 +++++++++++++++++++ .../csharp-generate-serializer/index.spec.ts | 15 ++++ examples/csharp-generate-serializer/index.ts | 27 ++++++ .../package-lock.json | 10 +++ .../csharp-generate-serializer/package.json | 12 +++ 8 files changed, 177 insertions(+), 2 deletions(-) create mode 100644 examples/csharp-generate-serializer/README.md create mode 100644 examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap create mode 100644 examples/csharp-generate-serializer/index.spec.ts create mode 100644 examples/csharp-generate-serializer/index.ts create mode 100644 examples/csharp-generate-serializer/package-lock.json create mode 100644 examples/csharp-generate-serializer/package.json diff --git a/docs/languages/Csharp.md b/docs/languages/Csharp.md index d130816a43..434704e4e9 100644 --- a/docs/languages/Csharp.md +++ b/docs/languages/Csharp.md @@ -1,4 +1,5 @@ # C# + There are special use-cases that each language supports; this document pertains to **C# models**. @@ -11,9 +12,13 @@ There are special use-cases that each language supports; this document pertains ## Generate serializer and deserializer functionality -TODO + +Sometimes you want to serialize the data models into JSON. In order to do that use the preset `CSHARP_JSON_SERIALIZER_PRESET` + +Check out this [example for a live demonstration](../../examples/csharp-generate-serializer). ## Generate models with equals and GetHashCode methods + To overwrite the `Equal` and `GetHashCode` methods, use the preset `CSHARP_COMMON_PRESET` and provide the options `equal: true` and `hashCode: true` -Check out this [example for a live demonstration](../../examples/csharp-generate-equals-and-hashcode). \ No newline at end of file +Check out this [example for a live demonstration](../../examples/csharp-generate-equals-and-hashcode). diff --git a/examples/README.md b/examples/README.md index 59e4c2344a..4e2fd91743 100644 --- a/examples/README.md +++ b/examples/README.md @@ -21,6 +21,7 @@ This directory contains a series of self-contained examples that you can use as - [TEMPLATE](./TEMPLATE) - A basic template used to create new examples. - [java-generate-tostring](./java-generate-tostring) - A basic example that shows how to generate models that overwrite the `toString` method - [csharp-generate-equals-and-hashcode](./csharp-generate-equals-and-hashcode) - A basic example on how to generate models that overwrite the `Equal` and `GetHashCode` methods +- [csharp-generate-serializer](./csharp-generate-serializer) - A basic example on how to generate models that include function to serialize the data models to JSON - [generate-javascript-models](./generate-javascript-models) - A basic example to generate JavaScript data models - [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. - [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. diff --git a/examples/csharp-generate-serializer/README.md b/examples/csharp-generate-serializer/README.md new file mode 100644 index 0000000000..85f00b1fe5 --- /dev/null +++ b/examples/csharp-generate-serializer/README.md @@ -0,0 +1,17 @@ +# C# Generate serializer functions + +A basic example of how to generate models and which includes a way to serialize them into JSON. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap b/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..86d0518a2f --- /dev/null +++ b/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap @@ -0,0 +1,88 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate a model with functions to serialize the data model into JSON and should log expected output to console 1`] = ` +Array [ + "[JsonConverter(typeof(RootConverter))] +public class Root { + private string email; + + public string Email + { + get { return email; } + set { email = value; } + } +} + +internal class RootConverter : JsonConverter +{ + public override bool CanConvert(Type objectType) + { + // this converter can be applied to any type + return true; + } + public override Root Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(); + } + + var instance = new Root(); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + return instance; + } + + // Get the key. + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException(); + } + + string propertyName = reader.GetString(); + if (propertyName == \\"email\\") + { + var value = JsonSerializer.Deserialize(ref reader, options); + instance.Email = value; + continue; + } + + + + + } + + throw new JsonException(); + } + public override void Write(Utf8JsonWriter writer, Root value, JsonSerializerOptions options) + { + if (value == null) + { + JsonSerializer.Serialize(writer, null); + return; + } + var properties = value.GetType().GetProperties(); + + writer.WriteStartObject(); + + if(value.Email != null) { + // write property name and let the serializer serialize the value itself + writer.WritePropertyName(\\"email\\"); + JsonSerializer.Serialize(writer, value.Email); + } + + + + + + + writer.WriteEndObject(); + } + +} +", +] +`; diff --git a/examples/csharp-generate-serializer/index.spec.ts b/examples/csharp-generate-serializer/index.spec.ts new file mode 100644 index 0000000000..daa49a7090 --- /dev/null +++ b/examples/csharp-generate-serializer/index.spec.ts @@ -0,0 +1,15 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to generate a model with functions to serialize the data model into JSON ', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/csharp-generate-serializer/index.ts b/examples/csharp-generate-serializer/index.ts new file mode 100644 index 0000000000..2751d2346e --- /dev/null +++ b/examples/csharp-generate-serializer/index.ts @@ -0,0 +1,27 @@ +import { CSharpGenerator, CSHARP_JSON_SERIALIZER_PRESET } from '../../src'; + +const generator = new CSharpGenerator({ + presets: [ + CSHARP_JSON_SERIALIZER_PRESET + ] +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/csharp-generate-serializer/package-lock.json b/examples/csharp-generate-serializer/package-lock.json new file mode 100644 index 0000000000..98c488824f --- /dev/null +++ b/examples/csharp-generate-serializer/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "csharp-generate-serializer", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/csharp-generate-serializer/package.json b/examples/csharp-generate-serializer/package.json new file mode 100644 index 0000000000..b11ff1f3c6 --- /dev/null +++ b/examples/csharp-generate-serializer/package.json @@ -0,0 +1,12 @@ +{ + "config" : { + "example_name" : "csharp-generate-serializer" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From acaea00ec879f2d1bb26e31a3f4cc72367ac26f4 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 11 Jan 2022 14:52:31 +0100 Subject: [PATCH 34/82] chore(release): v0.43.0 (#574) Co-authored-by: asyncapi-bot Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9ff3c788c2..a3414878fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.42.2", + "version": "0.43.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.42.2", + "version": "0.43.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 6fc4db4880..25b797312b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.42.2", + "version": "0.43.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 1dc565edb4afcfc9229f4f33982c753a1a4e4ebd Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 16:47:22 +0100 Subject: [PATCH 35/82] docs: add ron-debajyoti as a contributor for doc, example (#576) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: Jonas Lagoni --- .all-contributorsrc | 4 +++- README.md | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index f1496bdbee..8a9293999d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -214,7 +214,9 @@ "profile": "https://github.com/ron-debajyoti", "contributions": [ "code", - "test" + "test", + "doc", + "example" ] } ], diff --git a/README.md b/README.md index 594a1f51e7..0a8cf52c21 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
quadrrem

πŸ’» ⚠️
Kamil Janeček

⚠️ πŸ› πŸ’»
mahakporwal02

πŸ’‘ ⚠️ πŸ“– πŸ’» -
Debajyoti Halder

πŸ’» ⚠️ +
Debajyoti Halder

πŸ’» ⚠️ πŸ“– πŸ’‘ From e22c1369501cdc06330dd8f9ab6f8ac38ce5d6e1 Mon Sep 17 00:00:00 2001 From: Debajyoti Halder Date: Tue, 11 Jan 2022 23:41:38 +0530 Subject: [PATCH 36/82] docs: generate C# models (#578) --- docs/usage.md | 18 ++++++++++----- examples/README.md | 1 + examples/generate-csharp-models/README.md | 17 ++++++++++++++ .../__snapshots__/index.spec.ts.snap | 15 +++++++++++++ examples/generate-csharp-models/index.spec.ts | 14 ++++++++++++ examples/generate-csharp-models/index.ts | 22 +++++++++++++++++++ .../generate-csharp-models/package-lock.json | 10 +++++++++ examples/generate-csharp-models/package.json | 10 +++++++++ 8 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 examples/generate-csharp-models/README.md create mode 100644 examples/generate-csharp-models/__snapshots__/index.spec.ts.snap create mode 100644 examples/generate-csharp-models/index.spec.ts create mode 100644 examples/generate-csharp-models/index.ts create mode 100644 examples/generate-csharp-models/package-lock.json create mode 100644 examples/generate-csharp-models/package.json diff --git a/docs/usage.md b/docs/usage.md index 5cfb1458ce..5a1a10aab9 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,4 +1,5 @@ # Usages + Modelina can be used in many different contexts and has many features, all depending on the output language. This document will walk you through you the library's basic usages. For more advanced use-cases, please check out the [advanced document](./advanced.md). @@ -23,7 +24,8 @@ For more specific integration options, please check out the [integration documen ## Understanding the output format -TODO + +TODO ## Generate models from AsyncAPI documents @@ -49,6 +51,7 @@ We support both draft-4, draft-6, and draft-7 documents. The library expects the `$schema` property for the document to be set in order to understand the input format. By default, if no other inputs are detected, it defaults to `JSON Schema draft 7`. The process of interpreting a JSON Schema to a model can be read [here](./interpretation_of_JSON_Schema.md). ## Generate models from Swagger 2.0 documents + There are one way to generate models from a Swagger 2.0 document - [Generate from a pure JS object](../examples/swagger2.0-from-object) @@ -58,6 +61,7 @@ The Swagger input processor expects that the property `swagger` is defined in or The response payload and `body` parameters, since it is a JSON Schema variant, is [interpreted as a such](./interpretation_of_JSON_Schema.md). ## Generate models from OpenAPI documents + There are one way to generate models from an OpenAPI document - [Generate from a pure JS object](../examples/openapi-from-object) @@ -67,17 +71,21 @@ The OpenAPI input processor expects that the property `openapi` is defined in or The response and request payloads, since it is a JSON Schema variant, is [interpreted as a such](./interpretation_of_JSON_Schema.md). ## Generate Go models -Go is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-go-models) + +Go is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-go-models) ## Generate C# models -TODO + +C# is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-csharp-models) ## Generate Java models -Java is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-java-models) + +Java is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-java-models) ## Generate TypeScript models + TypeScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-typescript-models) and the following [TypeScript documentation for more advanced use-cases](./languages/TypeScript.md). ## Generate JavaScript models -JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) +JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) diff --git a/examples/README.md b/examples/README.md index 4e2fd91743..3dee378496 100644 --- a/examples/README.md +++ b/examples/README.md @@ -28,3 +28,4 @@ This directory contains a series of self-contained examples that you can use as - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. - [generate-go-models](./generate-go-models) - A basic example to generate Go data models - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. +- [generate-csharp-models](./generate-csharp-models) - A basic example to generate C# data models diff --git a/examples/generate-csharp-models/README.md b/examples/generate-csharp-models/README.md new file mode 100644 index 0000000000..1de0943b18 --- /dev/null +++ b/examples/generate-csharp-models/README.md @@ -0,0 +1,17 @@ +# C# data models + +A basic example of how to use Modelina and output a C# data model. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap b/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..3429fbf841 --- /dev/null +++ b/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render C# models and should log expected output to console 1`] = ` +Array [ + "public class Root { + private string email; + + public string Email + { + get { return email; } + set { email = value; } + } +}", +] +`; diff --git a/examples/generate-csharp-models/index.spec.ts b/examples/generate-csharp-models/index.spec.ts new file mode 100644 index 0000000000..adf3b7871d --- /dev/null +++ b/examples/generate-csharp-models/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import { generate } from './index'; + +describe('Should be able to render C# models ', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/generate-csharp-models/index.ts b/examples/generate-csharp-models/index.ts new file mode 100644 index 0000000000..9cdff58448 --- /dev/null +++ b/examples/generate-csharp-models/index.ts @@ -0,0 +1,22 @@ +import { CSharpGenerator } from '../../src'; + +const generator = new CSharpGenerator(); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/generate-csharp-models/package-lock.json b/examples/generate-csharp-models/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/generate-csharp-models/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/generate-csharp-models/package.json b/examples/generate-csharp-models/package.json new file mode 100644 index 0000000000..b4aacc45c7 --- /dev/null +++ b/examples/generate-csharp-models/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "generate-csharp-models" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From 928daa07db669f4f3fa96fcdbf81a8b5c1444e2c Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Wed, 12 Jan 2022 02:59:30 +0530 Subject: [PATCH 37/82] docs: generate Java data models that overwrite equal method (#577) --- docs/languages/Java.md | 5 ++- examples/README.md | 1 + examples/java-generate-equals/README.md | 17 ++++++++++ .../__snapshots__/index.spec.ts.snap | 25 ++++++++++++++ examples/java-generate-equals/index.spec.ts | 14 ++++++++ examples/java-generate-equals/index.ts | 34 +++++++++++++++++++ .../java-generate-equals/package-lock.json | 10 ++++++ examples/java-generate-equals/package.json | 12 +++++++ 8 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 examples/java-generate-equals/README.md create mode 100644 examples/java-generate-equals/__snapshots__/index.spec.ts.snap create mode 100644 examples/java-generate-equals/index.spec.ts create mode 100644 examples/java-generate-equals/index.ts create mode 100644 examples/java-generate-equals/package-lock.json create mode 100644 examples/java-generate-equals/package.json diff --git a/docs/languages/Java.md b/docs/languages/Java.md index ac4f34d84d..0a4af3bd89 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -16,7 +16,10 @@ There are special use-cases that each language supports; this document pertains ## Include equals function for the class -TODO +To overwrite the `equal` method, use the preset `JAVA_COMMON_PRESET` and provide the option `equal: true`. + +Check out this [example for a live demonstration](../../examples/java-generate-equals). + ## Include hashCode function for the class TODO diff --git a/examples/README.md b/examples/README.md index 3dee378496..3487ed1e12 100644 --- a/examples/README.md +++ b/examples/README.md @@ -28,4 +28,5 @@ This directory contains a series of self-contained examples that you can use as - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. - [generate-go-models](./generate-go-models) - A basic example to generate Go data models - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. +- [java-generate-equals](./java-generate-equals) - A basic example that shows how to generate models that overwrite the `equal` method - [generate-csharp-models](./generate-csharp-models) - A basic example to generate C# data models diff --git a/examples/java-generate-equals/README.md b/examples/java-generate-equals/README.md new file mode 100644 index 0000000000..5af3b94c57 --- /dev/null +++ b/examples/java-generate-equals/README.md @@ -0,0 +1,17 @@ +# Java Generate `Equal` + +A basic example on how to generate models that overwrite the `Equal` methods + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/java-generate-equals/__snapshots__/index.spec.ts.snap b/examples/java-generate-equals/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..20d699d7b6 --- /dev/null +++ b/examples/java-generate-equals/__snapshots__/index.spec.ts.snap @@ -0,0 +1,25 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate a model to overwrite the Equal methods and should log expected output to console 1`] = ` +Array [ + "public class Root { + private Object email; + + public Object getEmail() { return this.email; } + public void setEmail(Object email) { this.email = email; } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Root self = (Root) o; + return + Objects.equals(this.email, self.email); + } +}", +] +`; diff --git a/examples/java-generate-equals/index.spec.ts b/examples/java-generate-equals/index.spec.ts new file mode 100644 index 0000000000..905b579e2b --- /dev/null +++ b/examples/java-generate-equals/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to generate a model to overwrite the Equal methods', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/java-generate-equals/index.ts b/examples/java-generate-equals/index.ts new file mode 100644 index 0000000000..113ea8f4f3 --- /dev/null +++ b/examples/java-generate-equals/index.ts @@ -0,0 +1,34 @@ +import { JavaGenerator, JAVA_COMMON_PRESET } from '../../src'; + +const generator = new JavaGenerator({ + presets: [ + { + preset: JAVA_COMMON_PRESET, + options: { + equal: true, + hashCode: false, + classToString: false + } + } + ] +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/java-generate-equals/package-lock.json b/examples/java-generate-equals/package-lock.json new file mode 100644 index 0000000000..93bbb3a0dd --- /dev/null +++ b/examples/java-generate-equals/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "java-generate-equals", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/java-generate-equals/package.json b/examples/java-generate-equals/package.json new file mode 100644 index 0000000000..e399cc029b --- /dev/null +++ b/examples/java-generate-equals/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "java-generate-equals" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From d9266db982d0440c1934f58043fec6d48ac1c57a Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Thu, 13 Jan 2022 02:58:03 +0530 Subject: [PATCH 38/82] docs: generate Java data models that overwrite hashCode method (#580) --- docs/languages/Java.md | 4 ++- examples/README.md | 1 + examples/java-generate-hashcode/README.md | 17 ++++++++++ .../__snapshots__/index.spec.ts.snap | 17 ++++++++++ examples/java-generate-hashcode/index.spec.ts | 14 ++++++++ examples/java-generate-hashcode/index.ts | 34 +++++++++++++++++++ .../java-generate-hashcode/package-lock.json | 10 ++++++ examples/java-generate-hashcode/package.json | 10 ++++++ 8 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 examples/java-generate-hashcode/README.md create mode 100644 examples/java-generate-hashcode/__snapshots__/index.spec.ts.snap create mode 100644 examples/java-generate-hashcode/index.spec.ts create mode 100644 examples/java-generate-hashcode/index.ts create mode 100644 examples/java-generate-hashcode/package-lock.json create mode 100644 examples/java-generate-hashcode/package.json diff --git a/docs/languages/Java.md b/docs/languages/Java.md index 0a4af3bd89..4831f779af 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -22,7 +22,9 @@ Check out this [example for a live demonstration](../../examples/java-generate-e ## Include hashCode function for the class -TODO +To overwrite the `hashCode` method, use the preset `JAVA_COMMON_PRESET` and provide the option `hashCode: true`. + +Check out this [example for a live demonstration](../../examples/java-generate-hashcode). ## Change the collection type for arrays TODO diff --git a/examples/README.md b/examples/README.md index 3487ed1e12..539c3a6510 100644 --- a/examples/README.md +++ b/examples/README.md @@ -30,3 +30,4 @@ This directory contains a series of self-contained examples that you can use as - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. - [java-generate-equals](./java-generate-equals) - A basic example that shows how to generate models that overwrite the `equal` method - [generate-csharp-models](./generate-csharp-models) - A basic example to generate C# data models +- [java-generate-hashcode](./java-generate-hashcode) - A basic example that shows how to generate models that overwrite the `hashCode` method \ No newline at end of file diff --git a/examples/java-generate-hashcode/README.md b/examples/java-generate-hashcode/README.md new file mode 100644 index 0000000000..a984386bda --- /dev/null +++ b/examples/java-generate-hashcode/README.md @@ -0,0 +1,17 @@ +# Java Generate `HashCode` + +A basic example on how to generate models that overwrite `hashCode` method + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/java-generate-hashcode/__snapshots__/index.spec.ts.snap b/examples/java-generate-hashcode/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..a49b7a1fed --- /dev/null +++ b/examples/java-generate-hashcode/__snapshots__/index.spec.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate a model to overwrite the hashCode method and should log expected output to console 1`] = ` +Array [ + "public class Root { + private Object email; + + public Object getEmail() { return this.email; } + public void setEmail(Object email) { this.email = email; } + + @Override + public int hashCode() { + return Objects.hash((Object)email); + } +}", +] +`; diff --git a/examples/java-generate-hashcode/index.spec.ts b/examples/java-generate-hashcode/index.spec.ts new file mode 100644 index 0000000000..11cc623a40 --- /dev/null +++ b/examples/java-generate-hashcode/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to generate a model to overwrite the hashCode method', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/java-generate-hashcode/index.ts b/examples/java-generate-hashcode/index.ts new file mode 100644 index 0000000000..38737ab381 --- /dev/null +++ b/examples/java-generate-hashcode/index.ts @@ -0,0 +1,34 @@ +import { JavaGenerator, JAVA_COMMON_PRESET } from '../../src'; + +const generator = new JavaGenerator({ + presets: [ + { + preset: JAVA_COMMON_PRESET, + options: { + equal: false, + hashCode: true, + classToString: false + } + } + ] +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/java-generate-hashcode/package-lock.json b/examples/java-generate-hashcode/package-lock.json new file mode 100644 index 0000000000..c8eba7e034 --- /dev/null +++ b/examples/java-generate-hashcode/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "java-generate-hashcode", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/java-generate-hashcode/package.json b/examples/java-generate-hashcode/package.json new file mode 100644 index 0000000000..c8cfffadc1 --- /dev/null +++ b/examples/java-generate-hashcode/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "java-generate-hashcode" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From 17273c18134b22857a1532bcc239fd84ab100126 Mon Sep 17 00:00:00 2001 From: Debajyoti Halder Date: Thu, 13 Jan 2022 18:15:19 +0530 Subject: [PATCH 39/82] docs: model to change collection types for Java models (#579) --- docs/languages/Java.md | 13 +++++++-- examples/README.md | 3 ++- .../java-change-collection-type/README.md | 17 ++++++++++++ .../__snapshots__/index.spec.ts.snap | 12 +++++++++ .../java-change-collection-type/index.spec.ts | 14 ++++++++++ examples/java-change-collection-type/index.ts | 27 +++++++++++++++++++ .../package-lock.json | 10 +++++++ .../java-change-collection-type/package.json | 10 +++++++ 8 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 examples/java-change-collection-type/README.md create mode 100644 examples/java-change-collection-type/__snapshots__/index.spec.ts.snap create mode 100644 examples/java-change-collection-type/index.spec.ts create mode 100644 examples/java-change-collection-type/index.ts create mode 100644 examples/java-change-collection-type/package-lock.json create mode 100644 examples/java-change-collection-type/package.json diff --git a/docs/languages/Java.md b/docs/languages/Java.md index 4831f779af..ea362bd632 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -1,4 +1,5 @@ # Java + There are special use-cases that each language supports; this document pertains to **Java models**. @@ -16,33 +17,41 @@ There are special use-cases that each language supports; this document pertains ## Include equals function for the class + To overwrite the `equal` method, use the preset `JAVA_COMMON_PRESET` and provide the option `equal: true`. Check out this [example for a live demonstration](../../examples/java-generate-equals). - ## Include hashCode function for the class + To overwrite the `hashCode` method, use the preset `JAVA_COMMON_PRESET` and provide the option `hashCode: true`. Check out this [example for a live demonstration](../../examples/java-generate-hashcode). ## Change the collection type for arrays -TODO + +Sometimes, we might want to render a different collection type, and instead of the default `Array` use as `List` type. To do so, provide the option `collectionType: 'List'`. + +Check out this [example for a live demonstration](../../examples/java-change-collection-type). ## Include toString function for the class + To overwrite the `toString` method, use the preset `JAVA_COMMON_PRESET` and provide the option `classToString: true`. Check out this [example for a live demonstration](../../examples/java-generate-tostring). ## Include JavaDoc for properties + To generate models containing `JavaDocs` from description and examples, use the `JAVA_DESCRIPTION_PRESET` option. Check out this [example for a live demonstration](../../examples/java-generate-javadoc). ## Include Javax validation constraint annotations for properties + In some cases, when you generate the models from JSON Schema, you may want to include `javax.validation.constraint` annotations. Check out this [example for a live demonstration](../../examples/java-generate-javax-constraint-annotation). ## Include Jackson annotations for the class + TODO diff --git a/examples/README.md b/examples/README.md index 539c3a6510..2a8c947537 100644 --- a/examples/README.md +++ b/examples/README.md @@ -30,4 +30,5 @@ This directory contains a series of self-contained examples that you can use as - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. - [java-generate-equals](./java-generate-equals) - A basic example that shows how to generate models that overwrite the `equal` method - [generate-csharp-models](./generate-csharp-models) - A basic example to generate C# data models -- [java-generate-hashcode](./java-generate-hashcode) - A basic example that shows how to generate models that overwrite the `hashCode` method \ No newline at end of file +- [java-change-collection-type](./java-change-collection-type) - An example to render collections as List in Java. +- [java-generate-hashcode](./java-generate-hashcode) - A basic example that shows how to generate models that overwrite the `hashCode` method diff --git a/examples/java-change-collection-type/README.md b/examples/java-change-collection-type/README.md new file mode 100644 index 0000000000..dbcad0ec55 --- /dev/null +++ b/examples/java-change-collection-type/README.md @@ -0,0 +1,17 @@ +# Java change collection type + +A basic example to render collections as List type in Java. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/java-change-collection-type/__snapshots__/index.spec.ts.snap b/examples/java-change-collection-type/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..2be47b3f8b --- /dev/null +++ b/examples/java-change-collection-type/__snapshots__/index.spec.ts.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render collections in Java as List and should log expected output to console 1`] = ` +Array [ + "public class Root { + private List email; + + public List getEmail() { return this.email; } + public void setEmail(List email) { this.email = email; } +}", +] +`; diff --git a/examples/java-change-collection-type/index.spec.ts b/examples/java-change-collection-type/index.spec.ts new file mode 100644 index 0000000000..16f6686758 --- /dev/null +++ b/examples/java-change-collection-type/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to render collections in Java as List', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/java-change-collection-type/index.ts b/examples/java-change-collection-type/index.ts new file mode 100644 index 0000000000..ec637f7076 --- /dev/null +++ b/examples/java-change-collection-type/index.ts @@ -0,0 +1,27 @@ +import { JavaGenerator } from '../../src'; + +const generator = new JavaGenerator({ + collectionType: 'List' +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'array', + items: { + type: 'string', + format: 'email' + } + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/java-change-collection-type/package-lock.json b/examples/java-change-collection-type/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/java-change-collection-type/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/java-change-collection-type/package.json b/examples/java-change-collection-type/package.json new file mode 100644 index 0000000000..29a2821bd3 --- /dev/null +++ b/examples/java-change-collection-type/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "java-change-collection-type" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} From 2a058d6e15d8f7cc8a0577a1d35e168379fae5fb Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 13 Jan 2022 20:17:57 +0100 Subject: [PATCH 40/82] ci: update global workflows --- .github/workflows/automerge-for-humans-merging.yml | 2 +- .github/workflows/automerge.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automerge-for-humans-merging.yml b/.github/workflows/automerge-for-humans-merging.yml index b91ef75487..37ee722fd6 100644 --- a/.github/workflows/automerge-for-humans-merging.yml +++ b/.github/workflows/automerge-for-humans-merging.yml @@ -27,6 +27,6 @@ jobs: GITHUB_TOKEN: "${{ secrets.GH_TOKEN }}" MERGE_LABELS: "!do-not-merge,ready-to-merge" MERGE_METHOD: "squash" - MERGE_COMMIT_MESSAGE: "pull-request-title" + MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})" MERGE_RETRIES: "20" MERGE_RETRY_SLEEP: "30000" \ No newline at end of file diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 4b41128cfd..161e89a1f2 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -54,6 +54,6 @@ jobs: GITHUB_LOGIN: asyncapi-bot MERGE_LABELS: "" MERGE_METHOD: "squash" - MERGE_COMMIT_MESSAGE: "pull-request-title" + MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})" MERGE_RETRIES: "20" MERGE_RETRY_SLEEP: "30000" From 51ae27130e3985f5214aa2e1ad88ce15496d6532 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Fri, 14 Jan 2022 08:27:47 +0100 Subject: [PATCH 41/82] ci: update global workflows (#584) --- .github/workflows/if-nodejs-release.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/if-nodejs-release.yml b/.github/workflows/if-nodejs-release.yml index 71f76077b9..2682e5b35a 100644 --- a/.github/workflows/if-nodejs-release.yml +++ b/.github/workflows/if-nodejs-release.yml @@ -47,7 +47,7 @@ jobs: release: needs: test - name: Publish to NPM and GitHub + name: Publish to any of NPM, Github, and Docker Hub runs-on: ubuntu-latest steps: - name: Set git to use LF #to once and for all finish neverending fight between Unix and Windows @@ -68,11 +68,13 @@ jobs: name: Install dependencies run: npm install - if: steps.packagejson.outputs.exists == 'true' - name: Release to NPM and GitHub + name: Publish to any of NPM, Github, and Docker Hub id: release env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} GIT_AUTHOR_NAME: asyncapi-bot GIT_AUTHOR_EMAIL: info@asyncapi.io GIT_COMMITTER_NAME: asyncapi-bot From ef07448cafd87ea977f1456f42fe84527bfeb4cd Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Fri, 14 Jan 2022 09:23:30 +0100 Subject: [PATCH 42/82] ci: update global workflows (#585) --- .github/workflows/add-good-first-issue-labels.yml | 4 ++-- .github/workflows/help-command.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/add-good-first-issue-labels.yml b/.github/workflows/add-good-first-issue-labels.yml index 3b816b6314..b9cdd0674c 100644 --- a/.github/workflows/add-good-first-issue-labels.yml +++ b/.github/workflows/add-good-first-issue-labels.yml @@ -11,7 +11,7 @@ on: jobs: add-labels: - if: github.event.issue && github.event.issue.state != 'closed' + if: ${{!github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot'}} runs-on: ubuntu-latest steps: - name: Add label @@ -32,7 +32,7 @@ jobs: values[1] = 'docs'; } if(values.length != 2 || !areas.includes(values[1])){ - const message = `Hey @${context.payload.sender.login}, something is wrong with your command please use \`/help\` for help.` + const message = `Hey @${context.payload.sender.login}, your message doesn't follow the requirements, you can try \`/help\`.` await github.rest.issues.createComment({ issue_number: context.issue.number, diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index eee7730184..fd7ed3999e 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -10,7 +10,7 @@ on: jobs: create_help_comment_pr: - if: github.event.issue.pull_request && contains(github.event.comment.body, '/help') + if: github.event.issue.pull_request && contains(github.event.comment.body, '/help' && github.actor != 'asyncapi-bot') runs-on: ubuntu-latest steps: - uses: actions-ecosystem/action-create-comment@v1 @@ -26,7 +26,7 @@ jobs: - `/ready-to-merge` or `/rtm` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added - `/do-not-merge` or `/dnm` - This comment will block automerging even if all conditions are met and ready-to-merge label is added create_help_comment_issue: - if: ${{ !github.event.issue.pull_request && contains(github.event.comment.body, '/help') }} + if: ${{ !github.event.issue.pull_request && contains(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot'}} runs-on: ubuntu-latest steps: - uses: actions-ecosystem/action-create-comment@v1 From ffc0cd8673791b262926093e381c17823fbe9565 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Fri, 14 Jan 2022 13:36:58 +0100 Subject: [PATCH 43/82] docs: add missing documentation for indentation example (#541) --- docs/advanced.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/advanced.md b/docs/advanced.md index 51bf63dc91..cd201625dc 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -73,7 +73,9 @@ The library uses 4 different logging levels: Check out this [example out for a live demonstration](../examples/custom-logging). ## Change the generated indentation type and size -TODO +In some scenarios, depending on how you stitch them together, you might need to change the indentation type or size and both of these cases are fully supported. + +Check out this [example out for a live demonstration](../examples/indentation-type-and-size). ## Change the naming format for properties TODO From 1c684c548cf52cbc64d4e1d050d82607e580268b Mon Sep 17 00:00:00 2001 From: Ritik Rawal Date: Sat, 15 Jan 2022 00:19:51 +0530 Subject: [PATCH 44/82] chore: added nvmrc (#582) --- .gitignore | 2 +- .nvmrc | 1 + docs/development.md | 15 ++++++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 .nvmrc diff --git a/.gitignore b/.gitignore index 8e6a8c4a57..d6c16e1b48 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ node_modules .vscode coverage lib -*.DS_Store +*.DS_Store \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..958b5a36e1 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v14 diff --git a/docs/development.md b/docs/development.md index efac94498a..899022471b 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,7 +1,9 @@ # Development + These are some of the development guidelines and help to setup the library for development. ## Docker + A [Dockerfile](../Dockerfile) is provided and can be used for running test suites or any other command. You can either build the image and run the needed commands manually or rather use any of the following npm scripts: @@ -12,10 +14,13 @@ You can either build the image and run the needed commands manually or rather us ## Environment setup To setup the environment follow these steps: -1. Setup the project by first installing the dependencies `npm install` -2. Make sure the tests pass by running `npm run test` script - - You can update snapshots by running `npm run test -- -u` -3. Make sure code is well formatted and secure `npm run lint` + +1. Make sure to use the appropriate node version as listed in the [package.json file](https://github.com/asyncapi/modelina/blob/ffc0cd8673791b262926093e381c17823fbe9565/package.json#L11). If you use `nvm`, you can simply do `nvm use`. +2. Setup the project by first installing the dependencies `npm install` +3. Make sure the tests pass by running `npm run test` script + - You can update snapshots by running `npm run test -- -u` +4. Make sure code is well formatted and secure `npm run lint` ## BlackBox testing -We have several BlackBox tests that are run separately from the `npm run test` script. Please refer to the [BlackBox documentation](../test/blackbox) for further information. \ No newline at end of file + +We have several BlackBox tests that are run separately from the `npm run test` script. Please refer to the [BlackBox documentation](../test/blackbox) for further information. From 18564f8e57cd805f008d808382e132e52eb0ba34 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Fri, 14 Jan 2022 20:09:44 +0100 Subject: [PATCH 45/82] docs: add ritik307 as a contributor for doc (#588) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8a9293999d..042e7db1e2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -218,6 +218,15 @@ "doc", "example" ] + }, + { + "login": "ritik307", + "name": "Ritik Rawal", + "avatar_url": "https://avatars.githubusercontent.com/u/22374829?v=4", + "profile": "https://ritik307.github.io/portfolio/", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 0a8cf52c21..766052e50c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-19-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-20-orange.svg?style=flat-square)](#contributors-) --- @@ -157,6 +157,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Kamil Janeček

⚠️ πŸ› πŸ’»
mahakporwal02

πŸ’‘ ⚠️ πŸ“– πŸ’»
Debajyoti Halder

πŸ’» ⚠️ πŸ“– πŸ’‘ +
Ritik Rawal

πŸ“– From 8ff4bb9fed7feb00e3d0ed2d8e10171dbcdafb0c Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Sat, 15 Jan 2022 19:50:20 +0530 Subject: [PATCH 46/82] docs: linked to advance language usage (#589) --- docs/usage.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 5a1a10aab9..d694ac20a1 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -72,15 +72,15 @@ The response and request payloads, since it is a JSON Schema variant, is [interp ## Generate Go models -Go is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-go-models) +Go is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-go-models) and the following [Go documentation for more advanced use-cases](./languages/Go.md). ## Generate C# models -C# is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-csharp-models) +C# is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-csharp-models) and the following [C# documentation for more advanced use-cases](./languages/Csharp.md). ## Generate Java models -Java is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-java-models) +Java is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-java-models) and the following [Java documentation for more advanced use-cases](./languages/Java.md). ## Generate TypeScript models @@ -88,4 +88,4 @@ TypeScript is one of the many output languages we support. Check out this [basic ## Generate JavaScript models -JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) +JavaScript is one of the many output languages we support. Check out this [basic example for a live demonstration](../examples/generate-javascript-models) and the following [JavaScript documentation for more advanced use-cases](./languages/JavaScript.md). From 5622923731bab2f45c4ede416761227bd4557ce3 Mon Sep 17 00:00:00 2001 From: mahakporwal02 <56486682+mahakporwal02@users.noreply.github.com> Date: Sat, 15 Jan 2022 20:09:59 +0530 Subject: [PATCH 47/82] feat: assign optional arguments in the constructor for JS generator (#586) --- .../__snapshots__/index.spec.ts.snap | 4 +++- .../__snapshots__/index.spec.ts.snap | 8 ++++++-- .../__snapshots__/index.spec.ts.snap | 8 ++++++-- .../javascript/renderers/ClassRenderer.ts | 8 +++++++- .../javascript/JavaScriptGenerator.spec.ts | 6 ++++++ .../JavaScriptGenerator.spec.ts.snap | 18 ++++++++++++++++++ 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap b/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap index 29c3ac7120..5126bb38b4 100644 --- a/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-javascript-models/__snapshots__/index.spec.ts.snap @@ -6,7 +6,9 @@ Array [ email; constructor(input) { - + if (input.hasOwnProperty('email')) { + this.email = input.email; + } } get email() { return this.email; } diff --git a/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap index 1f7ab44a5a..10f1cd67da 100644 --- a/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap +++ b/examples/javascript-use-cjs/__snapshots__/index.spec.ts.snap @@ -8,7 +8,9 @@ class Person { email; constructor(input) { - + if (input.hasOwnProperty('email')) { + this.email = input.email; + } } get email() { return this.email; } @@ -26,7 +28,9 @@ class Root { person; constructor(input) { - + if (input.hasOwnProperty('person')) { + this.person = input.person; + } } get person() { return this.person; } diff --git a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap index d012b39644..4eca8f9fdd 100644 --- a/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap +++ b/examples/javascript-use-esm/__snapshots__/index.spec.ts.snap @@ -8,7 +8,9 @@ class Person { email; constructor(input) { - + if (input.hasOwnProperty('email')) { + this.email = input.email; + } } get email() { return this.email; } @@ -27,7 +29,9 @@ class Root { person; constructor(input) { - + if (input.hasOwnProperty('person')) { + this.person = input.person; + } } get person() { return this.person; } diff --git a/src/generators/javascript/renderers/ClassRenderer.ts b/src/generators/javascript/renderers/ClassRenderer.ts index 96408d2bcf..e3a7e6249a 100644 --- a/src/generators/javascript/renderers/ClassRenderer.ts +++ b/src/generators/javascript/renderers/ClassRenderer.ts @@ -71,7 +71,13 @@ export const JS_DEFAULT_CLASS_PRESET: ClassPreset = { }, ctor({ renderer, model }) { const properties = model.properties || {}; - const assigments = Object.entries(properties).filter(([propertyName]) => model.isRequired(propertyName)).map(([propertyName, property]) => { + const assigments = Object.entries(properties).map(([propertyName, property]) => { + if (!model.isRequired(propertyName)) { + propertyName = renderer.nameProperty(propertyName, property); + return `if (input.hasOwnProperty('${propertyName}')) { + this.${propertyName} = input.${propertyName}; +}`; + } propertyName = renderer.nameProperty(propertyName, property); return `this.${propertyName} = input.${propertyName};`; }); diff --git a/test/generators/javascript/JavaScriptGenerator.spec.ts b/test/generators/javascript/JavaScriptGenerator.spec.ts index 504053a752..4566ea10ab 100644 --- a/test/generators/javascript/JavaScriptGenerator.spec.ts +++ b/test/generators/javascript/JavaScriptGenerator.spec.ts @@ -78,6 +78,12 @@ describe('JavaScriptGenerator', () => { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; + if (input.hasOwnProperty('marriage')) { + this.marriage = input.marriage; + } + if (input.hasOwnProperty('members')) { + this.members = input.members; + } this.arrayType = input.arrayType; } diff --git a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap index d99548a50f..03941edbdd 100644 --- a/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap +++ b/test/generators/javascript/__snapshots__/JavaScriptGenerator.spec.ts.snap @@ -20,7 +20,16 @@ class Address { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; + if (input.hasOwnProperty('marriage')) { + this.marriage = input.marriage; + } + if (input.hasOwnProperty('members')) { + this.members = input.members; + } this.arrayType = input.arrayType; + if (input.hasOwnProperty('otherModel')) { + this.otherModel = input.otherModel; + } } get streetName() { return this.streetName; } @@ -96,7 +105,16 @@ class Address { this.city = input.city; this.state = input.state; this.houseNumber = input.houseNumber; + if (input.hasOwnProperty('marriage')) { + this.marriage = input.marriage; + } + if (input.hasOwnProperty('members')) { + this.members = input.members; + } this.arrayType = input.arrayType; + if (input.hasOwnProperty('otherModel')) { + this.otherModel = input.otherModel; + } } get streetName() { return this.streetName; } From 5dc200ec64cfd4eab66eed9ab3f17c8687725777 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 17 Jan 2022 02:08:54 +0100 Subject: [PATCH 48/82] chore(release): v0.44.0 (#590) Co-authored-by: asyncapi-bot --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3414878fc..dedfe38b65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.43.0", + "version": "0.44.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.43.0", + "version": "0.44.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 25b797312b..b891f65ab1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.43.0", + "version": "0.44.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 88cf92df862bbac8e8606b3b7b5d9f6967683b12 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 17 Jan 2022 14:41:40 +0100 Subject: [PATCH 49/82] ci: fix coverage problems with checkout (#592) --- .github/workflows/coverall.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/coverall.yml b/.github/workflows/coverall.yml index a4e424e20d..1f7e181683 100644 --- a/.github/workflows/coverall.yml +++ b/.github/workflows/coverall.yml @@ -10,7 +10,7 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v2 - name: Setup Node.js uses: actions/setup-node@v1 with: From 57948b508f9f5472f6ee14b2ac130d5e5fee9c1d Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 20 Jan 2022 15:12:19 +0100 Subject: [PATCH 50/82] ci: update global workflows (#593) --- .github/workflows/help-command.yml | 4 ++-- .github/workflows/if-nodejs-release.yml | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/help-command.yml b/.github/workflows/help-command.yml index fd7ed3999e..f9d4773511 100644 --- a/.github/workflows/help-command.yml +++ b/.github/workflows/help-command.yml @@ -10,7 +10,7 @@ on: jobs: create_help_comment_pr: - if: github.event.issue.pull_request && contains(github.event.comment.body, '/help' && github.actor != 'asyncapi-bot') + if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }} runs-on: ubuntu-latest steps: - uses: actions-ecosystem/action-create-comment@v1 @@ -26,7 +26,7 @@ jobs: - `/ready-to-merge` or `/rtm` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added - `/do-not-merge` or `/dnm` - This comment will block automerging even if all conditions are met and ready-to-merge label is added create_help_comment_issue: - if: ${{ !github.event.issue.pull_request && contains(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot'}} + if: ${{ !github.event.issue.pull_request && contains(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }} runs-on: ubuntu-latest steps: - uses: actions-ecosystem/action-create-comment@v1 diff --git a/.github/workflows/if-nodejs-release.yml b/.github/workflows/if-nodejs-release.yml index 2682e5b35a..6cdfa8e56d 100644 --- a/.github/workflows/if-nodejs-release.yml +++ b/.github/workflows/if-nodejs-release.yml @@ -10,7 +10,10 @@ on: # below lines are not enough to have release supported for these branches # make sure configuration of `semantic-release` package mentiones these branches - next - - '**-release' + - next-major + - beta + - alpha + - '**-release' # custom jobs: From b2683cdae5b158be29afe56d0fa3d560ce4cc85e Mon Sep 17 00:00:00 2001 From: Samriddhi Date: Wed, 26 Jan 2022 21:00:04 +0530 Subject: [PATCH 51/82] feat: un/marshal helper function for JS (#591) --- .../javascript/JavaScriptRenderer.ts | 10 +- src/generators/javascript/index.ts | 1 + .../javascript/presets/CommonPreset.ts | 207 ++++++++++++++++++ src/generators/javascript/presets/index.ts | 1 + .../preset/MarshallingPreset.spec.ts | 49 +++++ .../MarshallingPreset.spec.ts.snap | 165 ++++++++++++++ 6 files changed, 428 insertions(+), 5 deletions(-) create mode 100644 src/generators/javascript/presets/CommonPreset.ts create mode 100644 src/generators/javascript/presets/index.ts create mode 100644 test/generators/javascript/preset/MarshallingPreset.spec.ts create mode 100644 test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap diff --git a/src/generators/javascript/JavaScriptRenderer.ts b/src/generators/javascript/JavaScriptRenderer.ts index b2042718ce..2c6de544e4 100644 --- a/src/generators/javascript/JavaScriptRenderer.ts +++ b/src/generators/javascript/JavaScriptRenderer.ts @@ -14,7 +14,7 @@ export abstract class JavaScriptRenderer extends AbstractRenderer, - model: CommonModel, + model: CommonModel, inputModel: CommonInputModel, ) { super(options, generator, presets, model, inputModel); @@ -29,7 +29,7 @@ export abstract class JavaScriptRenderer extends AbstractRenderer { - return this.runPreset('property', { propertyName, property, type}); + return this.runPreset('property', { propertyName, property, type }); } } diff --git a/src/generators/javascript/index.ts b/src/generators/javascript/index.ts index e9839415f3..586eb2b0c0 100644 --- a/src/generators/javascript/index.ts +++ b/src/generators/javascript/index.ts @@ -2,3 +2,4 @@ export * from './JavaScriptGenerator'; export * from './JavaScriptFileGenerator'; export { JS_DEFAULT_PRESET } from './JavaScriptPreset'; export type { JavaScriptPreset } from './JavaScriptPreset'; +export * from './presets'; diff --git a/src/generators/javascript/presets/CommonPreset.ts b/src/generators/javascript/presets/CommonPreset.ts new file mode 100644 index 0000000000..8117953efd --- /dev/null +++ b/src/generators/javascript/presets/CommonPreset.ts @@ -0,0 +1,207 @@ +import { JavaScriptRenderer } from '../JavaScriptRenderer'; +import { JavaScriptPreset } from '../JavaScriptPreset'; +import { getUniquePropertyName, DefaultPropertyNames, TypeHelpers, ModelKind } from '../../../helpers'; +import { CommonInputModel, CommonModel } from '../../../models'; + +export interface JavaScriptCommonPresetOptions { + marshalling: boolean; +} + +function realizePropertyFactory(prop: string) { + return `$\{typeof ${prop} === 'number' || typeof ${prop} === 'boolean' ? ${prop} : JSON.stringify(${prop})}`; +} +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: JavaScriptRenderer, 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 propMarshalCode = renderMarshalProperty(modelInstanceVariable, propModel, inputModel); + const marshalCode = `json += \`"${prop}": ${propMarshalCode},\`;`; + return `if(${modelInstanceVariable} !== undefined) { + ${marshalCode} +}`; + }); + return marshalProperties.join('\n'); +} + +function renderMarshalPatternProperties(model: CommonModel, renderer: JavaScriptRenderer, 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 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; + ${marshalCode} + } +}`; + } + } + return marshalPatternProperties; +} + +function renderMarshalAdditionalProperties(model: CommonModel, renderer: JavaScriptRenderer, inputModel: CommonInputModel) { + let marshalAdditionalProperties = ''; + if (model.additionalProperties !== undefined) { + let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties); + additionalPropertyName = renderer.nameProperty(additionalPropertyName, model.additionalProperties); + 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; + ${marshalCode} + } +}`; + } + return marshalAdditionalProperties; +} + +/** + * Render `marshal` function based on model + */ +function renderMarshal({ renderer, model, inputModel }: { + renderer: JavaScriptRenderer, + model: CommonModel, + inputModel: CommonInputModel +}): string { + return `marshal(){ + let json = '{' +${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 renderUnmarshalProperty(modelInstanceVariable: string, model: CommonModel, inputModel: CommonInputModel, renderer: JavaScriptRenderer) { + 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: JavaScriptRenderer, inputModel: CommonInputModel) { + const properties = model.properties || {}; + const propertyKeys = [...Object.entries(properties)]; + const unmarshalProperties = propertyKeys.map(([prop, propModel]) => { + const formattedPropertyName = renderer.nameProperty(prop, propModel); + 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: JavaScriptRenderer, 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); + const modelInstanceVariable = 'value'; + 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, ${unmarshalCode}); + continue; +}`; + } + } + return { unmarshalPatternProperties, setPatternPropertiesMap }; +} + +function renderUnmarshalAdditionalProperties(model: CommonModel, renderer: JavaScriptRenderer, inputModel: CommonInputModel) { + let unmarshalAdditionalProperties = ''; + let setAdditionalPropertiesMap = ''; + if (model.additionalProperties !== undefined) { + let additionalPropertyName = getUniquePropertyName(model, DefaultPropertyNames.additionalProperties); + additionalPropertyName = renderer.nameProperty(additionalPropertyName, model.additionalProperties); + const modelInstanceVariable = 'value'; + const unmarshalCode = renderUnmarshalProperty(modelInstanceVariable, model.additionalProperties, inputModel, renderer); + setAdditionalPropertiesMap = `if (instance.${additionalPropertyName} === undefined) {instance.${additionalPropertyName} = new Map();}`; + unmarshalAdditionalProperties = `instance.${additionalPropertyName}.set(key, ${unmarshalCode});`; + } + return { unmarshalAdditionalProperties, setAdditionalPropertiesMap }; +} + +/** + * Render `unmarshal` function based on model + */ +function renderUnmarshal({ renderer, model, inputModel }: { + renderer: JavaScriptRenderer, + model: CommonModel, + inputModel: CommonInputModel +}): string { + const properties = model.properties || {}; + 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 `unmarshal(json){ + const obj = typeof json === "object" ? json : JSON.parse(json); + const instance = new ${formattedModelName}({}); + +${renderer.indent(unmarshalProperties)} + + //Not part of core properties + ${setPatternPropertiesMap} + ${setAdditionalPropertiesMap} + for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![${propertyNames}].includes(key);}))) { +${renderer.indent(unmarshalPatternProperties, 4)} +${renderer.indent(unmarshalAdditionalProperties, 4)} + } + return instance; +}`; +} + +/** + * Preset which adds `marshal`, `unmarshal` functions to class. + * + * @implements {JavaScriptPreset} + */ +export const JS_COMMON_PRESET: JavaScriptPreset = { + class: { + additionalContent({ renderer, model, content, options, inputModel }) { + options = options || {}; + const blocks: string[] = []; + + if (options.marshalling === true) { + blocks.push(renderMarshal({ renderer, model, inputModel })); + blocks.push(renderUnmarshal({ renderer, model, inputModel })); + } + + return renderer.renderBlock([content, ...blocks], 2); + }, + } +}; diff --git a/src/generators/javascript/presets/index.ts b/src/generators/javascript/presets/index.ts new file mode 100644 index 0000000000..58c93bfea2 --- /dev/null +++ b/src/generators/javascript/presets/index.ts @@ -0,0 +1 @@ +export * from './CommonPreset'; diff --git a/test/generators/javascript/preset/MarshallingPreset.spec.ts b/test/generators/javascript/preset/MarshallingPreset.spec.ts new file mode 100644 index 0000000000..23cadf7b0d --- /dev/null +++ b/test/generators/javascript/preset/MarshallingPreset.spec.ts @@ -0,0 +1,49 @@ +/* eslint-disable */ + +import { JavaScriptGenerator, JS_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: {$ref: '#/definitions/NestedTest'}, + required: ['string prop'], + properties: { + 'string prop': { type: 'string' }, + numberProp: { type: 'number' }, + objectProp: { $ref: '#/definitions/NestedTest' } + }, + patternProperties: { + '^S(.?)test': { type: 'string' }, + '^S(.?)AnotherTest': { $ref: '#/definitions/NestedTest' }, + }, +}; +describe('Marshalling preset', () => { + test('should render un/marshal code', async () => { + const generator = new JavaScriptGenerator({ + presets: [ + { + preset: JS_COMMON_PRESET, + options: { + marshalling: true + } + } + ] + }); + const inputModel = await generator.process(doc); + + const testModel = inputModel.models['Test']; + const nestedTestModel = inputModel.models['NestedTest']; + + const testClass = await generator.renderClass(testModel, inputModel); + const nestedTestClass = await generator.renderClass(nestedTestModel, inputModel); + + expect(testClass.result).toMatchSnapshot(); + expect(nestedTestClass.result).toMatchSnapshot(); + }); +}); diff --git a/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap b/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap new file mode 100644 index 0000000000..31631df59f --- /dev/null +++ b/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap @@ -0,0 +1,165 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Marshalling preset should render un/marshal code 1`] = ` +"class Test { + stringProp; + numberProp; + objectProp; + additionalProperties; + sTestPatternProperties; + sAnotherTestPatternProperties; + + constructor(input) { + this.stringProp = input.stringProp; + if (input.hasOwnProperty('numberProp')) { + this.numberProp = input.numberProp; + } + if (input.hasOwnProperty('objectProp')) { + this.objectProp = input.objectProp; + } + } + + get stringProp() { return this.stringProp; } + set stringProp(stringProp) { this.stringProp = stringProp; } + + get numberProp() { return this.numberProp; } + set numberProp(numberProp) { this.numberProp = numberProp; } + + get objectProp() { return this.objectProp; } + set objectProp(objectProp) { this.objectProp = objectProp; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + get sTestPatternProperties() { return this.sTestPatternProperties; } + set sTestPatternProperties(sTestPatternProperties) { this.sTestPatternProperties = sTestPatternProperties; } + + get sAnotherTestPatternProperties() { return this.sAnotherTestPatternProperties; } + set sAnotherTestPatternProperties(sAnotherTestPatternProperties) { this.sAnotherTestPatternProperties = sAnotherTestPatternProperties; } + + marshal(){ + 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.numberProp !== undefined) { + 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()},`; + } + 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)},`; + } + }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}": ${value.marshal()},`; + } + } + + //Remove potential last comma + return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + } + + unmarshal(json){ + const obj = typeof json === "object" ? json : JSON.parse(json); + const instance = new Test({}); + + if (obj["string prop"] !== undefined) { + instance.stringProp = obj["string prop"]; + } + if (obj["numberProp"] !== undefined) { + instance.numberProp = obj["numberProp"]; + } + 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);}))) { + //Check all pattern properties + if (key.match(new RegExp('^S(.?)test'))) { + instance.sTestPatternProperties.set(key, value); + continue; + }//Check all pattern properties + if (key.match(new RegExp('^S(.?)AnotherTest'))) { + instance.sAnotherTestPatternProperties.set(key, NestedTest.unmarshal(value)); + continue; + } + instance.additionalProperties.set(key, NestedTest.unmarshal(value)); + } + return instance; + } +}" +`; + +exports[`Marshalling preset should render un/marshal code 2`] = ` +"class NestedTest { + stringProp; + additionalProperties; + + constructor(input) { + if (input.hasOwnProperty('stringProp')) { + this.stringProp = input.stringProp; + } + } + + get stringProp() { return this.stringProp; } + set stringProp(stringProp) { this.stringProp = stringProp; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + marshal(){ + let json = '{' + if(this.stringProp !== undefined) { + 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)},`; + } + } + + //Remove potential last comma + return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + } + + unmarshal(json){ + const obj = typeof json === "object" ? json : JSON.parse(json); + const instance = new NestedTest({}); + + if (obj["stringProp"] !== undefined) { + instance.stringProp = obj["stringProp"]; + } + + //Not part of core properties + + if (instance.additionalProperties === undefined) {instance.additionalProperties = new Map();} + for (const [key, value] of Object.entries(obj).filter((([key,]) => {return !["stringProp"].includes(key);}))) { + + instance.additionalProperties.set(key, value); + } + return instance; + } +}" +`; From 9341e33f05a9118c45657155a825540168b5d645 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 27 Jan 2022 09:12:00 +0100 Subject: [PATCH 52/82] chore(release): v0.45.0 (#600) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index dedfe38b65..e57de8a7ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.44.0", + "version": "0.45.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.44.0", + "version": "0.45.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index b891f65ab1..815f06960f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.44.0", + "version": "0.45.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 017d07b6785a664e93911ac45e1fa886ab881d2c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 27 Jan 2022 09:26:38 +0100 Subject: [PATCH 53/82] chore(deps): bump node-fetch from 2.6.5 to 2.6.7 (#602) --- package-lock.json | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e57de8a7ed..2519c4e8de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9088,14 +9088,22 @@ } }, "node_modules/node-fetch": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "dependencies": { "whatwg-url": "^5.0.0" }, "engines": { "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, "node_modules/node-int64": { @@ -21959,9 +21967,9 @@ } }, "node-fetch": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", - "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", "requires": { "whatwg-url": "^5.0.0" } From 810d607cb6ada153f8d4e884a1d864350e7e2845 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 27 Jan 2022 11:25:04 +0100 Subject: [PATCH 54/82] ci: update global workflows (#603) --- .github/workflows/automerge.yml | 10 ++++------ .github/workflows/autoupdate.yml | 14 +++++++++----- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 161e89a1f2..393e12f9bc 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -1,5 +1,5 @@ - # This action is centrally managed in https://github.com/asyncapi/.github/ - # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo. +# This action is centrally managed in https://github.com/asyncapi/.github/ +# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo. name: Automerge release bump PR @@ -19,9 +19,8 @@ on: - submitted jobs: - autoapprove: - if: github.event.pull_request.draft == false && (github.event.pull_request.user.login == 'asyncapi-bot' || github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'dependabot-preview[bot]') && !contains(github.event.pull_request.labels.*.name, 'released') + if: github.event.pull_request.draft == false && (github.actor == 'asyncapi-bot' || github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]') && !contains(github.event.pull_request.labels.*.name, 'released') runs-on: ubuntu-latest steps: - name: Autoapproving @@ -39,8 +38,7 @@ jobs: owner: context.repo.owner, repo: context.repo.repo, labels: ['autoapproved'] - }) - + }) automerge: needs: [autoapprove] diff --git a/.github/workflows/autoupdate.yml b/.github/workflows/autoupdate.yml index d147580ee0..b8faa4280a 100644 --- a/.github/workflows/autoupdate.yml +++ b/.github/workflows/autoupdate.yml @@ -2,7 +2,7 @@ #Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo #This workflow is designed to work with: -# - autoapprove and automerge workflows for dependabot and asyncapibot. +# - autoapprove and automerge workflows for dependabot and asyncapibot. # - special release branches that we from time to time create in upstream repos. If we open up PRs for them from the very beginning of the release, the release branch will constantly update with new things from the destination branch they are opened against # It uses GitHub Action that auto-updates pull requests branches, whenever changes are pushed to their destination branch. @@ -11,17 +11,21 @@ name: autoupdate on: - push: {} - -jobs: + push: + branches-ignore: + - 'version-bump/**' + - 'dependabot/**' + - 'bot/**' + - 'all-contributors/**' +jobs: autoupdate: runs-on: ubuntu-latest steps: - name: Autoupdating uses: docker://chinthakagodawita/autoupdate-action:v1 env: - GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + GITHUB_TOKEN: '${{ secrets.GH_TOKEN }}' PR_FILTER: "labelled" PR_LABELS: "autoapproved" PR_READY_STATE: "ready_for_review" From 079db7941e2525c8d3aee136da51275e75170ff4 Mon Sep 17 00:00:00 2001 From: Samriddhi Date: Mon, 31 Jan 2022 15:01:21 +0530 Subject: [PATCH 55/82] docs: added jackson annotation example (#601) --- docs/languages/Java.md | 4 +++- .../README.md | 17 ++++++++++++++ .../__snapshots__/index.spec.ts.snap | 22 +++++++++++++++++++ .../index.spec.ts | 14 ++++++++++++ .../java-generate-jackson-annotation/index.ts | 22 +++++++++++++++++++ .../package-lock.json | 10 +++++++++ .../package.json | 12 ++++++++++ 7 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 examples/java-generate-jackson-annotation/README.md create mode 100644 examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap create mode 100644 examples/java-generate-jackson-annotation/index.spec.ts create mode 100644 examples/java-generate-jackson-annotation/index.ts create mode 100644 examples/java-generate-jackson-annotation/package-lock.json create mode 100644 examples/java-generate-jackson-annotation/package.json diff --git a/docs/languages/Java.md b/docs/languages/Java.md index ea362bd632..f6a8b06c08 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -54,4 +54,6 @@ Check out this [example for a live demonstration](../../examples/java-generate-j ## Include Jackson annotations for the class -TODO +To generate Java data models with Jackson annotation using `JAVA_JACKSON_PRESET` option. + +Check out this [example for a live demonstration](../../examples/java-generate-jackson-annotation). diff --git a/examples/java-generate-jackson-annotation/README.md b/examples/java-generate-jackson-annotation/README.md new file mode 100644 index 0000000000..cfae43c36d --- /dev/null +++ b/examples/java-generate-jackson-annotation/README.md @@ -0,0 +1,17 @@ +# Java Generate Jackson Annotation + +A basic example on how to generate models for jackson annotation + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap b/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..400c7945b1 --- /dev/null +++ b/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate data models for jackson annotation and should log expected output to console 1`] = ` +Array [ + "public class Root { + private Double minNumberProp; + private Double maxNumberProp; + private Map additionalProperties; + + @JsonProperty(\\"min_number_prop\\") + public Double getMinNumberProp() { return this.minNumberProp; } + public void setMinNumberProp(Double minNumberProp) { this.minNumberProp = minNumberProp; } + + @JsonProperty(\\"max_number_prop\\") + public Double getMaxNumberProp() { return this.maxNumberProp; } + public void setMaxNumberProp(Double maxNumberProp) { this.maxNumberProp = maxNumberProp; } + + public Map getAdditionalProperties() { return this.additionalProperties; } + public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } +}", +] +`; diff --git a/examples/java-generate-jackson-annotation/index.spec.ts b/examples/java-generate-jackson-annotation/index.spec.ts new file mode 100644 index 0000000000..34cc2aaa96 --- /dev/null +++ b/examples/java-generate-jackson-annotation/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to generate data models for jackson annotation', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/java-generate-jackson-annotation/index.ts b/examples/java-generate-jackson-annotation/index.ts new file mode 100644 index 0000000000..3a1d4e2f31 --- /dev/null +++ b/examples/java-generate-jackson-annotation/index.ts @@ -0,0 +1,22 @@ +import { JavaGenerator, JAVA_JACKSON_PRESET } from '../../src'; + +const generator = new JavaGenerator({ + presets: [JAVA_JACKSON_PRESET] +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + properties: { + min_number_prop: { type: 'number' }, + max_number_prop: { type: 'number' }, + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/java-generate-jackson-annotation/package-lock.json b/examples/java-generate-jackson-annotation/package-lock.json new file mode 100644 index 0000000000..9f20d91e28 --- /dev/null +++ b/examples/java-generate-jackson-annotation/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "java-generate-jackson-annotation", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} \ No newline at end of file diff --git a/examples/java-generate-jackson-annotation/package.json b/examples/java-generate-jackson-annotation/package.json new file mode 100644 index 0000000000..7dc7424795 --- /dev/null +++ b/examples/java-generate-jackson-annotation/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "java-generate-jackson-annotation" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} \ No newline at end of file From bc2f3efbb2c6bf2646e45bd40e75c1363e34ad17 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 31 Jan 2022 20:53:37 +0100 Subject: [PATCH 56/82] feat: support AsyncAPI v2.3.0 (#563) --- README.md | 2 +- package-lock.json | 30 +- package.json | 2 +- src/models/AsyncapiV2Schema.ts | 4 +- src/processors/AsyncAPIInputProcessor.ts | 2 +- test/blackbox/README.md | 1 + test/blackbox/docs/AsyncAPI-2_3/dummy.json | 574 ++++++++++++++++++ .../processors/AsyncAPIInputProcessor.spec.ts | 4 + 8 files changed, 600 insertions(+), 19 deletions(-) create mode 100644 test/blackbox/docs/AsyncAPI-2_3/dummy.json diff --git a/README.md b/README.md index 766052e50c..cbf624d6b0 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ To see the complete feature list for each language, please click the individual AsyncAPI - We support the following AsyncAPI versions: 2.0.0, 2.1.0 and 2.2.0, which generates models for all the defined message payloads. + We support the following AsyncAPI versions: 2.0.0, 2.1.0, 2.2.0 and 2.3.0, which generates models for all the defined message payloads. JSON Schema diff --git a/package-lock.json b/package-lock.json index 2519c4e8de..8229e8a493 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@apidevtools/swagger-parser": "^10.0.3", - "@asyncapi/parser": "^1.12.0", + "@asyncapi/parser": "^1.14.0", "change-case": "^4.1.2", "openapi-types": "9.3.0" }, @@ -82,12 +82,12 @@ } }, "node_modules/@asyncapi/parser": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.12.0.tgz", - "integrity": "sha512-SIM6DDVk/DLvFlSdWF0UelOaOy8zItWGl1vQn79NkAXN9JfBV6eUZ+Sp9xb2pVrMcELtOKsy4Qp9UeDHPpInfg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.14.0.tgz", + "integrity": "sha512-OHqvInhquPwthrSEkglxqjj6+6A2gZW3NnmyOoXmWb7/9jS90hJwn9bQOMkd4bx2lT6PWmlZjjKFEldH8ILRQg==", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@asyncapi/specs": "^2.11.0", + "@asyncapi/specs": "^2.13.0", "@fmvilas/pseudo-yaml-ast": "^0.3.1", "ajv": "^6.10.1", "js-yaml": "^3.13.1", @@ -133,9 +133,9 @@ } }, "node_modules/@asyncapi/specs": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-2.12.0.tgz", - "integrity": "sha512-X4Xkrl+9WXSk5EJhsueIxNx6ymHI5wpkw4ofetV+VRnPLNob/XO4trPSJClrL5hlknxbGADLvlrkI5d3XJ996g==" + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-2.13.0.tgz", + "integrity": "sha512-X0OrxJtzwRH8iLILO/gUTDqjGVPmagmdlgdyuBggYAoGXzF6ZuAws3XCLxtPNve5eA/0V/1puwpUYEGekI22og==" }, "node_modules/@babel/code-frame": { "version": "7.15.8", @@ -14978,12 +14978,12 @@ } }, "@asyncapi/parser": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.12.0.tgz", - "integrity": "sha512-SIM6DDVk/DLvFlSdWF0UelOaOy8zItWGl1vQn79NkAXN9JfBV6eUZ+Sp9xb2pVrMcELtOKsy4Qp9UeDHPpInfg==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.14.0.tgz", + "integrity": "sha512-OHqvInhquPwthrSEkglxqjj6+6A2gZW3NnmyOoXmWb7/9jS90hJwn9bQOMkd4bx2lT6PWmlZjjKFEldH8ILRQg==", "requires": { "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@asyncapi/specs": "^2.11.0", + "@asyncapi/specs": "^2.13.0", "@fmvilas/pseudo-yaml-ast": "^0.3.1", "ajv": "^6.10.1", "js-yaml": "^3.13.1", @@ -15024,9 +15024,9 @@ } }, "@asyncapi/specs": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-2.12.0.tgz", - "integrity": "sha512-X4Xkrl+9WXSk5EJhsueIxNx6ymHI5wpkw4ofetV+VRnPLNob/XO4trPSJClrL5hlknxbGADLvlrkI5d3XJ996g==" + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-2.13.0.tgz", + "integrity": "sha512-X0OrxJtzwRH8iLILO/gUTDqjGVPmagmdlgdyuBggYAoGXzF6ZuAws3XCLxtPNve5eA/0V/1puwpUYEGekI22og==" }, "@babel/code-frame": { "version": "7.15.8", diff --git a/package.json b/package.json index 815f06960f..1b0c7b12ad 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@apidevtools/swagger-parser": "^10.0.3", - "@asyncapi/parser": "^1.12.0", + "@asyncapi/parser": "^1.14.0", "change-case": "^4.1.2", "openapi-types": "9.3.0" }, diff --git a/src/models/AsyncapiV2Schema.ts b/src/models/AsyncapiV2Schema.ts index 8b1c7d4cfa..fc97d9811b 100644 --- a/src/models/AsyncapiV2Schema.ts +++ b/src/models/AsyncapiV2Schema.ts @@ -13,12 +13,14 @@ export class AsyncapiV2ExternalDocumentation { } /** - * AsyncAPI 2.0 + 2.1 schema model + * AsyncAPI schema model * * Based on Draft 7 with additions * * https://www.asyncapi.com/docs/specifications/v2.0.0#schemaObject * https://www.asyncapi.com/docs/specifications/v2.1.0#schemaObject + * https://www.asyncapi.com/docs/specifications/v2.2.0#schemaObject + * https://www.asyncapi.com/docs/specifications/v2.3.0#schemaObject */ export class AsyncapiV2Schema { $schema?: string; diff --git a/src/processors/AsyncAPIInputProcessor.ts b/src/processors/AsyncAPIInputProcessor.ts index 78eabd7ef5..b556918922 100644 --- a/src/processors/AsyncAPIInputProcessor.ts +++ b/src/processors/AsyncAPIInputProcessor.ts @@ -9,7 +9,7 @@ import { AsyncapiV2Schema } from '../models/AsyncapiV2Schema'; * Class for processing AsyncAPI inputs */ export class AsyncAPIInputProcessor extends AbstractInputProcessor { - static supportedVersions = ['2.0.0', '2.1.0', '2.2.0']; + static supportedVersions = ['2.0.0', '2.1.0', '2.2.0', '2.3.0']; /** * Process the input as an AsyncAPI document diff --git a/test/blackbox/README.md b/test/blackbox/README.md index 13c4ed434a..8fb06b4510 100644 --- a/test/blackbox/README.md +++ b/test/blackbox/README.md @@ -6,6 +6,7 @@ The documents being tested can be found under [docs](./docs), which contain docu - [AsyncAPI 2.0](./docs/AsyncAPI-2_0) - [AsyncAPI 2.1](./docs/AsyncAPI-2_1) - [AsyncAPI 2.2](./docs/AsyncAPI-2_2) +- [AsyncAPI 2.3](./docs/AsyncAPI-2_3) - [JSON Schema draft 4](./docs/JsonSchemaDraft-4) - [JSON Schema draft 6](./docs/JsonSchemaDraft-6) - [JSON Schema draft 7](./docs/JsonSchemaDraft-7) diff --git a/test/blackbox/docs/AsyncAPI-2_3/dummy.json b/test/blackbox/docs/AsyncAPI-2_3/dummy.json new file mode 100644 index 0000000000..3aabc2c527 --- /dev/null +++ b/test/blackbox/docs/AsyncAPI-2_3/dummy.json @@ -0,0 +1,574 @@ +{ + "asyncapi": "2.3.0", + "externalDocs": { + "description": "Find more info here", + "url": "https://www.asyncapi.com" + }, + "info": { + "title": "Dummy example with all spec features included", + "version": "0.0.1", + "description": "This is an example of AsyncAPI specification file that is suppose to include all possible features of the AsyncAPI specification. Do not use it on production.\n\nIt's goal is to support development of documentation and code generation with the [AsyncAPI Generator](https://github.com/asyncapi/generator/) and [Template projects](https://github.com/search?q=topic%3Aasyncapi+topic%3Agenerator+topic%3Atemplate)\n", + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + }, + "contact": { + "name": "API Support", + "url": "http://www.asyncapi.com/support", + "email": "info@asyncapi.io" + }, + "x-twitter": "@AsyncAPISpec" + }, + "tags": [ + { + "name": "root-tag1", + "externalDocs": { + "description": "External docs description 1", + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "root-tag2", + "description": "Description 2", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "root-tag3" + }, + { + "name": "root-tag4", + "description": "Description 4" + }, + { + "name": "root-tag5", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + } + ], + "servers": { + "dummy-mqtt": { + "url": "mqtt://localhost", + "protocol": "mqtt", + "description": "dummy MQTT broker", + "bindings": { + "mqtt": { + "clientId": "guest", + "cleanSession": true + } + } + }, + "dummy-amqp": { + "url": "amqp://localhost:{port}", + "protocol": "amqp", + "description": "dummy AMQP broker", + "protocolVersion": "0.9.1", + "variables": { + "port": { + "enum": [ + "15672", + "5672" + ] + } + }, + "security": [ + { + "user-password": [] + } + ] + }, + "dummy-kafka": { + "url": "http://localhost:{port}", + "protocol": "kafka", + "description": "dummy Kafka broker", + "variables": { + "port": { + "default": "9092" + } + } + } + }, + "defaultContentType": "application/json", + "channels": { + "dummy/channel/with/{dummy}/parameter/create": { + "servers": [ + "dummy-kafka" + ], + "x-dummy-security": { + "$ref": "#/components/securitySchemes/supportedOauthFlows/flows/clientCredentials" + }, + "description": "Dummy channel description.", + "parameters": { + "dummy": { + "$ref": "#/components/parameters/dummy" + } + }, + "publish": { + "summary": "Inform whenever something dummy is created.", + "description": "Longer description.\n\nStill dummy though.\n", + "operationId": "receiveNewDummyInfo", + "tags": [ + { + "name": "oparation-tag1", + "externalDocs": { + "description": "External docs description 1", + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "oparation-tag2", + "description": "Description 2", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "oparation-tag3" + }, + { + "name": "oparation-tag4", + "description": "Description 4" + }, + { + "name": "oparation-tag5", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + } + ], + "traits": [ + { + "$ref": "#/components/operationTraits/kafka" + } + ], + "message": { + "$ref": "#/components/messages/dummyCreated" + } + } + }, + "dummy/channel/without/parameter": { + "bindings": { + "amqp": { + "is": "routingKey" + } + }, + "subscribe": { + "operationId": "receiveSystemInfo", + "bindings": { + "amqp": { + "expiration": 100000, + "userId": "guest", + "cc": [ + "user.logs" + ], + "priority": 10, + "deliveryMode": 2, + "mandatory": false, + "bcc": [ + "external.audit" + ], + "replyTo": "user.signedup", + "timestamp": true, + "ack": false, + "bindingVersion": "0.1.0" + } + }, + "message": { + "$ref": "#/components/messages/dummyInfo" + } + } + } + }, + "components": { + "messages": { + "dummyCreated": { + "name": "dummyCreated", + "title": "Dummy created message", + "summary": "This is just a dummy create message", + "correlationId": { + "description": "This is a dummy correlation ID.", + "location": "$message.header#/correlationId" + }, + "tags": [ + { + "name": "message-tag1", + "externalDocs": { + "description": "External docs description 1", + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "message-tag2", + "description": "Description 2", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + }, + { + "name": "message-tag3" + }, + { + "name": "message-tag4", + "description": "Description 4" + }, + { + "name": "message-tag5", + "externalDocs": { + "url": "https://www.asyncapi.com/" + } + } + ], + "headers": { + "type": "object", + "properties": { + "my-custom-app-header": { + "type": "string" + }, + "correlationId": { + "type": "string" + } + } + }, + "payload": { + "$ref": "#/components/schemas/dummyCreated" + }, + "bindings": { + "kafka": { + "key": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string", + "enum": [ + "type1", + "type2" + ] + } + } + }, + "bindingVersion": "0.1.0" + }, + "amqp": { + "contentEncoding": "gzip", + "messageType": "user.signup", + "bindingVersion": "0.1.0" + } + }, + "x-response": { + "$ref": "#/components/messages/dummyInfo" + } + }, + "dummyInfo": { + "name": "dummyInfo", + "title": "Dummy system info", + "summary": "This is just a dummy info message", + "correlationId": { + "location": "$message.header#/correlationId" + }, + "description": "More description for a dummy message.\n\nIt is a dummy system info message.\n", + "traits": [ + { + "$ref": "#/components/messageTraits/commonHeaders" + } + ], + "payload": { + "$ref": "#/components/schemas/dummyInfo" + }, + "examples": [ + { + "name": "option1example", + "summary": "this is dummy summary for option1example", + "headers": { + "my-app-header": 12 + }, + "payload": { + "prop1": "option1", + "sentAt": "2020-01-31T13:24:53.000Z" + } + }, + { + "name": "headerExample", + "headers": { + "my-app-header": 13 + } + }, + { + "payload": { + "prop1": "option2", + "sentAt": "2020-01-31T13:24:53.000Z" + } + } + ] + } + }, + "schemas": { + "dummyCreated": { + "type": "object", + "required": [ + "prop2" + ], + "x-schema-extensions-as-object": { + "type": "object", + "properties": { + "prop1": { + "type": "string" + }, + "prop2": { + "type": "integer", + "minimum": 0 + } + } + }, + "x-schema-extensions-as-primitive": "dummy", + "x-schema-extensions-as-array": [ + "item1", + "item2" + ], + "properties": { + "prop1": { + "type": "integer", + "minimum": 0, + "description": "Dummy prop1", + "x-prop1-dummy": "dummy extension" + }, + "prop2": { + "type": "string", + "description": "Dummy prop2" + }, + "sentAt": { + "$ref": "#/components/schemas/sentAt" + }, + "dummyArrayWithObject": { + "$ref": "#/components/schemas/dummyArrayWithObject" + }, + "dummyArrayWithArray": { + "$ref": "#/components/schemas/dummyArrayWithArray" + }, + "dummyObject": { + "$ref": "#/components/schemas/dummyObject" + }, + "dummyArrayRank": { + "$ref": "#/components/schemas/dummyArrayRank" + } + } + }, + "dummyInfo": { + "type": "object", + "required": [ + "prop1" + ], + "properties": { + "prop1": { + "type": "string", + "enum": [ + "option1", + "option2" + ], + "description": "Dummy prop1" + }, + "sentAt": { + "$ref": "#/components/schemas/sentAt" + } + } + }, + "dummyArrayWithObject": { + "type": "array", + "items": { + "$ref": "#/components/schemas/dummyInfo" + } + }, + "dummyArrayWithArray": { + "type": "array", + "items": [ + { + "$ref": "#/components/schemas/dummyInfo" + }, + { + "type": "string" + }, + { + "type": "number" + } + ] + }, + "dummyObject": { + "type": "object", + "properties": { + "dummyObjectProp1": { + "$ref": "#/components/schemas/sentAt" + }, + "dummyObjectProp2": { + "$ref": "#/components/schemas/dummyRecursiveObject" + }, + "dummyObjectProp3": { + "type": "object", + "additionalProperties": true + }, + "dummyObjectProp4": { + "type": "object", + "additionalProperties": false + } + } + }, + "dummyRecursiveObject": { + "type": "object", + "properties": { + "dummyRecursiveProp1": { + "$ref": "#/components/schemas/dummyObject" + }, + "dummyRecursiveProp2": { + "type": "string" + } + } + }, + "sentAt": { + "type": "string", + "format": "date-time", + "description": "Date and time when the message was sent." + }, + "dummyArrayRank": { + "type": "object", + "properties": { + "dummyArrayValueRank": { + "$ref": "#/components/schemas/dummyArrayValueRank" + }, + "dummyArrayDimensions": { + "$ref": "#/components/schemas/dummyArrayArrayDimensions" + } + } + }, + "dummyArrayValueRank": { + "description": "This Attribute indicates whether the val Attribute of the datapoint is an array and how many dimensions the array has.\n", + "type": "integer", + "default": -1, + "examples": [ + 2 + ], + "oneOf": [ + { + "const": -1, + "description": "Scalar: The value is not an array." + }, + { + "const": 0, + "description": "OneOrMoreDimensions: The value is an array with one or more dimensions." + }, + { + "const": 1, + "description": "OneDimension: The value is an array with one dimension." + }, + { + "const": 2, + "description": "The value is an array with two dimensions." + } + ] + }, + "dummyArrayArrayDimensions": { + "type": "array", + "items": { + "type": "integer", + "minimum": 0 + }, + "examples": [ + [ + 3, + 5 + ] + ] + } + }, + "securitySchemes": { + "user-password": { + "type": "userPassword" + }, + "apiKey": { + "type": "apiKey", + "in": "user", + "description": "Provide your API key as the user and leave the password empty." + }, + "supportedOauthFlows": { + "type": "oauth2", + "description": "Flows to support OAuth 2.0", + "flows": { + "implicit": { + "authorizationUrl": "https://authserver.example/auth", + "scopes": { + "dummy:created": "Ability to create dummy message", + "dymmy:read": "Ability to read dummy info" + } + }, + "password": { + "tokenUrl": "https://authserver.example/token", + "scopes": { + "dummy:created": "Ability to create dummy message", + "dymmy:read": "Ability to read dummy info" + } + }, + "clientCredentials": { + "tokenUrl": "https://authserver.example/token", + "scopes": { + "dummy:created": "Ability to create dummy message", + "dymmy:read": "Ability to read dummy info" + } + }, + "authorizationCode": { + "authorizationUrl": "https://authserver.example/auth", + "tokenUrl": "https://authserver.example/token", + "refreshUrl": "https://authserver.example/refresh", + "scopes": { + "dummy:created": "Ability to create dummy message", + "dymmy:read": "Ability to read dummy info" + } + } + } + }, + "openIdConnectWellKnown": { + "type": "openIdConnect", + "openIdConnectUrl": "https://authserver.example/.well-known" + } + }, + "parameters": { + "dummy": { + "description": "The ID of the new dummy message.", + "schema": { + "type": "string", + "description": "Description that not be rendered, as parameter has explicit description." + } + } + }, + "messageTraits": { + "commonHeaders": { + "headers": { + "type": "object", + "properties": { + "my-app-header": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "correlationId": { + "type": "string" + } + } + } + } + }, + "operationTraits": { + "kafka": { + "bindings": { + "kafka": { + "groupId": "my-app-group-id", + "clientId": "my-app-client-id", + "bindingVersion": "0.1.0" + } + } + } + } + } +} \ No newline at end of file diff --git a/test/processors/AsyncAPIInputProcessor.spec.ts b/test/processors/AsyncAPIInputProcessor.spec.ts index f23001c261..f84a696de7 100644 --- a/test/processors/AsyncAPIInputProcessor.spec.ts +++ b/test/processors/AsyncAPIInputProcessor.spec.ts @@ -46,6 +46,10 @@ describe('AsyncAPIInputProcessor', () => { const parsedObject = {asyncapi: '2.2.0'}; expect(processor.shouldProcess(parsedObject)).toEqual(true); }); + test('should be able to process AsyncAPI 2.3.0', () => { + const parsedObject = {asyncapi: '2.3.0'}; + expect(processor.shouldProcess(parsedObject)).toEqual(true); + }); }); describe('tryGetVersionOfDocument()', () => { const processor = new AsyncAPIInputProcessor(); From 71ac65a5aafd44731f7d421aec88c2ccfbfc2cad Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Mon, 31 Jan 2022 21:46:13 +0100 Subject: [PATCH 57/82] chore(release): v0.46.0 (#606) Co-authored-by: asyncapi-bot --- API.md | 10 +++++++--- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/API.md b/API.md index d3748d4f06..7181a88098 100644 --- a/API.md +++ b/API.md @@ -8,10 +8,12 @@

Abstract renderer with common helper methods

AsyncapiV2Schema
-

AsyncAPI 2.0 + 2.1 schema model

+

AsyncAPI schema model

Based on Draft 7 with additions

https://www.asyncapi.com/docs/specifications/v2.0.0#schemaObject -https://www.asyncapi.com/docs/specifications/v2.1.0#schemaObject

+https://www.asyncapi.com/docs/specifications/v2.1.0#schemaObject +https://www.asyncapi.com/docs/specifications/v2.2.0#schemaObject +https://www.asyncapi.com/docs/specifications/v2.3.0#schemaObject

CommonInputModel

This class is the wrapper for simplified models and the rest of the context needed for further generate typed models.

@@ -227,12 +229,14 @@ Adds a dependency while ensuring that only one dependency is preset at a time. ## AsyncapiV2Schema -AsyncAPI 2.0 + 2.1 schema model +AsyncAPI schema model Based on Draft 7 with additions https://www.asyncapi.com/docs/specifications/v2.0.0#schemaObject https://www.asyncapi.com/docs/specifications/v2.1.0#schemaObject +https://www.asyncapi.com/docs/specifications/v2.2.0#schemaObject +https://www.asyncapi.com/docs/specifications/v2.3.0#schemaObject **Kind**: global class diff --git a/package-lock.json b/package-lock.json index 8229e8a493..38ca1c9a77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.45.0", + "version": "0.46.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.45.0", + "version": "0.46.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 1b0c7b12ad..dc655880be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.45.0", + "version": "0.46.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 51062c1d74e6bf0514619510e0e6f413d73bf4e3 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 2 Feb 2022 17:06:39 +0100 Subject: [PATCH 58/82] fix: missing namespace for Type in C# JsonSerializerPreset (#597) --- .../__snapshots__/index.spec.ts.snap | 4 ++-- src/generators/csharp/presets/JsonSerializerPreset.ts | 4 ++-- .../__snapshots__/JsonSerializerPreset.spec.ts.snap | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap b/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap index 86d0518a2f..c6f6982c8d 100644 --- a/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap +++ b/examples/csharp-generate-serializer/__snapshots__/index.spec.ts.snap @@ -15,12 +15,12 @@ public class Root { internal class RootConverter : JsonConverter { - public override bool CanConvert(Type objectType) + public override bool CanConvert(System.Type objectType) { // this converter can be applied to any type return true; } - public override Root Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override Root Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { diff --git a/src/generators/csharp/presets/JsonSerializerPreset.ts b/src/generators/csharp/presets/JsonSerializerPreset.ts index 61d405c07c..d913051ae0 100644 --- a/src/generators/csharp/presets/JsonSerializerPreset.ts +++ b/src/generators/csharp/presets/JsonSerializerPreset.ts @@ -205,7 +205,7 @@ function renderDeserialize({ renderer, model, inputModel }: { const deserializeProperties = renderDeserializeProperties(model, renderer, inputModel); const deserializePatternProperties = renderDeserializePatternProperties(model, renderer, inputModel); const deserializeAdditionalProperties = renderDeserializeAdditionalProperties(model, renderer, inputModel); - return `public override ${formattedModelName} Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + return `public override ${formattedModelName} Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { @@ -260,7 +260,7 @@ ${content} internal class ${formattedModelName}Converter : JsonConverter<${formattedModelName}> { - public override bool CanConvert(Type objectType) + public override bool CanConvert(System.Type objectType) { // this converter can be applied to any type return true; diff --git a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap index c0f02bc9e6..adde16cc75 100644 --- a/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap +++ b/test/generators/csharp/presets/__snapshots__/JsonSerializerPreset.spec.ts.snap @@ -21,12 +21,12 @@ public class NestedTest { internal class NestedTestConverter : JsonConverter { - public override bool CanConvert(Type objectType) + public override bool CanConvert(System.Type objectType) { // this converter can be applied to any type return true; } - public override NestedTest Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override NestedTest Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { @@ -157,12 +157,12 @@ public class Test { internal class TestConverter : JsonConverter { - public override bool CanConvert(Type objectType) + public override bool CanConvert(System.Type objectType) { // this converter can be applied to any type return true; } - public override Test Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + public override Test Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) { From 7b2a33f65c06795c36c1b995334665a327068698 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Thu, 3 Feb 2022 00:03:41 +0100 Subject: [PATCH 59/82] chore(release): v0.46.1 (#611) Co-authored-by: asyncapi-bot --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 38ca1c9a77..5ddc32fc11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.46.0", + "version": "0.46.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.46.0", + "version": "0.46.1", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index dc655880be..8e2d72014c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.46.0", + "version": "0.46.1", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 881832108d46b33cec3187052d3811e051d69793 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 8 Feb 2022 11:02:49 +0100 Subject: [PATCH 60/82] ci: update global workflows (#617) --- .github/workflows/if-go-pr-testing.yml | 24 +++++++++++++++------- .github/workflows/if-nodejs-pr-testing.yml | 14 +++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/.github/workflows/if-go-pr-testing.yml b/.github/workflows/if-go-pr-testing.yml index 4a4078ff13..8893baec88 100644 --- a/.github/workflows/if-go-pr-testing.yml +++ b/.github/workflows/if-go-pr-testing.yml @@ -6,16 +6,21 @@ name: PR testing - if Go project on: pull_request: types: [opened, reopened, synchronize, ready_for_review] - + jobs: lint: - if: github.event.pull_request.draft == false name: lint runs-on: ubuntu-latest steps: - - name: Checkout repository + - if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))" + id: should_run + name: Should Run + run: echo "::set-output name=shouldrun::true" + - if: steps.should_run.outputs.shouldrun == 'true' + name: Checkout repository uses: actions/checkout@v2 - - name: Check if Go project and has go.mod + - if: steps.should_run.outputs.shouldrun == 'true' + name: Check if Go project and has go.mod id: gomod run: test -e ./go.mod && echo "::set-output name=exists::true" || echo "::set-output name=exists::false" shell: bash @@ -31,16 +36,21 @@ jobs: skip-go-installation: true # we wanna control the version of Go in use test: - if: github.event.pull_request.draft == false name: ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - name: Checkout repository + - if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))" + id: should_run + name: Should Run + run: echo "::set-output name=shouldrun::true" + - if: steps.should_run.outputs.shouldrun == 'true' + name: Checkout repository uses: actions/checkout@v2 - - name: Check if Go project and has go.mod + - if: steps.should_run.outputs.shouldrun == 'true' + name: Check if Go project and has go.mod id: gomod run: test -e ./go.mod && echo "::set-output name=exists::true" || echo "::set-output name=exists::false" shell: bash diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index 812e73af79..6a9ad91c3e 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -9,20 +9,26 @@ on: jobs: test: - if: github.event.pull_request.draft == false name: ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - - name: Set git to use LF #to once and for all finish neverending fight between Unix and Windows + - if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))" + id: should_run + name: Should Run + run: echo "::set-output name=shouldrun::true" + - if: steps.should_run.outputs.shouldrun == 'true' + name: Set git to use LF #to once and for all finish neverending fight between Unix and Windows run: | git config --global core.autocrlf false git config --global core.eol lf - - name: Checkout repository + - if: steps.should_run.outputs.shouldrun == 'true' + name: Checkout repository uses: actions/checkout@v2 - - name: Check if Node.js project and has package.json + - if: steps.should_run.outputs.shouldrun == 'true' + name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "::set-output name=exists::true" || echo "::set-output name=exists::false" shell: bash From 388495e15b748386494ed083a80d6cb7d4f6b1de Mon Sep 17 00:00:00 2001 From: Ishan Date: Tue, 8 Feb 2022 17:00:59 +0530 Subject: [PATCH 61/82] feat: exclude underscore from TS key enum rendering (#613) --- package-lock.json | 2 +- .../typescript/renderers/EnumRenderer.ts | 2 +- .../MarshallingPreset.spec.ts.snap | 44 +++++++++---------- .../typescript/renderers/EnumRenderer.spec.ts | 21 +++++++++ 4 files changed, 45 insertions(+), 24 deletions(-) create mode 100644 test/generators/typescript/renderers/EnumRenderer.spec.ts diff --git a/package-lock.json b/package-lock.json index 5ddc32fc11..0e4f8d6d5c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26301,4 +26301,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/generators/typescript/renderers/EnumRenderer.ts b/src/generators/typescript/renderers/EnumRenderer.ts index 045fb134cd..024cc41a57 100644 --- a/src/generators/typescript/renderers/EnumRenderer.ts +++ b/src/generators/typescript/renderers/EnumRenderer.ts @@ -50,7 +50,7 @@ ${this.indent(this.renderBlock(content, 2))} break; } default: { - key = FormatHelpers.replaceSpecialCharacters(String(value), { exclude: [' '], separator: '_' }); + key = FormatHelpers.replaceSpecialCharacters(String(value), { exclude: [' ','_'], separator: '_' }); //Ensure no special char can be the beginning letter if (!(/^[a-zA-Z]+$/).test(key.charAt(0))) { key = `String_${key}`; diff --git a/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap b/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap index 31631df59f..f79f17868d 100644 --- a/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap +++ b/test/generators/javascript/preset/__snapshots__/MarshallingPreset.spec.ts.snap @@ -40,51 +40,51 @@ exports[`Marshalling preset should render un/marshal code 1`] = ` marshal(){ 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.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()},`; + 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}": ${value.marshal()},`; + json += \`\\"\${key}\\": \${value.marshal()},\`; } } //Remove potential last comma - return `${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}`; + return \`\${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}\`; } unmarshal(json){ - const obj = typeof json === "object" ? json : JSON.parse(json); + const obj = typeof json === \\"object\\" ? json : JSON.parse(json); const instance = new Test({}); - if (obj["string prop"] !== undefined) { - instance.stringProp = obj["string prop"]; + if (obj[\\"string prop\\"] !== undefined) { + instance.stringProp = obj[\\"string prop\\"]; } - if (obj["numberProp"] !== undefined) { - instance.numberProp = obj["numberProp"]; + if (obj[\\"numberProp\\"] !== undefined) { + instance.numberProp = obj[\\"numberProp\\"]; } - if (obj["objectProp"] !== undefined) { - instance.objectProp = NestedTest.unmarshal(obj["objectProp"]); + if (obj[\\"objectProp\\"] !== undefined) { + instance.objectProp = NestedTest.unmarshal(obj[\\"objectProp\\"]); } //Not part of core properties @@ -92,7 +92,7 @@ exports[`Marshalling preset should render un/marshal code 1`] = ` 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\\",\\"numberProp\\",\\"objectProp\\"].includes(key);}))) { //Check all pattern properties if (key.match(new RegExp('^S(.?)test'))) { instance.sTestPatternProperties.set(key, value); @@ -129,33 +129,33 @@ exports[`Marshalling preset should render un/marshal code 2`] = ` marshal(){ 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}}`; + return \`\${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}\`; } unmarshal(json){ - const obj = typeof json === "object" ? json : JSON.parse(json); + const obj = typeof json === \\"object\\" ? json : JSON.parse(json); const instance = new NestedTest({}); - if (obj["stringProp"] !== undefined) { - instance.stringProp = obj["stringProp"]; + if (obj[\\"stringProp\\"] !== undefined) { + instance.stringProp = obj[\\"stringProp\\"]; } //Not part of core properties if (instance.additionalProperties === undefined) {instance.additionalProperties = new Map();} - for (const [key, value] of Object.entries(obj).filter((([key,]) => {return !["stringProp"].includes(key);}))) { + for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![\\"stringProp\\"].includes(key);}))) { instance.additionalProperties.set(key, value); } diff --git a/test/generators/typescript/renderers/EnumRenderer.spec.ts b/test/generators/typescript/renderers/EnumRenderer.spec.ts new file mode 100644 index 0000000000..e305031f45 --- /dev/null +++ b/test/generators/typescript/renderers/EnumRenderer.spec.ts @@ -0,0 +1,21 @@ +import { TypeScriptGenerator } from '../../../../src/generators'; +import { EnumRenderer } from '../../../../src/generators/typescript/renderers/EnumRenderer'; +import { CommonInputModel, CommonModel } from '../../../../src/models'; + +describe('EnumRenderer', () => { + let renderer: EnumRenderer; + beforeEach(() => { + renderer = new EnumRenderer(TypeScriptGenerator.defaultOptions, new TypeScriptGenerator(), [], new CommonModel(), new CommonInputModel()); + }); + + describe('normalizeKey()', () => { + test('should correctly format " " to correct key', () => { + const key = renderer.normalizeKey('something something'); + expect(key).toEqual('SOMETHING_SOMETHING'); + }); + test('should correctly format "_" to correct key', () => { + const key = renderer.normalizeKey('something_something'); + expect(key).toEqual('SOMETHING_SOMETHING'); + }); + }); +}); From b819c6fff9337005c6837be81daadb23901cfc83 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 8 Feb 2022 12:51:35 +0100 Subject: [PATCH 62/82] chore(release): v0.47.0 (#618) --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e4f8d6d5c..044c9094fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.46.1", + "version": "0.47.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.46.1", + "version": "0.47.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", @@ -26301,4 +26301,4 @@ } } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 8e2d72014c..28c783896b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.46.1", + "version": "0.47.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From e3aeeb13faaa53689052212406a31a228e4b1d15 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Tue, 8 Feb 2022 18:14:04 +0100 Subject: [PATCH 63/82] ci: update global workflows (#620) --- .github/workflows/bump.yml | 5 +- .../workflows/notify-tsc-members-mention.yml | 142 ++++++++++++++++++ 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/notify-tsc-members-mention.yml diff --git a/.github/workflows/bump.yml b/.github/workflows/bump.yml index 66af7a55e9..a6016b93b5 100644 --- a/.github/workflows/bump.yml +++ b/.github/workflows/bump.yml @@ -15,6 +15,7 @@ on: jobs: bump: + if: startsWith(github.event.commits[0].message, 'chore(release):') runs-on: ubuntu-latest steps: - name: Checkout repo @@ -22,9 +23,9 @@ jobs: - name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "::set-output name=exists::true" || echo "::set-output name=exists::false" - - if: steps.packagejson.outputs.exists == 'true' && startsWith(github.event.commits[0].message, 'chore(release):') + - if: steps.packagejson.outputs.exists == 'true' name: Bumping latest version of this package in other repositories - uses: derberg/npm-dependency-manager-for-your-github-org@v3 + uses: derberg/npm-dependency-manager-for-your-github-org@v4 with: github_token: ${{ secrets.GH_TOKEN }} committer_username: asyncapi-bot diff --git a/.github/workflows/notify-tsc-members-mention.yml b/.github/workflows/notify-tsc-members-mention.yml new file mode 100644 index 0000000000..5d342af813 --- /dev/null +++ b/.github/workflows/notify-tsc-members-mention.yml @@ -0,0 +1,142 @@ +#This action is centrally managed in https://github.com/asyncapi/.github/ +#Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo + +#This action notifies community on slack whenever there is a new issue, PR or discussion started in given repository +name: Notify slack whenever TSC members are mentioned in GitHub + +on: + issue_comment: + types: + - created + - edited + + discussion_comment: + types: + - created + - edited + + issues: + types: + - opened + - reopened + + pull_request_target: + types: + - opened + - reopened + - ready_for_review + + discussion: + types: + - created + - edited + +jobs: + + issue: + if: github.event_name == 'issues' && contains(github.event.issue.body, '@asyncapi/tsc_members') + name: On every new issue + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: issuemarkdown + with: + text: "[${{github.event.issue.title}}](${{github.event.issue.html_url}}) \n ${{github.event.issue.body}}" + - name: Send info about issue + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New issue that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} + MSG_MINIMAL: true + + pull_request: + if: github.event_name == 'pull_request_target' && contains(github.event.pull_request.body, '@asyncapi/tsc_members') + name: On every new pull request + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: prmarkdown + with: + text: "[${{github.event.pull_request.title}}](${{github.event.pull_request.html_url}}) \n ${{github.event.pull_request.body}}" + - name: Send info about pull request + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New PR that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.prmarkdown.outputs.text}} + MSG_MINIMAL: true + + discussion: + if: github.event_name == 'discussion' && contains(github.event.discussion.body, '@asyncapi/tsc_members') + name: On every new discussion + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: discussionmarkdown + with: + text: "[${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n ${{github.event.discussion.body}}" + - name: Send info about pull request + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New discussion that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}} + MSG_MINIMAL: true + + issue_comment: + if: ${{ github.event_name == 'issue_comment' && !github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members') }} + name: On every new comment in issue + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: issuemarkdown + with: + text: "[${{github.event.issue.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" + - name: Send info about issue comment + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New comment under existing issue that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} + MSG_MINIMAL: true + + pr_comment: + if: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members') + name: On every new comment in pr + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: prmarkdown + with: + text: "[${{github.event.issue.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" + - name: Send info about PR comment + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New comment under existing PR that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.prmarkdown.outputs.text}} + MSG_MINIMAL: true + + discussion_comment: + if: github.event_name == 'discussion_comment' && contains(github.event.comment.body, '@asyncapi/tsc_members') + name: On every new comment in discussion + runs-on: ubuntu-latest + steps: + - name: Convert markdown to slack markdown + uses: LoveToKnow/slackify-markdown-action@v1.0.0 + id: discussionmarkdown + with: + text: "[${{github.event.discussion.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" + - name: Send info about discussion comment + uses: rtCamp/action-slack-notify@v2 + env: + SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} + SLACK_TITLE: πŸ†˜ New comment under existing discussion that requires TSC Members attention πŸ†˜ + SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}} + MSG_MINIMAL: true \ No newline at end of file From b82a78b18e62096d75bdd0705db72bc0cb88e116 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 9 Feb 2022 21:14:59 +0100 Subject: [PATCH 64/82] docs: add Ishan-Saini as a contributor for code, test (#619) * docs: update README.md * docs: update .all-contributorsrc Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: Jonas Lagoni --- .all-contributorsrc | 10 ++++++++++ README.md | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 042e7db1e2..7dc63b24a9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -227,6 +227,16 @@ "contributions": [ "doc" ] + }, + { + "login": "Ishan-Saini", + "name": "Ishan", + "avatar_url": "https://avatars.githubusercontent.com/u/54525602?v=4", + "profile": "https://github.com/Ishan-Saini", + "contributions": [ + "code", + "test" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index cbf624d6b0..4afa4144bd 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-20-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-21-orange.svg?style=flat-square)](#contributors-) --- @@ -158,6 +158,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
mahakporwal02

πŸ’‘ ⚠️ πŸ“– πŸ’»
Debajyoti Halder

πŸ’» ⚠️ πŸ“– πŸ’‘
Ritik Rawal

πŸ“– +
Ishan

πŸ’» ⚠️ From 8a79fc09c97ec195586946fa85fc1ee1b24f4046 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Fri, 11 Feb 2022 17:23:56 +0100 Subject: [PATCH 65/82] ci: update global workflows (#631) --- .github/workflows/automerge.yml | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 393e12f9bc..2d0e1c71ce 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -6,21 +6,15 @@ name: Automerge release bump PR on: pull_request_target: types: - - labeled - - unlabeled - - synchronize - opened - - edited - - ready_for_review - - reopened - - unlocked - pull_request_review: - types: - - submitted + - synchronize jobs: autoapprove: - if: github.event.pull_request.draft == false && (github.actor == 'asyncapi-bot' || github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]') && !contains(github.event.pull_request.labels.*.name, 'released') + if: > + contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]"]'), github.event.pull_request.user.login) && + contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]"]'), github.actor) && + !contains(github.event.pull_request.labels.*.name, 'released') runs-on: ubuntu-latest steps: - name: Autoapproving @@ -42,7 +36,6 @@ jobs: automerge: needs: [autoapprove] - if: github.event.pull_request.user.login == 'asyncapi-bot' || github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'dependabot-preview[bot]' runs-on: ubuntu-latest steps: - name: Automerging From e943a71ff63b5222c42154460ec1001d8bae8e81 Mon Sep 17 00:00:00 2001 From: Samriddhi Date: Sat, 12 Feb 2022 23:32:59 +0530 Subject: [PATCH 66/82] docs: added dependency info for C# serializer preset (#630) --- docs/languages/Csharp.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/languages/Csharp.md b/docs/languages/Csharp.md index 434704e4e9..620a2596fa 100644 --- a/docs/languages/Csharp.md +++ b/docs/languages/Csharp.md @@ -15,6 +15,9 @@ There are special use-cases that each language supports; this document pertains Sometimes you want to serialize the data models into JSON. In order to do that use the preset `CSHARP_JSON_SERIALIZER_PRESET` +**External dependencies:** +Requires [System.Text.Json](https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/), [System.Text.Json.Serialization](https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?pivots=dotnet-6-0) and [System.Text.RegularExpressions](https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions?view=net-6.0) to work. + Check out this [example for a live demonstration](../../examples/csharp-generate-serializer). ## Generate models with equals and GetHashCode methods From b3c10bfe5c19513edb6da6ddb5449d56007a4c46 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Sun, 13 Feb 2022 01:04:52 +0100 Subject: [PATCH 67/82] ci: only run workflows when necessary (#624) --- .github/workflows/blackbox-testing.yml | 2 +- .github/workflows/coverall.yml | 27 +++++++++++++------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.github/workflows/blackbox-testing.yml b/.github/workflows/blackbox-testing.yml index 6888b5c407..f8cea2c191 100644 --- a/.github/workflows/blackbox-testing.yml +++ b/.github/workflows/blackbox-testing.yml @@ -5,8 +5,8 @@ on: types: [opened, reopened, synchronize, ready_for_review] jobs: test: - if: github.event.pull_request.draft == false name: BlackBox testing ${{ matrix.os }} + if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))" runs-on: ${{ matrix.os }} strategy: matrix: diff --git a/.github/workflows/coverall.yml b/.github/workflows/coverall.yml index 1f7e181683..392481c179 100644 --- a/.github/workflows/coverall.yml +++ b/.github/workflows/coverall.yml @@ -7,19 +7,20 @@ on: name: Check test coverage jobs: build: + if: "github.event.pull_request.draft == false &&!((github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'ci: update global workflows')) || (github.actor == 'asyncapi-bot' && startsWith(github.event.pull_request.title, 'chore(release):')) || (github.actor == 'allcontributors' && startsWith(github.event.pull_request.title, 'docs: add')))" name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Setup Node.js - uses: actions/setup-node@v1 - with: - node-version: 14 - - name: npm install, run test - run: | - npm install - npm run test - - name: Coveralls - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v2 + - name: Setup Node.js + uses: actions/setup-node@v1 + with: + node-version: 14 + - name: npm install, run test + run: | + npm install + npm run test + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From afe46b1e637b03ab0ae764b144f1affc656417fd Mon Sep 17 00:00:00 2001 From: Ritik Rawal Date: Sun, 13 Feb 2022 16:40:09 +0530 Subject: [PATCH 68/82] feat: add un/marshal JSON preset for Java (#596) --- docs/languages/Java.md | 9 ++ examples/java-generate-equals/index.ts | 3 +- examples/java-generate-hashcode/index.ts | 3 +- examples/java-generate-marshalling/README.md | 17 ++++ .../__snapshots__/index.spec.ts.snap | 29 +++++++ .../java-generate-marshalling/index.spec.ts | 14 +++ examples/java-generate-marshalling/index.ts | 35 ++++++++ .../package-lock.json | 10 +++ .../java-generate-marshalling/package.json | 10 +++ examples/java-generate-tostring/index.ts | 1 + src/generators/java/presets/CommonPreset.ts | 87 ++++++++++++++++++- .../java/presets/CommonPreset.spec.ts | 29 ++++++- .../__snapshots__/CommonPreset.spec.ts.snap | 59 +++++++------ 13 files changed, 271 insertions(+), 35 deletions(-) create mode 100644 examples/java-generate-marshalling/README.md create mode 100644 examples/java-generate-marshalling/__snapshots__/index.spec.ts.snap create mode 100644 examples/java-generate-marshalling/index.spec.ts create mode 100644 examples/java-generate-marshalling/index.ts create mode 100644 examples/java-generate-marshalling/package-lock.json create mode 100644 examples/java-generate-marshalling/package.json diff --git a/docs/languages/Java.md b/docs/languages/Java.md index f6a8b06c08..37f28444d1 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -57,3 +57,12 @@ Check out this [example for a live demonstration](../../examples/java-generate-j To generate Java data models with Jackson annotation using `JAVA_JACKSON_PRESET` option. Check out this [example for a live demonstration](../../examples/java-generate-jackson-annotation). + +## Include JSON marshaling and unmarshaling methods + +Sometimes you just want to convert your class to JSON without the use of annotations such as Jackson. + +Check out this [example for a live demonstration](../../examples/java-generate-marshalling). + +External dependencies +- Requires [org.json package](https://search.maven.org/artifact/org.json/json/20211205/bundle) to work diff --git a/examples/java-generate-equals/index.ts b/examples/java-generate-equals/index.ts index 113ea8f4f3..ba80aed520 100644 --- a/examples/java-generate-equals/index.ts +++ b/examples/java-generate-equals/index.ts @@ -7,7 +7,8 @@ const generator = new JavaGenerator({ options: { equal: true, hashCode: false, - classToString: false + classToString: false, + marshalling: false, } } ] diff --git a/examples/java-generate-hashcode/index.ts b/examples/java-generate-hashcode/index.ts index 38737ab381..9caabfd64f 100644 --- a/examples/java-generate-hashcode/index.ts +++ b/examples/java-generate-hashcode/index.ts @@ -7,7 +7,8 @@ const generator = new JavaGenerator({ options: { equal: false, hashCode: true, - classToString: false + classToString: false, + marshalling: false, } } ] diff --git a/examples/java-generate-marshalling/README.md b/examples/java-generate-marshalling/README.md new file mode 100644 index 0000000000..204acfdf3b --- /dev/null +++ b/examples/java-generate-marshalling/README.md @@ -0,0 +1,17 @@ +# Java Data Models with un/marshalling functionality + +A basic example of how to use the un/marshalling functionality of the java class. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/java-generate-marshalling/__snapshots__/index.spec.ts.snap b/examples/java-generate-marshalling/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..6f1ab20826 --- /dev/null +++ b/examples/java-generate-marshalling/__snapshots__/index.spec.ts.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate ts data model with marshal und unmarshal functions and should log expected output to console 1`] = ` +Array [ + "public class Root { + private Object email; + + public Object getEmail() { return this.email; } + public void setEmail(Object email) { this.email = email; } + + public String marshal() { + List propList = new ArrayList(); + if(this.email != null) { + propList.add(\\"email:\\"+this.email.toString()); + } + return propList.stream().collect(Collectors.joining(\\",\\")); + } + + public static Root unmarshal(String json) { + Root result = new Root(); + JSONObject jsonObject = new JSONObject(json); + if(jsonObject.has(\\"email\\")) { + result.setEmail(jsonObject.getString(\\"email\\")); + } + return result; + } +}", +] +`; diff --git a/examples/java-generate-marshalling/index.spec.ts b/examples/java-generate-marshalling/index.spec.ts new file mode 100644 index 0000000000..28b2ada9c0 --- /dev/null +++ b/examples/java-generate-marshalling/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import {generate} from './index'; + +describe('Should be able to generate ts data model with marshal und unmarshal functions', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/java-generate-marshalling/index.ts b/examples/java-generate-marshalling/index.ts new file mode 100644 index 0000000000..06d21f8afd --- /dev/null +++ b/examples/java-generate-marshalling/index.ts @@ -0,0 +1,35 @@ +import { JavaGenerator, JAVA_COMMON_PRESET } from '../../src'; + +const generator = new JavaGenerator({ + presets: [ + { + preset: JAVA_COMMON_PRESET, + options: { + equal: false, + hashCode: false, + classToString: false, + marshalling: true, + } + } + ] +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate() : Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/java-generate-marshalling/package-lock.json b/examples/java-generate-marshalling/package-lock.json new file mode 100644 index 0000000000..4db0c613a7 --- /dev/null +++ b/examples/java-generate-marshalling/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "java-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/java-generate-marshalling/package.json b/examples/java-generate-marshalling/package.json new file mode 100644 index 0000000000..4388b2eb7c --- /dev/null +++ b/examples/java-generate-marshalling/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "java-generate-marshalling" }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} diff --git a/examples/java-generate-tostring/index.ts b/examples/java-generate-tostring/index.ts index 263e14b108..07ac50142f 100644 --- a/examples/java-generate-tostring/index.ts +++ b/examples/java-generate-tostring/index.ts @@ -8,6 +8,7 @@ const generator = new JavaGenerator({ equal: false, hashCode: false, classToString: true, + marshalling: false, }, }, ], diff --git a/src/generators/java/presets/CommonPreset.ts b/src/generators/java/presets/CommonPreset.ts index 7955989247..0b21f33a3b 100644 --- a/src/generators/java/presets/CommonPreset.ts +++ b/src/generators/java/presets/CommonPreset.ts @@ -1,13 +1,15 @@ import { JavaRenderer } from '../JavaRenderer'; import { JavaPreset } from '../JavaPreset'; -import { getUniquePropertyName, DefaultPropertyNames } from '../../../helpers'; +import { getUniquePropertyName, DefaultPropertyNames, FormatHelpers } from '../../../helpers'; import { CommonModel } from '../../../models'; +import {Logger} from '../../../utils/LoggingInterface'; export interface JavaCommonPresetOptions { equal: boolean; hashCode: boolean; classToString: boolean; + marshalling: boolean; } /** @@ -97,6 +99,76 @@ private String toIndentedString(Object o) { }`; } +function renderMarshalProperties(renderer: JavaRenderer, model:CommonModel) { + const properties = model.properties || {}; + const propertyKeys = [...Object.keys(properties)]; + const marshalProperties = propertyKeys.map(prop => { + const formattedPropertyName = renderer.nameProperty(prop,model); + const modelInstanceVariable = `this.${formattedPropertyName}`; + return `if(${modelInstanceVariable} != null) { + propList.add("${formattedPropertyName}:"+${modelInstanceVariable}.toString()); + }`; + }); + return marshalProperties.join('\n'); +} +/** + * Render `marshal` function based on model's properties + */ +function renderMarshalling({ renderer, model }: { + renderer: JavaRenderer, + model: CommonModel, +}): string { + return `public String marshal() { + List propList = new ArrayList(); + ${renderer.indent(renderMarshalProperties(renderer,model))} + return propList.stream().collect(Collectors.joining(",")); +}`; +} + +function renderUnmarshalProperties(renderer: JavaRenderer, model:CommonModel) { + const properties = model.properties || {}; + const propertyKeys = [...Object.keys(properties)]; + const unmarshalProperties = propertyKeys.map(prop => { + const formattedPropertyName = renderer.nameProperty(prop,model); + const setterFunction = `set${formattedPropertyName.charAt(0).toUpperCase()}${formattedPropertyName.slice(1)}`; + const propModel = properties[String(prop)]; + if (propModel.type === 'undefined') { + Logger.error(`Could not render unmarshal for property ${prop}`); + return; + } + if (propModel.type === 'array') { + return `if(jsonObject.has("${formattedPropertyName}")) { + JSONArray jsonArray = jsonObject.getJSONArray("${formattedPropertyName}"); + String[] ${formattedPropertyName} = new String[jsonArray.length()]; + for(int i = 0; i < jsonArray.length(); i++) { + ${formattedPropertyName}[i] = jsonArray.getString(i); + } + result.${setterFunction}(${formattedPropertyName}); + }`; + } + const getType = `jsonObject.get${FormatHelpers.upperFirst(propModel.type?.toString() || '')}`; + return `if(jsonObject.has("${formattedPropertyName}")) { + result.${setterFunction}(${getType}("${formattedPropertyName}")); + }`; + }); + return unmarshalProperties.join('\n'); +} +/** + * Render `unmarshal` function based on model's properties + */ +function renderUnmarshalling({ renderer, model }: { + renderer: JavaRenderer, + model: CommonModel, +}): string { + const formattedModelName = renderer.nameType(model.$id); + return `public static ${formattedModelName} unmarshal(String json) { + ${formattedModelName} result = new ${formattedModelName}(); + JSONObject jsonObject = new JSONObject(json); + ${renderer.indent(renderUnmarshalProperties(renderer,model))} + return result; +}`; +} + /** * Preset which adds `equal`, `hashCode`, `toString` functions to class. * @@ -110,15 +182,26 @@ export const JAVA_COMMON_PRESET: JavaPreset = { const shouldContainEqual = options.equal === undefined || options.equal === true; const shouldContainHashCode = options.hashCode === undefined || options.hashCode === true; const shouldContainToString = options.classToString === undefined || options.classToString === true; + const shouldContainMarshal = options.marshalling === true; if (shouldContainEqual === true || shouldContainHashCode === true) { renderer.addDependency('import java.util.Objects;'); } + if (shouldContainMarshal === true) { + renderer.addDependency('import java.util.stream;'); + renderer.addDependency('import org.json.JSONObject;'); + renderer.addDependency('import java.util.Map;'); + } + if (shouldContainEqual) {blocks.push(renderEqual({ renderer, model }));} if (shouldContainHashCode) {blocks.push(renderHashCode({ renderer, model }));} if (shouldContainToString) {blocks.push(renderToString({ renderer, model }));} - + + if (shouldContainMarshal === true) { + blocks.push(renderMarshalling({ renderer, model })); + blocks.push(renderUnmarshalling({ renderer, model })); + } return renderer.renderBlock([content, ...blocks], 2); }, } diff --git a/test/generators/java/presets/CommonPreset.spec.ts b/test/generators/java/presets/CommonPreset.spec.ts index 62529a4902..9052bb8776 100644 --- a/test/generators/java/presets/CommonPreset.spec.ts +++ b/test/generators/java/presets/CommonPreset.spec.ts @@ -39,6 +39,7 @@ describe('JAVA_COMMON_PRESET', () => { equal: true, hashCode: true, classToString: true, + marshalling: false, } }] } @@ -50,11 +51,12 @@ describe('JAVA_COMMON_PRESET', () => { expect(classModel.result).toMatchSnapshot(); expect(classModel.dependencies.includes('import java.util.Objects;')).toEqual(true); }); - test('should not render any functions when all 3 options are disabled', async () => { + test('should not render any functions when all 4 options are disabled', async () => { const options: JavaCommonPresetOptions = { equal: false, hashCode: false, classToString: false, + marshalling: false, }; const generator = new JavaGenerator( @@ -80,6 +82,7 @@ describe('JAVA_COMMON_PRESET', () => { equal: true, hashCode: false, classToString: false, + marshalling: false, } }] } @@ -100,6 +103,7 @@ describe('JAVA_COMMON_PRESET', () => { equal: false, hashCode: true, classToString: false, + marshalling: false, } }] } @@ -120,6 +124,7 @@ describe('JAVA_COMMON_PRESET', () => { equal: false, hashCode: false, classToString: true, + marshalling: false, } }] } @@ -130,5 +135,27 @@ describe('JAVA_COMMON_PRESET', () => { const classModel = await generator.renderClass(model, inputModel); expect(classModel.result).toMatchSnapshot(); }); + test('should render un/marshal', async () => { + const generator = new JavaGenerator( + { + presets: [{ + preset: JAVA_COMMON_PRESET, + options: { + equal: false, + hashCode: false, + classToString: false, + marshalling: true, + } + }] + } + ); + const inputModel = await generator.process(doc); + const model = inputModel.models['Clazz']; + + const classModel = await generator.renderClass(model, inputModel); + expect(classModel.dependencies.includes('import java.util.Map;')).toEqual(true); + expect(classModel.dependencies.includes('import java.util.stream;')).toEqual(true); + expect(classModel.dependencies.includes('import org.json.JSONObject;')).toEqual(true); + }); }); }); diff --git a/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap index 5a057d129c..3f62d1bc1d 100644 --- a/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap +++ b/test/generators/java/presets/__snapshots__/CommonPreset.spec.ts.snap @@ -144,6 +144,35 @@ exports[`JAVA_COMMON_PRESET should render common function in class by common pre }" `; +exports[`JAVA_COMMON_PRESET with option should not render any functions when all 4 options are disabled 1`] = ` +"public class Clazz { + private Boolean requiredProp; + private String stringProp; + private Double numberProp; + private Boolean booleanProp; + private String[] arrayProp; + private Map additionalProperties; + + public Boolean getRequiredProp() { return this.requiredProp; } + public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; } + + public String getStringProp() { return this.stringProp; } + public void setStringProp(String stringProp) { this.stringProp = stringProp; } + + public Double getNumberProp() { return this.numberProp; } + public void setNumberProp(Double numberProp) { this.numberProp = numberProp; } + + public Boolean getBooleanProp() { return this.booleanProp; } + public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; } + + public String[] getArrayProp() { return this.arrayProp; } + public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; } + + public Map getAdditionalProperties() { return this.additionalProperties; } + public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } +}" +`; + exports[`JAVA_COMMON_PRESET with option should render all functions 1`] = ` "public class Clazz { private Boolean requiredProp; @@ -219,36 +248,6 @@ exports[`JAVA_COMMON_PRESET with option should render all functions 1`] = ` }" `; - -exports[`JAVA_COMMON_PRESET with option should not render any functions when all 3 options are disabled 1`] = ` -"public class Clazz { - private Boolean requiredProp; - private String stringProp; - private Double numberProp; - private Boolean booleanProp; - private String[] arrayProp; - private Map additionalProperties; - - public Boolean getRequiredProp() { return this.requiredProp; } - public void setRequiredProp(Boolean requiredProp) { this.requiredProp = requiredProp; } - - public String getStringProp() { return this.stringProp; } - public void setStringProp(String stringProp) { this.stringProp = stringProp; } - - public Double getNumberProp() { return this.numberProp; } - public void setNumberProp(Double numberProp) { this.numberProp = numberProp; } - - public Boolean getBooleanProp() { return this.booleanProp; } - public void setBooleanProp(Boolean booleanProp) { this.booleanProp = booleanProp; } - - public String[] getArrayProp() { return this.arrayProp; } - public void setArrayProp(String[] arrayProp) { this.arrayProp = arrayProp; } - - public Map getAdditionalProperties() { return this.additionalProperties; } - public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } -}" -`; - exports[`JAVA_COMMON_PRESET with option should render classToString 1`] = ` "public class Clazz { private Boolean requiredProp; From 9f596f8c52cf38cd5ead24458962a4b6bc60901c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 13 Feb 2022 12:27:26 +0100 Subject: [PATCH 69/82] docs: add ritik307 as a contributor for code, test, example (#632) --- .all-contributorsrc | 5 ++++- README.md | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 7dc63b24a9..79edf5d66d 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -225,7 +225,10 @@ "avatar_url": "https://avatars.githubusercontent.com/u/22374829?v=4", "profile": "https://ritik307.github.io/portfolio/", "contributions": [ - "doc" + "doc", + "code", + "test", + "example" ] }, { diff --git a/README.md b/README.md index 4afa4144bd..2298961b5d 100644 --- a/README.md +++ b/README.md @@ -157,7 +157,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Kamil Janeček

⚠️ πŸ› πŸ’»
mahakporwal02

πŸ’‘ ⚠️ πŸ“– πŸ’»
Debajyoti Halder

πŸ’» ⚠️ πŸ“– πŸ’‘ -
Ritik Rawal

πŸ“– +
Ritik Rawal

πŸ“– πŸ’» ⚠️ πŸ’‘
Ishan

πŸ’» ⚠️ From 594e7f140fa85a282f8fac49729ccac4ea898b31 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Sun, 13 Feb 2022 13:31:23 +0100 Subject: [PATCH 70/82] chore(release): v0.48.0 (#633) --- docs/languages/Java.md | 1 + package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/languages/Java.md b/docs/languages/Java.md index 37f28444d1..3c262fb26d 100644 --- a/docs/languages/Java.md +++ b/docs/languages/Java.md @@ -13,6 +13,7 @@ There are special use-cases that each language supports; this document pertains - [Include JavaDoc for properties](#include-javadoc-for-properties) - [Include Javax validation constraint annotations for properties](#include-javax-validation-constraint-annotations-for-properties) - [Include Jackson annotations for the class](#include-jackson-annotations-for-the-class) +- [Include JSON marshaling and unmarshaling methods](#include-json-marshaling-and-unmarshaling-methods) diff --git a/package-lock.json b/package-lock.json index 044c9094fc..7f4ad7d0a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.47.0", + "version": "0.48.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.47.0", + "version": "0.48.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 28c783896b..79de210481 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.47.0", + "version": "0.48.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 5567586c7998120d2a906e544f5850a57ed117ff Mon Sep 17 00:00:00 2001 From: Samriddhi Date: Mon, 14 Feb 2022 20:31:20 +0530 Subject: [PATCH 71/82] docs: add javascript marshaling example (#635) --- docs/languages/JavaScript.md | 12 ++++- examples/README.md | 1 + .../javascript-generate-marshalling/README.md | 17 +++++++ .../__snapshots__/index.spec.ts.snap | 48 +++++++++++++++++++ .../index.spec.ts | 14 ++++++ .../javascript-generate-marshalling/index.ts | 33 +++++++++++++ .../package-lock.json | 10 ++++ .../package.json | 12 +++++ 8 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 examples/javascript-generate-marshalling/README.md create mode 100644 examples/javascript-generate-marshalling/__snapshots__/index.spec.ts.snap create mode 100644 examples/javascript-generate-marshalling/index.spec.ts create mode 100644 examples/javascript-generate-marshalling/index.ts create mode 100644 examples/javascript-generate-marshalling/package-lock.json create mode 100644 examples/javascript-generate-marshalling/package.json diff --git a/docs/languages/JavaScript.md b/docs/languages/JavaScript.md index 1d407bb2f0..99ce66c9f0 100644 --- a/docs/languages/JavaScript.md +++ b/docs/languages/JavaScript.md @@ -6,6 +6,7 @@ There are special use-cases that each language supports; this document pertains - [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) +- [Generate un/marshal functions for classes](#generate-unmarshal-functions-for-classes) @@ -14,4 +15,13 @@ In some cases you might need to render the complete models to a specific module Check out this [example for a live demonstration how to generate the complete JavaScript models to use ESM module system](../../examples/javascript-use-esm). -Check out this [example for a live demonstration how to generate the complete JavaScript models to use CJS module system](../../examples/javascript-use-cjs). \ No newline at end of file +Check out this [example for a live demonstration how to generate the complete JavaScript models to use CJS module system](../../examples/javascript-use-cjs). + + +## Generate un/marshal functions for classes + +Sometimes you want to use the models for data transfers, and while most cases would work out of the box, custom serializer functionality is needed for the advanced cases. If you generated the data models based on a JSON Schema document and you want the serialized data to validate against the schema, this functionality is REQUIRED. + +Here, this can be done by including the preset `JS_COMMON_PRESET` using the option `marshalling`. + +Check out this [example out for a live demonstration](../../examples/javascript-generate-marshalling). diff --git a/examples/README.md b/examples/README.md index 2a8c947537..30fb253ccf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -25,6 +25,7 @@ This directory contains a series of self-contained examples that you can use as - [generate-javascript-models](./generate-javascript-models) - A basic example to generate JavaScript data models - [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. - [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. +- [javascript-generate-marshalling](./javascript-generate-marshalling) - A basic example of how to use the un/marshalling functionality of the javascript class. - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. - [generate-go-models](./generate-go-models) - A basic example to generate Go data models - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. diff --git a/examples/javascript-generate-marshalling/README.md b/examples/javascript-generate-marshalling/README.md new file mode 100644 index 0000000000..3238358bfc --- /dev/null +++ b/examples/javascript-generate-marshalling/README.md @@ -0,0 +1,17 @@ +# JavaScript Data Models with un/marshalling functionality + +A basic example of how to use the un/marshalling functionality of the javascript class. + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/javascript-generate-marshalling/__snapshots__/index.spec.ts.snap b/examples/javascript-generate-marshalling/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..d55d967ddd --- /dev/null +++ b/examples/javascript-generate-marshalling/__snapshots__/index.spec.ts.snap @@ -0,0 +1,48 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate ts data model with marshal und unmarshal functions and should log expected output to console 1`] = ` +Array [ + "class Test { + email; + + constructor(input) { + if (input.hasOwnProperty('email')) { + this.email = input.email; + } + } + + get email() { return this.email; } + set email(email) { this.email = email; } + + marshal(){ + let json = '{' + if(this.email !== undefined) { + json += \`\\"email\\": \${typeof this.email === 'number' || typeof this.email === 'boolean' ? this.email : JSON.stringify(this.email)},\`; + } + + + + //Remove potential last comma + return \`\${json.charAt(json.length-1) === ',' ? json.slice(0, json.length-1) : json}}\`; + } + + unmarshal(json){ + const obj = typeof json === \\"object\\" ? json : JSON.parse(json); + const instance = new Test({}); + + if (obj[\\"email\\"] !== undefined) { + instance.email = obj[\\"email\\"]; + } + + //Not part of core properties + + + for (const [key, value] of Object.entries(obj).filter((([key,]) => {return ![\\"email\\"].includes(key);}))) { + + + } + return instance; + } +}", +] +`; diff --git a/examples/javascript-generate-marshalling/index.spec.ts b/examples/javascript-generate-marshalling/index.spec.ts new file mode 100644 index 0000000000..f279d13040 --- /dev/null +++ b/examples/javascript-generate-marshalling/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import { generate } from './index'; + +describe('Should be able to generate ts data model with marshal und unmarshal functions', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/javascript-generate-marshalling/index.ts b/examples/javascript-generate-marshalling/index.ts new file mode 100644 index 0000000000..dfdc5e2826 --- /dev/null +++ b/examples/javascript-generate-marshalling/index.ts @@ -0,0 +1,33 @@ +import { JavaScriptGenerator } from '../../src'; +import { JS_COMMON_PRESET } from '../../src'; + +const generator = new JavaScriptGenerator({ + presets: [ + { + preset: JS_COMMON_PRESET, + options: { + marshalling: true + } + } + ] +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + $id: 'Test', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/javascript-generate-marshalling/package-lock.json b/examples/javascript-generate-marshalling/package-lock.json new file mode 100644 index 0000000000..2c120e1672 --- /dev/null +++ b/examples/javascript-generate-marshalling/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "javascript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} \ No newline at end of file diff --git a/examples/javascript-generate-marshalling/package.json b/examples/javascript-generate-marshalling/package.json new file mode 100644 index 0000000000..bbdc05acb0 --- /dev/null +++ b/examples/javascript-generate-marshalling/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "javascript-generate-marshalling" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} \ No newline at end of file From c9980fc8a48dda87bf2e575c23719bbe8fb7ad57 Mon Sep 17 00:00:00 2001 From: Samriddhi Date: Tue, 15 Feb 2022 18:09:02 +0530 Subject: [PATCH 72/82] feat: add generate example preset for JS (#629) --- docs/languages/JavaScript.md | 7 ++ examples/README.md | 1 + .../javascript-generate-example/README.md | 18 +++++ .../__snapshots__/index.spec.ts.snap | 24 +++++++ .../javascript-generate-example/index.spec.ts | 14 ++++ examples/javascript-generate-example/index.ts | 32 +++++++++ .../package-lock.json | 10 +++ .../javascript-generate-example/package.json | 12 ++++ .../javascript/presets/CommonPreset.ts | 6 +- .../presets/utils/ExampleFunction.ts | 66 ++++++++++++++++++ .../javascript/preset/ExamplePreset.spec.ts | 40 +++++++++++ .../__snapshots__/ExamplePreset.spec.ts.snap | 69 +++++++++++++++++++ .../preset/utils/ExampleFunctions.spec.ts | 60 ++++++++++++++++ 13 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 examples/javascript-generate-example/README.md create mode 100644 examples/javascript-generate-example/__snapshots__/index.spec.ts.snap create mode 100644 examples/javascript-generate-example/index.spec.ts create mode 100644 examples/javascript-generate-example/index.ts create mode 100644 examples/javascript-generate-example/package-lock.json create mode 100644 examples/javascript-generate-example/package.json create mode 100644 src/generators/javascript/presets/utils/ExampleFunction.ts create mode 100644 test/generators/javascript/preset/ExamplePreset.spec.ts create mode 100644 test/generators/javascript/preset/__snapshots__/ExamplePreset.spec.ts.snap create mode 100644 test/generators/javascript/preset/utils/ExampleFunctions.spec.ts diff --git a/docs/languages/JavaScript.md b/docs/languages/JavaScript.md index 99ce66c9f0..770ec6137f 100644 --- a/docs/languages/JavaScript.md +++ b/docs/languages/JavaScript.md @@ -7,6 +7,7 @@ There are special use-cases that each language supports; this document pertains - [Rendering complete models to a specific module system](#rendering-complete-models-to-a-specific-module-system) - [Generate un/marshal functions for classes](#generate-unmarshal-functions-for-classes) +- [Generate example data function](#generate-example-data-function) @@ -25,3 +26,9 @@ Sometimes you want to use the models for data transfers, and while most cases wo Here, this can be done by including the preset `JS_COMMON_PRESET` using the option `marshalling`. Check out this [example out for a live demonstration](../../examples/javascript-generate-marshalling). + +## Generate example data function + +Generate example instance of the data model including the preset `JS_COMMON_PRESET` using the option `example`. + +Check out this [example out for a live demonstration](../../examples/javascript-generate-example). diff --git a/examples/README.md b/examples/README.md index 30fb253ccf..098d35918d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -26,6 +26,7 @@ This directory contains a series of self-contained examples that you can use as - [javascript-use-esm](./javascript-use-esm) - A basic example that generate the models to use ESM module system. - [javascript-use-cjs](./javascript-use-cjs) - A basic example that generate the models to use CJS module system. - [javascript-generate-marshalling](./javascript-generate-marshalling) - A basic example of how to use the un/marshalling functionality of the javascript class. +- [javascript-generate-example](./javascript-generate-example) - A basic example of how to use Modelina and output a JavaScript class with an example function. - [generate-java-models](./generate-java-models) - A basic example to generate Java data models. - [generate-go-models](./generate-go-models) - A basic example to generate Go data models - [include-custom-function](./include-custom-function) - A basic example where a custom function is included. diff --git a/examples/javascript-generate-example/README.md b/examples/javascript-generate-example/README.md new file mode 100644 index 0000000000..ee905c6326 --- /dev/null +++ b/examples/javascript-generate-example/README.md @@ -0,0 +1,18 @@ +# JavaScript Data Models with example function + +A basic example of how to use Modelina and output a TypeScript class with an example function. + + +## How to run this example + +Run this example using: + +```sh +npm i && npm run start +``` + +If you are on Windows, use the `start:windows` script instead: + +```sh +npm i && npm run start:windows +``` diff --git a/examples/javascript-generate-example/__snapshots__/index.spec.ts.snap b/examples/javascript-generate-example/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..06bf8bc95b --- /dev/null +++ b/examples/javascript-generate-example/__snapshots__/index.spec.ts.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to generate ts data model with example function and should log expected output to console 1`] = ` +Array [ + "class Root { + email; + + constructor(input) { + if (input.hasOwnProperty('email')) { + this.email = input.email; + } + } + + get email() { return this.email; } + set email(email) { this.email = email; } + + example(){ + const instance = new Root({}); + instance.email = \\"string\\"; + return instance; + } +}", +] +`; diff --git a/examples/javascript-generate-example/index.spec.ts b/examples/javascript-generate-example/index.spec.ts new file mode 100644 index 0000000000..3436cf41e5 --- /dev/null +++ b/examples/javascript-generate-example/index.spec.ts @@ -0,0 +1,14 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { return; }); +import { generate } from './index'; + +describe('Should be able to generate ts data model with example function', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + //Generate is called 2x, so even though we expect 1 model, we double it + expect(spy.mock.calls.length).toEqual(2); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/javascript-generate-example/index.ts b/examples/javascript-generate-example/index.ts new file mode 100644 index 0000000000..f9473cbac4 --- /dev/null +++ b/examples/javascript-generate-example/index.ts @@ -0,0 +1,32 @@ +import { JavaScriptGenerator } from '../../src'; +import { JS_COMMON_PRESET } from '../../src'; + +const generator = new JavaScriptGenerator({ + presets: [ + { + preset: JS_COMMON_PRESET, + options: { + example: true + } + } + ] +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + format: 'email' + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +generate(); diff --git a/examples/javascript-generate-example/package-lock.json b/examples/javascript-generate-example/package-lock.json new file mode 100644 index 0000000000..2c120e1672 --- /dev/null +++ b/examples/javascript-generate-example/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "javascript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} \ No newline at end of file diff --git a/examples/javascript-generate-example/package.json b/examples/javascript-generate-example/package.json new file mode 100644 index 0000000000..2e27995d85 --- /dev/null +++ b/examples/javascript-generate-example/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "javascript-generate-example" + }, + "scripts": { + "install": "cd ../.. && npm i", + "start": "../../node_modules/.bin/ts-node --cwd ../../ ./examples/$npm_package_config_example_name/index.ts", + "start:windows": "..\\..\\node_modules\\.bin\\ts-node --cwd ..\\..\\ .\\examples\\%npm_package_config_example_name%\\index.ts", + "test": "../../node_modules/.bin/jest --config=../../jest.config.js ./examples/$npm_package_config_example_name/index.spec.ts", + "test:windows": "..\\..\\node_modules\\.bin\\jest --config=..\\..\\jest.config.js examples/%npm_package_config_example_name%/index.spec.ts" + } +} \ No newline at end of file diff --git a/src/generators/javascript/presets/CommonPreset.ts b/src/generators/javascript/presets/CommonPreset.ts index 8117953efd..75fd99d63d 100644 --- a/src/generators/javascript/presets/CommonPreset.ts +++ b/src/generators/javascript/presets/CommonPreset.ts @@ -2,9 +2,11 @@ import { JavaScriptRenderer } from '../JavaScriptRenderer'; import { JavaScriptPreset } from '../JavaScriptPreset'; import { getUniquePropertyName, DefaultPropertyNames, TypeHelpers, ModelKind } from '../../../helpers'; import { CommonInputModel, CommonModel } from '../../../models'; +import renderExampleFunction from './utils/ExampleFunction'; export interface JavaScriptCommonPresetOptions { marshalling: boolean; + example: boolean; } function realizePropertyFactory(prop: string) { @@ -200,7 +202,9 @@ export const JS_COMMON_PRESET: JavaScriptPreset = { blocks.push(renderMarshal({ renderer, model, inputModel })); blocks.push(renderUnmarshal({ renderer, model, inputModel })); } - + if (options.example === true) { + blocks.push(renderExampleFunction({ renderer, model })); + } return renderer.renderBlock([content, ...blocks], 2); }, } diff --git a/src/generators/javascript/presets/utils/ExampleFunction.ts b/src/generators/javascript/presets/utils/ExampleFunction.ts new file mode 100644 index 0000000000..9510ce7bb0 --- /dev/null +++ b/src/generators/javascript/presets/utils/ExampleFunction.ts @@ -0,0 +1,66 @@ +import { JavaScriptRenderer } from '../../JavaScriptRenderer'; +import { CommonModel } from '../../../../models'; + +export function renderValueFromModel(model: CommonModel, renderer: JavaScriptRenderer): string | undefined { + if (model.$ref !== undefined) { + return `${renderer.nameType(model.$ref)}.example()`; + } + if (Array.isArray(model.type)) { + if (model.type.length > 0) { + return renderValueFromType(model.type[0], model, renderer); + } + return undefined; + } + return renderValueFromType(model.type, model, renderer); +} + +export function renderValueFromType(modelType: string | undefined, model: CommonModel, renderer: JavaScriptRenderer): string | undefined { + if (modelType === undefined) { + return undefined; + } + switch (modelType) { + case 'string': + return '"string"'; + case 'integer': + case 'number': + return '0'; + case 'boolean': + return 'true'; + case 'array': { + if (model.items === undefined) { + return '[]'; + } + if (Array.isArray(model.items)) { + const arrayValues = model.items.map((item) => { + return renderValueFromModel(item, renderer); + }); + return `[${arrayValues.join(', ')}]`; + } + const arrayType = renderValueFromModel(model.items, renderer); + return `[${arrayType}]`; + } + } + return undefined; +} + +export default function renderExampleFunction({ renderer, model }: { + renderer: JavaScriptRenderer, + model: CommonModel +}): string { + const properties = model.properties || {}; + const setProperties = []; + for (const [propertyName, property] of Object.entries(properties)) { + const formattedPropertyName = renderer.nameProperty(propertyName, property); + const potentialRenderedValue = renderValueFromModel(property, renderer); + if (potentialRenderedValue === undefined) { + continue; + } + setProperties.push(` instance.${formattedPropertyName} = ${potentialRenderedValue};`); + } + const formattedModelName = renderer.nameType(model.$id); + return `example(){ + const instance = new ${formattedModelName}({}); +${(setProperties.join('\n'))} + return instance; +}`; +} diff --git a/test/generators/javascript/preset/ExamplePreset.spec.ts b/test/generators/javascript/preset/ExamplePreset.spec.ts new file mode 100644 index 0000000000..885e69a5ef --- /dev/null +++ b/test/generators/javascript/preset/ExamplePreset.spec.ts @@ -0,0 +1,40 @@ +import { JavaScriptGenerator, JS_COMMON_PRESET } from '../../../../src/generators'; +const doc = { + $id: 'Test', + type: 'object', + additionalProperties: true, + required: ['string prop'], + properties: { + 'string prop': { type: 'string' }, + numberProp: { type: 'number' }, + objectProp: { type: 'object', $id: 'NestedTest', properties: { stringProp: { type: 'string' } } } + }, + patternProperties: { + '^S(.?)test': { + type: 'string' + } + }, +}; +describe('Example function generation', () => { + test('should render example function for model', async () => { + const generator = new JavaScriptGenerator({ + presets: [ + { + preset: JS_COMMON_PRESET, + options: { + example: true + } + } + ] + }); + const inputModel = await generator.process(doc); + const testModel = inputModel.models['Test']; + const nestedTestModel = inputModel.models['NestedTest']; + + const testClass = await generator.renderClass(testModel, inputModel); + const nestedTestClass = await generator.renderClass(nestedTestModel, inputModel); + + expect(testClass.result).toMatchSnapshot(); + expect(nestedTestClass.result).toMatchSnapshot(); + }); +}); diff --git a/test/generators/javascript/preset/__snapshots__/ExamplePreset.spec.ts.snap b/test/generators/javascript/preset/__snapshots__/ExamplePreset.spec.ts.snap new file mode 100644 index 0000000000..46f550772f --- /dev/null +++ b/test/generators/javascript/preset/__snapshots__/ExamplePreset.spec.ts.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Example function generation should render example function for model 1`] = ` +"class Test { + stringProp; + numberProp; + objectProp; + additionalProperties; + sTestPatternProperties; + + constructor(input) { + this.stringProp = input.stringProp; + if (input.hasOwnProperty('numberProp')) { + this.numberProp = input.numberProp; + } + if (input.hasOwnProperty('objectProp')) { + this.objectProp = input.objectProp; + } + } + + get stringProp() { return this.stringProp; } + set stringProp(stringProp) { this.stringProp = stringProp; } + + get numberProp() { return this.numberProp; } + set numberProp(numberProp) { this.numberProp = numberProp; } + + get objectProp() { return this.objectProp; } + set objectProp(objectProp) { this.objectProp = objectProp; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + get sTestPatternProperties() { return this.sTestPatternProperties; } + set sTestPatternProperties(sTestPatternProperties) { this.sTestPatternProperties = sTestPatternProperties; } + + example(){ + const instance = new Test({}); + instance.stringProp = \\"string\\"; + instance.numberProp = 0; + instance.objectProp = NestedTest.example(); + return instance; + } +}" +`; + +exports[`Example function generation should render example function for model 2`] = ` +"class NestedTest { + stringProp; + additionalProperties; + + constructor(input) { + if (input.hasOwnProperty('stringProp')) { + this.stringProp = input.stringProp; + } + } + + get stringProp() { return this.stringProp; } + set stringProp(stringProp) { this.stringProp = stringProp; } + + get additionalProperties() { return this.additionalProperties; } + set additionalProperties(additionalProperties) { this.additionalProperties = additionalProperties; } + + example(){ + const instance = new NestedTest({}); + instance.stringProp = \\"string\\"; + return instance; + } +}" +`; diff --git a/test/generators/javascript/preset/utils/ExampleFunctions.spec.ts b/test/generators/javascript/preset/utils/ExampleFunctions.spec.ts new file mode 100644 index 0000000000..d4f80e0ec1 --- /dev/null +++ b/test/generators/javascript/preset/utils/ExampleFunctions.spec.ts @@ -0,0 +1,60 @@ +import { JavaScriptGenerator } from '../../../../../src/generators'; +import { renderValueFromModel } from '../../../../../src/generators/javascript/presets/utils/ExampleFunction'; +import { JavaScriptRenderer } from '../../../../../src/generators/javascript/JavaScriptRenderer'; +import { CommonInputModel, CommonModel } from '../../../../../src/models'; +class MockJavaScriptRenderer extends JavaScriptRenderer { +} +const renderer = new MockJavaScriptRenderer(JavaScriptGenerator.defaultOptions, new JavaScriptGenerator(), [], new CommonModel(), new CommonInputModel()); +describe('Example preset', () => { + describe('.renderValueFromModel()', () => { + test('should render refs correctly', () => { + const input = CommonModel.toCommonModel({ $ref: 'SomeOtherModel' }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('SomeOtherModel.example()'); + }); + describe('types', () => { + test('Should render strings correctly', () => { + const input = CommonModel.toCommonModel({ type: 'string' }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('"string"'); + }); + test('Should render numbers correctly', () => { + const input = CommonModel.toCommonModel({ type: 'number' }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('0'); + }); + test('Should render booleans correctly', () => { + const input = CommonModel.toCommonModel({ type: 'boolean' }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('true'); + }); + test('Should use first value if there is more then one', () => { + const input = CommonModel.toCommonModel({ type: ['boolean', 'string'] }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('true'); + }); + describe('array', () => { + test('should not render anything if no items are defined', () => { + const input = CommonModel.toCommonModel({ type: 'array' }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('[]'); + }); + test('should render multiple array values', () => { + const input = CommonModel.toCommonModel({ type: 'array', items: [{ type: 'string' }, { type: 'number' }] }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('["string", 0]'); + }); + test('should render single array value', () => { + const input = CommonModel.toCommonModel({ type: 'array', items: { type: 'string' } }); + const output = renderValueFromModel(input, renderer); + expect(output).toEqual('["string"]'); + }); + }); + test('Should ignore if none are present', () => { + const input = CommonModel.toCommonModel({ type: [] }); + const output = renderValueFromModel(input, renderer); + expect(output).toBeUndefined(); + }); + }); + }); +}); From c773f4cdfe66704082dd6ed309ae796e48db4855 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 16 Feb 2022 16:23:37 +0100 Subject: [PATCH 73/82] feat: new `accessor` preset hook for C# class renderer (#626) --- docs/presets.md | 1 + src/generators/csharp/CSharpPreset.ts | 10 ++- .../csharp/renderers/ClassRenderer.ts | 39 ++++---- .../generators/csharp/CSharpGenerator.spec.ts | 89 +++++++++++-------- .../CSharpGenerator.spec.ts.snap | 49 ++++++---- 5 files changed, 110 insertions(+), 78 deletions(-) diff --git a/docs/presets.md b/docs/presets.md index 4c3206fe37..c6f26b9f94 100644 --- a/docs/presets.md +++ b/docs/presets.md @@ -211,6 +211,7 @@ There are no additional methods. |---|---|---| | `ctor` | A method to extend rendered constructor for a given class. | - | | `property` | A method to extend rendered given property. | `propertyName` as a name of a given property, `property` object as a [`CommonModel`](../src/models/CommonModel.ts) instance. | +| `accessor` | A method to extend rendered given property accessor. | `propertyName` as a name of a given property, `property` object as a [`CommonModel`](../src/models/CommonModel.ts) instance. | | `setter` | A method to extend setter for a given property. | `propertyName` as a name of a given property, `property` object as a [`CommonModel`](../src/models/CommonModel.ts) instance. | | `getter` | A method to extend getter for a given property. | `propertyName` as a name of a given property, `property` object as a [`CommonModel`](../src/models/CommonModel.ts) instance. | diff --git a/src/generators/csharp/CSharpPreset.ts b/src/generators/csharp/CSharpPreset.ts index 2e0c340bb5..8928a25e66 100644 --- a/src/generators/csharp/CSharpPreset.ts +++ b/src/generators/csharp/CSharpPreset.ts @@ -1,10 +1,14 @@ -/* eslint-disable @typescript-eslint/ban-types */ -import { Preset, EnumPreset, ClassPreset } from '../../models'; +import { Preset, EnumPreset, ClassPreset, PresetArgs, PropertyArgs } from '../../models'; import { ClassRenderer, CSHARP_DEFAULT_CLASS_PRESET } from './renderers/ClassRenderer'; import { CSHARP_DEFAULT_ENUM_PRESET, EnumRenderer } from './renderers/EnumRenderer'; +// Our class preset uses custom `accessor` hook to craft getter and setters. +export interface CsharpClassPreset extends ClassPreset { + accessor?: (args: PresetArgs & PropertyArgs) => Promise | string; +} + export type CSharpPreset = Preset<{ - class: ClassPreset; + class: CsharpClassPreset; enum: EnumPreset }>; diff --git a/src/generators/csharp/renderers/ClassRenderer.ts b/src/generators/csharp/renderers/ClassRenderer.ts index 7b310b545e..2fb351d782 100644 --- a/src/generators/csharp/renderers/ClassRenderer.ts +++ b/src/generators/csharp/renderers/ClassRenderer.ts @@ -1,7 +1,8 @@ import { CSharpRenderer } from '../CSharpRenderer'; -import { ClassPreset, CommonModel, PropertyType } from '../../../models'; +import { CommonModel, PropertyType } from '../../../models'; import { DefaultPropertyNames, getUniquePropertyName } from '../../../helpers'; import { pascalCase } from 'change-case'; +import { CsharpClassPreset } from '../CSharpPreset'; /** * Renderer for CSharp's `struct` type @@ -53,35 +54,23 @@ ${this.indent(this.renderBlock(content, 2))} return this.renderBlock(content); } - async accessorFactory(property: CommonModel, propertyName: string, type: PropertyType): Promise { - const formattedAccessorName = pascalCase(this.nameProperty(propertyName, property)); - let propertyType = this.renderType(property); - if (type === PropertyType.additionalProperty || type === PropertyType.patternProperties) { - propertyType = `Dictionary`; - } - return `public ${propertyType} ${formattedAccessorName} -{ - ${await this.runGetterPreset(propertyName, property, type)} - ${await this.runSetterPreset(propertyName, property, type)} -}`; - } async renderAccessors(): Promise { const properties = this.model.properties || {}; const content: string[] = []; for (const [propertyName, property] of Object.entries(properties)) { - content.push(await this.accessorFactory(property, propertyName, PropertyType.property)); + content.push(await this.runAccessorPreset(propertyName, property, PropertyType.property)); } if (this.model.additionalProperties !== undefined) { const propertyName = getUniquePropertyName(this.model, DefaultPropertyNames.additionalProperties); - content.push(await this.accessorFactory(this.model.additionalProperties, propertyName, PropertyType.additionalProperty)); + content.push(await this.runAccessorPreset(propertyName, this.model.additionalProperties, PropertyType.additionalProperty)); } if (this.model.patternProperties !== undefined) { for (const [pattern, patternModel] of Object.entries(this.model.patternProperties)) { const propertyName = getUniquePropertyName(this.model, `${pattern}${DefaultPropertyNames.patternProperties}`); - content.push(await this.accessorFactory(patternModel, propertyName, PropertyType.patternProperties)); + content.push(await this.runAccessorPreset(propertyName, patternModel, PropertyType.patternProperties)); } } @@ -92,6 +81,10 @@ ${this.indent(this.renderBlock(content, 2))} return this.runPreset('ctor'); } + runAccessorPreset(propertyName: string, property: CommonModel, type: PropertyType = PropertyType.property): Promise { + return this.runPreset('accessor', { propertyName, property, type}); + } + runPropertyPreset(propertyName: string, property: CommonModel, type: PropertyType = PropertyType.property): Promise { return this.runPreset('property', { propertyName, property, type}); } @@ -105,7 +98,7 @@ ${this.indent(this.renderBlock(content, 2))} } } -export const CSHARP_DEFAULT_CLASS_PRESET: ClassPreset = { +export const CSHARP_DEFAULT_CLASS_PRESET: CsharpClassPreset = { self({ renderer }) { return renderer.defaultSelf(); }, @@ -117,6 +110,18 @@ export const CSHARP_DEFAULT_CLASS_PRESET: ClassPreset = { } return `private ${propertyType} ${propertyName};`; }, + async accessor({ renderer, propertyName, property, type }) { + const formattedAccessorName = pascalCase(renderer.nameProperty(propertyName, property)); + let propertyType = renderer.renderType(property); + if (type === PropertyType.additionalProperty || type === PropertyType.patternProperties) { + propertyType = `Dictionary`; + } + return `public ${propertyType} ${formattedAccessorName} +{ + ${await renderer.runGetterPreset(propertyName, property, type)} + ${await renderer.runSetterPreset(propertyName, property, type)} +}`; + }, getter({ renderer, propertyName, property }) { const formattedPropertyName = renderer.nameProperty(propertyName, property); return `get { return ${formattedPropertyName}; }`; diff --git a/test/generators/csharp/CSharpGenerator.spec.ts b/test/generators/csharp/CSharpGenerator.spec.ts index 991dc1c59e..dbb59112ac 100644 --- a/test/generators/csharp/CSharpGenerator.spec.ts +++ b/test/generators/csharp/CSharpGenerator.spec.ts @@ -63,36 +63,6 @@ describe('CSharpGenerator', () => { expect(classModel.dependencies).toEqual(['using System.Collections.Generic;']); }); - test('should work custom preset for `class` type', async () => { - const doc = { - $id: 'CustomClass', - type: 'object', - properties: { - property: { type: 'string' }, - }, - additionalProperties: { - type: 'string' - } - }; - - generator = new CSharpGenerator({ presets: [ - { - class: { - property({ propertyName, property, renderer }) { - return `private ${propertyName} ${renderer.renderType(property)}`; - }, - } - } - ] }); - - const inputModel = await generator.process(doc); - const model = inputModel.models['CustomClass']; - - const classModel = await generator.render(model, inputModel); - expect(classModel.result).toMatchSnapshot(); - expect(classModel.dependencies).toEqual(['using System.Collections.Generic;']); - }); - test.each([ { name: 'with enums sharing same type', @@ -148,15 +118,7 @@ describe('CSharpGenerator', () => { enum: ['test+', 'test', 'test-', 'test?!', '*test'] }; - generator = new CSharpGenerator({ presets: [ - { - enum: { - self({ content }) { - return content; - }, - } - } - ]}); + generator = new CSharpGenerator(); const inputModel = await generator.process(doc); const model = inputModel.models['States']; @@ -222,4 +184,53 @@ describe('CSharpGenerator', () => { const expectedError = new Error('You cannot use reserved CSharp keyword (true) as namespace, please use another.'); await expect(generator.generateCompleteModels(doc, config)).rejects.toEqual(expectedError); }); + + describe('class renderer', () => { + const doc = { + $id: 'CustomClass', + type: 'object', + properties: { + property: { type: 'string' }, + }, + additionalProperties: { + type: 'string' + } + }; + + test('should be able to overwrite accessor preset hook', async () => { + generator = new CSharpGenerator({ presets: [ + { + class: { + accessor() { + return 'my own custom factory'; + } + } + } + ] }); + + const inputModel = await generator.process(doc); + const model = inputModel.models['CustomClass']; + + const classModel = await generator.render(model, inputModel); + expect(classModel.result).toMatchSnapshot(); + }); + + test('should be able to overwrite property preset hook', async () => { + generator = new CSharpGenerator({ presets: [ + { + class: { + property() { + return 'my own property'; + }, + } + } + ] }); + + const inputModel = await generator.process(doc); + const model = inputModel.models['CustomClass']; + + const classModel = await generator.render(model, inputModel); + expect(classModel.result).toMatchSnapshot(); + }); + }); }); diff --git a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap index 29533dc18c..6222545e1b 100644 --- a/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap +++ b/test/generators/csharp/__snapshots__/CSharpGenerator.spec.ts.snap @@ -1,5 +1,35 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`CSharpGenerator class renderer should be able to overwrite accessor preset hook 1`] = ` +"public class CustomClass { + private string property; + private Dictionary additionalProperties; + + my own custom factory + + my own custom factory +}" +`; + +exports[`CSharpGenerator class renderer should be able to overwrite property preset hook 1`] = ` +"public class CustomClass { + my own property + my own property + + public string Property + { + get { return property; } + set { property = value; } + } + + public Dictionary AdditionalProperties + { + get { return additionalProperties; } + set { additionalProperties = value; } + } +}" +`; + exports[`CSharpGenerator should not render reserved keyword 1`] = ` "public class Address { private string reservedReservedEnum; @@ -492,25 +522,6 @@ exports[`CSharpGenerator should render models and their dependencies 2`] = ` }" `; -exports[`CSharpGenerator should work custom preset for \`class\` type 1`] = ` -"public class CustomClass { - private property string - private additionalProperties string - - public string Property - { - get { return property; } - set { property = value; } - } - - public Dictionary AdditionalProperties - { - get { return additionalProperties; } - set { additionalProperties = value; } - } -}" -`; - exports[`CSharpGenerator should work custom preset for \`enum\` type 1`] = ` "public enum CustomEnum { Texas, Alabama, California From 0ff2e89a2ffac41264638d3b5664baac40a6eb31 Mon Sep 17 00:00:00 2001 From: asyncapi-bot <61865014+asyncapi-bot@users.noreply.github.com> Date: Wed, 16 Feb 2022 16:44:32 +0100 Subject: [PATCH 74/82] chore(release): v0.49.0 (#650) --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f4ad7d0a8..2090a7b648 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/modelina", - "version": "0.48.0", + "version": "0.49.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/modelina", - "version": "0.48.0", + "version": "0.49.0", "license": "Apache-2.0", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", diff --git a/package.json b/package.json index 79de210481..e3e5757a39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@asyncapi/modelina", - "version": "0.48.0", + "version": "0.49.0", "description": "The Model SDK for generating data models", "license": "Apache-2.0", "homepage": "https://github.com/asyncapi/modelina", From 9e4add4eaad216005a9f5d98abf213e9f27481f0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 16 Feb 2022 17:08:14 +0100 Subject: [PATCH 75/82] docs: add Samridhi-98 as a contributor for code, test, doc, example (#651) --- .all-contributorsrc | 12 ++++++++++++ README.md | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 79edf5d66d..82bad9d44b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -240,6 +240,18 @@ "code", "test" ] + }, + { + "login": "Samridhi-98", + "name": "Samriddhi", + "avatar_url": "https://avatars.githubusercontent.com/u/54466041?v=4", + "profile": "https://samridhi-98.github.io/Portfolio", + "contributions": [ + "code", + "test", + "doc", + "example" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index 2298961b5d..20d2b2b576 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) -[![All Contributors](https://img.shields.io/badge/all_contributors-21-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-22-orange.svg?style=flat-square)](#contributors-) --- @@ -160,6 +160,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Ritik Rawal

πŸ“– πŸ’» ⚠️ πŸ’‘
Ishan

πŸ’» ⚠️ + +
Samriddhi

πŸ’» ⚠️ πŸ“– πŸ’‘ + From 10aca3b10d985596241761f8976697a72dc360e1 Mon Sep 17 00:00:00 2001 From: Ritik Rawal Date: Wed, 16 Feb 2022 23:11:53 +0530 Subject: [PATCH 76/82] docs: add java un/marshalling reference to docs (#645) --- examples/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README.md b/examples/README.md index 098d35918d..a986d3683e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -34,3 +34,4 @@ This directory contains a series of self-contained examples that you can use as - [generate-csharp-models](./generate-csharp-models) - A basic example to generate C# data models - [java-change-collection-type](./java-change-collection-type) - An example to render collections as List in Java. - [java-generate-hashcode](./java-generate-hashcode) - A basic example that shows how to generate models that overwrite the `hashCode` method +- [java-generate-marshalling](./java-generate-marshalling) - A basic example of how to use the un/marshalling functionality of the java class. From b0a41ca9c9ae758a1e1e914eafa6a2c89906b523 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Feb 2022 20:07:36 +0100 Subject: [PATCH 77/82] Added models --- src/models/ConstrainedMetaModel.ts | 64 ++++++++++++++++++++++++++++++ src/models/MetaModel.ts | 62 +++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 src/models/ConstrainedMetaModel.ts create mode 100644 src/models/MetaModel.ts diff --git a/src/models/ConstrainedMetaModel.ts b/src/models/ConstrainedMetaModel.ts new file mode 100644 index 0000000000..4f59138394 --- /dev/null +++ b/src/models/ConstrainedMetaModel.ts @@ -0,0 +1,64 @@ +import { MetaModel } from "./MetaModel"; + +export class ConstrainedMetaModel extends MetaModel { + type: string; + constructor(name: string, type: string) { + super(name); + this.type = type; + } +} + +export class ConstrainedReferencedModel extends ConstrainedMetaModel { + referencedModel?: ConstrainedMetaModel +} +export class ConstrainedAnyModel extends ConstrainedMetaModel { } +export class ConstrainedFloatModel extends ConstrainedMetaModel { } +export class ConstrainedIntegerModel extends ConstrainedMetaModel { } +export class ConstrainedStringModel extends ConstrainedMetaModel { } +export class ConstrainedBooleanModel extends ConstrainedMetaModel { } +export class ConstrainedTupleValueModel { + index: number; + value: ConstrainedMetaModel; + constructor(index: number, value: ConstrainedMetaModel) { + this.index = index; + this.value = value; + } +} +export class ConstrainedTupleModel extends ConstrainedMetaModel { + tupleModels: ConstrainedTupleValueModel[] = []; +} +export class ConstrainedObjectModel extends ConstrainedMetaModel { + properties: { [key: string]: ConstrainedMetaModel; } = {}; +} +export class ConstrainedArrayModel extends ConstrainedMetaModel { + valueModel: ConstrainedMetaModel; + constructor(name: string, type: string, valueModel: ConstrainedMetaModel) { + super(name, type); + this.valueModel = valueModel; + } +} +export class ConstrainedUnionModel extends ConstrainedMetaModel { + unionModels: ConstrainedMetaModel[] = []; +} +export class ConstrainedEnumValueModel { + key: string; + value: any; + constructor(key: string, value: any) { + this.key = key; + this.value = value; + } +} +export class ConstrainedEnumModel extends ConstrainedMetaModel { + values: ConstrainedEnumValueModel[] = []; +} +export class ConstrainedDictionaryModel extends ConstrainedMetaModel { + keyModel: ConstrainedMetaModel; + valueModel: ConstrainedMetaModel; + serializationType: 'unwrap' | 'normal' = 'normal'; + + constructor(name: string, type: string, keyModel: ConstrainedMetaModel, valueModel: ConstrainedMetaModel) { + super(name, type); + this.keyModel = keyModel; + this.valueModel = valueModel; + } +} \ No newline at end of file diff --git a/src/models/MetaModel.ts b/src/models/MetaModel.ts new file mode 100644 index 0000000000..046a2eb49b --- /dev/null +++ b/src/models/MetaModel.ts @@ -0,0 +1,62 @@ +export class MetaModel { + name: string; + originalInput: any; + constructor(name: string) { + this.name = name; + } +} + +export class ReferencedModel extends MetaModel { + referencedModel?: MetaModel +} +export class AnyModel extends MetaModel { } +export class FloatModel extends MetaModel { } +export class IntegerModel extends MetaModel { } +export class StringModel extends MetaModel { } +export class BooleanModel extends MetaModel { } +export class TupleValueModel { + index: number; + value: MetaModel; + constructor(index: number, value: MetaModel) { + this.index = index; + this.value = value; + } +} +export class TupleModel extends MetaModel { + tupleModels: TupleValueModel[] = []; +} +export class ObjectModel extends MetaModel { + properties: { [key: string]: MetaModel; } = {}; +} +export class ArrayModel extends MetaModel { + valueModel: MetaModel; + constructor(name: string, valueModel: MetaModel) { + super(name); + this.valueModel = valueModel; + } +} +export class UnionModel extends MetaModel { + unionModels: MetaModel[] = []; +} +export class EnumValueModel { + key: string; + value: any; + constructor(key: string, value: any) { + this.key = key; + this.value = value; + } +} +export class EnumModel extends MetaModel { + values: EnumValueModel[] = []; +} +export class DictionaryModel extends MetaModel { + keyModel: MetaModel; + valueModel: MetaModel; + serializationType: 'unwrap' | 'normal' = 'normal'; + + constructor(name: string, keyModel: MetaModel, valueModel: MetaModel) { + super(name); + this.keyModel = keyModel; + this.valueModel = valueModel; + } +} \ No newline at end of file From ca0a1b206cbe4d286ab1dec600a4c49a606b4a00 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Wed, 2 Mar 2022 19:14:40 +0100 Subject: [PATCH 78/82] fixed lint errors --- src/models/ConstrainedMetaModel.ts | 4 ++-- src/models/MetaModel.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/models/ConstrainedMetaModel.ts b/src/models/ConstrainedMetaModel.ts index 4f59138394..eb5b638a16 100644 --- a/src/models/ConstrainedMetaModel.ts +++ b/src/models/ConstrainedMetaModel.ts @@ -1,4 +1,4 @@ -import { MetaModel } from "./MetaModel"; +import { MetaModel } from './MetaModel'; export class ConstrainedMetaModel extends MetaModel { type: string; @@ -61,4 +61,4 @@ export class ConstrainedDictionaryModel extends ConstrainedMetaModel { this.keyModel = keyModel; this.valueModel = valueModel; } -} \ No newline at end of file +} diff --git a/src/models/MetaModel.ts b/src/models/MetaModel.ts index 046a2eb49b..7e33ab9cf9 100644 --- a/src/models/MetaModel.ts +++ b/src/models/MetaModel.ts @@ -59,4 +59,4 @@ export class DictionaryModel extends MetaModel { this.keyModel = keyModel; this.valueModel = valueModel; } -} \ No newline at end of file +} From 6bc51a9aa9016a01ba7d9ff52baad6ac374dbe7b Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Fri, 4 Mar 2022 15:09:43 +0100 Subject: [PATCH 79/82] Switched to inline modifiers for constructor --- src/models/MetaModel.ts | 82 +++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/src/models/MetaModel.ts b/src/models/MetaModel.ts index 7e33ab9cf9..d97b0bf650 100644 --- a/src/models/MetaModel.ts +++ b/src/models/MetaModel.ts @@ -1,13 +1,17 @@ export class MetaModel { - name: string; - originalInput: any; - constructor(name: string) { - this.name = name; + constructor( + public name: string, + public originalInput: any) { } } export class ReferencedModel extends MetaModel { - referencedModel?: MetaModel + constructor( + public name: string, + public originalInput: any, + public referencedModel: MetaModel) { + super(name, originalInput); + } } export class AnyModel extends MetaModel { } export class FloatModel extends MetaModel { } @@ -15,48 +19,64 @@ export class IntegerModel extends MetaModel { } export class StringModel extends MetaModel { } export class BooleanModel extends MetaModel { } export class TupleValueModel { - index: number; - value: MetaModel; - constructor(index: number, value: MetaModel) { - this.index = index; - this.value = value; + constructor( + public index: number, + public value: MetaModel) { } } export class TupleModel extends MetaModel { - tupleModels: TupleValueModel[] = []; + constructor( + public name: string, + public originalInput: any, + public tupleModels: TupleValueModel[]) { + super(name, originalInput); + } } export class ObjectModel extends MetaModel { - properties: { [key: string]: MetaModel; } = {}; + constructor( + public name: string, + public originalInput: any, + public properties: { [key: string]: MetaModel; }) { + super(name, originalInput); + } } export class ArrayModel extends MetaModel { - valueModel: MetaModel; - constructor(name: string, valueModel: MetaModel) { - super(name); - this.valueModel = valueModel; + constructor( + public name: string, + public originalInput: any, + public valueModel: MetaModel) { + super(name, originalInput); } } export class UnionModel extends MetaModel { - unionModels: MetaModel[] = []; + constructor( + public name: string, + public originalInput: any, + public unionModels: MetaModel[]) { + super(name, originalInput); + } } export class EnumValueModel { - key: string; - value: any; - constructor(key: string, value: any) { - this.key = key; - this.value = value; + constructor( + public key: string, + public value: any) { } } export class EnumModel extends MetaModel { - values: EnumValueModel[] = []; + constructor( + public name: string, + public originalInput: any, + public values: EnumValueModel[]) { + super(name, originalInput); + } } export class DictionaryModel extends MetaModel { - keyModel: MetaModel; - valueModel: MetaModel; - serializationType: 'unwrap' | 'normal' = 'normal'; - - constructor(name: string, keyModel: MetaModel, valueModel: MetaModel) { - super(name); - this.keyModel = keyModel; - this.valueModel = valueModel; + constructor( + public name: string, + public originalInput: any, + public keyModel: MetaModel, + public valueModel: MetaModel, + public serializationType: 'unwrap' | 'normal' = 'normal') { + super(name, originalInput); } } From 842aad30edc29b3beb283207e5b713ec49e7de85 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Fri, 4 Mar 2022 15:32:15 +0100 Subject: [PATCH 80/82] Changed naming of models --- src/models/ConstrainedMetaModel.ts | 93 ++++++++++++++++++++---------- src/models/MetaModel.ts | 12 ++-- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/models/ConstrainedMetaModel.ts b/src/models/ConstrainedMetaModel.ts index eb5b638a16..dc4d497cb0 100644 --- a/src/models/ConstrainedMetaModel.ts +++ b/src/models/ConstrainedMetaModel.ts @@ -1,15 +1,22 @@ import { MetaModel } from './MetaModel'; export class ConstrainedMetaModel extends MetaModel { - type: string; - constructor(name: string, type: string) { - super(name); - this.type = type; + constructor( + public name: string, + public originalInput: any, + public type: string) { + super(name, originalInput); } } -export class ConstrainedReferencedModel extends ConstrainedMetaModel { - referencedModel?: ConstrainedMetaModel +export class ConstrainedReferenceModel extends ConstrainedMetaModel { + constructor( + public name: string, + public originalInput: any, + public type: string, + public ref: ConstrainedMetaModel) { + super(name, originalInput, type); + } } export class ConstrainedAnyModel extends ConstrainedMetaModel { } export class ConstrainedFloatModel extends ConstrainedMetaModel { } @@ -17,48 +24,70 @@ export class ConstrainedIntegerModel extends ConstrainedMetaModel { } export class ConstrainedStringModel extends ConstrainedMetaModel { } export class ConstrainedBooleanModel extends ConstrainedMetaModel { } export class ConstrainedTupleValueModel { - index: number; - value: ConstrainedMetaModel; - constructor(index: number, value: ConstrainedMetaModel) { - this.index = index; - this.value = value; + constructor( + public index: number, + public value: ConstrainedMetaModel) { } } export class ConstrainedTupleModel extends ConstrainedMetaModel { - tupleModels: ConstrainedTupleValueModel[] = []; + constructor( + public name: string, + public originalInput: any, + public type: string, + public tuple: ConstrainedTupleValueModel[]) { + super(name, originalInput, type); + } } export class ConstrainedObjectModel extends ConstrainedMetaModel { - properties: { [key: string]: ConstrainedMetaModel; } = {}; + constructor( + public name: string, + public originalInput: any, + public type: string, + public properties: { [key: string]: ConstrainedMetaModel; }) { + super(name, originalInput, type); + } } export class ConstrainedArrayModel extends ConstrainedMetaModel { - valueModel: ConstrainedMetaModel; - constructor(name: string, type: string, valueModel: ConstrainedMetaModel) { - super(name, type); - this.valueModel = valueModel; + constructor( + public name: string, + public originalInput: any, + public type: string, + public valueModel: ConstrainedMetaModel) { + super(name, originalInput, type); } } export class ConstrainedUnionModel extends ConstrainedMetaModel { - unionModels: ConstrainedMetaModel[] = []; + constructor( + public name: string, + public originalInput: any, + public type: string, + public union: ConstrainedMetaModel[]) { + super(name, originalInput, type); + } } export class ConstrainedEnumValueModel { - key: string; - value: any; - constructor(key: string, value: any) { - this.key = key; - this.value = value; + constructor( + public key: string, + public value: any) { } } export class ConstrainedEnumModel extends ConstrainedMetaModel { - values: ConstrainedEnumValueModel[] = []; + constructor( + public name: string, + public originalInput: any, + public type: string, + public values: ConstrainedEnumValueModel[]) { + super(name, originalInput, type); + } } export class ConstrainedDictionaryModel extends ConstrainedMetaModel { - keyModel: ConstrainedMetaModel; - valueModel: ConstrainedMetaModel; - serializationType: 'unwrap' | 'normal' = 'normal'; - - constructor(name: string, type: string, keyModel: ConstrainedMetaModel, valueModel: ConstrainedMetaModel) { - super(name, type); - this.keyModel = keyModel; - this.valueModel = valueModel; + constructor( + public name: string, + public originalInput: any, + public type: string, + public key: ConstrainedMetaModel, + public value: ConstrainedMetaModel, + public serializationType: 'unwrap' | 'normal' = 'normal') { + super(name, originalInput, type); } } diff --git a/src/models/MetaModel.ts b/src/models/MetaModel.ts index d97b0bf650..d0561b324c 100644 --- a/src/models/MetaModel.ts +++ b/src/models/MetaModel.ts @@ -5,11 +5,11 @@ export class MetaModel { } } -export class ReferencedModel extends MetaModel { +export class ReferenceModel extends MetaModel { constructor( public name: string, public originalInput: any, - public referencedModel: MetaModel) { + public ref: MetaModel) { super(name, originalInput); } } @@ -28,7 +28,7 @@ export class TupleModel extends MetaModel { constructor( public name: string, public originalInput: any, - public tupleModels: TupleValueModel[]) { + public tuple: TupleValueModel[]) { super(name, originalInput); } } @@ -52,7 +52,7 @@ export class UnionModel extends MetaModel { constructor( public name: string, public originalInput: any, - public unionModels: MetaModel[]) { + public union: MetaModel[]) { super(name, originalInput); } } @@ -74,8 +74,8 @@ export class DictionaryModel extends MetaModel { constructor( public name: string, public originalInput: any, - public keyModel: MetaModel, - public valueModel: MetaModel, + public key: MetaModel, + public value: MetaModel, public serializationType: 'unwrap' | 'normal' = 'normal') { super(name, originalInput); } From 2c2e3ca3ec6e35212db2fbca03ae1b85f4b0bb74 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Fri, 4 Mar 2022 16:19:44 +0100 Subject: [PATCH 81/82] Added export of models --- src/models/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/models/index.ts b/src/models/index.ts index 46cafa0afa..77c57843b3 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -10,3 +10,6 @@ export * from './Draft6Schema'; export * from './Draft4Schema'; export * from './SwaggerV2Schema'; export * from './OpenapiV3Schema'; +export * from './MetaModel'; +export * from './ConstrainedMetaModel'; + From aeec94e5fed84f78d9def403bad0591c8e97ef4d Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 8 Mar 2022 13:02:20 +0100 Subject: [PATCH 82/82] Removed unnecessary redefining of properties --- src/models/ConstrainedMetaModel.ts | 46 +++++++++++++++--------------- src/models/MetaModel.ts | 28 +++++++++--------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/models/ConstrainedMetaModel.ts b/src/models/ConstrainedMetaModel.ts index dc4d497cb0..5a138f675e 100644 --- a/src/models/ConstrainedMetaModel.ts +++ b/src/models/ConstrainedMetaModel.ts @@ -2,8 +2,8 @@ import { MetaModel } from './MetaModel'; export class ConstrainedMetaModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public type: string) { super(name, originalInput); } @@ -11,9 +11,9 @@ export class ConstrainedMetaModel extends MetaModel { export class ConstrainedReferenceModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public ref: ConstrainedMetaModel) { super(name, originalInput, type); } @@ -31,36 +31,36 @@ export class ConstrainedTupleValueModel { } export class ConstrainedTupleModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public tuple: ConstrainedTupleValueModel[]) { super(name, originalInput, type); } } export class ConstrainedObjectModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public properties: { [key: string]: ConstrainedMetaModel; }) { super(name, originalInput, type); } } export class ConstrainedArrayModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public valueModel: ConstrainedMetaModel) { super(name, originalInput, type); } } export class ConstrainedUnionModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public union: ConstrainedMetaModel[]) { super(name, originalInput, type); } @@ -73,18 +73,18 @@ export class ConstrainedEnumValueModel { } export class ConstrainedEnumModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public values: ConstrainedEnumValueModel[]) { super(name, originalInput, type); } } export class ConstrainedDictionaryModel extends ConstrainedMetaModel { constructor( - public name: string, - public originalInput: any, - public type: string, + name: string, + originalInput: any, + type: string, public key: ConstrainedMetaModel, public value: ConstrainedMetaModel, public serializationType: 'unwrap' | 'normal' = 'normal') { diff --git a/src/models/MetaModel.ts b/src/models/MetaModel.ts index d0561b324c..acc8b5cbad 100644 --- a/src/models/MetaModel.ts +++ b/src/models/MetaModel.ts @@ -7,8 +7,8 @@ export class MetaModel { export class ReferenceModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public ref: MetaModel) { super(name, originalInput); } @@ -26,32 +26,32 @@ export class TupleValueModel { } export class TupleModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public tuple: TupleValueModel[]) { super(name, originalInput); } } export class ObjectModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public properties: { [key: string]: MetaModel; }) { super(name, originalInput); } } export class ArrayModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public valueModel: MetaModel) { super(name, originalInput); } } export class UnionModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public union: MetaModel[]) { super(name, originalInput); } @@ -64,16 +64,16 @@ export class EnumValueModel { } export class EnumModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public values: EnumValueModel[]) { super(name, originalInput); } } export class DictionaryModel extends MetaModel { constructor( - public name: string, - public originalInput: any, + name: string, + originalInput: any, public key: MetaModel, public value: MetaModel, public serializationType: 'unwrap' | 'normal' = 'normal') {