From e9e46b38b0b2173a4a98ec184b9149ce3be5c0ae Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 28 Jan 2025 11:56:52 +0100 Subject: [PATCH] feat!: release v4 (#2162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kenneth Aasan Co-authored-by: jano-petras Co-authored-by: Nilkanth Parmar Co-authored-by: Moritz Kalwa <62842654+moritzkalwa@users.noreply.github.com> Co-authored-by: Jean-François Côté Co-authored-by: souvik Co-authored-by: Ashmit JaiSarita Gupta <43639341+devilkiller-ag@users.noreply.github.com> Co-authored-by: Daniel Kenyon-Jones Co-authored-by: Daniel Kenyon-Jones Co-authored-by: Akshit Gupta <96991785+akkshitgupta@users.noreply.github.com> Co-authored-by: borrull Co-authored-by: Borrull Alonso Co-authored-by: jespitae Co-authored-by: Axel Hecht Co-authored-by: Jens Spitaels Co-authored-by: memdal <77838566+memdal@users.noreply.github.com> Co-authored-by: TertiumOrganum1 <51286827+TertiumOrganum1@users.noreply.github.com> Co-authored-by: Владислав Муранов Co-authored-by: fr-th <61010557+fr-th@users.noreply.github.com> Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> Co-authored-by: Jesse Wayde Brandão --- .eslintignore | 1 + .github/workflows/blackbox-testing.yml | 44 - .github/workflows/bump-homebrew-formula.yml | 40 + .../chocolatey/asyncapi-modelina.nuspec | 31 + .../workflows/deploy/chocolatey/replace.ps1 | 19 + .../chocolatey/tools/chocolateyinstall.ps1 | 26 + .github/workflows/if-nodejs-pr-testing.yml | 1 + .github/workflows/release-chocolatey.yml | 93 + .github/workflows/upload-release-assets.yml | 89 + .prettierignore | 1 + .prettierrc | 3 +- .releaserc | 75 +- README.md | 17 +- docs/README.md | 4 - docs/contributing.md | 2 - docs/development.md | 4 - docs/generators.md | 167 - docs/languages/Go.md | 29 +- docs/languages/Python.md | 9 + docs/languages/TypeScript.md | 6 +- docs/migrations/version-3-to-4.md | 326 + docs/presets.md | 31 +- docs/usage.md | 14 +- examples/README.md | 6 + examples/avro-schema-from-object/README.md | 17 + .../__snapshots__/index.spec.ts.snap | 18 + .../avro-schema-from-object/index.spec.ts | 15 + examples/avro-schema-from-object/index.ts | 27 + .../avro-schema-from-object/package-lock.json | 10 + examples/avro-schema-from-object/package.json | 12 + .../__snapshots__/index.spec.ts.snap | 4 + .../csharp-generate-handle-nullable/index.ts | 18 +- .../__snapshots__/index.spec.ts.snap | 16 + .../__snapshots__/index.spec.ts.snap | 10 +- .../__snapshots__/index.spec.ts.snap | 2 +- .../__snapshots__/index.spec.ts.snap | 4 +- examples/file-uri-input/index.spec.ts | 34 +- .../__snapshots__/index.spec.ts.snap | 4 +- .../generate-go-asyncapi-comments/README.md | 17 + .../__snapshots__/index.spec.ts.snap | 27 + .../index.spec.ts | 16 + .../generate-go-asyncapi-comments/index.ts | 116 + .../package-lock.json | 10 + .../package.json | 12 + .../__snapshots__/index.spec.ts.snap | 9 +- .../__snapshots__/index.spec.ts.snap | 3 +- .../__snapshots__/index.spec.ts.snap | 128 +- .../__snapshots__/index.spec.ts.snap | 14 +- .../__snapshots__/index.spec.ts.snap | 10 +- examples/go-json-tags/README.md | 17 + .../__snapshots__/index.spec.ts.snap | 94 + examples/go-json-tags/index.spec.ts | 17 + examples/go-json-tags/index.ts | 37 + examples/go-json-tags/package-lock.json | 10 + examples/go-json-tags/package.json | 10 + examples/go-union-type/README.md | 26 + .../__snapshots__/index.spec.ts.snap | 59 + examples/go-union-type/index.spec.ts | 20 + examples/go-union-type/index.ts | 33 + examples/go-union-type/package-lock.json | 10 + examples/go-union-type/package.json | 10 + .../scripts/modelina/package-lock.json | 13 +- .../__snapshots__/index.spec.ts.snap | 2 + .../README.md | 17 + .../__snapshots__/index.spec.ts.snap | 24 + .../index.spec.ts | 15 + .../index.ts | 29 + .../package-lock.json | 10 + .../package.json | 10 + .../README.md | 19 + .../__snapshots__/index.spec.ts.snap | 17 + .../index.spec.ts | 15 + .../json-schema-single-enum-as-const/index.ts | 30 + .../package-lock.json | 10 + .../package.json | 10 + examples/openapi-include-components/README.md | 17 + .../__snapshots__/index.spec.ts.snap | 18 + .../openapi-include-components/index.spec.ts | 14 + examples/openapi-include-components/index.ts | 39 + .../package-lock.json | 10 + .../openapi-include-components/package.json | 10 + .../__snapshots__/index.spec.ts.snap | 32 +- .../__snapshots__/index.spec.ts.snap | 4 +- jest.config.js | 3 +- modelina-cli/.eslintignore | 5 + modelina-cli/.eslintrc | 28 + modelina-cli/.gitignore | 17 + modelina-cli/.mocharc.json | 16 + modelina-cli/.prettierrc.json | 1 + modelina-cli/README.md | 791 + modelina-cli/bin/dev | 17 + modelina-cli/bin/dev.cmd | 3 + modelina-cli/bin/run | 12 + modelina-cli/bin/run.cmd | 3 + modelina-cli/bin/run_bin | 13 + modelina-cli/bin/run_bin.cmd | 3 + modelina-cli/package-lock.json | 15780 +++ modelina-cli/package.json | 111 + modelina-cli/scripts/releasePackagesRename.js | 80 + modelina-cli/src/base.ts | 14 + .../src/commands/config/context/add.ts | 57 + .../src/commands/config/context/current.ts | 54 + .../src/commands/config/context/edit.ts | 49 + .../src/commands/config/context/index.ts | 13 + .../src/commands/config/context/init.ts | 27 + .../src/commands/config/context/list.ts | 48 + .../src/commands/config/context/remove.ts | 45 + .../src/commands/config/context/use.ts | 45 + modelina-cli/src/commands/config/index.ts | 11 + modelina-cli/src/commands/generate.ts | 49 + modelina-cli/src/errors/context-error.ts | 75 + modelina-cli/src/errors/specification-file.ts | 57 + modelina-cli/src/helpers/csharp.ts | 85 + modelina-cli/src/helpers/csplusplus.ts | 26 + modelina-cli/src/helpers/dart.ts | 27 + modelina-cli/src/helpers/generate.ts | 124 + modelina-cli/src/helpers/go.ts | 46 + modelina-cli/src/helpers/java.ts | 61 + modelina-cli/src/helpers/javascript.ts | 19 + modelina-cli/src/helpers/kotlin.ts | 27 + modelina-cli/src/helpers/php.ts | 26 + modelina-cli/src/helpers/python.ts | 33 + modelina-cli/src/helpers/rust.ts | 19 + modelina-cli/src/helpers/scala.ts | 25 + modelina-cli/src/helpers/typescript.ts | 107 + modelina-cli/src/index.ts | 3 + modelina-cli/src/models/Context.ts | 391 + modelina-cli/src/models/SpecificationFile.ts | 229 + modelina-cli/test/fixtures/asyncapi_v2.yml | 26 + modelina-cli/test/fixtures/asyncapi_v3.json | 56 + modelina-cli/test/fixtures/asyncapi_v3.yml | 34 + modelina-cli/test/helpers/generate.test.ts | 42 + modelina-cli/test/integration/context.test.ts | 279 + .../test/integration/generate.test.ts | 374 + modelina-cli/test/test_helpers/index.ts | 138 + modelina-cli/test/test_helpers/init.js | 9 + modelina-cli/test/tsconfig.json | 6 + modelina-cli/tsconfig.json | 26 + package-lock.json | 10547 +- package.json | 79 +- src/generators/AbstractGenerator.ts | 95 +- .../cplusplus/CplusplusGenerator.ts | 24 +- src/generators/csharp/CSharpConstrainer.ts | 14 +- src/generators/csharp/CSharpGenerator.ts | 30 +- src/generators/csharp/Constants.ts | 14 + .../csharp/constrainer/ConstantConstrainer.ts | 48 +- .../csharp/presets/JsonSerializerPreset.ts | 50 +- .../presets/NewtonsoftSerializerPreset.ts | 55 +- .../csharp/renderers/ClassRenderer.ts | 22 +- .../csharp/renderers/EnumRenderer.ts | 4 +- .../csharp/renderers/RecordRenderer.ts | 5 + src/generators/dart/DartGenerator.ts | 29 +- src/generators/go/GoConstrainer.ts | 62 +- src/generators/go/GoFileGenerator.ts | 8 +- src/generators/go/GoGenerator.ts | 78 +- src/generators/go/GoPreset.ts | 39 +- src/generators/go/index.ts | 1 + src/generators/go/presets/CommonPreset.ts | 78 + .../go/presets/DescriptionPreset.ts | 42 + src/generators/go/presets/index.ts | 2 + src/generators/go/renderers/EnumRenderer.ts | 60 +- src/generators/go/renderers/StructRenderer.ts | 57 +- src/generators/go/renderers/UnionRenderer.ts | 100 + src/generators/java/JavaConstrainer.ts | 9 +- src/generators/java/JavaGenerator.ts | 27 +- src/generators/java/presets/JacksonPreset.ts | 19 + .../java/renderers/ClassRenderer.ts | 64 +- .../javascript/JavaScriptGenerator.ts | 32 +- src/generators/kotlin/KotlinGenerator.ts | 28 +- src/generators/php/PhpGenerator.ts | 32 +- src/generators/python/PythonConstrainer.ts | 15 +- .../python/PythonDependencyManager.ts | 69 +- src/generators/python/PythonGenerator.ts | 36 +- .../python/constrainer/ConstantConstrainer.ts | 48 +- .../constrainer/ModelNameConstrainer.ts | 2 +- .../constrainer/PropertyKeyConstrainer.ts | 2 +- .../python/presets/JsonSerializer.ts | 4 +- src/generators/python/presets/Pydantic.ts | 96 +- .../python/renderers/ClassRenderer.ts | 74 +- .../python/renderers/EnumRenderer.ts | 2 +- src/generators/rust/RustGenerator.ts | 27 +- src/generators/scala/ScalaGenerator.ts | 27 +- src/generators/template/TemplateGenerator.ts | 26 +- .../typescript/TypeScriptGenerator.ts | 23 +- .../presets/utils/MarshalFunction.ts | 5 +- src/helpers/AvroToMetaModel.ts | 362 + src/helpers/CommonModelToMetaModel.ts | 377 +- src/helpers/ConstrainHelpers.ts | 648 +- src/helpers/ConstrainedTypes.ts | 314 + src/helpers/FileHelpers.ts | 2 +- src/helpers/FormatHelpers.ts | 25 +- src/helpers/MetaModelToConstrained.ts | 555 + src/helpers/index.ts | 1 + src/models/AsyncapiV2Schema.ts | 24 +- src/models/AvroSchema.ts | 25 + src/models/CommonModel.ts | 20 +- src/models/ConstrainedMetaModel.ts | 1 + src/models/Draft4Schema.ts | 24 +- src/models/Draft6Schema.ts | 24 +- src/models/Draft7Schema.ts | 26 +- src/models/OpenapiV3Schema.ts | 24 +- src/models/ProcessorOptions.ts | 11 +- src/models/SwaggerV2Schema.ts | 24 +- src/models/index.ts | 1 + src/processors/AsyncAPIInputProcessor.ts | 107 +- src/processors/AvroSchemaInputProcessor.ts | 59 + src/processors/InputProcessor.ts | 2 + src/processors/JsonSchemaInputProcessor.ts | 102 +- src/processors/OpenAPIInputProcessor.ts | 43 +- src/processors/SwaggerInputProcessor.ts | 21 +- src/processors/TypeScriptInputProcessor.ts | 25 +- src/processors/index.ts | 1 + src/utils/Partials.ts | 4 +- test/TestUtils/GeneralUtils.ts | 47 + test/TestUtils/TestConstrainer.ts | 26 +- test/TestUtils/TestRenderers.ts | 2 +- test/blackbox/.gitignore | 1 - test/blackbox/BlackBoxTestFiles.ts | 86 - test/blackbox/README.md | 37 - test/blackbox/blackbox-cplusplus.spec.ts | 62 - test/blackbox/blackbox-csharp.spec.ts | 54 - test/blackbox/blackbox-go.spec.ts | 52 - test/blackbox/blackbox-java.spec.ts | 84 - test/blackbox/blackbox-javascript.spec.ts | 62 - test/blackbox/blackbox-kotlin.spec.ts | 101 - test/blackbox/blackbox-php.spec.ts | 79 - test/blackbox/blackbox-python.spec.ts | 62 - test/blackbox/blackbox-rust.spec.ts | 87 - test/blackbox/blackbox-typescript.spec.ts | 72 - .../java/jackson-annotations-2.12.3.jar | Bin 75703 -> 0 bytes .../kotlin/validation-api-2.0.1.Final.jar | Bin 93107 -> 0 bytes test/blackbox/docs/AsyncAPI-2_0/dummy.json | 568 - .../AsyncAPI-2_0/zbos_mqtt-all-asyncapi.json | 23150 ---- test/blackbox/docs/AsyncAPI-2_1/dummy.json | 571 - test/blackbox/docs/AsyncAPI-2_2/dummy.json | 574 - test/blackbox/docs/AsyncAPI-2_3/dummy.json | 574 - test/blackbox/docs/AsyncAPI-2_4/dummy.json | 574 - .../streetlights-operation-security.json | 296 - .../docs/AsyncAPI-2_5/streetlight_kafka.json | 279 - test/blackbox/docs/AsyncAPI-2_6/dummy.json | 82 - .../JsonSchemaDraft-4/aws-cloudformation.json | 101252 --------------- .../JsonSchemaDraft-4/chrome-manifest.json | 758 - .../JsonSchemaDraft-4/circleci-config.json | 1317 - .../docs/JsonSchemaDraft-4/draft-4-core.json | 149 - .../grafana-dashboard-5.json | 264 - .../JsonSchemaDraft-4/jenkins-config.json | 1623 - .../docs/JsonSchemaDraft-4/nuget-project.json | 205 - .../docs/JsonSchemaDraft-4/openapi-3.json | 1654 - .../docs/JsonSchemaDraft-4/swagger-2_0.json | 1607 - .../docs/JsonSchemaDraft-4/traefik-v2.json | 1184 - .../docs/JsonSchemaDraft-6/draft-6-core.json | 155 - .../docs/JsonSchemaDraft-6/fhir-full.json | 60923 --------- .../docs/JsonSchemaDraft-7/asyncapi-2_0.json | 1370 - .../better-code-hub-config.json | 98 - .../docs/JsonSchemaDraft-7/draft-7-core.json | 172 - .../docs/JsonSchemaDraft-7/dummy.json | 147 - .../docs/JsonSchemaDraft-7/github-action.json | 656 - .../JsonSchemaDraft-7/github-workflow.json | 1533 - .../docs/JsonSchemaDraft-7/gitlab-ci.json | 1649 - .../graphql-code-generator.json | 5312 - .../docs/JsonSchemaDraft-7/netlify.json | 283 - .../JsonSchemaDraft-7/portman-config.json | 993 - .../postman-collection-1_0.json | 1338 - .../postman-collection-2_0.json | 1099 - .../postman-collection-2_1.json | 1146 - .../JsonSchemaDraft-7/prometheus-config.json | 927 - .../JsonSchemaDraft-7/prometheus-rules.json | 148 - test/blackbox/docs/OpenAPI-3_0/petstore.json | 1225 - .../docs/OpenAPI-3_0/postman-api.json | 6874 - .../docs/OpenAPI-3_0/twilio-1_13.json | 30476 ----- test/blackbox/docs/Swagger-2_0/petstore.json | 1054 - test/blackbox/docs/Swagger-2_0/slack-1_7.json | 27441 ---- test/blackbox/utils/Utils.ts | 99 - test/generators/FileGenerators.spec.ts | 65 +- .../__snapshots__/FileGenerators.spec.ts.snap | 23 + .../csharp/CSharpConstrainer.spec.ts | 30 +- .../generators/csharp/CSharpGenerator.spec.ts | 48 +- .../CSharpGenerator.spec.ts.snap | 43 +- .../presets/JsonSerializerPreset.spec.ts | 1 + .../NewtonsoftSerializerPreset.spec.ts | 1 + .../JsonSerializerPreset.spec.ts.snap | 43 + .../NewtonsoftSerializerPreset.spec.ts.snap | 34 +- test/generators/go/GoConstrainer.spec.ts | 118 +- test/generators/go/GoGenerator.spec.ts | 307 +- test/generators/go/GoRenderer.spec.ts | 2 +- .../go/__snapshots__/GoGenerator.spec.ts.snap | 293 +- .../go/presets/CommonPreset.spec.ts | 43 + .../go/presets/DescriptionPreset.spec.ts | 38 + .../__snapshots__/CommonPreset.spec.ts.snap | 44 + .../DescriptionPreset.spec.ts.snap | 18 + test/generators/java/JavaRenderer.spec.ts | 2 +- .../__snapshots__/JavaGenerator.spec.ts.snap | 22 + .../java/presets/CommonPreset.spec.ts | 16 +- .../java/presets/DescriptionPreset.spec.ts | 2 +- .../DescriptionPreset.spec.ts.snap | 2 +- .../__snapshots__/JacksonPreset.spec.ts.snap | 20 + .../__snapshots__/PhpGenerator.spec.ts.snap | 44 +- .../python/PythonConstrainer.spec.ts | 44 +- .../python/PythonDependencyManager.spec.ts | 32 + .../generators/python/PythonGenerator.spec.ts | 47 +- test/generators/python/PythonRenderer.spec.ts | 2 +- .../PythonGenerator.spec.ts.snap | 219 +- .../constrainer/ConstantConstrainer.spec.ts | 81 +- .../constrainer/EnumConstrainer.spec.ts | 36 +- .../constrainer/ModelNameConstrainer.spec.ts | 30 +- .../PropertyKeyConstrainer.spec.ts | 29 +- .../__snapshots__/JsonSerializer.spec.ts.snap | 32 +- .../__snapshots__/Pydantic.spec.ts.snap | 222 +- .../PropertyKeyConstrainer.spec.ts | 4 + .../JsonBinPackPreset.spec.ts.snap | 12 +- .../MarshallingPreset.spec.ts.snap | 6 +- test/helpers/AvroToMetaModel.spec.ts | 191 + test/helpers/CommonModelToMetaModel.spec.ts | 180 +- test/helpers/ConstrainHelpers.spec.ts | 48 +- test/interpreter/Intepreter.spec.ts | 14 +- .../__snapshots__/Intepreter.spec.ts.snap | 51 + test/models/ConstrainedMetaModel.spec.ts | 2 +- .../processors/AsyncAPIInputProcessor.spec.ts | 56 +- .../operation_with_reply.json | 94 + .../AvroSchemaInputProcessor.spec.ts | 67 + .../AvroSchemaInputProcessor/basic.json | 68 + test/processors/InputProcessor.spec.ts | 28 +- .../JsonSchemaInputProcessor.spec.ts | 6 +- test/processors/OpenAPIInputProcessor.spec.ts | 28 +- .../OpenAPIInputProcessor/basic.json | 60 +- .../OpenAPIInputProcessor/no_paths.json | 26 + .../references_circular.json | 54 + test/processors/SwaggerInputProcessor.spec.ts | 40 +- .../references_circular.json | 40 + .../AsyncAPIInputProcessor.spec.ts.snap | 663 +- .../AvroSchemaInputProcessor.spec.ts.snap | 284 + .../OpenAPIInputProcessor.spec.ts.snap | 206 +- .../SwaggerInputProcessor.spec.ts.snap | 95 +- .../TypeScriptInputProcessor.spec.ts.snap | 20 +- test/runtime/generic-input-all.json | 78 + test/runtime/generic-input-simple.json | 49 + test/runtime/runtime-cplusplus.spec.ts | 2 +- test/runtime/runtime-csharp.spec.ts | 2 +- test/runtime/runtime-go.spec.ts | 2 +- test/runtime/runtime-java.spec.ts | 2 +- test/runtime/runtime-kotlin.spec.ts | 2 +- test/runtime/runtime-php.spec.ts | 2 +- test/runtime/runtime-python.spec.ts | 6 +- test/runtime/runtime-python/tests/__init__.py | 7 + .../runtime-python/{test => tests}/main.py | 6 +- test/runtime/runtime-rust.spec.ts | 2 +- test/runtime/runtime-scala.spec.ts | 2 +- .../mycompany/app/generic/AddressSpec.scala | 4 +- test/runtime/runtime-typescript.ts | 46 +- .../test/DefaultAddressTest.spec.ts | 41 +- .../test/JsonBinPackPreset.spec.ts | 29 +- .../test/Marshalling.spec.ts | 108 +- .../test/NamedAddressTest.spec.ts | 41 +- 353 files changed, 33905 insertions(+), 290641 deletions(-) delete mode 100644 .github/workflows/blackbox-testing.yml create mode 100644 .github/workflows/bump-homebrew-formula.yml create mode 100644 .github/workflows/deploy/chocolatey/asyncapi-modelina.nuspec create mode 100644 .github/workflows/deploy/chocolatey/replace.ps1 create mode 100644 .github/workflows/deploy/chocolatey/tools/chocolateyinstall.ps1 create mode 100644 .github/workflows/release-chocolatey.yml create mode 100644 .github/workflows/upload-release-assets.yml delete mode 100644 docs/generators.md create mode 100644 docs/migrations/version-3-to-4.md create mode 100644 examples/avro-schema-from-object/README.md create mode 100644 examples/avro-schema-from-object/__snapshots__/index.spec.ts.snap create mode 100644 examples/avro-schema-from-object/index.spec.ts create mode 100644 examples/avro-schema-from-object/index.ts create mode 100644 examples/avro-schema-from-object/package-lock.json create mode 100644 examples/avro-schema-from-object/package.json create mode 100644 examples/generate-go-asyncapi-comments/README.md create mode 100644 examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap create mode 100644 examples/generate-go-asyncapi-comments/index.spec.ts create mode 100644 examples/generate-go-asyncapi-comments/index.ts create mode 100644 examples/generate-go-asyncapi-comments/package-lock.json create mode 100644 examples/generate-go-asyncapi-comments/package.json create mode 100644 examples/go-json-tags/README.md create mode 100644 examples/go-json-tags/__snapshots__/index.spec.ts.snap create mode 100644 examples/go-json-tags/index.spec.ts create mode 100644 examples/go-json-tags/index.ts create mode 100644 examples/go-json-tags/package-lock.json create mode 100644 examples/go-json-tags/package.json create mode 100644 examples/go-union-type/README.md create mode 100644 examples/go-union-type/__snapshots__/index.spec.ts.snap create mode 100644 examples/go-union-type/index.spec.ts create mode 100644 examples/go-union-type/index.ts create mode 100644 examples/go-union-type/package-lock.json create mode 100644 examples/go-union-type/package.json create mode 100644 examples/json-schema-additional-properties-representation/README.md create mode 100644 examples/json-schema-additional-properties-representation/__snapshots__/index.spec.ts.snap create mode 100644 examples/json-schema-additional-properties-representation/index.spec.ts create mode 100644 examples/json-schema-additional-properties-representation/index.ts create mode 100644 examples/json-schema-additional-properties-representation/package-lock.json create mode 100644 examples/json-schema-additional-properties-representation/package.json create mode 100644 examples/json-schema-single-enum-as-const/README.md create mode 100644 examples/json-schema-single-enum-as-const/__snapshots__/index.spec.ts.snap create mode 100644 examples/json-schema-single-enum-as-const/index.spec.ts create mode 100644 examples/json-schema-single-enum-as-const/index.ts create mode 100644 examples/json-schema-single-enum-as-const/package-lock.json create mode 100644 examples/json-schema-single-enum-as-const/package.json create mode 100644 examples/openapi-include-components/README.md create mode 100644 examples/openapi-include-components/__snapshots__/index.spec.ts.snap create mode 100644 examples/openapi-include-components/index.spec.ts create mode 100644 examples/openapi-include-components/index.ts create mode 100644 examples/openapi-include-components/package-lock.json create mode 100644 examples/openapi-include-components/package.json create mode 100644 modelina-cli/.eslintignore create mode 100644 modelina-cli/.eslintrc create mode 100644 modelina-cli/.gitignore create mode 100644 modelina-cli/.mocharc.json create mode 100644 modelina-cli/.prettierrc.json create mode 100644 modelina-cli/README.md create mode 100644 modelina-cli/bin/dev create mode 100644 modelina-cli/bin/dev.cmd create mode 100755 modelina-cli/bin/run create mode 100644 modelina-cli/bin/run.cmd create mode 100755 modelina-cli/bin/run_bin create mode 100644 modelina-cli/bin/run_bin.cmd create mode 100644 modelina-cli/package-lock.json create mode 100644 modelina-cli/package.json create mode 100644 modelina-cli/scripts/releasePackagesRename.js create mode 100644 modelina-cli/src/base.ts create mode 100644 modelina-cli/src/commands/config/context/add.ts create mode 100644 modelina-cli/src/commands/config/context/current.ts create mode 100644 modelina-cli/src/commands/config/context/edit.ts create mode 100644 modelina-cli/src/commands/config/context/index.ts create mode 100644 modelina-cli/src/commands/config/context/init.ts create mode 100644 modelina-cli/src/commands/config/context/list.ts create mode 100644 modelina-cli/src/commands/config/context/remove.ts create mode 100644 modelina-cli/src/commands/config/context/use.ts create mode 100644 modelina-cli/src/commands/config/index.ts create mode 100644 modelina-cli/src/commands/generate.ts create mode 100644 modelina-cli/src/errors/context-error.ts create mode 100644 modelina-cli/src/errors/specification-file.ts create mode 100644 modelina-cli/src/helpers/csharp.ts create mode 100644 modelina-cli/src/helpers/csplusplus.ts create mode 100644 modelina-cli/src/helpers/dart.ts create mode 100644 modelina-cli/src/helpers/generate.ts create mode 100644 modelina-cli/src/helpers/go.ts create mode 100644 modelina-cli/src/helpers/java.ts create mode 100644 modelina-cli/src/helpers/javascript.ts create mode 100644 modelina-cli/src/helpers/kotlin.ts create mode 100644 modelina-cli/src/helpers/php.ts create mode 100644 modelina-cli/src/helpers/python.ts create mode 100644 modelina-cli/src/helpers/rust.ts create mode 100644 modelina-cli/src/helpers/scala.ts create mode 100644 modelina-cli/src/helpers/typescript.ts create mode 100644 modelina-cli/src/index.ts create mode 100644 modelina-cli/src/models/Context.ts create mode 100644 modelina-cli/src/models/SpecificationFile.ts create mode 100644 modelina-cli/test/fixtures/asyncapi_v2.yml create mode 100644 modelina-cli/test/fixtures/asyncapi_v3.json create mode 100644 modelina-cli/test/fixtures/asyncapi_v3.yml create mode 100644 modelina-cli/test/helpers/generate.test.ts create mode 100644 modelina-cli/test/integration/context.test.ts create mode 100644 modelina-cli/test/integration/generate.test.ts create mode 100644 modelina-cli/test/test_helpers/index.ts create mode 100644 modelina-cli/test/test_helpers/init.js create mode 100644 modelina-cli/test/tsconfig.json create mode 100644 modelina-cli/tsconfig.json create mode 100644 src/generators/go/presets/CommonPreset.ts create mode 100644 src/generators/go/presets/DescriptionPreset.ts create mode 100644 src/generators/go/presets/index.ts create mode 100644 src/generators/go/renderers/UnionRenderer.ts create mode 100644 src/helpers/AvroToMetaModel.ts create mode 100644 src/helpers/ConstrainedTypes.ts create mode 100644 src/helpers/MetaModelToConstrained.ts create mode 100644 src/models/AvroSchema.ts create mode 100644 src/processors/AvroSchemaInputProcessor.ts create mode 100644 test/TestUtils/GeneralUtils.ts delete mode 100644 test/blackbox/.gitignore delete mode 100644 test/blackbox/BlackBoxTestFiles.ts delete mode 100644 test/blackbox/README.md delete mode 100644 test/blackbox/blackbox-cplusplus.spec.ts delete mode 100644 test/blackbox/blackbox-csharp.spec.ts delete mode 100644 test/blackbox/blackbox-go.spec.ts delete mode 100644 test/blackbox/blackbox-java.spec.ts delete mode 100644 test/blackbox/blackbox-javascript.spec.ts delete mode 100644 test/blackbox/blackbox-kotlin.spec.ts delete mode 100644 test/blackbox/blackbox-php.spec.ts delete mode 100644 test/blackbox/blackbox-python.spec.ts delete mode 100644 test/blackbox/blackbox-rust.spec.ts delete mode 100644 test/blackbox/blackbox-typescript.spec.ts delete mode 100644 test/blackbox/dependencies/java/jackson-annotations-2.12.3.jar delete mode 100644 test/blackbox/dependencies/kotlin/validation-api-2.0.1.Final.jar delete mode 100644 test/blackbox/docs/AsyncAPI-2_0/dummy.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_0/zbos_mqtt-all-asyncapi.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_1/dummy.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_2/dummy.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_3/dummy.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_4/dummy.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_4/streetlights-operation-security.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_5/streetlight_kafka.json delete mode 100644 test/blackbox/docs/AsyncAPI-2_6/dummy.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/aws-cloudformation.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/chrome-manifest.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/circleci-config.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/draft-4-core.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/grafana-dashboard-5.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/jenkins-config.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/nuget-project.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/openapi-3.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/swagger-2_0.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-4/traefik-v2.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-6/draft-6-core.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-6/fhir-full.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/asyncapi-2_0.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/better-code-hub-config.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/draft-7-core.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/dummy.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/github-action.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/github-workflow.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/gitlab-ci.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/graphql-code-generator.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/netlify.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/portman-config.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/postman-collection-1_0.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/postman-collection-2_0.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/postman-collection-2_1.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/prometheus-config.json delete mode 100644 test/blackbox/docs/JsonSchemaDraft-7/prometheus-rules.json delete mode 100644 test/blackbox/docs/OpenAPI-3_0/petstore.json delete mode 100644 test/blackbox/docs/OpenAPI-3_0/postman-api.json delete mode 100644 test/blackbox/docs/OpenAPI-3_0/twilio-1_13.json delete mode 100644 test/blackbox/docs/Swagger-2_0/petstore.json delete mode 100644 test/blackbox/docs/Swagger-2_0/slack-1_7.json delete mode 100644 test/blackbox/utils/Utils.ts create mode 100644 test/generators/__snapshots__/FileGenerators.spec.ts.snap create mode 100644 test/generators/go/presets/CommonPreset.spec.ts create mode 100644 test/generators/go/presets/DescriptionPreset.spec.ts create mode 100644 test/generators/go/presets/__snapshots__/CommonPreset.spec.ts.snap create mode 100644 test/generators/go/presets/__snapshots__/DescriptionPreset.spec.ts.snap create mode 100644 test/generators/python/PythonDependencyManager.spec.ts create mode 100644 test/helpers/AvroToMetaModel.spec.ts create mode 100644 test/interpreter/__snapshots__/Intepreter.spec.ts.snap create mode 100644 test/processors/AsyncAPIInputProcessor/operation_with_reply.json create mode 100644 test/processors/AvroSchemaInputProcessor.spec.ts create mode 100644 test/processors/AvroSchemaInputProcessor/basic.json create mode 100644 test/processors/OpenAPIInputProcessor/no_paths.json create mode 100644 test/processors/OpenAPIInputProcessor/references_circular.json create mode 100644 test/processors/SwaggerInputProcessor/references_circular.json create mode 100644 test/processors/__snapshots__/AvroSchemaInputProcessor.spec.ts.snap create mode 100644 test/runtime/generic-input-all.json create mode 100644 test/runtime/generic-input-simple.json create mode 100644 test/runtime/runtime-python/tests/__init__.py rename test/runtime/runtime-python/{test => tests}/main.py (89%) diff --git a/.eslintignore b/.eslintignore index 5ea878327f..1699ec4581 100644 --- a/.eslintignore +++ b/.eslintignore @@ -9,5 +9,6 @@ examples/integrate-with-react src/processors/TemplateInputProcessor.ts test/processors/TemplateInputProcessor.spec.ts modelina-website +modelina-cli test/runtime/runtime-** \ No newline at end of file diff --git a/.github/workflows/blackbox-testing.yml b/.github/workflows/blackbox-testing.yml deleted file mode 100644 index 807ba92da0..0000000000 --- a/.github/workflows/blackbox-testing.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Blackbox testing (Stay Awhile and Listen) -on: - push: - pull_request: - types: [opened, reopened, synchronize, ready_for_review] -jobs: - test: - 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: - os: [ubuntu-latest] - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - name: Check package-lock version - uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master - id: lockversion - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: "${{ steps.lockversion.outputs.version }}" - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - - name: Build library - run: npm install && npm run build - - uses: actions/setup-java@v2 - with: - distribution: 'adopt' - java-version: '11' - - if: matrix.os != 'windows-latest' - name: Setup dotnet - uses: actions/setup-dotnet@v1 - with: - dotnet-version: '5.0.x' - - if: matrix.os == 'windows-latest' - name: Setup csc.exe - uses: yoavain/Setup-CSC@v7 - - uses: actions/setup-go@v2 - with: - go-version: '1.16.8' - - name: Test output - run: npm run test:blackbox \ No newline at end of file diff --git a/.github/workflows/bump-homebrew-formula.yml b/.github/workflows/bump-homebrew-formula.yml new file mode 100644 index 0000000000..6c673c4dc3 --- /dev/null +++ b/.github/workflows/bump-homebrew-formula.yml @@ -0,0 +1,40 @@ +name: Bump Homebrew formula for Modelina + +on: + # Since now release depends on schedule, might be that there is a situation we cannot wait for schedule and trigger release manually + workflow_dispatch: + # We cannot run brew release continusly every time we release something as sometimes we release a couple of times a day and overload brew pipelines + # More details https://github.com/asyncapi/cli/issues/503 + # schedule: + # - cron: "0 23 * * *" + +jobs: + bump-formula-in-homebrew: + if: github.repository == 'asyncapi/modelina' + name: Bump the formula in homebrew-core repo + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Get version from package.json + id: extractver + run: echo "version=$(npm run get-version --silent)" >> $GITHUB_OUTPUT + - uses: mislav/bump-homebrew-formula-action@v2 + with: + # A PR will be sent to github.com/Homebrew/homebrew-core to update AsyncAPI Modelina formula: + formula-name: modelina + # https://github.com/mislav/bump-homebrew-formula-action/issues/58 + formula-path: Formula/a/modelina.rb + tag-name: ${{ steps.extractver.outputs.version }} + download-url: https://registry.npmjs.org/@asyncapi/modelina/-/modelina-${{ steps.extractver.outputs.version }}.tgz #we need to point to npm not github as there is a dist that is not on github + env: + COMMITTER_TOKEN: ${{ secrets.GH_TOKEN_BOT_EVE }} + - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel + name: Report workflow run status to Slack + uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 + with: + status: ${{ job.status }} + fields: repo,action,workflow + text: 'AsyncAPI Modelina release to BREW failed' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} \ No newline at end of file diff --git a/.github/workflows/deploy/chocolatey/asyncapi-modelina.nuspec b/.github/workflows/deploy/chocolatey/asyncapi-modelina.nuspec new file mode 100644 index 0000000000..5704160d1a --- /dev/null +++ b/.github/workflows/deploy/chocolatey/asyncapi-modelina.nuspec @@ -0,0 +1,31 @@ + + + + + modelina + {{version}} + https://github.com/asyncapi/modelina/releases/v{{version}} + AsyncAPI_Initiative + + + + modelina + AsyncAPI_Initiative + https://www.asyncapi.com/ + https://avatars.githubusercontent.com/u/16401334?s=200 + 2024 AsyncAPI Initiative + https://github.com/asyncapi/modelina/blob/master/LICENSE + false + https://github.com/asyncapi/modelina/releases/v{{version}} + https://github.com/asyncapi/modelina + https://www.asyncapi.com/docs/tools/modelina + https://github.com/asyncapi/modelina/issues/new/choose + asyncapi-modelina modelina nodejs api asyncapi + Modelina CLI to generate any kind of model from any kind of input! + Modelina CLI to generate any kind of model in TypeScript, Java, Kotlin, C#, C++, and so much more from AsyncAPI, JSON Schema, OpenAPI, TypeScript files, etc! + + + + + + diff --git a/.github/workflows/deploy/chocolatey/replace.ps1 b/.github/workflows/deploy/chocolatey/replace.ps1 new file mode 100644 index 0000000000..bb4617dd62 --- /dev/null +++ b/.github/workflows/deploy/chocolatey/replace.ps1 @@ -0,0 +1,19 @@ +param ( + [Parameter(Mandatory=$true)] + [string]$version, + [string]$checksum, + [string]$checksum64 +) + +$filePaths = @( + './tools/chocolateyinstall.ps1' + './modelina.nuspec' +) + +foreach ($filePath in $filePaths) { + $fileContents = Get-Content $filePath + $fileContents = $fileContents -replace '{{version}}', $version + $fileContents = $fileContents -replace '{{checksum}}', $checksum + $fileContents = $fileContents -replace '{{checksum64}}', $checksum64 + Set-Content $filePath $fileContents +} \ No newline at end of file diff --git a/.github/workflows/deploy/chocolatey/tools/chocolateyinstall.ps1 b/.github/workflows/deploy/chocolatey/tools/chocolateyinstall.ps1 new file mode 100644 index 0000000000..69c0591cb7 --- /dev/null +++ b/.github/workflows/deploy/chocolatey/tools/chocolateyinstall.ps1 @@ -0,0 +1,26 @@ +$ErrorActionPreference = 'Stop' # stop on all errors +$toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" + +$url = 'https://github.com/asyncapi/modelina/releases/download/v{{version}}/modelina.x86.exe' +$url64 = 'https://github.com/asyncapi/modelina/releases/download/v{{version}}/modelina.x64.exe' + +$packageArgs = @{ + packageName = $env:ChocolateyPackageName + unzipLocation = $toolsDir + fileType = 'EXE' + url = $url + url64bit = $url64 + #file = $fileLocation NOTE: Commented out because we are using url instead + + softwareName = 'modelina*' + + checksum = '{{checksum}}' + checksumType = 'sha256' #default is md5, can also be sha1, sha256 or sha512 + checksum64 = '{{checksum64}}' + checksumType64= 'sha256' #default is checksumType + + validExitCodes= @(0, 3010, 1641) + silentArgs = '/S' # NSIS +} + +Install-ChocolateyPackage @packageArgs # https://docs.chocolatey.org/en-us/create/functions/install-chocolateypackage diff --git a/.github/workflows/if-nodejs-pr-testing.yml b/.github/workflows/if-nodejs-pr-testing.yml index 9ce9f9a19c..22d7413cf5 100644 --- a/.github/workflows/if-nodejs-pr-testing.yml +++ b/.github/workflows/if-nodejs-pr-testing.yml @@ -31,6 +31,7 @@ jobs: ) ) id: should_run + shell: bash name: Should Run run: echo "shouldrun=true" >> $GITHUB_OUTPUT - if: steps.should_run.outputs.shouldrun == 'true' diff --git a/.github/workflows/release-chocolatey.yml b/.github/workflows/release-chocolatey.yml new file mode 100644 index 0000000000..90200481d6 --- /dev/null +++ b/.github/workflows/release-chocolatey.yml @@ -0,0 +1,93 @@ +name: Release Chocolatey Package +on: + # We cannot run chocolatey release continuously every time we release something as sometimes we release a couple of times a day and overload chocolatey pipelines + # More details https://github.com/asyncapi/cli/issues/503 + # schedule: + # - cron: '0 23 * * *' # Run every day at 23:00 UTC + # Since now release depends on schedule, might be that there is a situation we cannot wait for schedule and trigger release manually + workflow_dispatch: + inputs: + version: + description: 'Version to release (optional)' + required: false + +jobs: + release: + name: Publish to Chocolatey Community + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set Version + id: release_version + run: | + if ( "${{ github.event_name }}" -eq "workflow_dispatch" -and "${{ github.event.inputs.version }}" -ne "" ) { + $version = "${{ github.event.inputs.version }}" + } + else { + $version = $(npm pkg get version) + } + + $version = $version.Replace("`"", "") + echo "Setting version to $version" + echo "version=$version" >> $env:GITHUB_OUTPUT + + - name: Check if this is a new version to release + id: check_new_version + run: | + $output = choco search asyncapi-cli --version=${{ steps.release_version.outputs.version }} + # Output is of the form: + # Chocolatey v2.2.2 + # asyncapi-cli 0.0.1 [Approved] + # 1 packages found. + # If the version is not found, the output will of the form: + # Chocolatey v2.2.2 + # 0 packages found. + if ($output -match "0 packages found.") { + echo "This is a new version to release" + echo "new_version=true" >> $env:GITHUB_OUTPUT + } + else { + echo "This is not a new version to release" + echo "new_version=false" >> $env:GITHUB_OUTPUT + } + - name: Download release + if: steps.check_new_version.outputs.new_version == 'true' + run: | + echo "Downloading release assets for version ${{ steps.release_version.outputs.version }}" + mkdir -p ./dist + curl -L "https://github.com/asyncapi/modelina/releases/download/v${{ steps.release_version.outputs.version }}/modelina.x64.exe" -o "./modelina-cli/dist/win32/modelina.x64.exe" + curl -L "https://github.com/asyncapi/modelina/releases/download/v${{ steps.release_version.outputs.version }}/modelina.x86.exe" -o "./modelina-cli/dist/win32/modelina.x86.exe" + + - name: Get Checksum of the release + id: release_checksum + run: | + $checksum = (Get-FileHash -Path "./modelina-cli/dist/win32/modelina.x86.exe" -Algorithm SHA256).Hash + $checksum64 = (Get-FileHash -Path "./modelina-cli/dist/win32/modelina.x64.exe" -Algorithm SHA256).Hash + echo "Setting checksum to $checksum" + echo "checksum=$checksum" >> $env:GITHUB_OUTPUT + echo "Setting checksum64 to $checksum64" + echo "checksum64=$checksum64" >> $env:GITHUB_OUTPUT + + - name: Make nuspec from the template + run: | + cd ./.github/workflows/deploy/chocolatey + pwsh -File ./replace.ps1 -version ${{ steps.release_version.outputs.version }} -checksum ${{ steps.release_checksum.outputs.checksum }} -checksum64 ${{ steps.release_checksum.outputs.checksum64 }} + + - name: Run Chocolatey Pack + run: | + cd ./.github/workflows/deploy/chocolatey + choco pack ./modelina.nuspec + choco apikey add --source "'https://push.chocolatey.org/'" --key ${{ secrets.CHOCOLATEY_API_KEY }} + choco push ./modelina.${{ steps.release_version.outputs.version }}.nupkg --source "'https://push.chocolatey.org/'" + + - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel + name: Report workflow run status to Slack + uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 + with: + status: ${{ job.status }} + fields: repo,action,workflow + text: 'AsyncAPI Modelina release to Chocolatey failed' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} \ No newline at end of file diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml new file mode 100644 index 0000000000..ba7c8c4685 --- /dev/null +++ b/.github/workflows/upload-release-assets.yml @@ -0,0 +1,89 @@ +name: Upload custom assets to GitHub release + +on: + # It cannot run on release event as when release is created then version is not yet bumped in package.json + # This means we cannot extract easily latest version and have a risk that package is not yet on npm + push: + branches: + - master + - next + +jobs: + upload-assets: + name: Generate and upload assets + if: startsWith(github.event.commits[0].message, 'chore(release):') + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + npm_script: pack:linux + dist_folder: deb + extension: deb + - os: ubuntu-latest + npm_script: pack:tarballs + dist_folder: tar + extension: tar.gz + - os: windows-latest + npm_script: pack:windows + dist_folder: win32 + extension: x64.exe + - os: windows-latest + npm_script: pack:windows + dist_folder: win32 + extension: x86.exe + - os: macos-latest + npm_script: pack:macos + dist_folder: macos + extension: arm64.pkg + - os: macos-latest + npm_script: pack:macos + dist_folder: macos + extension: x64.pkg + steps: + - 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 + uses: actions/checkout@v3 + - name: Check package-lock version + uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master + id: lockversion + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: "${{ steps.lockversion.outputs.version }}" + cache: 'npm' + cache-dependency-path: '**/package-lock.json' + - name: Get version from package.json + uses: actions/github-script@v6 + id: extractver + with: + script: | + const packageJson = require('./package.json'); + const packageJsonVersion = packageJson.version; + core.setOutput('version', packageJsonVersion); + - name: Install dependencies + run: npm install + - name: Build project + run: npm run prepublishOnly + - name: Assets generation + shell: bash + run: cd modelina-cli && npm run ${{ matrix.npm_script }} + - name: Update release + uses: softprops/action-gh-release@v1 + with: + files: modelina-cli/dist/${{ matrix.dist_folder }}/modelina.${{ matrix.extension }} + tag_name: v${{ steps.extractver.outputs.version }} + token: ${{ secrets.GH_TOKEN }} + - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel + name: Report workflow run status to Slack + uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 + with: + status: ${{ job.status }} + fields: repo,action,workflow + text: 'AsyncAPI Modelina release build artifacts failed' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} diff --git a/.prettierignore b/.prettierignore index f15f3a4191..69a4c0e2b5 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ lib node_modules modelina-website +modelina-cli test/runtime/runtime-** \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index fc98bd3760..09d944ef77 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,5 +2,6 @@ "semi": true, "trailingComma": "none", "singleQuote": true, - "printWidth": 80 + "printWidth": 80, + "endOfLine": "auto" } \ No newline at end of file diff --git a/.releaserc b/.releaserc index 1ac05cb151..5b04b680c6 100644 --- a/.releaserc +++ b/.releaserc @@ -1,24 +1,51 @@ ---- -branches: -- master -# by default release workflow reacts on push not only to master. -#This is why out of the box sematic release is configured for all these branches -- name: next-spec - prerelease: true -- name: next-major - prerelease: true -- name: next-major-spec - prerelease: true -- name: beta - prerelease: true -- name: alpha - prerelease: true -- name: next - prerelease: true -plugins: -- - "@semantic-release/commit-analyzer" - - preset: conventionalcommits -- - "@semantic-release/release-notes-generator" - - preset: conventionalcommits -- "@semantic-release/npm" -- "@semantic-release/github" +{ + "branches": [ + "master", + { + "name": "next-spec", + "prerelease": true + }, + { + "name": "next-major", + "prerelease": true + }, + { + "name": "next-major-spec", + "prerelease": true + }, + { + "name": "beta", + "prerelease": true + }, + { + "name": "alpha", + "prerelease": true + }, + { + "name": "next", + "prerelease": true + } + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits" + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits" + } + ], + "@semantic-release/npm", + [ + "@semantic-release/npm", + { + "pkgRoot": "modelina-cli" + } + ], + "@semantic-release/github" + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 9a7f8c0668..03671a9d58 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ [![AsyncAPI Modelina](./docs/img/readme-banner.png)](https://www.modelina.org) -[![blackbox pipeline status]()](https://github.com/asyncapi/modelina/actions/workflows/blackbox-testing.yml?query=branch%3Amaster++) [![Coverage Status](https://coveralls.io/repos/github/asyncapi/modelina/badge.svg?branch=master)](https://coveralls.io/github/asyncapi/modelina?branch=master) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) ![Maintenance score](https://img.shields.io/npms-io/maintenance-score/@asyncapi/modelina) @@ -12,6 +11,7 @@ [![All Contributors](https://img.shields.io/badge/all_contributors-100-orange.svg?style=flat-square)](#contributors-) + Your one-stop tool for generating accurate and well-tested models for representing the message payloads. Use it as a tool in your development workflow, or a library in a larger integrations, entirely in your control. --- @@ -21,7 +21,6 @@ Your one-stop tool for generating accurate and well-tested models for representi - [Installing Modelina](#installing-modelina) -- [AsyncAPI CLI](#asyncapi-cli) - [Features](#features) - [Requirements](#requirements) - [Documentation](#documentation) @@ -35,18 +34,16 @@ Your one-stop tool for generating accurate and well-tested models for representi ## Installing Modelina -Run this command to install Modelina in your project: +Install Modelina directly as a dependency to your project: ```bash npm install @asyncapi/modelina ``` -## AsyncAPI CLI - -If you have the [AsyncAPI CLI installed](https://github.com/asyncapi/cli#installation) (ONLY support AsyncAPI inputs), you can run the following command to use [Modelina](https://github.com/asyncapi/cli#usage): +Or if you want to [run Modelina, use the CLI](./modelina-cli/README.md). ```bash -asyncapi generate models ./asyncapi.json +modelina generate ./asyncapi.json ```

What Does Modelina Do?

@@ -193,7 +190,11 @@ The following table provides a short summary of available features for supported AsyncAPI - We support the following AsyncAPI versions: 2.0.0 -> 2.6.0, which generates models for all the defined message payloads. It supports the following schemaFormats AsyncAPI Schema object, JSON Schema draft 7, AVRO 1.9, RAML 1.0 data type, and OpenAPI 3.0 Schema. + We support the following AsyncAPI versions: 2.0.0 -> 3.0.0, which generates models for all the defined message payloads. It supports the following schemaFormats AsyncAPI Schema object, JSON Schema draft 7, AVRO 1.9, RAML 1.0 data type, and OpenAPI 3.0 Schema. + + + Avro Schema + We support the following Avro versions: v1.x JSON Schema diff --git a/docs/README.md b/docs/README.md index 9364e2fe9e..c4b3d28c6b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,7 +10,6 @@ - [Advanced](#advanced) - [Integration](#integration) - [Development](#development) -- [Generators](#generators) - [Presets](#presets) - [Interpretation of JSON Schema](#interpretation-of-json-schema) - [Migration](#migration) @@ -42,9 +41,6 @@ Contains many advanced ways to integrate Modelina _(i.e. websites)_. ### [Development](./development.md) Explains how to setup the project for development. -### [Generators](./generators.md) -Details which different generator options are supported. - ### [Presets](./presets.md) Goes more in-depth into how the preset system works, which enables full customization of generators. diff --git a/docs/contributing.md b/docs/contributing.md index 0613935690..67f6061ee0 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -132,7 +132,6 @@ Time to adapt the tests, cause without tests, it's just an empty promise. The te 4. Adapt the [generator tests](../test/generators/template/TemplateGenerator.spec.ts) 5. Adapt the [renderer tests](../test/generators/template/TemplateRenderer.spec.ts) 6. Add your generator to the [FileGenerators test](../test/generators/FileGenerators.spec.ts) to ensure the models are accurately written to files. -7. Lastly, we have (arguably) the most important tests, [the BlackBox tests](./development.md#blackbox-testing). They are to ensure that real-world inputs generate usable models that do not contain syntax errors. You can read more about the BlackBox tests [here](./development.md#blackbox-testing). Lastly, we need to adapt some of the docs to showcase your new awesome generator! Cause if the users cant find it, it dont exist. 1. Add your [generator specific documentation under languages](./languages/) and add it to the [list of generators](./README.md#languages) @@ -163,7 +162,6 @@ That said, here is a general rundown on what's triggered by each PR: - We inherit all [AsyncAPI core GitHub workflows](https://github.com/asyncapi/.github/tree/master/.github/workflows), including the most important one: - [A standard PR workflow](https://github.com/asyncapi/.github/blob/master/.github/workflows/if-nodejs-pr-testing.yml) which ensures that the following commands need to succeed: `npm run test`, `npm run lint`, and `npm run generate:assets`. -- [BlackBox testing](https://github.com/asyncapi/modelina/tree/master/test/blackbox) has its [own workflow](https://github.com/asyncapi/modelina/blob/master/.github/workflows/blackbox-testing.yml) which ensures that all supported inputs generate syntactically correct outputs to any of the output languages. This check takes a while (usually +5 minutes). Generally, you don't need to worry about this one, unless the code were to suddenly generate syntactically incorrect code (we will guide you if this happens). - [Coverall](https://github.com/asyncapi/modelina/blob/master/.github/workflows/coverall.yml) ensures we get test coverage statistics in each PR, thus ensuring we see how it affects overall test coverage. It creates a comment on the PR with the coverage status. - [SonarCloud](https://sonarcloud.io/dashboard?id=asyncapi_generator-model-sdk) runs a code analysis to ensure no bugs, security concerns, code smells, or duplicated code blocks. Make sure you address any concerns found by this bot, because it generates a comment to the PR if it finds any issue. diff --git a/docs/development.md b/docs/development.md index 62db7265c8..e4894c23fd 100644 --- a/docs/development.md +++ b/docs/development.md @@ -9,7 +9,6 @@ You can either build the image and run the needed commands manually or rather us - `npm run docker:build` builds the docker image with the tag `asyncapi/modelina` (the rest of the scripts run this one as well). - `npm run docker:test` runs the main test suite. -- `npm run docker:test:blackbox` runs the BlackBox test suite. ## Environment setup @@ -21,6 +20,3 @@ To setup the environment follow these steps: - You can update snapshots by running `npm run test -- -u` 4. Make sure code is well formatted and secure with eslint by running `npm run lint`, you can also auto format your code with `npm run format` -## 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. diff --git a/docs/generators.md b/docs/generators.md deleted file mode 100644 index 71c7029523..0000000000 --- a/docs/generators.md +++ /dev/null @@ -1,167 +0,0 @@ -# Generators - - - - - -- [Generator's options](#generators-options) - * [TypeScript](#typescript) - + [Generator options](#generator-options) - + [Render complete model options](#render-complete-model-options) - * [Java](#java) - + [Generator options](#generator-options-1) - + [Render complete model options](#render-complete-model-options-1) - * [JavaScript](#javascript) - + [Generator options](#generator-options-2) - + [Render complete model options](#render-complete-model-options-2) - * [Go](#go) - + [Generator options](#generator-options-3) - + [Render complete model options](#render-complete-model-options-3) - * [C#](#c%23) - + [Generator options](#generator-options-4) - + [Render complete model options](#render-complete-model-options-4) -- [Custom generator](#custom-generator) - - - -**Generators** are classes that are used to render models for a given language. - -## Generator's options - -For Modelina, there exist 3 types of options for the generation process. -1. Default options, are the default options the rest overwrite. -2. Generator options, are used as the baseline that is by default used for each model render. -3. Render options, are the last resort to specialize options for the individual rendering of a model, that overwrite the generator options. - -Generator options are passed as the first argument to the generator's constructor. Check the example: - -```ts -const generator = new TypeScriptGenerator({ ...options }); -``` - -Render options are passed as the first argument to the generator's render function. Check the example: - -```ts -const generator = ... -const model = ... -const inputModel = ... -generator.render(model, inputModel, { ...options }); -``` - -Default generator options (common to all generators) are as follows: - -| Option | Type | Description | Default value | -|---|---|---|---| -| `indentation` | Object | Options for indentation ([example](../examples/indentation-type-and-size)). | - | -| `indentation.type` | String | Type of indentation. Its value can be either `SPACES` or `TABS` and are typed by `IndentationTypes`| `SPACES` | -| `indentation.size` | String | Size of indentation. | 2 | -| `defaultPreset` | Object | Default preset for generator. For more information, read [customization](./presets.md) document. | _Implemented by generator_ | -| `presets` | Array | Array contains **presets**. For more information, read [customization](./presets.md) document. | `[]` | - -In addition, generators take additional options when calling their `renderCompleteModel(input, options)` functions. -This allows the caller to specify additional options when generating a multi-file model from the input with cross dependencies. - -Below is a list of additional options available for a given generator. - -### [TypeScript](./languages/TypeScript.md) - -#### Generator options - -| Option | Type | Description | Default value | -|---|---|---|---| -| `renderTypes` | Boolean | Render signature for types. | `true` | -| `mapType` | String | It indicates which mapping type should be rendered for the `object` type. Its value can be one of `map`, `record` or `indexedObject`. | `map` | -| `modelType` | String | It indicates which model type should be rendered for the `object` type. Its value can be either `interface` or `class`. | `class` | -| `enumType` | String | It indicates which type should be rendered for the `enum` type. Its value can be either `union` or `enum`. | `enum` | -| `namingConvention` | Object | Options for naming conventions. | - | -| `namingConvention.type` | Function | A function that returns the format of the type. | _Returns pascal cased name, and ensures that reserved keywords are never rendered__ | -| `namingConvention.property` | Function | A function that returns the format of the property. | _Returns camel cased name, and ensures that names of properties does not clash against reserved keywords for TS, as well as JS to ensure painless transpilation_ | - -#### Render complete model options - -| Option | Type | Description | Default value | -|----------------|--------------------------|----------------------------------------------------------------------------|---------------| -| `moduleSystem` | 'ESM' | 'CJS' | Which module system the generated files should use (`import` or `require`) | 'CJS' | -| `exportType` | 'default' | 'named' | Whether the exports should be default or named exports | 'default' | - -### [Java](./languages/Java.md) - -#### Generator options - -| Option | Type | Description | Default value | -|---|---|---|---| -| `collectionType` | String | It indicates with which signature should be rendered the `array` type. Its value can be either `List` (`List<{type}>`) or `Array` (`{type}[]`). | `List` | -| `namingConvention` | Object | Options for naming conventions. | - | -| `namingConvention.type` | Function | A function that returns the format of the type. | _Returns pascal cased name, and ensures that reserved keywords are never rendered__ | -| `namingConvention.property` | Function | A function that returns the format of the property. | _Returns camel cased name, and ensures that names of properties does not clash against reserved keywords_ | - -#### Render complete model options - -| Option | Type | Description | Default value | -|---------------|--------|-----------------------------------------------|---------------| -| `packageName` | string | The package name to generate the models under | [required] | - -### [JavaScript](./languages/JavaScript.md) - -#### Generator options - -| Option | Type | Description | Default value | -|---|---|---|---| -| `namingConvention` | Object | Options for naming conventions. | - | -| `namingConvention.type` | Function | A function that returns the format of the type. | _Returns pascal cased name, and ensures that reserved keywords are never rendered_ | -| `namingConvention.property` | Function | A function that returns the format of the property. | _Returns camel cased name, and ensures that names of properties does not clash against reserved keywords_ | - -#### Render complete model options - -| Option | Type | Description | Default value | -|----------------|--------------------------|----------------------------------------------------------------------------|---------------| -| `moduleSystem` | 'ESM' | 'CJS' | Which module system the generated files should use (`import` or `require`) | 'CJS' | - -### [Go](./languages/Go.md) - -#### Generator options - -| Option | Type | Description | Default value | -|---|---|---|---| -| `namingConvention` | Object | Options for naming conventions. | - | -| `namingConvention.type` | Function | A function that returns the format of the type. | _Returns pascal cased name_ | -| `namingConvention.field` | Function | A function that returns the format of the field. | _Returns pascal cased name_ | - -#### Render complete model options - -| Option | Type | Description | Default value | -|---------------|--------|-----------------------------------------------|---------------| -| `packageName` | string | The package name to generate the models under | [required] | - -### [C#](./languages/Csharp.md) - -#### Generator options - -| Option | Type | Description | Default value | -|---|---|---|---| -| `namingConvention` | Object | Options for naming conventions. | - | -| `namingConvention.type` | Function | A function that returns the format of the type. | _Returns pascal cased name, and ensures that reserved keywords are never rendered__ | -| `namingConvention.property` | Function | A function that returns the format of the property. | _Returns camel cased name, and ensures that names of properties does not clash against reserved keywords_ | - -#### Render complete model options - -| Option | Type | Description | Default value | -|-------------|--------|--------------------------------------------|---------------| -| `namespace` | string | The namespace to generate the models under | [required] | - -## Custom generator - -The minimum set of required actions to create a new generator are: - -- Source code must be included in [generators](../src/generators) folder. -- Must extend the abstract [`AbstractGenerator`](../src/generators/AbstractGenerator.ts) class, -- Must define [`Preset`](./customization.md)'s shape for the language, -- Must define language options by passing an interface describing additional options to the first generic argument of [`AbstractGenerator`](../src/generators/AbstractGenerator.ts). The interface must also be extended by `CommonGeneratorOptions` interface, -- Must define default options as static class's field, which must be extended by `defaultGeneratorOptions`, -- Default options must include `defaultPreset` property, -- Must implement `render` function, -- Must define **Renderers** classes for available model types in a given language. **Renderer** is an instance of the class with common helper functions to render appropriate model type and must be extended by [`AbstractRenderer`](../src/generators/AbstractRenderer.ts) class - [example](../src/generators/typescript/renderers/ClassRenderer.ts). - -Check the [generator implementation](../src/generators/typescript/TypeScriptGenerator.ts) for `TypeScript` language to see how it should look like. - -If you created a generator then you can contribute it to the AsyncAPI Model SDK and it will become the official supported generator. diff --git a/docs/languages/Go.md b/docs/languages/Go.md index 7cfa209ce8..a3c537df3c 100644 --- a/docs/languages/Go.md +++ b/docs/languages/Go.md @@ -4,24 +4,41 @@ There are special use-cases that each language supports; this document pertains -- [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) - * [To and from JSON](#to-and-from-json) - * [To and from XML](#to-and-from-xml) - * [To and from binary](#to-and-from-binary) +- [Go](#go) + - [Generate serializer and deserializer functionality](#generate-serializer-and-deserializer-functionality) + - [To and from JSON](#to-and-from-json) + - [JSON Tags](#json-tags) + - [To and from XML](#to-and-from-xml) + - [To and from binary](#to-and-from-binary) + - [Rendering comments from description and example fields](#rendering-comments-from-description-and-example-fields) ## Generate serializer and deserializer functionality -The most widely used usecase for Modelina is to generate models that include serialization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. +The most widely used use-case for Modelina is to generate models that include serialization and deserialization functionality to convert the models into payload data. This payload data can of course be many different kinds, JSON, XML, raw binary, you name it. As you normally only need one library to do this, we developers can never get enough with creating new stuff, therefore there might be one specific library you need or want to integrate with. Therefore there is not one specific preset that offers everything. Below is a list of all the supported serialization presets. ### To and from JSON -Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! +Here are all the supported presets and the libraries they use for converting to and from JSON: + +- [JSON Tags](#json-tags) + +#### JSON Tags + +To generate go models that work correctly with JSON marshal functions we need to generate appropriate JSON `struct-tags`, use the preset `GO_COMMON_PRESET` and provide the option `addJsonTag: true` (added in CLI by default). + +check out this [example for a live demonstration](../../examples/go-json-tags/) ### To and from XML Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! ### To and from binary Currently not supported, [let everyone know you need it](https://github.com/asyncapi/modelina/issues/new?assignees=&labels=enhancement&template=enhancement.md)! + +## Rendering comments from description and example fields + +You can use the `GO_DESCRIPTION_PRESET` to generate comments from description fields in your model. + +See [this example](../../examples/generate-go-asyncapi-comments) for how this can be used. diff --git a/docs/languages/Python.md b/docs/languages/Python.md index 4fe3b21590..63704e4dc3 100644 --- a/docs/languages/Python.md +++ b/docs/languages/Python.md @@ -2,6 +2,8 @@ There are special use-cases that each language supports; this document pertains to **Python models**. +The generated Python models require at least v[3.7](https://docs.python.org/release/3.7.0/). + @@ -13,14 +15,21 @@ There are special use-cases that each language supports; this document pertains ## Generate Pydantic models + In some cases you might want to use [pydantic](https://pypi.org/project/pydantic/) data validation and settings management using Python type hints for the models. +Modelina follows Pydantic v2. + +There are some limitations to the current implementation: +1. The preset doesn't unwrap properties of type `ConstrainedDictionaryModel` with `serialilzationType = unwrap`, they are simply excluded from the serialization You can find an example of its use [here](../../examples/generate-python-pydantic-models/index.ts) ## Generate models with JSON Serializer and Deserializer methods + Using the preset `PYTON_JSON_SERIALIZER`, you can generate `serializeToJson` method to convert model instance to JSON and `deserializeFromJson` method to convert JSON to model instance. ### Limitations + 1. Above preset doesn't unwrap properties of type `ConstrainedDictionaryModel` with `serialilzationType = unwrap` 2. The serialized JSON object will have the same property names as defined in the model object. diff --git a/docs/languages/TypeScript.md b/docs/languages/TypeScript.md index 68f82494be..b72b2d84cc 100644 --- a/docs/languages/TypeScript.md +++ b/docs/languages/TypeScript.md @@ -24,13 +24,13 @@ There are special use-cases that each language supports; this document pertains ## Generate an interface instead of classes -Sometimes you don't care about classes, but rather have interfaces generated. This can be changed through the [modelType configuration](https://github.com/asyncapi/modelina/blob/master/docs/generators.md#typescript). +Sometimes you don't care about classes, but rather have interfaces generated. This can be changed through the `modelType` configuration Check out this [example out for a live demonstration](../../examples/typescript-interface). ## Generate different `mapType`s for an `object` -Typescript offers different `mapType`s which can simplify the use based on the needs. This behavior can be changed through the [`mapType` configuration](https://github.com/asyncapi/modelina/blob/master/docs/generators.md#typescript). +Typescript offers different `mapType`s which can simplify the use based on the needs. This behavior can be changed through the `mapType` configuration. - Use `map` when you need a dynamic collection of key-value pairs with built-in methods for manipulation. - Use `record` when you want to define an object with specific keys and their corresponding value types. @@ -53,7 +53,7 @@ Also, check out this [example for a live demonstration](../../examples/typescrip ## Generate union types instead of enums -Typescript offers union types which can simplify the use as no keywords are needed and the values can be set directly. This behavior can be changed through the [modelType configuration](https://github.com/asyncapi/modelina/blob/master/docs/generators.md#typescript). An example of the generated code can be seen below: +Typescript offers union types which can simplify the use as no keywords are needed and the values can be set directly. This behavior can be changed through the `modelType` configuration. An example of the generated code can be seen below: ```ts // enumType = 'enum' diff --git a/docs/migrations/version-3-to-4.md b/docs/migrations/version-3-to-4.md new file mode 100644 index 0000000000..32fa966193 --- /dev/null +++ b/docs/migrations/version-3-to-4.md @@ -0,0 +1,326 @@ +# Migration from v3 to v4 + +This document contain all the breaking changes and migrations guidelines for adapting your code to the new version. + +## Deprecation of `processor.interpreter` + +Since the early days we had the option to set `processorOptions.interpreter` options to change how JSON Schema is interpreted to Meta models. However, these options are more accurately part of the `processorOptions.jsonSchema` options. + +Use this instead going forward. + +## Fixed edge cases for camel case names + +Naming such as object properties using camel case formatting had an edge case where if they contained a number followed by an underscore and a letter it would be incorrectly formatted. This has been fixed in this version, which might mean properties, model names, etc that use camel case might be renamed. + +This example contains such a string: + +```yaml +type: object +properties: + aa_00_testAttribute: + type: string +``` + +This used to generate: + +```ts +interface AnonymousSchema_1 { + aa_00TestAttribute?: string; +} +``` + +but will now generate: + +```ts +interface AnonymousSchema_1 { + aa_00_testAttribute?: string; +} +``` + +## C# + +### Constant values are now properly rendered as const properties + +This example used to generate a `string` with a getter and setter, but will now generate a const string that is initialized to the const value provided. + +```yaml +type: object +properties: + property: + type: string + const: 'abc' +``` + +will generate + +```csharp +public class TestClass { + private const string property = "test"; + + public string Property + { + get { return property; } + } + ... +} +``` + +Notice that `Property` no longer has a `set` method. This might break existing models. + +### DateTime and DateTimeOffset are now properly rendered based on specification format + +In the previous version, `date-time` and `date` formats were rendered as `DateTime` and `DateTimeOffset` respectively. +This has been changed to render `DateTimeOffset` for `date-time` and `DateTime` for `date` formats. + +This might break existing implementation and require manual changes. + +The best thing to do is to fix your specification and use what you really need. If you don't care about the time and time zone, use `date` instead of `date-time`. +Otherwise, keep the `date-time` format and update your code to use `DateTimeOffset` instead of `DateTime`. +That usually means doing this: + +```csharp +var dateTime = new DateTime(2008, 6, 19, 7, 0, 0); + +// Set the DateTime property of the ModelinaModel +var modelinaModel = new ModelinaModel(); +modelinaModel.DateTime = dateTime; +Console.WriteLine(modelinaModel.DateTime); + +// Get the DateTime property from the ModelinaModel +DateTime dateTime2 = modelinaModel.DateTime.LocalDateTime; +Console.WriteLine(dateTime2); +``` + +## Python + +Models are aiming to be >= v3.7 compliant. + +### Unique types in unions + +In v4, unions types are rendered unique, meaning you will never see `str | str` but just `str`. + +### Pydantic now follows v2 instead of v1 + +Reference: https://docs.pydantic.dev/2.6/migration/ + +The schema description is now a description and not an alias: + +```python +class Message(BaseModel): + identifier: str = Field(description='''The Identifier for the Message''') +``` + +In Modelina v3 this used is rendered as: + +```python +class Message(BaseModel): + identifier: str = Field(alias='''The Identifier for the Message''') +``` + +### Following standardized styling guide + +Before names of properties and model names did not follow any specific styling standard. + +In v4, we switched to using the following: + +- Variables and functions: https://peps.python.org/pep-0008/#function-and-variable-names +- Model names: https://peps.python.org/pep-0008/#class-names + +This means that properties and their accessor methods (getter and setters) have been renamed from: + +```diff +- self._someWeirdValueExclamationQuotationHash_2 = input.someWeirdValueExclamationQuotationHash_2 ++ self._some_weird_value_exclamation_quotation_hash_2 = input.some_weird_value_exclamation_quotation_hash_2 +``` + +And model names have been renamed to: + +```diff +- class AsyncApi_3Dot_0Dot_0SchemaDot: ++ class AsyncApi3Dot0Dot0SchemaDot: +``` + +If you are using the Python preset `PYTHON_JSON_SERIALIZER_PRESET`, the functions have also been renamed: + +```diff +- serializeToJson ++ serialize_to_json + +- deserializeFromJson ++ deserialize_from_json +``` + +### Type hints + +Classes now have type hints on all properties and accessor functions. + +Before: + +```python +from typing import Any, Dict +class ObjProperty: + def __init__(self, input): + if hasattr(input, 'number'): + self._number = input['number'] + if hasattr(input, 'additional_properties'): + self._additional_properties = input['additional_properties'] + + @property + def number(self): + return self._number + @number.setter + def number(self, number): + self._number = number + + @property + def additional_properties(self): + return self._additional_properties + @additional_properties.setter + def additional_properties(self, additional_properties): + self._additional_properties = additional_properties +``` + +After: + +```python +from typing import Any, Dict +class ObjProperty: + def __init__(self, input: Dict): + if hasattr(input, 'number'): + self._number: float = input['number'] + if hasattr(input, 'additional_properties'): + self._additional_properties: dict[str, Any] = input['additional_properties'] + + @property + def number(self) -> float: + return self._number + @number.setter + def number(self, number: float): + self._number = number + + @property + def additional_properties(self) -> dict[str, Any]: + return self._additional_properties + @additional_properties.setter + def additional_properties(self, additional_properties: dict[str, Any]): + self._additional_properties = additional_properties +``` + +### Initialization of correct models + +Before in the constructor, if a property was another class, they would not correctly be initialized. Now a new instance of the object is created. + +### Constants are now rendered + +Before, constants where completely ignored, now they are respected and also means you don't have the possibility to change it through setters for example. + +```python +class Address: + def __init__(self, input: Dict): + self._street_name: str = 'someAddress' + + @property + def street_name(self) -> str: + return self._street_name +``` + +### Import style deprecation + +All models are from this point onwards imported using explicit styles `from . import ${model.name}` to allow for circular model dependencies to work. This means that the option `importsStyle` is deprecated and is no longer in use. It will be removed at some point in the future. + +## Go + +### File names + +In v4, file names for go will be formatted as `snake_case.go`. This is the "standard" in go: https://github.com/golang/go/issues/36060 + +### Union types will be generated correctly with struct embeddings + +Modelina now supports union types for `Go`. Since `Go` does not have native union types support modelina uses `struct embeddings` to mock union types. + +```go +type Union struct { + CustomStruct + int + string + ModelinaArrType []string + ModelinaDictType map[string] interface{} + ModelinaAnyType interface {} +} +``` + +`ModelinaArrType`, `ModelinaDictType`, `ModelinaAnyType` are generated by default by modelina, users can change the names by passing different names to the `GoGenerator Options`, for example: + +```ts +const generator = new GoGenerator({ + unionAnyModelName: 'ModelinaAnyType', + unionArrModelName: 'ModelinaArrType', + unionDictModelName: 'ModelinaDictType' +}); +``` + +### Union type with discriminator will render an interface and the children will implement that interface + +While the above changes work for primitives, it's problematic for objects with a discriminator. This is solved by creating an interface for the parent with the discriminator and each child implements the interface: + +```go +type Vehicle interface { + IsVehicleVehicleType() +} + +type Car struct { + VehicleType *VehicleType + RegistrationPlate string + AdditionalProperties map[string]interface{} +} + +func (r Car) IsVehicleVehicleType() {} + +type Truck struct { + VehicleType *VehicleType + RegistrationPlate string + AdditionalProperties map[string]interface{} +} + +func (r Truck) IsVehicleVehicleType() {} + +type VehicleType uint + +const ( + VehicleTypeCar VehicleType = iota + VehicleTypeTruck +) + +// Value returns the value of the enum. +func (op VehicleType) Value() any { + if op >= VehicleType(len(VehicleTypeValues)) { + return nil + } + return VehicleTypeValues[op] +} + +var VehicleTypeValues = []any{\\"Car\\",\\"Truck\\"} +var ValuesToVehicleType = map[any]VehicleType{ + VehicleTypeValues[VehicleTypeCar]: VehicleTypeCar, + VehicleTypeValues[VehicleTypeTruck]: VehicleTypeTruck, +} +``` + +### Nullable and required properties + +Modelina now has support for nullable and required properties in go structs. This support exists for generic types like `int`, `string`, `bool`, `float64`. + +```go +type info struct { + name string // required + description *string // nullable + version *float64 + isDevelopment *bool +} +``` + +## Java + +### When `allowInheritance` is true, Modelina no longer renders the setter for enums in interfaces if the property exist in the implemented by class with a constant value + +In Java, when a class implements an interface, it must implement all the methods of that interface. Therefore, if `allowInheritance` is set to true, Modelina will no longer render the setter for enums in interfaces if the property exists in the implemented by class with a constant value. diff --git a/docs/presets.md b/docs/presets.md index e348523da2..8775e6ff2d 100644 --- a/docs/presets.md +++ b/docs/presets.md @@ -10,7 +10,7 @@ Modelina uses something called **presets** to extend the rendered model. You can * [Hello world!](#hello-world) * [Presets in depth](#presets-in-depth) + [Overwriting existing rendered content](#overwriting-existing-rendered-content) - + [Ap/pre-pending to existng rendered content](#appre-pending-to-existng-rendered-content) + + [Ap/pre-pending to existing rendered content](#appre-pending-to-existing-rendered-content) + [Reusing presets (options)](#reusing-presets-options) + [Adding new dependencies](#adding-new-dependencies) + [Overriding the default preset](#overriding-the-default-preset) @@ -27,30 +27,31 @@ Modelina uses something called **presets** to extend the rendered model. You can - [**Type**](#type) + [Go](#go) - [**Struct**](#struct) + - [**Enum**](#enum-2) + [C#](#c%23) - [**Class**](#class-3) - - [**Enum**](#enum-2) + - [**Enum**](#enum-3) + [Rust](#rust) - [**Struct**](#struct-1) - - [**Enum**](#enum-3) + - [**Enum**](#enum-4) - [**Package**](#package) - [**Union**](#union) - [**Tuple**](#tuple) + [Dart](#dart) - [**Class**](#class-4) - - [**Enum**](#enum-4) + - [**Enum**](#enum-5) + [Python](#python) - [**Class**](#class-5) - - [**Enum**](#enum-5) + - [**Enum**](#enum-6) + [C++ (csplusplus)](#c-csplusplus) - [**Class**](#class-6) - - [**Enum**](#enum-6) + - [**Enum**](#enum-7) + [Kotlin](#kotlin) - [**Class**](#class-7) - - [**Enum**](#enum-7) + - [**Enum**](#enum-8) + [PHP](#php) - [**Class**](#class-8) - - [**Enum**](#enum-8) + - [**Enum**](#enum-9) - [Limitations](#limitations) * [Hard for two presets to write to the exact same location within a class](#hard-for-two-presets-to-write-to-the-exact-same-location-within-a-class) @@ -187,7 +188,7 @@ class Root { } ``` -### Ap/pre-pending to existng rendered content +### Ap/pre-pending to existing rendered content As the hello world example appended content, this time lets prepend some content to the properties. ```ts import { TypeScriptGenerator } from '@asyncapi/modelina'; @@ -198,7 +199,7 @@ const generator = new TypeScriptGenerator({ class: { property({ content }) { const description = '// Hello world!' - return `${description}\n${content}`; + return `${content}\n${description}`; } } } @@ -304,7 +305,7 @@ self({ dependencyManager, content }) { Some languages has specific helper functions, and some very basic interfaces, such as for Java. -In TypeScript because you can have different import syntaxes based on the module system such as [CJS](../examples/typescript-use-cjs/) or [ESM](../examples/typescript-use-esm/), therefore it provies a specific function `addTypeScriptDependency` that takes care of that logic, and you just have to remember `addTypeScriptDependency('ImportanWhat', 'FromWhere')`. +In TypeScript because you can have different import syntaxes based on the module system such as [CJS](../examples/typescript-use-cjs/) or [ESM](../examples/typescript-use-esm/), therefore it provides a specific function `addTypeScriptDependency` that takes care of that logic, and you just have to remember `addTypeScriptDependency('Import what', 'From where')`. ### Overriding the default preset @@ -416,6 +417,14 @@ This preset is a generator for the meta model `ConstrainedObjectModel` and [can |---|---|---| | `field` | A method to extend rendered given field. | `field` object as a [`ConstrainedObjectPropertyModel`](./internal-model.md#the-constrained-meta-model) instance. | +#### **Enum** + +This preset is a generator for the meta model `ConstrainedEnumModel` and [can be accessed through the `model` argument](#presets-shape). + +| Method | Description | Additional arguments | +|---|---|---| +| `item` | A method to extend rendering the enum items. | `item` object as a [`ConstrainedEnumValueModel`](./internal-model.md#the-constrained-meta-model) instance. `index` as `number`, the current enum item being rendered. | + ### C# #### **Class** diff --git a/docs/usage.md b/docs/usage.md index 61ac2f3a0f..e37dd4a4c8 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -16,6 +16,7 @@ For more specific integration options, please check out the [integration documen * [Limitations and Compatibility](#limitations-and-compatibility) + [Polymorphism](#polymorphism) - [Generate models from JSON Schema documents](#generate-models-from-json-schema-documents) +- [Generate models from Avro Schema documents](#generate-models-from-avro-schema-documents) - [Generate models from Swagger 2.0 documents](#generate-models-from-swagger-20-documents) * [Limitations and Compatibility](#limitations-and-compatibility-1) + [Polymorphism](#polymorphism-1) @@ -64,7 +65,7 @@ generator.render(model, inputModel, { ...options }); The output format is designed for you to use the generated models in further contexts. It might be part of a larger code generation such as AsyncAPI templates. This means that you can glue multiple models together into one large file, or split it out as you see fit. -All [generate functions](./generators.md) return an array of `OutputModel`s, which contains the following properties. +All `generate` functions return an array of `OutputModel`s, which contains the following properties. | Property | Type | Description | |---|---|---| @@ -107,6 +108,16 @@ There are three ways to generate models for a JSON Schema document. 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](./inputs/JSON_Schema.md). +## Generate models from Avro Schema documents + +See the below example to get started with Avro Schema for generating models. + +- [Generate from an Avro Schema JS Object](../examples/avro-schema-from-object) + +The Avro input processor expects the `name` and `type` property, as per [Avro Schema specs](https://avro.apache.org/docs/1.11.1/specification/#schema-declaration), in the input object in order to proceed successfully. + +> Note: Currently, we do not have a support for `map`, `fixed` and `byte` data type. It would be introduced soon. + ## Generate models from Swagger 2.0 documents There are one way to generate models from a Swagger 2.0 document. @@ -132,6 +143,7 @@ There are one way to generate models from an OpenAPI document - [Generate from OpenAPI 3.0 JS object](../examples/openapi-from-object) - [Generate from OpenAPI 3.1 JS object](../examples/openapi-v3_1-from-object) +- [Generate from OpenAPI components](../examples/openapi-include-components) The OpenAPI input processor expects that the property `openapi` is defined in order to know it should be processed. diff --git a/examples/README.md b/examples/README.md index 332852ece6..750a0c08a1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -43,10 +43,16 @@ These examples show a specific input and how they can be used: - [asyncapi-raml-schema](./asyncapi-raml-schema) - A basic example of how to use Modelina with an AsyncAPI document using RAML 1.0 data types as payload format. - [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. - [asyncapi-from-v1-parser](./asyncapi-from-v1-parser) - A basic example where an AsyncAPI JS object from the old v1 [parser-js](https://github.com/asyncapi/parser-js) is used to generate models. +- [avro-schema-from-object](./avro-schema-from-object) - A basic example where an Avro Schema JS Object is used to generate models. - [json-schema-draft7-from-object](./json-schema-draft7-from-object) - A basic example where a JSON Schema draft 7 JS object is used to generate models. - [json-schema-draft6-from-object](./json-schema-draft6-from-object) - A basic example where a JSON Schema draft 6 JS object is used to generate models. - [json-schema-draft4-from-object](./json-schema-draft4-from-object) - A basic example where a JSON Schema draft 4 JS object is used to generate models. +- [json-schema-single-enum-as-const](./json-schema-single-enum-as-const) - An advanced example that shows how to change how `enum` are interpreted when containing a single value. +- [json-schema-additional-properties-representation](./json-schema-additional-properties-representation) - An advanced example that shows how to change the property name for additional properties - [swagger2.0-from-object](./swagger2.0-from-object) - A basic example where a Swagger 2.0 JS object is used to generate models. +- [openapi-from-object](./openapi-from-object) - A basic example where an OpenAPI v3.0 JS object is used to generate models. +- [openapi-include-components](./openapi-include-components) - A basic example where an OpenAPI document without paths is used to generate models by iterating the components. +- [openapi-v3_1-from-object](./openapi-v3_1-from-object) - A basic example where an OpenAPI v3.1 JS object is used to generate models. - [meta-model](./meta-model) - A basic example how to provide a meta model for the generator ## General examples diff --git a/examples/avro-schema-from-object/README.md b/examples/avro-schema-from-object/README.md new file mode 100644 index 0000000000..5d9185a34c --- /dev/null +++ b/examples/avro-schema-from-object/README.md @@ -0,0 +1,17 @@ +# Avro Schema Input + +A basic example of how to use Modelina with an Avro Schema JS object to generate models. + +## 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/avro-schema-from-object/__snapshots__/index.spec.ts.snap b/examples/avro-schema-from-object/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..9a10481a44 --- /dev/null +++ b/examples/avro-schema-from-object/__snapshots__/index.spec.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render model using Avro Schema and should log expected output to console 1`] = ` +Array [ + "class Person { + private _reservedName: string; + + constructor(input: { + reservedName: string, + }) { + this._reservedName = input.reservedName; + } + + get reservedName(): string { return this._reservedName; } + set reservedName(reservedName: string) { this._reservedName = reservedName; } +}", +] +`; diff --git a/examples/avro-schema-from-object/index.spec.ts b/examples/avro-schema-from-object/index.spec.ts new file mode 100644 index 0000000000..514eda6705 --- /dev/null +++ b/examples/avro-schema-from-object/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 model using Avro Schema', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/avro-schema-from-object/index.ts b/examples/avro-schema-from-object/index.ts new file mode 100644 index 0000000000..2a07a0b10f --- /dev/null +++ b/examples/avro-schema-from-object/index.ts @@ -0,0 +1,27 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator(); +const AvroSchemaDoc = { + name: 'Person', + namespace: 'com.company', + type: 'record', + fields: [ + { + name: 'name', + type: 'string', + example: 'Donkey', + minLength: 0, + maxLenght: 20 + } + ] +}; + +export async function generate(): Promise { + const models = await generator.generate(AvroSchemaDoc); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); +} diff --git a/examples/avro-schema-from-object/package-lock.json b/examples/avro-schema-from-object/package-lock.json new file mode 100644 index 0000000000..d7ba6c8425 --- /dev/null +++ b/examples/avro-schema-from-object/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "avro-to-models", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/avro-schema-from-object/package.json b/examples/avro-schema-from-object/package.json new file mode 100644 index 0000000000..56f1490f97 --- /dev/null +++ b/examples/avro-schema-from-object/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "avro-schema-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" + } +} diff --git a/examples/csharp-generate-handle-nullable/__snapshots__/index.spec.ts.snap b/examples/csharp-generate-handle-nullable/__snapshots__/index.spec.ts.snap index 8c8bc869bc..cd9838c69b 100644 --- a/examples/csharp-generate-handle-nullable/__snapshots__/index.spec.ts.snap +++ b/examples/csharp-generate-handle-nullable/__snapshots__/index.spec.ts.snap @@ -7,6 +7,10 @@ Array [ public string? Email { get; set; } public string Name { get; set; } = null!; public int Age { get; set; } + public System.DateTime ApplicationDate { get; set; } + public System.DateTimeOffset Timestamp { get; set; } + public System.DateTime? ApplicationDate2 { get; set; } + public System.DateTimeOffset? Timestamp2 { get; set; } public Dictionary[]? NullableFoos { get; set; } public Dictionary[] MandatoryFoos { get; set; } = null!; }", diff --git a/examples/csharp-generate-handle-nullable/index.ts b/examples/csharp-generate-handle-nullable/index.ts index ecaa345125..d98f2e656d 100644 --- a/examples/csharp-generate-handle-nullable/index.ts +++ b/examples/csharp-generate-handle-nullable/index.ts @@ -8,7 +8,7 @@ const jsonSchemaDraft7 = { $schema: 'http://json-schema.org/draft-07/schema#', type: 'object', additionalProperties: false, - required: ['name', 'age', 'mandatoryFoos'], + required: ['name', 'age', 'mandatoryFoos', 'applicationDate', 'timestamp'], properties: { email: { type: 'string', @@ -20,6 +20,22 @@ const jsonSchemaDraft7 = { age: { type: 'integer' }, + applicationDate: { + type: 'string', + format: 'date' + }, + timestamp: { + type: 'string', + format: 'date-time' + }, + applicationDate2: { + type: 'string', + format: 'date' + }, + timestamp2: { + type: 'string', + format: 'date-time' + }, nullableFoos: { type: 'array', items: { diff --git a/examples/csharp-generate-json-serializer/__snapshots__/index.spec.ts.snap b/examples/csharp-generate-json-serializer/__snapshots__/index.spec.ts.snap index 6c6e5716ea..ff01c4943d 100644 --- a/examples/csharp-generate-json-serializer/__snapshots__/index.spec.ts.snap +++ b/examples/csharp-generate-json-serializer/__snapshots__/index.spec.ts.snap @@ -12,6 +12,22 @@ public partial class Root get { return email; } set { this.email = value; } } + + + public string Serialize() + { + return this.Serialize(null); + } + public string Serialize(JsonSerializerOptions options = null) + { + return JsonSerializer.Serialize(this, options); + } + public static Root Deserialize(string json) + { + var deserializeOptions = new JsonSerializerOptions(); + deserializeOptions.Converters.Add(new RootConverter()); + return JsonSerializer.Deserialize(json, deserializeOptions); + } } internal class RootConverter : JsonConverter diff --git a/examples/csharp-generate-newtonsoft-serializer/__snapshots__/index.spec.ts.snap b/examples/csharp-generate-newtonsoft-serializer/__snapshots__/index.spec.ts.snap index 2778a9dd24..027d07fc54 100644 --- a/examples/csharp-generate-newtonsoft-serializer/__snapshots__/index.spec.ts.snap +++ b/examples/csharp-generate-newtonsoft-serializer/__snapshots__/index.spec.ts.snap @@ -19,6 +19,15 @@ public partial class Root get { return name; } set { this.name = value; } } + + public string Serialize() + { + return JsonConvert.SerializeObject(this); + } + public static Root Deserialize(string json) + { + return JsonConvert.DeserializeObject(json); + } } public class RootConverter : JsonConverter @@ -31,7 +40,6 @@ public class RootConverter : JsonConverter if(jo[\\"email\\"] is null){ throw new JsonSerializationException(\\"Required property 'email' is missing\\"); } - value.Email = jo[\\"email\\"].ToObject(serializer); if(jo[\\"name\\"] != null) { diff --git a/examples/csharp-overwrite-enum-naming/__snapshots__/index.spec.ts.snap b/examples/csharp-overwrite-enum-naming/__snapshots__/index.spec.ts.snap index cb1994815f..179e9f56d9 100644 --- a/examples/csharp-overwrite-enum-naming/__snapshots__/index.spec.ts.snap +++ b/examples/csharp-overwrite-enum-naming/__snapshots__/index.spec.ts.snap @@ -24,7 +24,7 @@ public static class OrderStatusExtensions return null; } - public static OrderStatus? ToOrderStatus(int? value) + public static OrderStatus? ToOrderStatus(dynamic? value) { switch (value) { diff --git a/examples/file-uri-input/__snapshots__/index.spec.ts.snap b/examples/file-uri-input/__snapshots__/index.spec.ts.snap index a563fe8ae8..5f4a652298 100644 --- a/examples/file-uri-input/__snapshots__/index.spec.ts.snap +++ b/examples/file-uri-input/__snapshots__/index.spec.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Should be able to generate models using file URI as input to output folder and should log expected output to console 1`] = ` +exports[`Should be able to render models using file URI as input with file generator and should log expected output to console 1`] = ` Array [ "class AnonymousSchema_1 { private _displayName?: string; @@ -29,7 +29,7 @@ Array [ ] `; -exports[`Should be able to render models using file URI as input and should log expected output to console 1`] = ` +exports[`Should be able to render models using file URI as input with regular generator and should log expected output to console 1`] = ` Array [ "class AnonymousSchema_1 { private _displayName?: string; diff --git a/examples/file-uri-input/index.spec.ts b/examples/file-uri-input/index.spec.ts index 428b0cf504..1190c6ee0e 100644 --- a/examples/file-uri-input/index.spec.ts +++ b/examples/file-uri-input/index.spec.ts @@ -4,23 +4,25 @@ const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { import { generate, generateToFiles } from './index'; describe('Should be able to render models using file URI as input', () => { - afterAll(() => { - jest.restoreAllMocks(); + describe('with regular generator', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); }); - test('and should log expected output to console', async () => { - await generate(); - expect(spy.mock.calls.length).toEqual(1); - expect(spy.mock.calls[0]).toMatchSnapshot(); - }); -}); -describe('Should be able to generate models using file URI as input to output folder', () => { - afterAll(() => { - jest.restoreAllMocks(); - }); - test('and should log expected output to console', async () => { - await generateToFiles(); - expect(spy.mock.calls.length).toEqual(1); - expect(spy.mock.calls[0]).toMatchSnapshot(); + describe('with file generator', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generateToFiles(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); }); }); diff --git a/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap b/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap index 902c74d45d..dc88369b31 100644 --- a/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-csharp-models/__snapshots__/index.spec.ts.snap @@ -5,7 +5,7 @@ Array [ "public partial class Root { private string? email; - private System.DateTime? today; + private System.DateTimeOffset? today; private System.TimeSpan? duration; private System.Guid? userId; @@ -15,7 +15,7 @@ Array [ set { this.email = value; } } - public System.DateTime? Today + public System.DateTimeOffset? Today { get { return today; } set { this.today = value; } diff --git a/examples/generate-go-asyncapi-comments/README.md b/examples/generate-go-asyncapi-comments/README.md new file mode 100644 index 0000000000..78bc37a44b --- /dev/null +++ b/examples/generate-go-asyncapi-comments/README.md @@ -0,0 +1,17 @@ +# Go Data Models from AsyncAPI + +A basic example of how to use Modelina and output a Go data model from AsyncAPI, including data tags and comments from description. + +## 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-asyncapi-comments/__snapshots__/index.spec.ts.snap b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..ed22309164 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/__snapshots__/index.spec.ts.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render Go Models and should log expected output to console 1`] = ` +Array [ + "// Payload for updating stock information +type StockUpdatePayload struct { + ProductId string \`json:\\"productId\\" binding:\\"required\\"\` + // The updated quantity of the product + Quantity int \`json:\\"quantity,omitempty\\"\` + // Warehouse location of the product + Location string \`json:\\"location,omitempty\\"\` +}", +] +`; + +exports[`Should be able to render Go Models and should log expected output to console 2`] = ` +Array [ + "// Payload for low stock alerts +type LowStockPayload struct { + ProductId string \`json:\\"productId\\" binding:\\"required\\"\` + // The stock level threshold + Threshold int \`json:\\"threshold\\" binding:\\"required\\"\` + // The current stock level + CurrentStock int \`json:\\"currentStock,omitempty\\"\` +}", +] +`; diff --git a/examples/generate-go-asyncapi-comments/index.spec.ts b/examples/generate-go-asyncapi-comments/index.spec.ts new file mode 100644 index 0000000000..41d9908c10 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.spec.ts @@ -0,0 +1,16 @@ +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[0]).toMatchSnapshot(); + expect(spy.mock.calls[1]).toMatchSnapshot(); + }); +}); diff --git a/examples/generate-go-asyncapi-comments/index.ts b/examples/generate-go-asyncapi-comments/index.ts new file mode 100644 index 0000000000..d241cf0a36 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/index.ts @@ -0,0 +1,116 @@ +import { + GoGenerator, + GO_DESCRIPTION_PRESET, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../src'; + +const options: GoCommonPresetOptions = { addJsonTag: true }; +const generator = new GoGenerator({ + presets: [GO_DESCRIPTION_PRESET, { preset: GO_COMMON_PRESET, options }] +}); + +const asyncAPIDocument = { + asyncapi: '3.0.0', + info: { + title: 'inventoryService', + version: '2.1.0' + }, + channels: { + inventory: { + address: '/inventory', + messages: { + updateStock: { + summary: 'Update stock levels', + payload: { + title: 'stockUpdatePayload', + type: 'object', + description: 'Payload for updating stock information', + required: ['productId'], + additionalProperties: false, + properties: { + productId: { + type: 'string' + }, + quantity: { + type: 'integer', + description: 'The updated quantity of the product' + }, + location: { + type: 'string', + description: 'Warehouse location of the product' + } + } + } + } + } + }, + alerts: { + address: '/alerts', + messages: { + lowStockAlert: { + summary: 'Low stock level alert', + payload: { + title: 'lowStockPayload', + type: 'object', + description: 'Payload for low stock alerts', + required: ['productId', 'threshold'], + additionalProperties: false, + properties: { + productId: { + type: 'string' + }, + threshold: { + type: 'integer', + description: 'The stock level threshold' + }, + currentStock: { + type: 'integer', + description: 'The current stock level' + } + } + } + } + } + } + }, + operations: { + updateInventory: { + title: 'Update Inventory Operation', + summary: 'Operation to update inventory stock levels', + channel: { + $ref: '#/channels/inventory' + }, + action: 'send', + messages: [ + { + $ref: '#/channels/inventory/messages/updateStock' + } + ] + }, + notifyLowStock: { + title: 'Notify Low Stock Operation', + summary: 'Operation to notify when stock is low', + channel: { + $ref: '#/channels/alerts' + }, + action: 'receive', + messages: [ + { + $ref: '#/channels/alerts/messages/lowStockAlert' + } + ] + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(asyncAPIDocument); + for (const model of models) { + console.log(model.result); + } +} + +if (require.main === module) { + generate(); +} diff --git a/examples/generate-go-asyncapi-comments/package-lock.json b/examples/generate-go-asyncapi-comments/package-lock.json new file mode 100644 index 0000000000..b1b6acf134 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "generate-go-asyncapi-comments", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/generate-go-asyncapi-comments/package.json b/examples/generate-go-asyncapi-comments/package.json new file mode 100644 index 0000000000..928aa251a0 --- /dev/null +++ b/examples/generate-go-asyncapi-comments/package.json @@ -0,0 +1,12 @@ +{ + "config": { + "example_name": "generate-go-asyncapi-comments" + }, + "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/examples/generate-go-enums/__snapshots__/index.spec.ts.snap b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap index 63a132b10e..88e4541c0f 100644 --- a/examples/generate-go-enums/__snapshots__/index.spec.ts.snap +++ b/examples/generate-go-enums/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ exports[`Should be able to render Go Enums and should log expected output to console 1`] = ` Array [ - "// Root represents a Root model. -type Root struct { + "type Root struct { Cities *Cities Options *Options }", @@ -12,8 +11,7 @@ type Root struct { exports[`Should be able to render Go Enums and should log expected output to console 2`] = ` Array [ - "// Cities represents an enum of Cities. -type Cities uint + "type Cities uint const ( CitiesLondon Cities = iota @@ -41,8 +39,7 @@ var ValuesToCities = map[any]Cities{ exports[`Should be able to render Go Enums and should log expected output to console 3`] = ` Array [ - "// Options represents an enum of Options. -type Options uint + "type Options uint const ( OptionsNumber_123 Options = iota diff --git a/examples/generate-go-models/__snapshots__/index.spec.ts.snap b/examples/generate-go-models/__snapshots__/index.spec.ts.snap index 36a43dc738..f3029176fc 100644 --- a/examples/generate-go-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-go-models/__snapshots__/index.spec.ts.snap @@ -2,8 +2,7 @@ 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 { + "type Root struct { Email string }", ] diff --git a/examples/generate-python-complete-models/__snapshots__/index.spec.ts.snap b/examples/generate-python-complete-models/__snapshots__/index.spec.ts.snap index 016d58009d..eb83273609 100644 --- a/examples/generate-python-complete-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-python-complete-models/__snapshots__/index.spec.ts.snap @@ -2,112 +2,116 @@ exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: nested-model 1`] = ` Array [ - " + "from __future__ import annotations +from typing import Any, Dict class ObjProperty: - def __init__(self, input): - if hasattr(input, 'number'): - self._number = input.number - if hasattr(input, 'additionalProperties'): - self._additionalProperties = input.additionalProperties + def __init__(self, input: Dict): + if 'number' in input: + self._number: float = input['number'] + if 'additional_properties' in input: + self._additional_properties: dict[str, Any] = input['additional_properties'] @property - def number(self): - return self._number + def number(self) -> float: + return self._number @number.setter - def number(self, number): - self._number = number + def number(self, number: float): + self._number = number @property - def additionalProperties(self): - return self._additionalProperties - @additionalProperties.setter - def additionalProperties(self, additionalProperties): - self._additionalProperties = additionalProperties + def additional_properties(self) -> dict[str, Any]: + return self._additional_properties + @additional_properties.setter + def additional_properties(self, additional_properties: dict[str, Any]): + self._additional_properties = additional_properties ", ] `; exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: nested-model 2`] = ` Array [ - " + "from __future__ import annotations +from typing import Any, Dict class ObjProperty: - def __init__(self, input): - if hasattr(input, 'number'): - self._number = input.number - if hasattr(input, 'additionalProperties'): - self._additionalProperties = input.additionalProperties + def __init__(self, input: Dict): + if 'number' in input: + self._number: float = input['number'] + if 'additional_properties' in input: + self._additional_properties: dict[str, Any] = input['additional_properties'] @property - def number(self): - return self._number + def number(self) -> float: + return self._number @number.setter - def number(self, number): - self._number = number + def number(self, number: float): + self._number = number @property - def additionalProperties(self): - return self._additionalProperties - @additionalProperties.setter - def additionalProperties(self, additionalProperties): - self._additionalProperties = additionalProperties + def additional_properties(self) -> dict[str, Any]: + return self._additional_properties + @additional_properties.setter + def additional_properties(self, additional_properties: dict[str, Any]): + self._additional_properties = additional_properties ", ] `; exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: root-model-explicit-import 1`] = ` Array [ - "from ObjProperty import ObjProperty - + "from __future__ import annotations +from typing import Any, Dict +from . import ObjProperty class Root: - def __init__(self, input): - if hasattr(input, 'email'): - self._email = input.email - if hasattr(input, 'objProperty'): - self._objProperty = input.objProperty + def __init__(self, input: Dict): + if 'email' in input: + self._email: str = input['email'] + if 'obj_property' in input: + self._obj_property: ObjProperty.ObjProperty = ObjProperty.ObjProperty(input['obj_property']) @property - def email(self): - return self._email + def email(self) -> str: + return self._email @email.setter - def email(self, email): - self._email = email + def email(self, email: str): + self._email = email @property - def objProperty(self): - return self._objProperty - @objProperty.setter - def objProperty(self, objProperty): - self._objProperty = objProperty + def obj_property(self) -> ObjProperty.ObjProperty: + return self._obj_property + @obj_property.setter + def obj_property(self, obj_property: ObjProperty.ObjProperty): + self._obj_property = obj_property ", ] `; exports[`Should be able to render python models and should generate \`implicit\` or \`explicit\` imports for models implementing referenced types: root-model-implicit-import 1`] = ` Array [ - "from ObjProperty import ObjProperty - + "from __future__ import annotations +from typing import Any, Dict +from . import ObjProperty class Root: - def __init__(self, input): - if hasattr(input, 'email'): - self._email = input.email - if hasattr(input, 'objProperty'): - self._objProperty = input.objProperty + def __init__(self, input: Dict): + if 'email' in input: + self._email: str = input['email'] + if 'obj_property' in input: + self._obj_property: ObjProperty.ObjProperty = ObjProperty.ObjProperty(input['obj_property']) @property - def email(self): - return self._email + def email(self) -> str: + return self._email @email.setter - def email(self, email): - self._email = email + def email(self, email: str): + self._email = email @property - def objProperty(self): - return self._objProperty - @objProperty.setter - def objProperty(self, objProperty): - self._objProperty = objProperty + def obj_property(self) -> ObjProperty.ObjProperty: + return self._obj_property + @obj_property.setter + def obj_property(self, obj_property: ObjProperty.ObjProperty): + self._obj_property = obj_property ", ] `; diff --git a/examples/generate-python-models/__snapshots__/index.spec.ts.snap b/examples/generate-python-models/__snapshots__/index.spec.ts.snap index cedc00dda2..bf629a654a 100644 --- a/examples/generate-python-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-python-models/__snapshots__/index.spec.ts.snap @@ -3,16 +3,16 @@ exports[`Should be able to render python models and should log expected output to console 1`] = ` Array [ "class Root: - def __init__(self, input): - if hasattr(input, 'email'): - self._email = input.email + def __init__(self, input: Dict): + if 'email' in input: + self._email: str = input['email'] @property - def email(self): - return self._email + def email(self) -> str: + return self._email @email.setter - def email(self, email): - self._email = email + def email(self, email: str): + self._email = email ", ] `; diff --git a/examples/generate-python-pydantic-models/__snapshots__/index.spec.ts.snap b/examples/generate-python-pydantic-models/__snapshots__/index.spec.ts.snap index 2a856c63b3..4633b73701 100644 --- a/examples/generate-python-pydantic-models/__snapshots__/index.spec.ts.snap +++ b/examples/generate-python-pydantic-models/__snapshots__/index.spec.ts.snap @@ -3,11 +3,11 @@ exports[`Should be able to render python models and should log expected output to console: class-model 1`] = ` Array [ "class Root(BaseModel): - optionalField: Optional[str] = Field(description='''this field is optional''', default=None) - requiredField: str = Field(description='''this field is required''') - noDescription: Optional[str] = Field(default=None) - options: Optional[Options] = Field(default=None) - contentType: Optional[str] = Field(default=None, alias='''content-type''') + optional_field: Optional[str] = Field(description='''this field is optional''', default=None, default=None) + required_field: str = Field(description='''this field is required''') + no_description: Optional[str] = Field(default=None, default=None) + options: Optional[Options.Options] = Field(default=None, default=None) + content_type: Optional[str] = Field(default=None, default=None) ", ] `; diff --git a/examples/go-json-tags/README.md b/examples/go-json-tags/README.md new file mode 100644 index 0000000000..dfbde05d33 --- /dev/null +++ b/examples/go-json-tags/README.md @@ -0,0 +1,17 @@ +# Go Struct Tags In Models + +`GO_COMMON_PRESET` to render JSON `struct-tags` in go `structs` along with adding custom `Marshaler` functions for enum. + +## 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/go-json-tags/__snapshots__/index.spec.ts.snap b/examples/go-json-tags/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..de241b60c2 --- /dev/null +++ b/examples/go-json-tags/__snapshots__/index.spec.ts.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render json-tags in struct and should log expected output to console 1`] = ` +Array [ + "type Root struct { + Cities *Cities \`json:\\"cities,omitempty\\"\` + Options *Options \`json:\\"options,omitempty\\"\` +}", +] +`; + +exports[`Should be able to render json-tags in struct and should log expected output to console 2`] = ` +Array [ + "type Cities uint + +const ( + CitiesLondon Cities = iota + CitiesRome + CitiesBrussels +) + +// Value returns the value of the enum. +func (op Cities) Value() any { + if op >= Cities(len(CitiesValues)) { + return nil + } + return CitiesValues[op] +} + +var CitiesValues = []any{\\"London\\",\\"Rome\\",\\"Brussels\\"} +var ValuesToCities = map[any]Cities{ + CitiesValues[CitiesLondon]: CitiesLondon, + CitiesValues[CitiesRome]: CitiesRome, + CitiesValues[CitiesBrussels]: CitiesBrussels, +} + + +func (op *Cities) UnmarshalJSON(raw []byte) error { + var v any + if err := json.Unmarshal(raw, &v); err != nil { + return err + } + *op = ValuesToCities[v] + return nil +} + +func (op Cities) MarshalJSON() ([]byte, error) { + return json.Marshal(op.Value()) +}", +] +`; + +exports[`Should be able to render json-tags in struct and should log expected output to console 3`] = ` +Array [ + "type Options uint + +const ( + OptionsNumber_123 Options = iota + OptionsNumber_213 + OptionsTrue + OptionsRun +) + +// Value returns the value of the enum. +func (op Options) Value() any { + if op >= Options(len(OptionsValues)) { + return nil + } + return OptionsValues[op] +} + +var OptionsValues = []any{123,213,true,\\"Run\\"} +var ValuesToOptions = map[any]Options{ + OptionsValues[OptionsNumber_123]: OptionsNumber_123, + OptionsValues[OptionsNumber_213]: OptionsNumber_213, + OptionsValues[OptionsTrue]: OptionsTrue, + OptionsValues[OptionsRun]: OptionsRun, +} + + +func (op *Options) UnmarshalJSON(raw []byte) error { + var v any + if err := json.Unmarshal(raw, &v); err != nil { + return err + } + *op = ValuesToOptions[v] + return nil +} + +func (op Options) MarshalJSON() ([]byte, error) { + return json.Marshal(op.Value()) +}", +] +`; diff --git a/examples/go-json-tags/index.spec.ts b/examples/go-json-tags/index.spec.ts new file mode 100644 index 0000000000..a9dd1db4e8 --- /dev/null +++ b/examples/go-json-tags/index.spec.ts @@ -0,0 +1,17 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { + return; +}); +import { generate } from './index'; + +describe('Should be able to render json-tags in struct', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(3); + expect(spy.mock.calls[0]).toMatchSnapshot(); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + }); +}); diff --git a/examples/go-json-tags/index.ts b/examples/go-json-tags/index.ts new file mode 100644 index 0000000000..512318ef87 --- /dev/null +++ b/examples/go-json-tags/index.ts @@ -0,0 +1,37 @@ +import { + GoGenerator, + GO_COMMON_PRESET, + GoCommonPresetOptions +} from '../../src'; + +const options: GoCommonPresetOptions = { addJsonTag: true }; +const generator = new GoGenerator({ + presets: [{ preset: GO_COMMON_PRESET, options }] +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + cities: { + $id: 'cities', + type: 'string', + enum: ['London', 'Rome', 'Brussels'] + }, + options: { + $id: 'options', + type: ['integer', 'boolean', 'string'], + enum: [123, 213, true, 'Run'] + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); +} diff --git a/examples/go-json-tags/package-lock.json b/examples/go-json-tags/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/go-json-tags/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/go-json-tags/package.json b/examples/go-json-tags/package.json new file mode 100644 index 0000000000..30756a14c7 --- /dev/null +++ b/examples/go-json-tags/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "go-json-tags" }, + "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/go-union-type/README.md b/examples/go-union-type/README.md new file mode 100644 index 0000000000..131cf33897 --- /dev/null +++ b/examples/go-union-type/README.md @@ -0,0 +1,26 @@ +# Go Union Types + +Modelina now supports union types for `Go`. Since `Go` does not have native union types support modelina uses `struct embeddings` to mock union types. Modelina has custom names for models that are not directly embedded in structs. Users can update the default names by passing custom values. + + +```ts +const generator = new GoGenerator({ + unionAnyModelName: 'ModelinaAnyType', + unionArrModelName: 'ModelinaArrType', + unionDictModelName: 'ModelinaDictType' +}); +``` + +## 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/go-union-type/__snapshots__/index.spec.ts.snap b/examples/go-union-type/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..a1088359ed --- /dev/null +++ b/examples/go-union-type/__snapshots__/index.spec.ts.snap @@ -0,0 +1,59 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render union types and should log expected output to console 1`] = ` +Array [ + "type AdditionalProperty struct { + AdditionalPropertyOneOf_0 + AdditionalPropertyOneOf_1 + string + float64 + ModelinaArrType []string + ModelinaArrType []Union + AdditionalPropertyOneOf_6 +}", +] +`; + +exports[`Should be able to render union types and should log expected output to console 2`] = ` +Array [ + "type Union struct { + string + float64 + ModelinaAnyType interface{} +}", +] +`; + +exports[`Should be able to render union types and should log expected output to console 3`] = ` +Array [ + "type AdditionalPropertyOneOf_6 struct { + string + float64 + bool +}", +] +`; + +exports[`Should be able to render union types and should log expected output to console 4`] = ` +Array [ + "", +] +`; + +exports[`Should be able to render union types and should log expected output to console 5`] = ` +Array [ + "type AdditionalPropertyOneOf_0 struct { + Ref string + AdditionalProperties map[string]interface{} +}", +] +`; + +exports[`Should be able to render union types and should log expected output to console 6`] = ` +Array [ + "type AdditionalPropertyOneOf_1 struct { + Id string + AdditionalProperties map[string]interface{} +}", +] +`; diff --git a/examples/go-union-type/index.spec.ts b/examples/go-union-type/index.spec.ts new file mode 100644 index 0000000000..550819e170 --- /dev/null +++ b/examples/go-union-type/index.spec.ts @@ -0,0 +1,20 @@ +const spy = jest.spyOn(global.console, 'log').mockImplementation(() => { + return; +}); +import { generate } from './index'; + +describe('Should be able to render union types', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(6); + expect(spy.mock.calls[0]).toMatchSnapshot(); + expect(spy.mock.calls[1]).toMatchSnapshot(); + expect(spy.mock.calls[2]).toMatchSnapshot(); + expect(spy.mock.calls[3]).toMatchSnapshot(); + expect(spy.mock.calls[4]).toMatchSnapshot(); + expect(spy.mock.calls[5]).toMatchSnapshot(); + }); +}); diff --git a/examples/go-union-type/index.ts b/examples/go-union-type/index.ts new file mode 100644 index 0000000000..06a6f71b33 --- /dev/null +++ b/examples/go-union-type/index.ts @@ -0,0 +1,33 @@ +import { GoGenerator } from '../../src'; + +const generator = new GoGenerator({ + unionAnyModelName: 'ModelinaAnyType', + unionArrModelName: 'ModelinaArrType', + unionDictModelName: 'ModelinaDictType' +}); + +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: { + oneOf: [ + { type: 'object', properties: { ref: { type: 'string' } } }, + { type: 'object', properties: { Id: { type: 'string' } } }, + { type: 'string' }, + { type: 'number' }, + { type: 'array', items: { type: 'string' } }, + { type: 'array', items: [{ type: 'string' }, { type: 'number' }] }, + { oneOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }] } + ] + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); +} diff --git a/examples/go-union-type/package-lock.json b/examples/go-union-type/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/go-union-type/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/go-union-type/package.json b/examples/go-union-type/package.json new file mode 100644 index 0000000000..7421097f82 --- /dev/null +++ b/examples/go-union-type/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "go-union-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" + } +} diff --git a/examples/integrate-with-maven/maven-project/scripts/modelina/package-lock.json b/examples/integrate-with-maven/maven-project/scripts/modelina/package-lock.json index 506cfc5437..9264bef880 100644 --- a/examples/integrate-with-maven/maven-project/scripts/modelina/package-lock.json +++ b/examples/integrate-with-maven/maven-project/scripts/modelina/package-lock.json @@ -14,15 +14,13 @@ }, "../../../../..": { "name": "@asyncapi/modelina", - "version": "2.0.1", + "version": "3.12.0", "license": "Apache-2.0", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.9", - "@apidevtools/swagger-parser": "^10.0.3", - "@asyncapi/avro-schema-parser": "^3.0.2", - "@asyncapi/openapi-schema-parser": "^3.0.5", - "@asyncapi/parser": "^2.1.0", - "@asyncapi/raml-dt-schema-parser": "^4.0.4", + "@apidevtools/json-schema-ref-parser": "^11.1.0", + "@apidevtools/swagger-parser": "^10.1.0", + "@asyncapi/multi-parser": "^2.1.1", + "@asyncapi/parser": "^3.1.0", "@swc/core": "^1.3.5", "@swc/jest": "^0.2.23", "@types/node": "^20.3.3", @@ -46,6 +44,7 @@ "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-security": "^1.7.1", "eslint-plugin-sonarjs": "^0.19.0", + "eslint-plugin-unused-imports": "^3.0.0", "jest": "^27.2.5", "markdown-toc": "^1.2.0", "ts-jest": "^27.0.5", diff --git a/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap b/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap index 1d3f1d6fc0..0a7c33e74e 100644 --- a/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap +++ b/examples/java-generate-jackson-annotation/__snapshots__/index.spec.ts.snap @@ -9,6 +9,7 @@ Array [ @JsonProperty(\\"max_number_prop\\") @JsonInclude(JsonInclude.Include.NON_NULL) private Double maxNumberProp; + @JsonAnySetter @JsonInclude(JsonInclude.Include.NON_NULL) private Map additionalProperties; @@ -18,6 +19,7 @@ Array [ public Double getMaxNumberProp() { return this.maxNumberProp; } public void setMaxNumberProp(Double maxNumberProp) { this.maxNumberProp = maxNumberProp; } + @JsonAnyGetter public Map getAdditionalProperties() { return this.additionalProperties; } public void setAdditionalProperties(Map additionalProperties) { this.additionalProperties = additionalProperties; } }", diff --git a/examples/json-schema-additional-properties-representation/README.md b/examples/json-schema-additional-properties-representation/README.md new file mode 100644 index 0000000000..89d2ce5803 --- /dev/null +++ b/examples/json-schema-additional-properties-representation/README.md @@ -0,0 +1,17 @@ +# JSON Schema change property name for additional properties + +This example shows how to use the `propertyNameForAdditionalProperties` option on the JSON Schema input processor to change the property name that is used for representing additional properties. + +## 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/json-schema-additional-properties-representation/__snapshots__/index.spec.ts.snap b/examples/json-schema-additional-properties-representation/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..8226953cb1 --- /dev/null +++ b/examples/json-schema-additional-properties-representation/__snapshots__/index.spec.ts.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render object with different additional property and should log expected output to console 1`] = ` +Array [ + "class Root { + private _email?: string; + private _extensions?: Map; + + constructor(input: { + email?: string, + extensions?: Map, + }) { + this._email = input.email; + this._extensions = input.extensions; + } + + get email(): string | undefined { return this._email; } + set email(email: string | undefined) { this._email = email; } + + get extensions(): Map | undefined { return this._extensions; } + set extensions(extensions: Map | undefined) { this._extensions = extensions; } +}", +] +`; diff --git a/examples/json-schema-additional-properties-representation/index.spec.ts b/examples/json-schema-additional-properties-representation/index.spec.ts new file mode 100644 index 0000000000..5bac9c599c --- /dev/null +++ b/examples/json-schema-additional-properties-representation/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 object with different additional property', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/json-schema-additional-properties-representation/index.ts b/examples/json-schema-additional-properties-representation/index.ts new file mode 100644 index 0000000000..656de9c2a6 --- /dev/null +++ b/examples/json-schema-additional-properties-representation/index.ts @@ -0,0 +1,29 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator({ + processorOptions: { + jsonSchema: { + propertyNameForAdditionalProperties: 'extensions' + } + } +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: true, + properties: { + email: { + type: 'string' + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); +} diff --git a/examples/json-schema-additional-properties-representation/package-lock.json b/examples/json-schema-additional-properties-representation/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/json-schema-additional-properties-representation/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/json-schema-additional-properties-representation/package.json b/examples/json-schema-additional-properties-representation/package.json new file mode 100644 index 0000000000..409205d5da --- /dev/null +++ b/examples/json-schema-additional-properties-representation/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "json-schema-additional-properties-representation" }, + "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/json-schema-single-enum-as-const/README.md b/examples/json-schema-single-enum-as-const/README.md new file mode 100644 index 0000000000..e503451261 --- /dev/null +++ b/examples/json-schema-single-enum-as-const/README.md @@ -0,0 +1,19 @@ +# JSON Schema interpret single enum as constant + +This example shows how to use the `interpretSingleEnumAsConst` option on the JSON Schema input processor to instead of interpreting `{enum: ['single value']}` as an enum, it will instead only be generated as a constant value. + +This ONLY applies when it's a single value. + +## 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/json-schema-single-enum-as-const/__snapshots__/index.spec.ts.snap b/examples/json-schema-single-enum-as-const/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..eb69dbe1ec --- /dev/null +++ b/examples/json-schema-single-enum-as-const/__snapshots__/index.spec.ts.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to render enum with single value as const and should log expected output to console 1`] = ` +Array [ + "class Root { + private _email?: 'test' = 'test'; + + constructor(input: { + + }) { + + } + + get email(): 'test' | undefined { return this._email; } +}", +] +`; diff --git a/examples/json-schema-single-enum-as-const/index.spec.ts b/examples/json-schema-single-enum-as-const/index.spec.ts new file mode 100644 index 0000000000..505a321c64 --- /dev/null +++ b/examples/json-schema-single-enum-as-const/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 enum with single value as const', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/json-schema-single-enum-as-const/index.ts b/examples/json-schema-single-enum-as-const/index.ts new file mode 100644 index 0000000000..7b71cb324f --- /dev/null +++ b/examples/json-schema-single-enum-as-const/index.ts @@ -0,0 +1,30 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator({ + processorOptions: { + jsonSchema: { + interpretSingleEnumAsConst: true + } + } +}); +const jsonSchemaDraft7 = { + $schema: 'http://json-schema.org/draft-07/schema#', + type: 'object', + additionalProperties: false, + properties: { + email: { + type: 'string', + enum: ['test'] + } + } +}; + +export async function generate(): Promise { + const models = await generator.generate(jsonSchemaDraft7); + for (const model of models) { + console.log(model.result); + } +} +if (require.main === module) { + generate(); +} diff --git a/examples/json-schema-single-enum-as-const/package-lock.json b/examples/json-schema-single-enum-as-const/package-lock.json new file mode 100644 index 0000000000..56ab4e873b --- /dev/null +++ b/examples/json-schema-single-enum-as-const/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "typescript-interface", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/json-schema-single-enum-as-const/package.json b/examples/json-schema-single-enum-as-const/package.json new file mode 100644 index 0000000000..e89a0f989c --- /dev/null +++ b/examples/json-schema-single-enum-as-const/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "json-schema-single-enum-as-const" }, + "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/openapi-include-components/README.md b/examples/openapi-include-components/README.md new file mode 100644 index 0000000000..c2fde6c48b --- /dev/null +++ b/examples/openapi-include-components/README.md @@ -0,0 +1,17 @@ +# OpenAPI include components + +A basic example of how to use Modelina with an OpenAPI document that iterates the components section to determine models. + +## 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-include-components/__snapshots__/index.spec.ts.snap b/examples/openapi-include-components/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..6e0b07de01 --- /dev/null +++ b/examples/openapi-include-components/__snapshots__/index.spec.ts.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Should be able to process a OpenAPI document that has no paths and should log expected output to console 1`] = ` +Array [ + "class TestSchema { + 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-include-components/index.spec.ts b/examples/openapi-include-components/index.spec.ts new file mode 100644 index 0000000000..50a91746fd --- /dev/null +++ b/examples/openapi-include-components/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 OpenAPI document that has no paths', () => { + afterAll(() => { + jest.restoreAllMocks(); + }); + test('and should log expected output to console', async () => { + await generate(); + expect(spy.mock.calls.length).toEqual(1); + expect(spy.mock.calls[0]).toMatchSnapshot(); + }); +}); diff --git a/examples/openapi-include-components/index.ts b/examples/openapi-include-components/index.ts new file mode 100644 index 0000000000..7c94ed2bea --- /dev/null +++ b/examples/openapi-include-components/index.ts @@ -0,0 +1,39 @@ +import { TypeScriptGenerator } from '../../src'; + +const generator = new TypeScriptGenerator({ + processorOptions: { openapi: { includeComponentSchemas: true } } +}); +const swaggerDocument = { + openapi: '3.0.3', + info: { + version: '0.1', + title: 'Simple basic api' + }, + paths: {}, + components: { + schemas: { + TestSchema: { + $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); + } +} + +if (require.main === module) { + generate(); +} diff --git a/examples/openapi-include-components/package-lock.json b/examples/openapi-include-components/package-lock.json new file mode 100644 index 0000000000..4a70e6387e --- /dev/null +++ b/examples/openapi-include-components/package-lock.json @@ -0,0 +1,10 @@ +{ + "name": "openapi-include-components", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "hasInstallScript": true + } + } +} diff --git a/examples/openapi-include-components/package.json b/examples/openapi-include-components/package.json new file mode 100644 index 0000000000..3449a167dc --- /dev/null +++ b/examples/openapi-include-components/package.json @@ -0,0 +1,10 @@ +{ + "config" : { "example_name" : "openapi-include-components" }, + "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/python-generate-json-serializer-and-deserializer/__snapshots__/index.spec.ts.snap b/examples/python-generate-json-serializer-and-deserializer/__snapshots__/index.spec.ts.snap index 0b0cb2eb43..a64ad85d29 100644 --- a/examples/python-generate-json-serializer-and-deserializer/__snapshots__/index.spec.ts.snap +++ b/examples/python-generate-json-serializer-and-deserializer/__snapshots__/index.spec.ts.snap @@ -3,31 +3,31 @@ exports[`Should be able to render JSON serialization and deserialization functions and should log expected output to console 1`] = ` Array [ "class Root: - def __init__(self, input): - if hasattr(input, 'email'): - self._email = input.email - if hasattr(input, 'additionalProperties'): - self._additionalProperties = input.additionalProperties + def __init__(self, input: Dict): + if 'email' in input: + self._email: str = input['email'] + if 'additional_properties' in input: + self._additional_properties: dict[str, Any] = input['additional_properties'] @property - def email(self): - return self._email + def email(self) -> str: + return self._email @email.setter - def email(self, email): - self._email = email + def email(self, email: str): + self._email = email @property - def additionalProperties(self): - return self._additionalProperties - @additionalProperties.setter - def additionalProperties(self, additionalProperties): - self._additionalProperties = additionalProperties + def additional_properties(self) -> dict[str, Any]: + return self._additional_properties + @additional_properties.setter + def additional_properties(self, additional_properties: dict[str, Any]): + self._additional_properties = additional_properties - def serializeToJson(self): + def serialize_to_json(self): return json.dumps(self.__dict__, default=lambda o: o.__dict__, indent=2) @staticmethod - def deserializeFromJson(json_string): + def deserialize_from_json(json_string): return Root(**json.loads(json_string)) ", ] diff --git a/examples/typescript-generate-jsonbinpack/__snapshots__/index.spec.ts.snap b/examples/typescript-generate-jsonbinpack/__snapshots__/index.spec.ts.snap index 218f23f291..c6f73d2be8 100644 --- a/examples/typescript-generate-jsonbinpack/__snapshots__/index.spec.ts.snap +++ b/examples/typescript-generate-jsonbinpack/__snapshots__/index.spec.ts.snap @@ -37,12 +37,12 @@ Array [ } public async jsonbinSerialize(): Promise{ const jsonData = JSON.parse(this.marshal()); - const jsonbinpackEncodedSchema = await jsonbinpack.compileSchema({\\"$schema\\":\\"https://json-schema.org/draft/2020-12/schema\\",\\"$id\\":\\"Test\\",\\"type\\":\\"object\\",\\"additionalProperties\\":false,\\"properties\\":{\\"email\\":{\\"type\\":\\"string\\",\\"format\\":\\"email\\",\\"x-modelgen-inferred-name\\":\\"email\\"}},\\"x-modelgen-inferred-name\\":\\"root\\"}); + const jsonbinpackEncodedSchema = await jsonbinpack.compileSchema({\\"$schema\\":\\"https://json-schema.org/draft/2020-12/schema\\",\\"type\\":\\"object\\",\\"properties\\":{\\"email\\":{\\"format\\":\\"email\\",\\"type\\":\\"string\\",\\"x-modelgen-inferred-name\\":\\"email\\"}},\\"additionalProperties\\":false,\\"$id\\":\\"Test\\",\\"x-modelgen-inferred-name\\":\\"root\\"}); return jsonbinpack.serialize(jsonbinpackEncodedSchema, jsonData); } public static async jsonbinDeserialize(buffer: Buffer): Promise { - const jsonbinpackEncodedSchema = await jsonbinpack.compileSchema({\\"$schema\\":\\"https://json-schema.org/draft/2020-12/schema\\",\\"$id\\":\\"Test\\",\\"type\\":\\"object\\",\\"additionalProperties\\":false,\\"properties\\":{\\"email\\":{\\"type\\":\\"string\\",\\"format\\":\\"email\\",\\"x-modelgen-inferred-name\\":\\"email\\"}},\\"x-modelgen-inferred-name\\":\\"root\\"}); + const jsonbinpackEncodedSchema = await jsonbinpack.compileSchema({\\"$schema\\":\\"https://json-schema.org/draft/2020-12/schema\\",\\"type\\":\\"object\\",\\"properties\\":{\\"email\\":{\\"format\\":\\"email\\",\\"type\\":\\"string\\",\\"x-modelgen-inferred-name\\":\\"email\\"}},\\"additionalProperties\\":false,\\"$id\\":\\"Test\\",\\"x-modelgen-inferred-name\\":\\"root\\"}); const json = jsonbinpack.deserialize(jsonbinpackEncodedSchema, buffer); return Test.unmarshal(json); } diff --git a/jest.config.js b/jest.config.js index 020994ab94..38aa27ed07 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,7 +28,8 @@ module.exports = { '/examples/TEMPLATE', '/test/generators/template', '/test/processors/TemplateInputProcessor.spec.ts', - 'modelina-website' + 'modelina-website', + 'modelina-cli' ], watchPathIgnorePatterns: ['/node_modules'] }; diff --git a/modelina-cli/.eslintignore b/modelina-cli/.eslintignore new file mode 100644 index 0000000000..0430133d29 --- /dev/null +++ b/modelina-cli/.eslintignore @@ -0,0 +1,5 @@ +/lib +/tmp +/scripts +/test/helpers/init.js +/test/fixtures/generate \ No newline at end of file diff --git a/modelina-cli/.eslintrc b/modelina-cli/.eslintrc new file mode 100644 index 0000000000..2044c8b836 --- /dev/null +++ b/modelina-cli/.eslintrc @@ -0,0 +1,28 @@ +{ + "extends": [ + "oclif", + "oclif-typescript", + "prettier" + ], + "rules": { + "@typescript-eslint/no-explicit-any": 0, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "new-cap": "off", + "require-await": "off", + "no-useless-call": "off", + "no-await-in-loop": "off", + "no-warning-comments": "error", + "prettier/prettier": "off", + "complexity": "off", + "unicorn/filename-case": "off", + "unicorn/prefer-array-some": "off", + "unicorn/prefer-top-level-await": "off", + "unicorn/no-abusive-eslint-disable": "off", + "unicorn/no-await-expression-member": "off", + "security/detect-non-literal-fs-filename": "off", + "no-underscore-dangle": "off", + "unicorn/prefer-module": "off", + "valid-jsdoc": "off" + } +} diff --git a/modelina-cli/.gitignore b/modelina-cli/.gitignore new file mode 100644 index 0000000000..ae06b9ff56 --- /dev/null +++ b/modelina-cli/.gitignore @@ -0,0 +1,17 @@ +**/.DS_Store +*-debug.log +*-error.log +/.idea +/.nyc_output +/lib +/tmp +/yarn.lock +node_modules +oclif.lock +oclif.manifest.json +dist + +# Because we cant use local references (bug with windows build), we have to pack the dependency ourself +scripts/modelina-package +test/fixtures/generate +coverage \ No newline at end of file diff --git a/modelina-cli/.mocharc.json b/modelina-cli/.mocharc.json new file mode 100644 index 0000000000..3ebf9e76a1 --- /dev/null +++ b/modelina-cli/.mocharc.json @@ -0,0 +1,16 @@ +{ + "require": [ + "ts-node/register", + "test/test_helpers/init.js" + ], + "watch-extensions": [ + "ts" + ], + "recursive": true, + "reporter": "spec", + "timeout": 100000, + "node-option": [ + "loader=ts-node/esm", + "experimental-specifier-resolution=node" + ] +} diff --git a/modelina-cli/.prettierrc.json b/modelina-cli/.prettierrc.json new file mode 100644 index 0000000000..6314335704 --- /dev/null +++ b/modelina-cli/.prettierrc.json @@ -0,0 +1 @@ +"@oclif/prettier-config" diff --git a/modelina-cli/README.md b/modelina-cli/README.md new file mode 100644 index 0000000000..ef92ec2f77 --- /dev/null +++ b/modelina-cli/README.md @@ -0,0 +1,791 @@ +[![AsyncAPI Modelina](../docs/img/readme-banner.png)](https://www.modelina.org) +[![License](https://img.shields.io/github/license/asyncapi/modelina)](https://github.com/asyncapi/modelina/blob/master/LICENSE) +[![Npm latest version](https://img.shields.io/npm/v/@asyncapi/modelina-cli)](https://www.npmjs.com/package/@asyncapi/modelina-cli) +![NPM Downloads](https://img.shields.io/npm/dm/modelina-cli?label=npm) +![homebrew downloads](https://img.shields.io/homebrew/installs/dm/modelina?label=Brew) +![Chocolatey Downloads](https://img.shields.io/chocolatey/dt/modelina?label=Chocolatey) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.x64.pkg?label=MacOS) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.arm64.pkg?label=MacOS) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.x86.exe?label=Win) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.x64.exe?label=Win) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.tar.gz?label=Linux) +![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/asyncapi/modelina/modelina.deb?label=Linux) + +--- + +> NOTICE: If you are only working exclusively with AsyncAPI documents, using the [AsyncAPI CLI is the preferred way to interact with Modelina](https://github.com/asyncapi/cli#installation) as it has the exact same features. + +# Table of contents + + +* [Table of contents](#table-of-contents) +* [Installation](#installation) +* [Download latest release](#download-latest-release) +* [Install it](#install-it) +* [Download latest release](#download-latest-release) +* [Install it](#install-it) +* [Download](#download) +* [Install](#install) +* [Download](#download) +* [Install](#install) +* [Usage](#usage) +* [Commands](#commands) + + +# Installation +Here are all the ways you can install and run the Modelina CLI. + +## MacOS + + + + + + + + + + + + + +
+Brew + +``` +brew install modelina +``` +
+MacOS x64 + +Install it through dedicated `.pkg` file as a MacOS Application + +``` +# Download latest release +curl -OL https://github.com/asyncapi/modelina/releases/latest/download/modelina.x64.pkg +# Install it +sudo installer -pkg modelina.pkg -target / +``` +
+MacOS arm64 + +Install it through dedicated `.pkg` file as a MacOS Application for arm64 +``` +# Download latest release +curl -OL https://github.com/asyncapi/modelina/releases/latest/download/modelina.arm64.pkg +# Install it +sudo installer -pkg modelina.pkg -target / +``` +
+ +## Windows + + + + + + + + + + + + + +
+Chocolatey + +``` +choco install modelina +``` +
Windows x64 + +Manually download and run [`modelina.x64.exe`](https://github.com/asyncapi/modelina/releases/latest/download/modelina.x64.exe) +
+Windows x32 + +Manually download and run the executable [`modelina.x86.exe`](https://github.com/asyncapi/modelina/releases/latest/download/modelina.x86.exe) +
+ + +## Linux + + + + + + + + + +
Debian + +``` +# Download +curl -OL https://github.com/asyncapi/modelina/releases/latest/download/modelina.deb + +# Install +sudo apt install ./modelina.deb +``` +
+Others + +``` +# Download +curl -OL https://github.com/asyncapi/modelina/releases/latest/download/modelina.tar.gz +# Install +tar -xzf modelina.tar.gz +``` + +Remember to symlink the binaries `ln -s /bin/modelina /user/local/bin/modelina` to access the CLI anywhere. +
+ +## Others + + + + + + +
+NPM + +```typescript +npm install -g @asyncapi/modelina-cli +``` +
+ +# Usage + +```sh-session +$ npm install -g @asyncapi/modelina-cli +$ modelina COMMAND +running command... +$ modelina (--version) +@asyncapi/modelina-cli/4.0.0-next.64 linux-x64 node-v18.20.5 +$ modelina --help [COMMAND] +USAGE + $ modelina COMMAND +... +``` + + +# Commands + + +* [`modelina autocomplete [SHELL]`](#modelina-autocomplete-shell) +* [`modelina config`](#modelina-config) +* [`modelina config context`](#modelina-config-context) +* [`modelina config context add CONTEXT-NAME SPEC-FILE-PATH`](#modelina-config-context-add-context-name-spec-file-path) +* [`modelina config context current`](#modelina-config-context-current) +* [`modelina config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#modelina-config-context-edit-context-name-new-spec-file-path) +* [`modelina config context init [CONTEXT-FILE-PATH]`](#modelina-config-context-init-context-file-path) +* [`modelina config context list`](#modelina-config-context-list) +* [`modelina config context remove CONTEXT-NAME`](#modelina-config-context-remove-context-name) +* [`modelina config context use CONTEXT-NAME`](#modelina-config-context-use-context-name) +* [`modelina generate LANGUAGE FILE`](#modelina-generate-language-file) +* [`modelina help [COMMAND]`](#modelina-help-command) +* [`modelina plugins`](#modelina-plugins) +* [`modelina plugins add PLUGIN`](#modelina-plugins-add-plugin) +* [`modelina plugins:inspect PLUGIN...`](#modelina-pluginsinspect-plugin) +* [`modelina plugins install PLUGIN`](#modelina-plugins-install-plugin) +* [`modelina plugins link PATH`](#modelina-plugins-link-path) +* [`modelina plugins remove [PLUGIN]`](#modelina-plugins-remove-plugin) +* [`modelina plugins reset`](#modelina-plugins-reset) +* [`modelina plugins uninstall [PLUGIN]`](#modelina-plugins-uninstall-plugin) +* [`modelina plugins unlink [PLUGIN]`](#modelina-plugins-unlink-plugin) +* [`modelina plugins update`](#modelina-plugins-update) +* [`modelina version`](#modelina-version) + +## `modelina autocomplete [SHELL]` + +Display autocomplete installation instructions. + +``` +USAGE + $ modelina autocomplete [SHELL] [-r] + +ARGUMENTS + SHELL (zsh|bash|powershell) Shell type + +FLAGS + -r, --refresh-cache Refresh cache (ignores displaying instructions) + +DESCRIPTION + Display autocomplete installation instructions. + +EXAMPLES + $ modelina autocomplete + + $ modelina autocomplete bash + + $ modelina autocomplete zsh + + $ modelina autocomplete powershell + + $ modelina autocomplete --refresh-cache +``` + +_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.1.1/modelina-cli/src/commands/autocomplete/index.ts)_ + +## `modelina config` + +CLI config settings + +``` +USAGE + $ modelina config + +DESCRIPTION + CLI config settings +``` + +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/index.ts)_ + +## `modelina config context` + +Manage short aliases for full paths to inputs + +``` +USAGE + $ modelina config context + +DESCRIPTION + Manage short aliases for full paths to inputs +``` + +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/index.ts)_ + +## `modelina config context add CONTEXT-NAME SPEC-FILE-PATH` + +Add a context to the store + +``` +USAGE + $ modelina config context add CONTEXT-NAME SPEC-FILE-PATH [-h] [-s] + +ARGUMENTS + CONTEXT-NAME context name + SPEC-FILE-PATH file path of the spec file + +FLAGS + -h, --help Show CLI help. + -s, --set-current Set context being added as the current context + +DESCRIPTION + Add a context to the store +``` + +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/add.ts)_ + +## `modelina config context current` + +Shows the current context that is being used + +``` +USAGE + $ modelina config context current [-h] + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + Shows the current context that is being used +``` + +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/current.ts)_ + +## `modelina config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` + +Edit a context in the store + +``` +USAGE + $ modelina config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH [-h] + +ARGUMENTS + CONTEXT-NAME context name + NEW-SPEC-FILE-PATH file path of the spec file + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + Edit a context in the store +``` + +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/edit.ts)_ + +## `modelina config context init [CONTEXT-FILE-PATH]` + +Initialize context + +``` +USAGE + $ modelina config context init [CONTEXT-FILE-PATH] [-h] + +ARGUMENTS + CONTEXT-FILE-PATH Specify directory in which context file should be created: + - current directory : modelina config context init . (default) + - root of current repository : modelina config context init ./ + - user's home directory : modelina config context init ~ + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + Initialize context +``` + +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/init.ts)_ + +## `modelina config context list` + +List all the stored contexts in the store + +``` +USAGE + $ modelina config context list [-h] + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + List all the stored contexts in the store +``` + +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/list.ts)_ + +## `modelina config context remove CONTEXT-NAME` + +Delete a context from the store + +``` +USAGE + $ modelina config context remove CONTEXT-NAME [-h] + +ARGUMENTS + CONTEXT-NAME Name of the context to delete + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + Delete a context from the store +``` + +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/remove.ts)_ + +## `modelina config context use CONTEXT-NAME` + +Set a context as current + +``` +USAGE + $ modelina config context use CONTEXT-NAME [-h] + +ARGUMENTS + CONTEXT-NAME name of the saved context + +FLAGS + -h, --help Show CLI help. + +DESCRIPTION + Set a context as current +``` + +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/modelina/blob/v4.0.0-next.64/modelina-cli/src/commands/config/context/use.ts)_ + +## `modelina generate LANGUAGE FILE` + +Generates typed models + +``` +USAGE + $ modelina generate LANGUAGE FILE [-h] [-o ] [--packageName ] [--namespace ] + [--tsModelType class|interface] [--tsEnumType enum|union] [--tsModuleSystem ESM|CJS] [--tsIncludeComments] + [--tsExportType default|named] [--tsJsonBinPack] [--tsMarshalling] [--tsExampleInstance] [--tsRawPropertyNames] + [--csharpAutoImplement] [--csharpNewtonsoft] [--csharpArrayType Array|List] [--csharpHashcode] [--csharpEqual] + [--csharpSystemJson] [--goIncludeComments] [--goIncludeTags] [--javaIncludeComments] [--javaJackson] + [--javaConstraints] [--javaArrayType Array|List] [--pyDantic] + +ARGUMENTS + LANGUAGE (typescript|csharp|golang|java|javascript|dart|python|rust|kotlin|php|cplusplus|scala) The language you want + the typed models generated for. + FILE Path or URL to the AsyncAPI document, or context-name + +FLAGS + -h, --help Show CLI help. + -o, --output= The output directory where the models should be written to. Omitting this flag will + write the models to `stdout`. + --csharpArrayType=