From 94790a8cdc25bd331991b6b877cfc6eaf639ff83 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 27 Jul 2023 02:45:50 +0200 Subject: [PATCH] fix: add v3 checks for all commands (#697) --- package-lock.json | 354 +++++++++++--------- package.json | 4 +- src/commands/bundle.ts | 18 +- src/commands/convert.ts | 2 +- src/commands/diff.ts | 13 +- src/commands/generate/fromTemplate.ts | 35 +- src/commands/generate/models.ts | 3 + src/commands/optimize.ts | 28 +- src/commands/validate.ts | 2 +- src/models/SpecificationFile.ts | 17 +- test/commands/bundle/bundle.test.ts | 15 + test/commands/diff.test.ts | 22 ++ test/commands/generate/fromTemplate.test.ts | 15 + test/commands/generate/models.test.ts | 14 +- test/commands/optimize.test.ts | 13 + test/specification-v3.yml | 258 ++++++++++++++ 16 files changed, 640 insertions(+), 173 deletions(-) create mode 100644 test/specification-v3.yml diff --git a/package-lock.json b/package-lock.json index 9bc6b17d9a7..6bb9af8f96b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "fs-extra": "^11.1.0", "indent-string": "^4.0.0", "inquirer": "^8.2.0", + "js-yaml": "^4.1.0", "lodash.template": "^4.4.0", "node-fetch": "^2.0.0", "oclif": "^3.7.3", @@ -56,6 +57,7 @@ "@types/fs-extra": "^11.0.1", "@types/inquirer": "^8.1.3", "@types/jest": "^29.0.3", + "@types/js-yaml": "^4.0.5", "@types/lodash.template": "^4.4.4", "@types/node": "^10.17.60", "@types/node-fetch": "^2.5.12", @@ -115,22 +117,6 @@ "js-yaml": "^4.1.0" } }, - "node_modules/@apidevtools/json-schema-ref-parser/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@apidevtools/json-schema-ref-parser/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@apidevtools/openapi-schemas": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz", @@ -171,6 +157,18 @@ "js-yaml": "^3.13.1" } }, + "node_modules/@apidevtools/swagger-parser/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@asyncapi/avro-schema-parser": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@asyncapi/avro-schema-parser/-/avro-schema-parser-3.0.2.tgz", @@ -193,22 +191,6 @@ "lodash": "^4.17.21" } }, - "node_modules/@asyncapi/bundler/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@asyncapi/bundler/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@asyncapi/bundler/node_modules/jsonpath-plus": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz", @@ -226,6 +208,18 @@ "js-yaml": "^3.14.1" } }, + "node_modules/@asyncapi/converter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@asyncapi/diff": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@asyncapi/diff/-/diff-0.4.1.tgz", @@ -236,22 +230,6 @@ "json2md": "^1.12.0" } }, - "node_modules/@asyncapi/diff/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@asyncapi/diff/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@asyncapi/generator": { "version": "1.10.10", "resolved": "https://registry.npmjs.org/@asyncapi/generator/-/generator-1.10.10.tgz", @@ -372,6 +350,18 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@asyncapi/generator-react-sdk/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@asyncapi/generator-react-sdk/node_modules/react": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", @@ -400,6 +390,18 @@ "node": ">=0.10.0" } }, + "node_modules/@asyncapi/generator/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "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", @@ -519,22 +521,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@asyncapi/optimizer/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@asyncapi/optimizer/node_modules/js-yaml/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/@asyncapi/optimizer/node_modules/jsonpath-plus": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz", @@ -575,22 +561,6 @@ "@types/json-schema": "^7.0.11" } }, - "node_modules/@asyncapi/parser/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@asyncapi/parser/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@asyncapi/raml-dt-schema-parser": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@asyncapi/raml-dt-schema-parser/-/raml-dt-schema-parser-4.0.3.tgz", @@ -602,22 +572,6 @@ "webapi-parser": "^0.5.0" } }, - "node_modules/@asyncapi/raml-dt-schema-parser/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/@asyncapi/raml-dt-schema-parser/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@asyncapi/react-component": { "version": "1.0.0-next.47", "resolved": "https://registry.npmjs.org/@asyncapi/react-component/-/react-component-1.0.0-next.47.tgz", @@ -698,6 +652,18 @@ "node": ">=10" } }, + "node_modules/@asyncapi/react-component/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@asyncapi/specs": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@asyncapi/specs/-/specs-4.2.0.tgz", @@ -831,11 +797,6 @@ "react-dom": ">=17" } }, - "node_modules/@asyncapi/studio/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, "node_modules/@asyncapi/studio/node_modules/conventional-changelog-conventionalcommits": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-5.0.0.tgz", @@ -849,17 +810,6 @@ "node": ">=10" } }, - "node_modules/@asyncapi/studio/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@asyncapi/studio/node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -2743,12 +2693,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "13.17.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", @@ -2764,18 +2708,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -2975,6 +2907,19 @@ "node": ">=8" } }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -3745,6 +3690,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@oclif/core/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@oclif/core/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -3909,6 +3866,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@oclif/plugin-help/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@oclif/plugin-help/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -4011,6 +3980,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@oclif/plugin-not-found/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@oclif/plugin-not-found/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -4116,6 +4097,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@oclif/plugin-warn-if-update-available/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@oclif/plugin-warn-if-update-available/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5338,6 +5331,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -9011,6 +9010,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-config-oclif-typescript/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "peer": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/eslint-config-oclif-typescript/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -9592,12 +9605,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/eslint/node_modules/eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", @@ -9667,18 +9674,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -10826,6 +10821,19 @@ "node": ">=0.10.0" } }, + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/grouped-queue": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-2.0.0.tgz", @@ -12520,17 +12528,21 @@ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -12959,6 +12971,18 @@ "node": ">=6" } }, + "node_modules/load-yaml-file/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/load-yaml-file/node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -14326,6 +14350,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/oclif/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/oclif/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -15316,6 +15352,18 @@ "node": ">= 6" } }, + "node_modules/ramldt2jsonschema/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/randomatic": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", diff --git a/package.json b/package.json index 1182a2b6991..ec3f651741c 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,8 @@ "strip-ansi": "^6.0.0", "unzipper": "^0.10.11", "wrap-ansi": "^4.0.0", - "ws": "^8.2.3" + "ws": "^8.2.3", + "js-yaml": "^4.1.0" }, "devDependencies": { "@asyncapi/minimaltemplate": "./test/minimaltemplate", @@ -61,6 +62,7 @@ "@types/ws": "^8.2.0", "@typescript-eslint/eslint-plugin": "^5.38.1", "@typescript-eslint/parser": "^5.38.1", + "@types/js-yaml": "^4.0.5", "acorn": "^8.5.0", "chai": "^4.3.6", "cross-env": "^7.0.3", diff --git a/src/commands/bundle.ts b/src/commands/bundle.ts index 1ec94769440..d014fbbe2ff 100644 --- a/src/commands/bundle.ts +++ b/src/commands/bundle.ts @@ -4,7 +4,7 @@ import Command from '../base'; import bundle from '@asyncapi/bundler'; import { promises } from 'fs'; import path from 'path'; -import { load } from '../models/SpecificationFile'; +import { Specification, load } from '../models/SpecificationFile'; const { writeFile } = promises; @@ -32,9 +32,19 @@ export default class Bundle extends Command { let baseFile; const outputFormat = path.extname(argv[0]); const AsyncAPIFiles = await this.loadFiles(argv); + + const containsAsyncAPI3 = AsyncAPIFiles.filter((file) => { + return file.isAsyncAPI3(); + }); + if (containsAsyncAPI3.length > 0) { + this.error('One of the files you tried to bundle is AsyncAPI v3 format, the bundle command does not support it yet, please checkout https://github.com/asyncapi/bundler/issues/133'); + } + if (flags.base) {baseFile = (await load(flags.base)).text();} - const document = await bundle(AsyncAPIFiles, + const fileContents = AsyncAPIFiles.map((file) => file.text()); + + const document = await bundle(fileContents, { referenceIntoComponents: flags['reference-into-components'], base: baseFile @@ -65,11 +75,11 @@ export default class Bundle extends Command { } } - async loadFiles(filepaths: string[]): Promise { + async loadFiles(filepaths: string[]): Promise { const files = []; for (const filepath of filepaths) { const file = await load(filepath); - files.push(file.text()); + files.push(file); } return files; } diff --git a/src/commands/convert.ts b/src/commands/convert.ts index 539ecdf69f5..fb265bf7dbf 100644 --- a/src/commands/convert.ts +++ b/src/commands/convert.ts @@ -47,7 +47,7 @@ export default class Convert extends Command { this.log(`URL ${specFile.getFileURL()} successfully converted!`); } } - + if (typeof convertedFile === 'object') { convertedFileFormatted = JSON.stringify(convertedFile, null, 4); } else { diff --git a/src/commands/diff.ts b/src/commands/diff.ts index 7255cfa2518..c515fafc26f 100644 --- a/src/commands/diff.ts +++ b/src/commands/diff.ts @@ -86,6 +86,11 @@ export default class Diff extends Command { try { firstDocument = await load(firstDocumentPath); + + if (firstDocument.isAsyncAPI3()) { + this.error('Diff command does not support AsyncAPI v3 yet which was your first document, please checkout https://github.com/asyncapi/diff/issues/154'); + } + enableWatch(watchMode, { spec: firstDocument, handler: this, @@ -107,6 +112,11 @@ export default class Diff extends Command { try { secondDocument = await load(secondDocumentPath); + + if (secondDocument.isAsyncAPI3()) { + this.error('Diff command does not support AsyncAPI v3 yet which was your second document, please checkout https://github.com/asyncapi/diff/issues/154'); + } + enableWatch(watchMode, { spec: secondDocument, handler: this, @@ -265,8 +275,7 @@ function throwOnBreakingChange(diffOutput: AsyncAPIDiff, outputFormat: string) { const breakingChanges = diffOutput.breaking(); if ( (outputFormat === 'json' && breakingChanges.length !== 0) || - ((outputFormat === 'yaml' || outputFormat === 'yml') && breakingChanges !== '[]\n') || - (outputFormat === 'md' && breakingChanges.length !== 0) + ((outputFormat === 'yaml' || outputFormat === 'yml') && breakingChanges !== '[]\n') ) { throw new DiffBreakingChangeError(); } diff --git a/src/commands/generate/fromTemplate.ts b/src/commands/generate/fromTemplate.ts index dbb679026ca..81624dc5cb3 100644 --- a/src/commands/generate/fromTemplate.ts +++ b/src/commands/generate/fromTemplate.ts @@ -30,6 +30,32 @@ interface ParsedFlags { mapBaseUrlToFolder: IMapBaseUrlToFlag } +const templatesNotSupportingV3: Record = { + '@asyncapi/minimaltemplate': 'some link', // For testing purpose + '@asyncapi/html-template': 'https://github.com/asyncapi/html-template/issues/430', + '@asyncapi/dotnet-nats-template': 'https://github.com/asyncapi/dotnet-nats-template/issues/384', + '@asyncapi/ts-nats-template': 'https://github.com/asyncapi/ts-nats-template/issues/545', + '@asyncapi/python-paho-template': 'https://github.com/asyncapi/python-paho-template/issues/189', + '@asyncapi/nodejs-ws-template': 'https://github.com/asyncapi/nodejs-ws-template/issues/294', + '@asyncapi/java-spring-cloud-stream-template': 'https://github.com/asyncapi/java-spring-cloud-stream-template/issues/336', + '@asyncapi/go-watermill-template': 'https://github.com/asyncapi/go-watermill-template/issues/243', + '@asyncapi/java-spring-template': 'https://github.com/asyncapi/java-spring-template/issues/308', + '@asyncapi/markdown-template': 'https://github.com/asyncapi/markdown-template/issues/341', + '@asyncapi/nodejs-template': 'https://github.com/asyncapi/nodejs-template/issues/215', + '@asyncapi/java-template': 'https://github.com/asyncapi/java-template/issues/118', + '@asyncapi/php-template': 'https://github.com/asyncapi/php-template/issues/191' +}; + +/** + * Verify that a given template support v3, if not, return the link to the issue that needs to be solved. + */ +function verifyTemplateSupportForV3(template: string) { + if (templatesNotSupportingV3[`${template}`] !== undefined) { + return templatesNotSupportingV3[`${template}`]; + } + return undefined; +} + export default class Template extends Command { static description = 'Generates whatever you want using templates compatible with AsyncAPI Generator.'; @@ -99,6 +125,7 @@ export default class Template extends Command { mapBaseUrlToFolder: parsedFlags.mapBaseUrlToFolder, disabledHooks: parsedFlags.disableHooks, }; + const asyncapiInput = (await load(asyncapi)) || (await load()); const watchTemplate = flags['watch']; const genOption: any = {}; @@ -106,7 +133,13 @@ export default class Template extends Command { genOption.resolve = {resolve: this.getMapBaseUrlToFolderResolver(parsedFlags.mapBaseUrlToFolder)}; } - await this.generate(asyncapi, template, output, options, genOption); + if (asyncapiInput.isAsyncAPI3()) { + const v3IssueLink = verifyTemplateSupportForV3(template); + if (v3IssueLink !== undefined) { + this.error(`${template} template does not support AsyncAPI v3 documents, please checkout ${v3IssueLink}`); + } + } + await this.generate(asyncapi, template, output, options, genOption); if (watchTemplate) { const watcherHandler = this.watcherHandler(asyncapi, template, output, options, genOption); await this.runWatchMode(asyncapi, template, output, watcherHandler); diff --git a/src/commands/generate/models.ts b/src/commands/generate/models.ts index fcd47035e25..daf976e4d5e 100644 --- a/src/commands/generate/models.ts +++ b/src/commands/generate/models.ts @@ -152,6 +152,9 @@ export default class Models extends Command { const { tsModelType, tsEnumType, tsIncludeComments, tsModuleSystem, tsExportType, tsJsonBinPack, tsMarshalling, tsExampleInstance, namespace, csharpAutoImplement, csharpArrayType, csharpNewtonsoft, csharpHashcode, csharpEqual, csharpSystemJson, packageName, output } = flags; const { language, file } = args; const inputFile = (await load(file)) || (await load()); + if (inputFile.isAsyncAPI3()) { + this.error('Generate Models command does not support AsyncAPI v3 yet, please checkout https://github.com/asyncapi/modelina/issues/1376'); + } const { document, diagnostics ,status } = await parse(this, inputFile, flags); if (!document || status === 'invalid') { const severityErrors = diagnostics.filter((obj) => obj.severity === 0); diff --git a/src/commands/optimize.ts b/src/commands/optimize.ts index d6948e04c2d..8c12c2dd57a 100644 --- a/src/commands/optimize.ts +++ b/src/commands/optimize.ts @@ -32,7 +32,7 @@ export default class Optimize extends Command { 'asyncapi optimize ./asyncapi.yaml --optimization=remove-components,reuse-components,move-to-components --no-tty', 'asyncapi optimize ./asyncapi.yaml --optimization=remove-components,reuse-components,move-to-components --output=terminal --no-tty', ]; - + static flags = { help: Flags.help({ char: 'h' }), optimization: Flags.string({char: 'p', default: Object.values(Optimizations), options: Object.values(Optimizations), multiple: true, description: 'select the type of optimizations that you want to apply.'}), @@ -48,10 +48,24 @@ export default class Optimize extends Command { const { args, flags } = await this.parse(Optimize); //NOSONAR const filePath = args['spec-file']; let specFile: Specification; + try { + specFile = await load(filePath); + } catch (err) { + this.error( + new ValidationError({ + type: 'invalid-file', + filepath: filePath, + }) + ); + } + + if (specFile.isAsyncAPI3()) { + this.error('Optimize command does not support AsyncAPI v3 yet, please checkout https://github.com/asyncapi/optimizer/issues/168'); + } + let optimizer: Optimizer; let report: Report; try { - specFile = await load(filePath); optimizer = new Optimizer(specFile.text()); report = await optimizer.getReport(); } catch (err) { @@ -65,7 +79,7 @@ export default class Optimize extends Command { this.isInteractive = !flags['no-tty']; this.optimizations = flags.optimization as Optimizations[]; this.outputMethod = flags.output as Outputs; - + if (!(report.moveToComponents?.length || report.removeComponents?.length || report.reuseComponents?.length)) { this.log(`No optimization has been applied since ${specFile.getFilePath() ?? specFile.getFileURL()} looks optimized!`); return; @@ -76,13 +90,13 @@ export default class Optimize extends Command { await this.interactiveRun(report); } - try { + try { const optimizedDocument = optimizer.getOptimizedDocument({rules: { moveToComponents: this.optimizations.includes(Optimizations.MOVE_TO_COMPONETS), removeComponents: this.optimizations.includes(Optimizations.REMOVE_COMPONENTS), reuseComponents: this.optimizations.includes(Optimizations.REUSE_COMPONENTS) }, output: Output.YAML}); - + const specPath = specFile.getFilePath(); let newPath = ''; if (specPath) { @@ -149,7 +163,7 @@ export default class Optimize extends Command { this.showOptimizations(report.reuseComponents); choices.push({name: 'reuse components', value: Optimizations.REUSE_COMPONENTS}); } - const optimizationRes = await inquirer.prompt([{ + const optimizationRes = await inquirer.prompt([{ name: 'optimization', message: 'select the type of optimization that you want to apply:', type: 'checkbox', @@ -158,7 +172,7 @@ export default class Optimize extends Command { }]); this.optimizations = optimizationRes.optimization; - + const outputRes = await inquirer.prompt([{ name: 'output', message: 'where do you want to save the result:', diff --git a/src/commands/validate.ts b/src/commands/validate.ts index 004b04183ec..7254b52f4f5 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -28,7 +28,7 @@ export default class Validate extends Command { if (watchMode) { specWatcher({ spec: specFile, handler: this, handlerName: 'validate' }); } - + await validate(this, specFile, flags); } } diff --git a/src/models/SpecificationFile.ts b/src/models/SpecificationFile.ts index 14335836797..e33c9118e4d 100644 --- a/src/models/SpecificationFile.ts +++ b/src/models/SpecificationFile.ts @@ -2,7 +2,7 @@ import { promises as fs } from 'fs'; import path from 'path'; import { URL } from 'url'; import fetch from 'node-fetch'; - +import yaml from 'js-yaml'; import { loadContext } from './Context'; import { ErrorLoadingSpec } from '../errors/specification-file'; import { MissingContextFileError } from '../errors/context-error'; @@ -34,6 +34,19 @@ export class Specification { } } + isAsyncAPI3() { + const jsObj = this.toJson(); + return jsObj.asyncapi === '3.0.0'; + } + + toJson(): Record { + try { + return yaml.load(this.spec, {json: true}) as Record; + } catch (e) { + return JSON.parse(this.spec); + } + } + text() { return this.spec; } @@ -137,7 +150,7 @@ export async function load(filePathOrContextName?: string, loadType?: LoadType): if (e instanceof MissingContextFileError) { throw new ErrorLoadingSpec(); } - + throw e; } } diff --git a/test/commands/bundle/bundle.test.ts b/test/commands/bundle/bundle.test.ts index 170a0819be8..ff06879a96f 100644 --- a/test/commands/bundle/bundle.test.ts +++ b/test/commands/bundle/bundle.test.ts @@ -4,6 +4,7 @@ import path from 'path'; import { fileCleanup } from '../../testHelper'; const spec = fs.readFileSync('./test/commands/bundle/final-asyncapi.yaml', {encoding: 'utf-8'}); +const asyncapiv3 = './test/specification-v3.yml'; function validateGeneratedSpec(filePath, spec) { const generatedSPec = fs.readFileSync(path.resolve(filePath), { encoding: 'utf-8' }); @@ -11,6 +12,20 @@ function validateGeneratedSpec(filePath, spec) { } describe('bundle', () => { + describe('should handle AsyncAPI v3 document correctly', () => { + test + .stderr() + .stdout() + .command([ + 'bundle', + asyncapiv3, + '--output=./test/commands/bundle/final.yaml']) + .it('give error', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: One of the files you tried to bundle is AsyncAPI v3 format, the bundle command does not support it yet, please checkout https://github.com/asyncapi/bundler/issues/133\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); test .stdout() .command([ diff --git a/test/commands/diff.test.ts b/test/commands/diff.test.ts index e82b08f63de..fb4efa9c1f3 100644 --- a/test/commands/diff.test.ts +++ b/test/commands/diff.test.ts @@ -1,6 +1,8 @@ /* eslint-disable sonarjs/no-duplicate-string */ import { test } from '@oclif/test'; +const asyncapiv3 = './test/specification-v3.yml'; +const asyncapiv2 = './test/specification.yml'; const noChangesJson = '"{\\n \\"changes\\": []\\n}\\n"'; const breakingChangesJson = '"[\\n {\\n \\"action\\": \\"edit\\",\\n \\"path\\": \\"/servers/mosquitto/protocol\\",\\n \\"before\\": \\"mqtt\\",\\n \\"after\\": \\"http\\",\\n \\"type\\": \\"breaking\\"\\n },\\n {\\n \\"action\\": \\"edit\\",\\n \\"path\\": \\"/servers/mosquitto/url\\",\\n \\"before\\": \\"mqtt://test.mosquitto.org\\",\\n \\"after\\": \\"http://test.mosquitto.org\\",\\n \\"type\\": \\"breaking\\"\\n }\\n]\\n"'; const nonBreakingChangesJson = '"[\\n {\\n \\"action\\": \\"add\\",\\n \\"path\\": \\"/channels/user~1signedup\\",\\n \\"after\\": {\\n \\"subscribe\\": {\\n \\"message\\": {\\n \\"payload\\": {\\n \\"type\\": \\"object\\",\\n \\"properties\\": {\\n \\"displayName\\": {\\n \\"type\\": \\"string\\",\\n \\"description\\": \\"Name of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"email\\": {\\n \\"type\\": \\"string\\",\\n \\"format\\": \\"email\\",\\n \\"description\\": \\"Email of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n }\\n },\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"x-parser-message-name\\": \\"UserSignedUp\\",\\n \\"x-parser-original-schema-format\\": \\"application/vnd.aai.asyncapi;version=2.1.0\\",\\n \\"schemaFormat\\": \\"application/vnd.aai.asyncapi;version=2.1.0\\",\\n \\"x-parser-original-payload\\": {\\n \\"type\\": \\"object\\",\\n \\"properties\\": {\\n \\"displayName\\": {\\n \\"type\\": \\"string\\",\\n \\"description\\": \\"Name of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"email\\": {\\n \\"type\\": \\"string\\",\\n \\"format\\": \\"email\\",\\n \\"description\\": \\"Email of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n }\\n },\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"x-parser-message-parsed\\": true\\n }\\n }\\n },\\n \\"type\\": \\"non-breaking\\"\\n },\\n {\\n \\"action\\": \\"edit\\",\\n \\"path\\": \\"/info/title\\",\\n \\"before\\": \\"Streetlights API\\",\\n \\"after\\": \\"Streetlights API V2\\",\\n \\"type\\": \\"non-breaking\\"\\n },\\n {\\n \\"action\\": \\"add\\",\\n \\"path\\": \\"/components\\",\\n \\"after\\": {\\n \\"messages\\": {\\n \\"UserSignedUp\\": {\\n \\"payload\\": {\\n \\"type\\": \\"object\\",\\n \\"properties\\": {\\n \\"displayName\\": {\\n \\"type\\": \\"string\\",\\n \\"description\\": \\"Name of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"email\\": {\\n \\"type\\": \\"string\\",\\n \\"format\\": \\"email\\",\\n \\"description\\": \\"Email of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n }\\n },\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"x-parser-message-name\\": \\"UserSignedUp\\",\\n \\"x-parser-original-schema-format\\": \\"application/vnd.aai.asyncapi;version=2.1.0\\",\\n \\"schemaFormat\\": \\"application/vnd.aai.asyncapi;version=2.1.0\\",\\n \\"x-parser-original-payload\\": {\\n \\"type\\": \\"object\\",\\n \\"properties\\": {\\n \\"displayName\\": {\\n \\"type\\": \\"string\\",\\n \\"description\\": \\"Name of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"email\\": {\\n \\"type\\": \\"string\\",\\n \\"format\\": \\"email\\",\\n \\"description\\": \\"Email of the user\\",\\n \\"x-parser-schema-id\\": \\"\\"\\n }\\n },\\n \\"x-parser-schema-id\\": \\"\\"\\n },\\n \\"x-parser-message-parsed\\": true\\n }\\n }\\n },\\n \\"type\\": \\"non-breaking\\"\\n }\\n]\\n"'; @@ -16,6 +18,26 @@ const markdownJsonOutput = "\"## Unclassified\\n\\n\\n - **Path**: `/channels/li const markdownYamlOutput = '"## Unclassified\\n\\n\\n - **Path**: `/channels/light~1measured/publish/message/x-parser-original-payload/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/x-parser-original-payload/properties/sentAt/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/x-parser-original-payload/properties/lumens/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/x-parser-original-payload/properties/id/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/x-parser-original-payload/properties/id/minimum`\\n - **Action**: edit\\n - **Before**: 0\\n - **After**: 1\\n \\n - **Path**: `/channels/light~1measured/publish/message/payload/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/payload/properties/sentAt/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/payload/properties/lumens/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/payload/properties/id/x-parser-schema-id`\\n - **Action**: edit\\n - **Before**: \\n - **After**: \\n \\n - **Path**: `/channels/light~1measured/publish/message/payload/properties/id/minimum`\\n - **Action**: edit\\n - **Before**: 0\\n - **After**: 1\\n \\n\\n## Non-breaking\\n\\n\\n - **Path**: `/channels/user~1signedup`\\n - **Action**: add\\n -
\\n After \\n \\n ```yaml\\n subscribe:\\n message:\\n payload:\\n type: object\\n properties:\\n displayName:\\n type: string\\n description: Name of the user\\n x-parser-schema-id: \\n email:\\n type: string\\n format: email\\n description: Email of the user\\n x-parser-schema-id: \\n x-parser-schema-id: \\n x-parser-message-name: UserSignedUp\\n x-parser-original-schema-format: application/vnd.aai.asyncapi;version=2.1.0\\n schemaFormat: application/vnd.aai.asyncapi;version=2.1.0\\n x-parser-original-payload:\\n type: object\\n properties:\\n displayName:\\n type: string\\n description: Name of the user\\n x-parser-schema-id: \\n email:\\n type: string\\n format: email\\n description: Email of the user\\n x-parser-schema-id: \\n x-parser-schema-id: \\n x-parser-message-parsed: true\\n \\n ``` \\n
\\n \\n \\n - **Path**: `/info/title`\\n - **Action**: edit\\n - **Before**: Streetlights API\\n - **After**: Streetlights API V2\\n \\n - **Path**: `/components`\\n - **Action**: add\\n -
\\n After \\n \\n ```yaml\\n messages:\\n UserSignedUp:\\n payload:\\n type: object\\n properties:\\n displayName:\\n type: string\\n description: Name of the user\\n x-parser-schema-id: \\n email:\\n type: string\\n format: email\\n description: Email of the user\\n x-parser-schema-id: \\n x-parser-schema-id: \\n x-parser-message-name: UserSignedUp\\n x-parser-original-schema-format: application/vnd.aai.asyncapi;version=2.1.0\\n schemaFormat: application/vnd.aai.asyncapi;version=2.1.0\\n x-parser-original-payload:\\n type: object\\n properties:\\n displayName:\\n type: string\\n description: Name of the user\\n x-parser-schema-id: \\n email:\\n type: string\\n format: email\\n description: Email of the user\\n x-parser-schema-id: \\n x-parser-schema-id: \\n x-parser-message-parsed: true\\n \\n ``` \\n
\\n \\n \\n\\n## Breaking\\n\\n\\n - **Path**: `/servers/mosquitto/protocol`\\n - **Action**: edit\\n - **Before**: mqtt\\n - **After**: http\\n \\n - **Path**: `/servers/mosquitto/url`\\n - **Action**: edit\\n - **Before**: mqtt://test.mosquitto.org\\n - **After**: http://test.mosquitto.org\\n \\n\\n"'; describe('diff', () => { + describe('should handle AsyncAPI v3 document correctly', () => { + test + .stderr() + .stdout() + .command(['diff', asyncapiv3, asyncapiv2]) + .it('give error when first document', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: Diff command does not support AsyncAPI v3 yet which was your first document, please checkout https://github.com/asyncapi/diff/issues/154\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + test + .stderr() + .stdout() + .command(['diff', asyncapiv2, asyncapiv3]) + .it('give error when second document', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: Diff command does not support AsyncAPI v3 yet which was your second document, please checkout https://github.com/asyncapi/diff/issues/154\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); describe('with file paths, and there are no difference between the files', () => { test .stderr() diff --git a/test/commands/generate/fromTemplate.test.ts b/test/commands/generate/fromTemplate.test.ts index 0faa2f55041..7a315b8bd13 100644 --- a/test/commands/generate/fromTemplate.test.ts +++ b/test/commands/generate/fromTemplate.test.ts @@ -8,6 +8,7 @@ const generalOptions = [ './test/specification.yml', '@asyncapi/minimaltemplate', ]; +const asyncapiv3 = './test/specification-v3.yml'; function cleanup(filepath: string) { rimraf.sync(filepath); @@ -28,6 +29,20 @@ describe('template', () => { done(); }); + describe('should handle AsyncAPI v3 document correctly', () => { + test + .stderr() + .stdout() + .command([ + 'generate:fromTemplate', + asyncapiv3, + '@asyncapi/minimaltemplate']) + .it('give error', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: @asyncapi/minimaltemplate template does not support AsyncAPI v3 documents, please checkout some link\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); describe('git clash', () => { const pathToOutput = './test/docs/2'; beforeAll(() => { diff --git a/test/commands/generate/models.test.ts b/test/commands/generate/models.test.ts index fe92b6478f9..c7a47c33933 100644 --- a/test/commands/generate/models.test.ts +++ b/test/commands/generate/models.test.ts @@ -5,7 +5,7 @@ import { test } from '@oclif/test'; import { createMockServer, stopMockServer } from '../../testHelper'; const generalOptions = ['generate:models']; const outputDir = './test/commands/generate/models'; - +const asyncapiv3 = './test/specification-v3.yml'; describe('models', () => { beforeAll(() => { createMockServer(); @@ -13,6 +13,18 @@ describe('models', () => { afterAll(() => { stopMockServer(); }); + describe('should handle AsyncAPI v3 document correctly', () => { + test + .stderr() + .stdout() + .command([ + ...generalOptions, 'typescript', asyncapiv3]) + .it('give error', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: Generate Models command does not support AsyncAPI v3 yet, please checkout https://github.com/asyncapi/modelina/issues/1376\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); test .stderr() .stdout() diff --git a/test/commands/optimize.test.ts b/test/commands/optimize.test.ts index b4d774093f1..c48b83529aa 100644 --- a/test/commands/optimize.test.ts +++ b/test/commands/optimize.test.ts @@ -8,8 +8,21 @@ const testHelper = new TestHelper(); const optimizedFilePath = './test/specification.yml'; const unoptimizedFile = './test/dummyspec/unoptimizedSpec.yml'; const invalidFile = './test/specification-invalid.yml'; +const asyncapiv3 = './test/specification-v3.yml'; describe('optimize', () => { + describe('should handle AsyncAPI v3 document correctly', () => { + test + .stderr() + .stdout() + .command(['optimize', asyncapiv3]) + .it('give error', (ctx, done) => { + expect(ctx.stderr).toEqual('Error: Optimize command does not support AsyncAPI v3 yet, please checkout https://github.com/asyncapi/optimizer/issues/168\n'); + expect(ctx.stdout).toEqual(''); + done(); + }); + }); + describe('no optimization needed', () => { beforeEach(() => { testHelper.createDummyContextFile(); diff --git a/test/specification-v3.yml b/test/specification-v3.yml new file mode 100644 index 00000000000..93cdabbb181 --- /dev/null +++ b/test/specification-v3.yml @@ -0,0 +1,258 @@ +asyncapi: 3.0.0 +id: 'urn:example:com:smartylighting:streetlights:server' +info: + title: AsyncAPI Sample App + version: 1.0.1 + description: This is a sample app. + termsOfService: 'https://asyncapi.com/terms/' + contact: + name: API Support + url: 'https://www.asyncapi.com/support' + email: support@asyncapi.org + license: + name: Apache 2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' + tags: + - name: e-commerce + - name: another-tag + description: Description... + externalDocs: + description: Find more info here + url: 'https://www.asyncapi.com' +defaultContentType: application/json +servers: + default: + host: 'api.streetlights.smartylighting.com:{port}' + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - $ref: '#/components/securitySchemes/apiKey' + - type: oauth2 + flows: + implicit: + authorizationUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + scopes: + - 'write:pets' + - type: openIdConnect + openIdConnectUrl: openIdConnectUrl + scopes: + - 'some:scope:1' + - 'some:scope:2' + production: + host: 'api.streetlights.smartylighting.com:{port}' + pathname: /some/path + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - $ref: '#/components/securitySchemes/apiKey' + withProtocol: + host: 'api.streetlights.smartylighting.com:{port}' + pathname: /some/path + protocol: mqtt + description: Test broker + variables: + port: + description: Secure connection (TLS) is available through port 8883. + default: '1883' + enum: + - '1883' + - '8883' + security: + - $ref: '#/components/securitySchemes/apiKey' +channels: + 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured': + address: 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured' + messages: + lightMeasured.message: + payload: + type: object + servers: + - $ref: '#/servers/production' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on': + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on' + messages: + publish.message: + $ref: '#/components/messages/lightMeasured' + subscribe.message.0: + $ref: '#/components/messages/turnOnOff' + customMessageId: + messageId: customMessageId + payload: + type: object + subscribe.message.2: + payload: + type: object + subscribe.message.3: + $ref: 'https://example.com/message' + servers: + - $ref: '#/servers/default' + - $ref: '#/servers/production' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + customChannelId: + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off' + messages: + turnOnOff.message: + $ref: '#/components/messages/turnOnOff' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' + x-channelId: customChannelId + 'smartylighting/streetlights/1/0/action/{streetlightId}/dim': + address: 'smartylighting/streetlights/1/0/action/{streetlightId}/dim' + messages: + dimLight.message: + $ref: '#/components/messages/dimLight' + parameters: + streetlightId: + $ref: '#/components/parameters/streetlightId' +operations: + lightMeasured: + action: receive + channel: + $ref: >- + #/channels/smartylighting~1streetlights~11~10~1event~1{streetlightId}~1lighting~1measured + messages: + - $ref: >- + #/channels/smartylighting~1streetlights~11~10~1event~1{streetlightId}~1lighting~1measured/messages/lightMeasured.message + 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on.publish': + action: receive + channel: + $ref: >- + #/channels/smartylighting~1streetlights~11~10~1action~1{streetlightId}~1turn~1on + messages: + - $ref: '#/components/messages/lightMeasured' + 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on.subscribe': + action: send + channel: + $ref: >- + #/channels/smartylighting~1streetlights~11~10~1action~1{streetlightId}~1turn~1on + messages: + - $ref: '#/components/messages/turnOnOff' + - $ref: >- + #/channels/smartylighting~1streetlights~11~10~1action~1{streetlightId}~1turn~1on/messages/customMessageId + - $ref: >- + #/channels/smartylighting~1streetlights~11~10~1action~1{streetlightId}~1turn~1on/messages/subscribe.message.2 + - $ref: 'https://example.com/message' + turnOnOff: + action: send + channel: + $ref: '#/channels/customChannelId' + messages: + - $ref: '#/components/messages/turnOnOff' + dimLight: + action: send + channel: + $ref: >- + #/channels/smartylighting~1streetlights~11~10~1action~1{streetlightId}~1dim + security: + - type: oauth2 + flows: + implicit: + authorizationUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + scopes: + - 'write:pets' + messages: + - $ref: '#/components/messages/dimLight' +components: + messages: + lightMeasured: + summary: >- + Inform about environmental lighting conditions for a particular + streetlight. + payload: + $ref: '#/components/schemas/lightMeasuredPayload' + turnOnOff: + summary: Command a particular streetlight to turn the lights on or off. + payload: + $ref: '#/components/schemas/turnOnOffPayload' + dimLight: + summary: Command a particular streetlight to dim the lights. + payload: + $ref: '#/components/schemas/dimLightPayload' + schemas: + lightMeasuredPayload: + type: object + properties: + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + $ref: '#/components/schemas/sentAt' + turnOnOffPayload: + type: object + properties: + command: + type: string + enum: + - 'on' + - 'off' + description: Whether to turn on or off the light. + sentAt: + $ref: '#/components/schemas/sentAt' + dimLightPayload: + type: object + properties: + percentage: + type: integer + description: Percentage to which the light should be dimmed to. + minimum: 0 + maximum: 100 + sentAt: + $ref: '#/components/schemas/sentAt' + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + securitySchemes: + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + flows: + type: oauth2 + flows: + implicit: + authorizationUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + openIdConnect: + type: openIdConnect + openIdConnectUrl: openIdConnectUrl + unusedFlows: + type: oauth2 + flows: + implicit: + authorizationUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + parameters: + streetlightId: + description: The ID of the streetlight.