diff --git a/.all-contributorsrc b/.all-contributorsrc index bdacc7798f3..84715bc5283 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -179,6 +179,33 @@ "contributions": [ "code" ] + }, + { + "login": "kaushik-rishi", + "name": "Rishi", + "avatar_url": "https://avatars.githubusercontent.com/u/52498617?v=4", + "profile": "https://github.com/kaushik-rishi", + "contributions": [ + "code" + ] + }, + { + "login": "Shurtu-gal", + "name": "Ashish Padhy", + "avatar_url": "https://avatars.githubusercontent.com/u/100484401?v=4", + "profile": "http://ashishpadhy.live", + "contributions": [ + "code" + ] + }, + { + "login": "meetagrawal09", + "name": "Meet Agrawal", + "avatar_url": "https://avatars.githubusercontent.com/u/73902874?v=4", + "profile": "https://github.com/meetagrawal09", + "contributions": [ + "infra" + ] } ], "contributorsPerLine": 7, diff --git a/.github/workflows/upload-release-assets.yml b/.github/workflows/upload-release-assets.yml index f491d7d8235..bf11cd4ab5c 100644 --- a/.github/workflows/upload-release-assets.yml +++ b/.github/workflows/upload-release-assets.yml @@ -68,3 +68,12 @@ jobs: files: dist/${{ matrix.dist_folder }}/asyncapi.${{ 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@v3 + with: + status: ${{ job.status }} + fields: repo,action,workflow + text: 'AsyncAPI CLI release build artifacts failed' + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} diff --git a/README.md b/README.md index f7511823fbb..71d70aa4be9 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,9 @@ Thanks go to these wonderful people ([emoji key](https://allcontributors.org/doc Sambhav Gupta
Sambhav Gupta

💻 ⚠️ Hippolyte Vergnol
Hippolyte Vergnol

💻 🚇 Jente Vets
Jente Vets

💻 + Rishi
Rishi

💻 + Ashish Padhy
Ashish Padhy

💻 + Meet Agrawal
Meet Agrawal

🚇 diff --git a/docs/usage.md b/docs/usage.md index 523438e8758..2bc42daf1a8 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -6,11 +6,13 @@ weight: 40 The AsyncAPI CLI makes it easier to work with AsyncAPI documents. To get **help**, run this command in your terminal: + ```sh asyncapi --help ``` It should print something similar to this: + ```sh All in one CLI for all AsyncAPI tools @@ -39,5 +41,7 @@ COMMANDS dart generate the models for Dart rust generate the models for Rust kotlin generate the models for Kotlin - fromTemplate generate whatever you want using templates compatible with AsyncAPI Generator + php generate the models for PHP + cplusplus generate the models for C++ + fromTemplate generate whatever you want using templates compatible with AsyncAPI Generator ``` diff --git a/package-lock.json b/package-lock.json index 88de1517df9..c08b1102d67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "@asyncapi/cli", - "version": "0.40.6", + "version": "0.45.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@asyncapi/cli", - "version": "0.40.6", + "version": "0.45.0", "license": "Apache-2.0", "dependencies": { "@asyncapi/avro-schema-parser": "^3.0.0", "@asyncapi/bundler": "^0.3.8", "@asyncapi/converter": "^1.2.0", "@asyncapi/diff": "^0.4.1", - "@asyncapi/generator": "^1.9.17", - "@asyncapi/modelina": "^1.5.0", + "@asyncapi/generator": "^1.10.1", + "@asyncapi/modelina": "^1.7.0", "@asyncapi/openapi-schema-parser": "^3.0.0", "@asyncapi/optimizer": "^0.1.18", "@asyncapi/parser": "^2.0.0", @@ -272,20 +272,19 @@ } }, "node_modules/@asyncapi/generator": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/@asyncapi/generator/-/generator-1.9.17.tgz", - "integrity": "sha512-VHtZn6f+2w0rqFS+0e7QxH7vkyZGbLkuFSNOGWfVGaQqkmtCHY70pYxpF5ojCvMrqAAQyKKKXvzjIfjCabDKhA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@asyncapi/generator/-/generator-1.10.1.tgz", + "integrity": "sha512-jSAX1mQPr/tSUNgxvdfM8G5rwBqGMgTCaQW8hhBViWhjxakzCWD/uRV4V2Tj1d51qvT7Brnj6PEWEX1ytlFV1w==", "dependencies": { - "@asyncapi/avro-schema-parser": "^1.1.0", + "@asyncapi/avro-schema-parser": "^3.0.0", "@asyncapi/generator-react-sdk": "^0.2.23", - "@asyncapi/openapi-schema-parser": "^2.0.1", - "@asyncapi/parser": "^1.18.0", - "@asyncapi/raml-dt-schema-parser": "^2.0.1", + "@asyncapi/openapi-schema-parser": "^3.0.0", + "@asyncapi/parser": "^2.0.0", + "@asyncapi/raml-dt-schema-parser": "^4.0.0", "@npmcli/arborist": "^2.2.4", - "ajv": "^6.10.2", + "ajv": "^8.12.0", "chokidar": "^3.4.0", "commander": "^6.1.0", - "conventional-changelog-conventionalcommits": "^5.0.0", "filenamify": "^4.1.0", "fs.extra": "^1.3.2", "global-dirs": "^3.0.0", @@ -420,76 +419,6 @@ "node": ">=0.10.0" } }, - "node_modules/@asyncapi/generator/node_modules/@asyncapi/avro-schema-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@asyncapi/avro-schema-parser/-/avro-schema-parser-1.1.0.tgz", - "integrity": "sha512-7J7pzSw0/jF2bXy/Mf+80VKJfXRRfyLTJz413MkKLbLXbbz9rV4sVpYfp31ofqXgyZ9bhfmHJzunbi0Bt7Jcww==", - "dependencies": { - "avsc": "^5.7.3" - } - }, - "node_modules/@asyncapi/generator/node_modules/@asyncapi/openapi-schema-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@asyncapi/openapi-schema-parser/-/openapi-schema-parser-2.0.3.tgz", - "integrity": "sha512-o9fvibjx2n3L2SKNlWUQ59CxO2x2BKhbHxh81U39NMLgowN/avk1wfxkMvzL3G9pg4FlgCdcayDhu4+TzDX47A==", - "dependencies": { - "@openapi-contrib/openapi-schema-to-json-schema": "~3.2.0", - "conventional-changelog-conventionalcommits": "^5.0.0" - } - }, - "node_modules/@asyncapi/generator/node_modules/@asyncapi/parser": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.18.1.tgz", - "integrity": "sha512-7sU9DajLV+vA2vShTYmD5lbtbTY6TOcGxB4Z4IcpRp8x5pejOsN32iU05eIYCnuamsi5SMscFxoi6fIO2vPK3Q==", - "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@asyncapi/specs": "^4.1.1", - "@fmvilas/pseudo-yaml-ast": "^0.3.1", - "ajv": "^6.10.1", - "js-yaml": "^3.13.1", - "json-to-ast": "^2.1.0", - "lodash.clonedeep": "^4.5.0", - "node-fetch": "^2.6.0", - "tiny-merge-patch": "^0.1.2" - } - }, - "node_modules/@asyncapi/generator/node_modules/@asyncapi/raml-dt-schema-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@asyncapi/raml-dt-schema-parser/-/raml-dt-schema-parser-2.0.1.tgz", - "integrity": "sha512-R7i35IbVbvGyPNm3t5ToPDtYUwDtVjWF/oCgCVPK/wLpNQ0uVZX5Y0JFhO78VUHEep0NKuuI2CZh6oLz0ebMVQ==", - "dependencies": { - "js-yaml": "^3.13.1", - "ramldt2jsonschema": "^1.1.0" - } - }, - "node_modules/@asyncapi/generator/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@asyncapi/generator/node_modules/conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@asyncapi/generator/node_modules/simple-git": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.17.0.tgz", @@ -521,18 +450,20 @@ "link": true }, "node_modules/@asyncapi/modelina": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-1.5.0.tgz", - "integrity": "sha512-YFoVCqf9YgZ/1xd6tVtFfkNhWcXq9cTLiVqUB/e/Fso8DHAEqYxOkKHSO/ywlhvnWdg+D3OO8BDse9x8cOZL6Q==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-1.7.0.tgz", + "integrity": "sha512-fIZ2pQEMubPRdShKYiUB2SN0NcxUQxvr6NEgZ1sfqInkWnkXyPQgung6LMEL5fkVOHIUa5tYBg1w23MISHF5eg==", "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@apidevtools/swagger-parser": "^10.0.3", + "@asyncapi/avro-schema-parser": "^3.0.0", + "@asyncapi/openapi-schema-parser": "^3.0.0", "@asyncapi/parser": "^2.0.0", + "@asyncapi/raml-dt-schema-parser": "^4.0.0", "@swc/core": "^1.3.5", "@swc/jest": "^0.2.23", "alterschema": "^1.1.2", "change-case": "^4.1.2", - "conventional-changelog-conventionalcommits": "^5.0.0", "openapi-types": "9.3.0", "typescript-json-schema": "^0.53.0" }, @@ -540,19 +471,6 @@ "node": ">=14" } }, - "node_modules/@asyncapi/modelina/node_modules/conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "dependencies": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@asyncapi/openapi-schema-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@asyncapi/openapi-schema-parser/-/openapi-schema-parser-3.0.0.tgz", @@ -23817,20 +23735,19 @@ } }, "@asyncapi/generator": { - "version": "1.9.17", - "resolved": "https://registry.npmjs.org/@asyncapi/generator/-/generator-1.9.17.tgz", - "integrity": "sha512-VHtZn6f+2w0rqFS+0e7QxH7vkyZGbLkuFSNOGWfVGaQqkmtCHY70pYxpF5ojCvMrqAAQyKKKXvzjIfjCabDKhA==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@asyncapi/generator/-/generator-1.10.1.tgz", + "integrity": "sha512-jSAX1mQPr/tSUNgxvdfM8G5rwBqGMgTCaQW8hhBViWhjxakzCWD/uRV4V2Tj1d51qvT7Brnj6PEWEX1ytlFV1w==", "requires": { - "@asyncapi/avro-schema-parser": "^1.1.0", + "@asyncapi/avro-schema-parser": "^3.0.0", "@asyncapi/generator-react-sdk": "^0.2.23", - "@asyncapi/openapi-schema-parser": "^2.0.1", - "@asyncapi/parser": "^1.18.0", - "@asyncapi/raml-dt-schema-parser": "^2.0.1", + "@asyncapi/openapi-schema-parser": "^3.0.0", + "@asyncapi/parser": "^2.0.0", + "@asyncapi/raml-dt-schema-parser": "^4.0.0", "@npmcli/arborist": "^2.2.4", - "ajv": "^6.10.2", + "ajv": "^8.12.0", "chokidar": "^3.4.0", "commander": "^6.1.0", - "conventional-changelog-conventionalcommits": "^5.0.0", "filenamify": "^4.1.0", "fs.extra": "^1.3.2", "global-dirs": "^3.0.0", @@ -23851,69 +23768,6 @@ "typescript": "^4.9.3" }, "dependencies": { - "@asyncapi/avro-schema-parser": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@asyncapi/avro-schema-parser/-/avro-schema-parser-1.1.0.tgz", - "integrity": "sha512-7J7pzSw0/jF2bXy/Mf+80VKJfXRRfyLTJz413MkKLbLXbbz9rV4sVpYfp31ofqXgyZ9bhfmHJzunbi0Bt7Jcww==", - "requires": { - "avsc": "^5.7.3" - } - }, - "@asyncapi/openapi-schema-parser": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@asyncapi/openapi-schema-parser/-/openapi-schema-parser-2.0.3.tgz", - "integrity": "sha512-o9fvibjx2n3L2SKNlWUQ59CxO2x2BKhbHxh81U39NMLgowN/avk1wfxkMvzL3G9pg4FlgCdcayDhu4+TzDX47A==", - "requires": { - "@openapi-contrib/openapi-schema-to-json-schema": "~3.2.0", - "conventional-changelog-conventionalcommits": "^5.0.0" - } - }, - "@asyncapi/parser": { - "version": "1.18.1", - "resolved": "https://registry.npmjs.org/@asyncapi/parser/-/parser-1.18.1.tgz", - "integrity": "sha512-7sU9DajLV+vA2vShTYmD5lbtbTY6TOcGxB4Z4IcpRp8x5pejOsN32iU05eIYCnuamsi5SMscFxoi6fIO2vPK3Q==", - "requires": { - "@apidevtools/json-schema-ref-parser": "^9.0.6", - "@asyncapi/specs": "^4.1.1", - "@fmvilas/pseudo-yaml-ast": "^0.3.1", - "ajv": "^6.10.1", - "js-yaml": "^3.13.1", - "json-to-ast": "^2.1.0", - "lodash.clonedeep": "^4.5.0", - "node-fetch": "^2.6.0", - "tiny-merge-patch": "^0.1.2" - } - }, - "@asyncapi/raml-dt-schema-parser": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@asyncapi/raml-dt-schema-parser/-/raml-dt-schema-parser-2.0.1.tgz", - "integrity": "sha512-R7i35IbVbvGyPNm3t5ToPDtYUwDtVjWF/oCgCVPK/wLpNQ0uVZX5Y0JFhO78VUHEep0NKuuI2CZh6oLz0ebMVQ==", - "requires": { - "js-yaml": "^3.13.1", - "ramldt2jsonschema": "^1.1.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "requires": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - } - }, "simple-git": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.17.0.tgz", @@ -24026,32 +23880,22 @@ } }, "@asyncapi/modelina": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-1.5.0.tgz", - "integrity": "sha512-YFoVCqf9YgZ/1xd6tVtFfkNhWcXq9cTLiVqUB/e/Fso8DHAEqYxOkKHSO/ywlhvnWdg+D3OO8BDse9x8cOZL6Q==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-1.7.0.tgz", + "integrity": "sha512-fIZ2pQEMubPRdShKYiUB2SN0NcxUQxvr6NEgZ1sfqInkWnkXyPQgung6LMEL5fkVOHIUa5tYBg1w23MISHF5eg==", "requires": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@apidevtools/swagger-parser": "^10.0.3", + "@asyncapi/avro-schema-parser": "^3.0.0", + "@asyncapi/openapi-schema-parser": "^3.0.0", "@asyncapi/parser": "^2.0.0", + "@asyncapi/raml-dt-schema-parser": "^4.0.0", "@swc/core": "^1.3.5", "@swc/jest": "^0.2.23", "alterschema": "^1.1.2", "change-case": "^4.1.2", - "conventional-changelog-conventionalcommits": "^5.0.0", "openapi-types": "9.3.0", "typescript-json-schema": "^0.53.0" - }, - "dependencies": { - "conventional-changelog-conventionalcommits": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", - "integrity": "sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==", - "requires": { - "compare-func": "^2.0.0", - "lodash": "^4.17.15", - "q": "^1.5.1" - } - } } }, "@asyncapi/openapi-schema-parser": { diff --git a/package.json b/package.json index 3c1d41c5626..043bb8867e3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asyncapi/cli", "description": "All in one CLI for all AsyncAPI tools", - "version": "0.40.6", + "version": "0.45.0", "author": "@asyncapi", "bin": { "asyncapi": "./bin/run" @@ -12,8 +12,8 @@ "@asyncapi/bundler": "^0.3.8", "@asyncapi/converter": "^1.2.0", "@asyncapi/diff": "^0.4.1", - "@asyncapi/generator": "^1.9.17", - "@asyncapi/modelina": "^1.5.0", + "@asyncapi/generator": "^1.10.1", + "@asyncapi/modelina": "^1.7.0", "@asyncapi/openapi-schema-parser": "^3.0.0", "@asyncapi/optimizer": "^0.1.18", "@asyncapi/parser": "^2.0.0", diff --git a/src/commands/config/versions.ts b/src/commands/config/versions.ts new file mode 100644 index 00000000000..76ce1953328 --- /dev/null +++ b/src/commands/config/versions.ts @@ -0,0 +1,56 @@ +import { Flags } from '@oclif/core'; +import Command from '../../base'; + +export default class Versions extends Command { + static description = 'Show versions of AsyncAPI tools used'; + + static flags = { + help: Flags.help({ char: 'h' }), + }; + + async run() { + const dependencies: string[] = []; + let dependency = ''; + + // Preparation of the array with all dependencies '@asyncapi/*' along with + // their versions. + for (const key in this.config.pjson.dependencies) { + // Making sure with .indexOf() that only package names which START with + // string '@asyncapi' are considered. + if (key.indexOf('@asyncapi', 0) === 0) { + // Avoiding obvious crash on manual removal or alteration of an + // '@asyncapi' package. + try { + // Goofy name `importedPJSON` is chosen to distinguish from name `pjson` + // used in `@oclif` source code. + const importedPJSON = await import(`${key}/package.json`); + dependencies.push(`${key}/${importedPJSON.default.version}`); + } catch (e) { + dependencies.push(`${key}/` + '`package.json` not found'); + } + } + } + + // Showing information available with `--version` flag. + this.log(this.config.userAgent); + + // Iteration through the array containing all dependencies '@asyncapi/*' + // along with their versions. + for (let i = 0; i < dependencies.length; i++) { + // Minimization of the theoretical possibility of a Generic Object + // Injection Sink, at the same time disabling eslint parsing for this + // line since it is actually a false positive. + // https://github.com/eslint-community/eslint-plugin-security/issues/21#issuecomment-530184612 + // https://github.com/eslint-community/eslint-plugin-security/issues/21#issuecomment-1157887653 + // https://web.archive.org/web/20150430062816/https://blog.liftsecurity.io/2015/01/15/the-dangers-of-square-bracket-notation + dependency = dependencies[i]; // eslint-disable-line + if (i !== dependencies.length - 1) { + this.log(` ├${dependency}`); + } else { + this.log(` └${dependency}\n`); + } + } + + this.log(`Repository: ${this.config.pjson.homepage}`); + } +} diff --git a/src/commands/generate/models.ts b/src/commands/generate/models.ts index ffd33d44954..e77c704ee12 100644 --- a/src/commands/generate/models.ts +++ b/src/commands/generate/models.ts @@ -1,4 +1,4 @@ -import { CSharpFileGenerator, JavaFileGenerator, JavaScriptFileGenerator, TypeScriptFileGenerator, GoFileGenerator, Logger, DartFileGenerator, PythonFileGenerator, RustFileGenerator, TS_COMMON_PRESET, TS_JSONBINPACK_PRESET, CSHARP_DEFAULT_PRESET, KotlinFileGenerator, TS_DESCRIPTION_PRESET } from '@asyncapi/modelina'; +import { CSharpFileGenerator, JavaFileGenerator, JavaScriptFileGenerator, TypeScriptFileGenerator, GoFileGenerator, Logger, DartFileGenerator, PythonFileGenerator, RustFileGenerator, TS_COMMON_PRESET, TS_JSONBINPACK_PRESET, CSHARP_DEFAULT_PRESET, CSHARP_NEWTONSOFT_SERIALIZER_PRESET, CSHARP_COMMON_PRESET, CSHARP_JSON_SERIALIZER_PRESET, KotlinFileGenerator, TS_DESCRIPTION_PRESET, PhpFileGenerator, CplusplusFileGenerator } from '@asyncapi/modelina'; import { Flags } from '@oclif/core'; import Command from '../../base'; import { load } from '../../models/SpecificationFile'; @@ -15,7 +15,9 @@ enum Languages { dart = 'dart', python = 'python', rust = 'rust', - kotlin='kotlin' + kotlin='kotlin', + php='php', + cplusplus='cplusplus' } const possibleLanguageValues = Object.values(Languages).join(', '); @@ -61,7 +63,7 @@ export default class Models extends Command { description: 'TypeScript specific, define the module system to be used.', required: false, default: 'ESM', - + }), tsIncludeComments: Flags.boolean({ description: 'TypeScript specific, if enabled add comments while generating models.', @@ -87,19 +89,28 @@ export default class Models extends Command { description: 'Go, Java and Kotlin specific, define the package to use for the generated models. This is required when language is `go`, `java` or `kotlin`.', required: false }), + /** - * C# specific options + * C++ and C# and PHP specific namespace to use for the generated models */ namespace: Flags.string({ - description: 'C# specific, define the namespace to use for the generated models. This is required when language is `csharp`.', + description: 'C#, C++ and PHP specific, define the namespace to use for the generated models. This is required when language is `csharp`,`c++` or `php`.', required: false }), + /** + * C# specific options + */ csharpAutoImplement: Flags.boolean({ description: 'C# specific, define whether to generate auto-implemented properties or not.', required: false, default: false }), + csharpNewtonsoft: Flags.boolean({ + description: 'C# specific, generate the models with newtonsoft serialization support', + required: false, + default: false + }), csharpArrayType: Flags.string({ type: 'option', description: 'C# specific, define which type of array needs to be generated.', @@ -107,13 +118,28 @@ export default class Models extends Command { required: false, default: 'Array' }), + csharpHashcode: Flags.boolean({ + description: 'C# specific, generate the models with the GetHashCode method overwritten', + required: false, + default: false + }), + csharpEqual: Flags.boolean({ + description: 'C# specific, generate the models with the Equal method overwritten', + required: false, + default: false + }), + csharpSystemJson: Flags.boolean({ + description: 'C# specific, generate the models with System.Text.Json serialization support', + required: false, + default: false + }), ...validationFlags({ logDiagnostics: false }), }; - + /* eslint-disable sonarjs/cognitive-complexity */ async run() { const { args, flags } = await this.parse(Models); - const { tsModelType, tsEnumType, tsIncludeComments, tsModuleSystem, tsExportType, tsJsonBinPack, namespace, csharpAutoImplement, csharpArrayType, packageName, output } = flags; + const { tsModelType, tsEnumType, tsIncludeComments, tsModuleSystem, tsExportType, tsJsonBinPack, namespace, csharpAutoImplement, csharpArrayType, csharpNewtonsoft, csharpHashcode, csharpEqual, csharpSystemJson, packageName, output } = flags; const { language, file } = args; const inputFile = (await load(file)) || (await load()); const { document, status } = await parse(this, inputFile, flags); @@ -172,22 +198,47 @@ export default class Models extends Command { throw new Error('In order to generate models to C#, we need to know which namespace they are under. Add `--namespace=NAMESPACE` to set the desired namespace.'); } - fileGenerator = new CSharpFileGenerator({ - presets: csharpAutoImplement ? [ - { - preset: CSHARP_DEFAULT_PRESET, - options: { - autoImplementedProperties: true - } + if (csharpAutoImplement) { + presets.push({ + preset: CSHARP_DEFAULT_PRESET, + options: { + autoImplementedProperties: true } - ] : [], + }); + } + if (csharpNewtonsoft) { + presets.push(CSHARP_NEWTONSOFT_SERIALIZER_PRESET); + } + if (csharpSystemJson) { + presets.push(CSHARP_JSON_SERIALIZER_PRESET); + } + if (csharpHashcode || csharpEqual) { + presets.push({ + preset: CSHARP_COMMON_PRESET, + options: { + hashCode: csharpHashcode, + equals: csharpEqual + } + }); + } + + fileGenerator = new CSharpFileGenerator({ + presets, collectionType: csharpArrayType as 'Array' | 'List' }); - + fileOptions = { namespace }; break; + case Languages.cplusplus: + if (namespace === undefined) { + throw new Error('In order to generate models to C++, we need to know which namespace they are under. Add `--namespace=NAMESPACE` to set the desired namespace.'); + } + fileGenerator = new CplusplusFileGenerator({ + namespace + }); + break; case Languages.golang: if (packageName === undefined) { throw new Error('In order to generate models to Go, we need to know which package they are under. Add `--packageName=PACKAGENAME` to set the desired package name.'); @@ -227,6 +278,15 @@ export default class Models extends Command { packageName }; break; + case Languages.php: + if (namespace === undefined) { + throw new Error('In order to generate models to PHP, we need to know which namespace they are under. Add `--namespace=NAMESPACE` to set the desired namespace.'); + } + fileGenerator = new PhpFileGenerator(); + fileOptions = { + namespace + }; + break; default: throw new Error(`Could not determine generator for language ${language}, are you using one of the following values ${possibleLanguageValues}?`); } diff --git a/test/commands/config/versions.test.ts b/test/commands/config/versions.test.ts new file mode 100644 index 00000000000..cf385a4a75e --- /dev/null +++ b/test/commands/config/versions.test.ts @@ -0,0 +1,27 @@ +import { test } from '@oclif/test'; + +describe('versions', () => { + describe('config:versions', () => { + test + .stderr() + .stdout() + .command(['config:versions']) + .it('should show versions of AsyncAPI tools used', (ctx, done) => { + expect(ctx.stdout).toContain('@asyncapi/cli/'); + expect(ctx.stdout).toContain('├@asyncapi/'); + expect(ctx.stdout).toContain('└@asyncapi/'); + expect(ctx.stderr).toEqual(''); + done(); + }); + + test + .stderr() + .stdout() + .command(['config:versions']) + .it('should show address of repository of AsyncAPI CLI', (ctx, done) => { + expect(ctx.stdout).toContain('https://github.com/asyncapi/cli'); + expect(ctx.stderr).toEqual(''); + done(); + }); + }); +}); diff --git a/test/commands/generate/models.test.ts b/test/commands/generate/models.test.ts index 77f7329c8d2..911b9ed22b9 100644 --- a/test/commands/generate/models.test.ts +++ b/test/commands/generate/models.test.ts @@ -15,17 +15,16 @@ describe('models', () => { expect(ctx.stdout).toMatchSnapshot(); done(); }); - + test .stderr() .stdout() .command([...generalOptions, 'random', './test/specification.yml', `-o=${ path.resolve(outputDir, './random')}`]) .it('fails when it dont know the language', (ctx, done) => { - expect(ctx.stderr).toEqual('Error: Expected random to be one of: typescript, csharp, golang, java, javascript, dart, python, rust, kotlin\nSee more help with --help\n'); + expect(ctx.stderr).toEqual('Error: Expected random to be one of: typescript, csharp, golang, java, javascript, dart, python, rust, kotlin, php, cplusplus\nSee more help with --help\n'); expect(ctx.stdout).toEqual(''); done(); }); - test .stderr() .stdout() @@ -35,8 +34,8 @@ describe('models', () => { expect(ctx.stdout).toMatchSnapshot(); done(); }); - - describe('for TypeScript', () => { + + describe('for TypeScript', () => { test .stderr() .stdout() @@ -70,7 +69,7 @@ describe('models', () => { }); }); - describe('for JavaScript', () => { + describe('for JavaScript', () => { test .stderr() .stdout() @@ -84,7 +83,7 @@ describe('models', () => { }); }); - describe('for Python', () => { + describe('for Python', () => { test .stderr() .stdout() @@ -98,7 +97,7 @@ describe('models', () => { }); }); - describe('for Rust', () => { + describe('for Rust', () => { test .stderr() .stdout() @@ -147,7 +146,54 @@ describe('models', () => { test .stderr() .stdout() - .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpArrayType=List']) + .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpNewtonsoft']) + .it('works when newtonsoft flag is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + test + .stderr() + .stdout() + .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpHashcode']) + .it('works when hash code flag is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + + test + .stderr() + .stdout() + .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpEqual']) + .it('works when equal flag is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + + test + .stderr() + .stdout() + .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpSystemJson']) + .it('works when system json flag is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + + test + .stderr() + .stdout() + .command([...generalOptions, 'csharp', './test/specification.yml', `-o=${ path.resolve(outputDir, './csharp')}`, '--namespace=\'asyncapi.models\'', '--csharpArrayType=List']) .it('works when array type is provided', (ctx, done) => { expect(ctx.stderr).toEqual(''); expect(ctx.stdout).toContain( @@ -157,6 +203,29 @@ describe('models', () => { }); }); + describe('for C++', () => { + test + .stderr() + .stdout() + .command([...generalOptions, 'cplusplus', './test/specification.yml', `-o=${path.resolve(outputDir, './cplusplus')}`, '--namespace=\'AsyncapiModels\'']) + .it('works when file path is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + test + .stderr() + .stdout() + .command([...generalOptions, 'cplusplus', './test/specification.yml', `-o=${ path.resolve(outputDir, './cplusplus')}`]) + .it('fails when no namespace provided', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: In order to generate models to C++, we need to know which namespace they are under. Add `--namespace=NAMESPACE` to set the desired namespace.\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); + describe('for Java', () => { test .stderr() @@ -179,8 +248,8 @@ describe('models', () => { done(); }); }); - - describe('for Go', () => { + + describe('for Go', () => { test .stderr() .stdout() @@ -203,7 +272,7 @@ describe('models', () => { }); }); - describe('for Kotlin', () => { + describe('for Kotlin', () => { test .stderr() .stdout() @@ -226,7 +295,7 @@ describe('models', () => { }); }); - describe('for Dart', () => { + describe('for Dart', () => { test .stderr() .stdout() @@ -249,6 +318,28 @@ describe('models', () => { }); }); + describe('for PHP', () => { + test + .stderr() + .stdout() + .command([...generalOptions, 'php', './test/specification.yml', `-o=${ path.resolve(outputDir, './php')}`, '--namespace=\'asyncapi.models\'']) + .it('works when file path is passed', (ctx, done) => { + expect(ctx.stderr).toEqual(''); + expect(ctx.stdout).toContain( + 'Successfully generated the following models: ' + ); + done(); + }); + test + .stderr() + .stdout() + .command([...generalOptions, 'php', './test/specification.yml', `-o=${ path.resolve(outputDir, './php')}`]) + .it('fails when no namespace defined', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: In order to generate models to PHP, we need to know which namespace they are under. Add `--namespace=NAMESPACE` to set the desired namespace.\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); describe('with logging diagnostics', () => { test .stderr()